sio.c revision 48557
1109864Sjeff/*- 2165762Sjeff * Copyright (c) 1991 The Regents of the University of California. 3109864Sjeff * All rights reserved. 4109864Sjeff * 5109864Sjeff * Redistribution and use in source and binary forms, with or without 6109864Sjeff * modification, are permitted provided that the following conditions 7109864Sjeff * are met: 8109864Sjeff * 1. Redistributions of source code must retain the above copyright 9109864Sjeff * notice, this list of conditions and the following disclaimer. 10109864Sjeff * 2. Redistributions in binary form must reproduce the above copyright 11109864Sjeff * notice, this list of conditions and the following disclaimer in the 12109864Sjeff * documentation and/or other materials provided with the distribution. 13109864Sjeff * 3. All advertising materials mentioning features or use of this software 14109864Sjeff * must display the following acknowledgement: 15109864Sjeff * This product includes software developed by the University of 16109864Sjeff * California, Berkeley and its contributors. 17109864Sjeff * 4. Neither the name of the University nor the names of its contributors 18109864Sjeff * may be used to endorse or promote products derived from this software 19109864Sjeff * without specific prior written permission. 20109864Sjeff * 21109864Sjeff * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22109864Sjeff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23109864Sjeff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24109864Sjeff * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25109864Sjeff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26109864Sjeff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27171482Sjeff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28171482Sjeff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29171482Sjeff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30171482Sjeff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31171482Sjeff * SUCH DAMAGE. 32171482Sjeff * 33172293Sjeff * $Id: sio.c,v 1.98 1999/06/24 10:51:35 kato Exp $ 34171482Sjeff * from: @(#)com.c 7.5 (Berkeley) 5/16/91 35171482Sjeff * from: i386/isa sio.c,v 1.234 36171482Sjeff */ 37171482Sjeff 38116182Sobrien#include "opt_comconsole.h" 39116182Sobrien#include "opt_compat.h" 40116182Sobrien#include "opt_ddb.h" 41147565Speter#include "opt_devfs.h" 42147565Speter#include "opt_sio.h" 43134649Sscottl#include "sio.h" 44109864Sjeff/* #include "pnp.h" */ 45109864Sjeff#define NPNP 0 46131929Smarcel 47109864Sjeff/* 48109864Sjeff * Serial driver, based on 386BSD-0.1 com driver. 49109864Sjeff * Mostly rewritten to use pseudo-DMA. 50109864Sjeff * Works for National Semiconductor NS8250-NS16550AF UARTs. 51109864Sjeff * COM driver, based on HP dca driver. 52112966Sjeff * 53122038Sjeff * Changes for PC-Card integration: 54109864Sjeff * - Added PC-Card driver table and handlers 55109864Sjeff */ 56109864Sjeff/*=============================================================== 57109864Sjeff * 386BSD(98),FreeBSD-1.1x(98) com driver. 58109864Sjeff * ----- 59139453Sjhb * modified for PC9801 by M.Ishii 60161599Sdavidxu * Kyoto University Microcomputer Club (KMC) 61109864Sjeff * Chou "TEFUTEFU" Hirotomi 62176735Sjeff * Kyoto Univ. the faculty of medicine 63109864Sjeff *=============================================================== 64109864Sjeff * FreeBSD-2.0.1(98) sio driver. 65109864Sjeff * ----- 66109864Sjeff * modified for pc98 Internal i8251 and MICRO CORE MC16550II 67109864Sjeff * T.Koike(hfc01340@niftyserve.or.jp) 68145256Sjkoshy * implement kernel device configuration 69145256Sjkoshy * aizu@orient.center.nitech.ac.jp 70145256Sjkoshy * 71145256Sjkoshy * Notes. 72109864Sjeff * ----- 73121790Sjeff * PC98 localization based on 386BSD(98) com driver. Using its PC98 local 74109864Sjeff * functions. 75172887Sgrehan * This driver is under debugging,has bugs. 76172345Sjeff * 77166190Sjeff * 1) config 78166190Sjeff * options COM_MULTIPORT #if using MC16550II 79171482Sjeff * device sio0 at nec? port 0x30 tty irq 4 #internal 80166137Sjeff * device sio1 at nec? port 0xd2 tty irq 5 flags 0x101 #mc1 81166137Sjeff * device sio2 at nec? port 0x8d2 tty flags 0x101 #mc2 82171482Sjeff * # ~~~~~iobase ~~multi port flag 83171482Sjeff * # ~ master device is sio1 84146954Sjeff * 2) device 85164936Sjulian * cd /dev; MAKEDEV ttyd0 ttyd1 .. 86171482Sjeff * 3) /etc/rc.serial 87171482Sjeff * 57600bps is too fast for sio0(internal8251) 88164936Sjulian * my ex. 89177009Sjeff * #set default speed 9600 90171482Sjeff * modem() 91171482Sjeff * : 92171482Sjeff * stty </dev/ttyid$i crtscts 9600 93164936Sjulian * : # ~~~~ default speed(can change after init.) 94164936Sjulian * modem 0 1 2 95164936Sjulian * 4) COMCONSOLE 96134791Sjulian * not changed. 97164936Sjulian * 5) PC9861K,PIO9032B,B98_01 98166108Sjeff * not tested. 99166108Sjeff */ 100121790Sjeff/* 101164936Sjulian * modified for AIWA B98-01 102109864Sjeff * by T.Hatanou <hatanou@yasuda.comm.waseda.ac.jp> last update: 15 Sep.1995 103176735Sjeff * 104176735Sjeff * How to configure... 105176735Sjeff * # options COM_MULTIPORT # support for MICROCORE MC16550II 106176735Sjeff * ... comment-out this line, which will conflict with B98_01. 107109864Sjeff * options "B98_01" # support for AIWA B98-01 108165762Sjeff * device sio1 at nec? port 0x00d1 tty irq ? 109111857Sjeff * device sio2 at nec? port 0x00d5 tty irq ? 110165762Sjeff * ... you can leave these lines `irq ?', irq will be autodetected. 111165762Sjeff */ 112165796Sjeff/* 113165762Sjeff * Modified by Y.Takahashi of Kogakuin University. 114165762Sjeff */ 115165762Sjeff 116165762Sjeff#ifdef PC98 117165762Sjeff#define COM_IF_INTERNAL 0x00 118165762Sjeff#define COM_IF_PC9861K_1 0x01 119165796Sjeff#define COM_IF_PC9861K_2 0x02 120165762Sjeff#define COM_IF_IND_SS_1 0x03 121165762Sjeff#define COM_IF_IND_SS_2 0x04 122165830Sjeff#define COM_IF_PIO9032B_1 0x05 123165762Sjeff#define COM_IF_PIO9032B_2 0x06 124165762Sjeff#define COM_IF_B98_01_1 0x07 125165762Sjeff#define COM_IF_B98_01_2 0x08 126165762Sjeff#define COM_IF_END1 COM_IF_B98_01_2 127165762Sjeff#define COM_IF_RSA98 0x10 /* same as COM_IF_NS16550 */ 128165762Sjeff#define COM_IF_NS16550 0x11 129165762Sjeff#define COM_IF_SECOND_CCU 0x12 /* same as COM_IF_NS16550 */ 130165762Sjeff#define COM_IF_MC16550II 0x13 131165762Sjeff#define COM_IF_MCRS98 0x14 /* same as COM_IF_MC16550II */ 132116642Sjeff#define COM_IF_RSB3000 0x15 133165762Sjeff#define COM_IF_RSB384 0x16 134165762Sjeff#define COM_IF_MODEM_CARD 0x17 /* same as COM_IF_NS16550 */ 135109864Sjeff#define COM_IF_RSA98III 0x18 136165762Sjeff#define COM_IF_ESP98 0x19 137121869Sjeff#define COM_IF_END2 COM_IF_ESP98 138165762Sjeff#endif /* PC98 */ 139165762Sjeff 140170787Sjeff#include <sys/param.h> 141165762Sjeff#include <sys/systm.h> 142165762Sjeff#include <sys/reboot.h> 143165827Sjeff#include <sys/malloc.h> 144165762Sjeff#include <sys/tty.h> 145109864Sjeff#include <sys/proc.h> 146109864Sjeff#include <sys/module.h> 147165762Sjeff#include <sys/conf.h> 148165762Sjeff#include <sys/dkstat.h> 149165762Sjeff#include <sys/fcntl.h> 150165762Sjeff#include <sys/interrupt.h> 151109864Sjeff#include <sys/kernel.h> 152110645Sjeff#include <sys/syslog.h> 153110645Sjeff#include <sys/sysctl.h> 154121868Sjeff#include <sys/bus.h> 155116365Sjeff#include <machine/bus.h> 156111857Sjeff#include <sys/rman.h> 157109864Sjeff#ifdef DEVFS 158165762Sjeff#include <sys/devfsext.h> 159165762Sjeff#endif 160116365Sjeff#include <sys/timepps.h> 161116365Sjeff 162121126Sjeff#ifdef PC98 163111857Sjeff#include <pc98/pc98/pc98.h> 164109864Sjeff#include <pc98/pc98/pc98_machdep.h> 165165762Sjeff#include <i386/isa/ic/i8251.h> 166165762Sjeff#else 167165762Sjeff#include <isa/isareg.h> 168165762Sjeff#endif 169165762Sjeff#include <isa/isavar.h> 170171482Sjeff#include <machine/lock.h> 171109864Sjeff 172165762Sjeff#include <machine/clock.h> 173165762Sjeff#include <machine/ipl.h> 174165762Sjeff#ifndef SMP 175177009Sjeff#include <machine/lock.h> 176172345Sjeff#endif 177172345Sjeff#include <machine/resource.h> 178172345Sjeff 179172345Sjeff#include <isa/sioreg.h> 180171482Sjeff 181172345Sjeff#ifdef COM_ESP 182172345Sjeff#include <i386/isa/ic/esp.h> 183172345Sjeff#endif 184172345Sjeff#include <i386/isa/ic/ns16550.h> 185177085Sjeff#ifdef PC98 186109864Sjeff#include <i386/isa/ic/rsa.h> 187109864Sjeff#endif 188171482Sjeff 189171482Sjeff#if 0 190171482Sjeff 191109864Sjeff#include "card.h" 192164936Sjulian#if NCARD > 0 193177009Sjeff#include <sys/module.h> 194177009Sjeff#include <pccard/cardinfo.h> 195176735Sjeff#include <pccard/slot.h> 196171482Sjeff#endif 197176735Sjeff 198177009Sjeff#if NPNP > 0 199177009Sjeff#include <i386/isa/pnp.h> 200177009Sjeff#endif 201166557Sjeff 202166557Sjeff#endif 203177009Sjeff 204177009Sjeff#ifndef __i386__ 205177009Sjeff#define disable_intr() 0 206176735Sjeff#define enable_intr() 0 207171482Sjeff#endif 208109864Sjeff 209166108Sjeff#ifdef SMP 210123433Sjeff#define disable_intr() COM_DISABLE_INTR() 211176735Sjeff#define enable_intr() COM_ENABLE_INTR() 212123433Sjeff#endif /* SMP */ 213176735Sjeff 214176735Sjeff#ifndef EXTRA_SIO 215166108Sjeff#if NPNP > 0 216123433Sjeff#define EXTRA_SIO MAX_PNP_CARDS 217166108Sjeff#else 218166108Sjeff#define EXTRA_SIO 0 219171506Sjeff#endif 220172409Sjeff#endif 221166108Sjeff 222172409Sjeff#define NSIOTOT (NSIO + EXTRA_SIO) 223171506Sjeff 224171506Sjeff#define LOTS_OF_EVENTS 64 /* helps separate urgent events from input */ 225166108Sjeff 226166108Sjeff#define CALLOUT_MASK 0x80 227165620Sjeff#define CONTROL_MASK 0x60 228109864Sjeff#define CONTROL_INIT_STATE 0x20 229164936Sjulian#define CONTROL_LOCK_STATE 0x40 230172409Sjeff#define DEV_TO_UNIT(dev) (MINOR_TO_UNIT(minor(dev))) 231172409Sjeff#define MINOR_MAGIC_MASK (CALLOUT_MASK | CONTROL_MASK) 232129982Sjeff#define MINOR_TO_UNIT(mynor) ((mynor) & ~MINOR_MAGIC_MASK) 233164936Sjulian 234164936Sjulian#ifdef COM_MULTIPORT 235171713Sjeff/* checks in flags for multiport and which is multiport "master chip" 236123433Sjeff * for a given card 237164936Sjulian */ 238129982Sjeff#define COM_ISMULTIPORT(flags) ((flags) & 0x01) 239170315Sjeff#define COM_MPMASTER(flags) (((flags) >> 8) & 0x0ff) 240164936Sjulian#define COM_NOTAST4(flags) ((flags) & 0x04) 241164936Sjulian#endif /* COM_MULTIPORT */ 242110028Sjeff 243109864Sjeff#define COM_CONSOLE(flags) ((flags) & 0x10) 244171482Sjeff#define COM_FORCECONSOLE(flags) ((flags) & 0x20) 245171482Sjeff#define COM_LLCONSOLE(flags) ((flags) & 0x40) 246171482Sjeff#define COM_DEBUGGER(flags) ((flags) & 0x80) 247171482Sjeff#define COM_LOSESOUTINTS(flags) ((flags) & 0x08) 248176735Sjeff#define COM_NOFIFO(flags) ((flags) & 0x02) 249171482Sjeff#define COM_ST16650A(flags) ((flags) & 0x20000) 250163709Sjb#define COM_C_NOPROBE (0x40000) 251146954Sjeff#define COM_NOPROBE(flags) ((flags) & COM_C_NOPROBE) 252163709Sjb#define COM_C_IIR_TXRDYBUG (0x80000) 253163709Sjb#define COM_IIR_TXRDYBUG(flags) ((flags) & COM_C_IIR_TXRDYBUG) 254163709Sjb#define COM_FIFOSIZE(flags) (((flags) & 0xff000000) >> 24) 255164936Sjulian 256109864Sjeff#ifdef PC98 257110267Sjeff#define com_emr com_msr /* Extension mode register for RSB-2000/3000 */ 258177435Sjeff#else 259164936Sjulian#define com_scr 7 /* scratch register for 16450-16550 (R/W) */ 260177435Sjeff#endif 261177435Sjeff 262177435Sjeff/* 263177435Sjeff * com state bits. 264177005Sjeff * (CS_BUSY | CS_TTGO) and (CS_BUSY | CS_TTGO | CS_ODEVREADY) must be higher 265164936Sjulian * than the other bits so that they can be tested as a group without masking 266165762Sjeff * off the low bits. 267171482Sjeff * 268110267Sjeff * The following com and tty flags correspond closely: 269176735Sjeff * CS_BUSY = TS_BUSY (maintained by comstart(), siopoll() and 270171482Sjeff * siostop()) 271177435Sjeff * CS_TTGO = ~TS_TTSTOP (maintained by comparam() and comstart()) 272177435Sjeff * CS_CTS_OFLOW = CCTS_OFLOW (maintained by comparam()) 273177435Sjeff * CS_RTS_IFLOW = CRTS_IFLOW (maintained by comparam()) 274177435Sjeff * TS_FLUSH is not used. 275172409Sjeff * XXX I think TIOCSETA doesn't clear TS_TTSTOP when it clears IXON. 276176735Sjeff * XXX CS_*FLOW should be CF_*FLOW in com->flags (control flags not state). 277177435Sjeff */ 278171482Sjeff#define CS_BUSY 0x80 /* output in progress */ 279171482Sjeff#define CS_TTGO 0x40 /* output not stopped by XOFF */ 280171713Sjeff#define CS_ODEVREADY 0x20 /* external device h/w ready (CTS) */ 281121790Sjeff#define CS_CHECKMSR 1 /* check of MSR scheduled */ 282110028Sjeff#define CS_CTS_OFLOW 2 /* use CTS output flow control */ 283165762Sjeff#define CS_DTR_OFF 0x10 /* DTR held off */ 284177253Srwatson#define CS_ODONE 4 /* output completed */ 285165762Sjeff#define CS_RTS_IFLOW 8 /* use RTS input flow control */ 286165762Sjeff#define CSE_BUSYCHECK 1 /* siobusycheck() scheduled */ 287177253Srwatson 288177253Srwatsonstatic char const * const error_desc[] = { 289165762Sjeff#define CE_OVERRUN 0 290171482Sjeff "silo overflow", 291171482Sjeff#define CE_INTERRUPT_BUF_OVERFLOW 1 292171482Sjeff "interrupt-level buffer overflow", 293165762Sjeff#define CE_TTY_BUF_OVERFLOW 2 294165762Sjeff "tty-level buffer overflow", 295165762Sjeff}; 296165762Sjeff 297177435Sjeff#define CE_NTYPES 3 298165762Sjeff#define CE_RECORD(com, errnum) (++(com)->delta_error_counts[errnum]) 299165762Sjeff 300165762Sjeff/* types. XXX - should be elsewhere */ 301165762Sjefftypedef u_int Port_t; /* hardware port */ 302165762Sjefftypedef u_char bool_t; /* boolean */ 303165762Sjeff 304165762Sjeff/* queue of linear buffers */ 305165762Sjeffstruct lbq { 306165762Sjeff u_char *l_head; /* next char to process */ 307165762Sjeff u_char *l_tail; /* one past the last char to process */ 308165762Sjeff struct lbq *l_next; /* next in queue */ 309177435Sjeff bool_t l_queued; /* nonzero if queued */ 310165762Sjeff}; 311177435Sjeff 312177435Sjeff/* com device structure */ 313165762Sjeffstruct com_s { 314165762Sjeff u_int flags; /* Copy isa device flags */ 315165762Sjeff u_char state; /* miscellaneous flag bits */ 316165762Sjeff bool_t active_out; /* nonzero if the callout device is open */ 317165762Sjeff u_char cfcr_image; /* copy of value written to CFCR */ 318171482Sjeff#ifdef COM_ESP 319171482Sjeff bool_t esp; /* is this unit a hayes esp board? */ 320171482Sjeff#endif 321113357Sjeff u_char extra_state; /* more flag bits, separate for order trick */ 322164936Sjulian u_char fifo_image; /* copy of value written to FIFO */ 323110267Sjeff bool_t hasfifo; /* nonzero for 16550 UARTs */ 324164936Sjulian bool_t st16650a; /* Is a Startech 16650A or RTS/CTS compat */ 325112994Sjeff bool_t loses_outints; /* nonzero if device loses output interrupts */ 326164936Sjulian u_char mcr_image; /* copy of value written to MCR */ 327112994Sjeff#ifdef COM_MULTIPORT 328171713Sjeff bool_t multiport; /* is this unit part of a multiport device? */ 329176735Sjeff#endif /* COM_MULTIPORT */ 330176735Sjeff bool_t no_irq; /* nonzero if irq is not attached */ 331165620Sjeff bool_t gone; /* hardware disappeared */ 332171482Sjeff bool_t poll; /* nonzero if polling is required */ 333165766Sjeff bool_t poll_output; /* nonzero if polling for output is required */ 334165762Sjeff int unit; /* unit number */ 335165762Sjeff int dtr_wait; /* time to hold DTR down on close (* 1/hz) */ 336165762Sjeff u_int tx_fifo_size; 337165762Sjeff u_int wopeners; /* # processes waiting for DCD in open() */ 338165762Sjeff 339165762Sjeff /* 340165620Sjeff * The high level of the driver never reads status registers directly 341171713Sjeff * because there would be too many side effects to handle conveniently. 342113357Sjeff * Instead, it reads copies of the registers stored here by the 343112994Sjeff * interrupt handler. 344177005Sjeff */ 345177005Sjeff u_char last_modem_status; /* last MSR read by intr handler */ 346177005Sjeff u_char prev_modem_status; /* last MSR handled by high level */ 347177005Sjeff 348177005Sjeff u_char hotchar; /* ldisc-specific char to be handled ASAP */ 349177005Sjeff u_char *ibuf; /* start of input buffer */ 350177005Sjeff u_char *ibufend; /* end of input buffer */ 351177005Sjeff u_char *ibufold; /* old input buffer, to be freed */ 352177005Sjeff u_char *ihighwater; /* threshold in input buffer */ 353177005Sjeff u_char *iptr; /* next free spot in input buffer */ 354177005Sjeff int ibufsize; /* size of ibuf (not include error bytes) */ 355177005Sjeff int ierroff; /* offset of error bytes in ibuf */ 356177005Sjeff 357177005Sjeff struct lbq obufq; /* head of queue of output buffers */ 358177005Sjeff struct lbq obufs[2]; /* output buffers */ 359177005Sjeff 360177005Sjeff#ifdef PC98 361177005Sjeff Port_t cmd_port; 362177005Sjeff Port_t sts_port; 363177005Sjeff Port_t in_modem_port; 364177005Sjeff Port_t intr_ctrl_port; 365177005Sjeff int intr_enable; 366177005Sjeff int pc98_prev_modem_status; 367177005Sjeff int pc98_modem_delta; 368177005Sjeff int modem_car_chg_timer; 369177005Sjeff int pc98_prev_siocmd; 370177005Sjeff int pc98_prev_siomod; 371177005Sjeff int modem_checking; 372177005Sjeff int pc98_if_type; 373177005Sjeff#endif /* PC98 */ 374177005Sjeff Port_t data_port; /* i/o ports */ 375177005Sjeff#ifdef COM_ESP 376177005Sjeff Port_t esp_port; 377171482Sjeff#endif 378171482Sjeff Port_t int_id_port; 379171482Sjeff Port_t iobase; 380171482Sjeff#ifdef PC98 381171482Sjeff Port_t rsabase; /* iobase address of a I/O-DATA RSA board */ 382171482Sjeff#endif 383122744Sjeff Port_t modem_ctl_port; 384177435Sjeff Port_t line_status_port; 385122744Sjeff Port_t modem_status_port; 386177435Sjeff Port_t intr_ctl_port; /* Ports of IIR register */ 387177042Sjeff 388177042Sjeff struct tty *tp; /* cross reference */ 389171482Sjeff 390177435Sjeff /* Initial state. */ 391177009Sjeff struct termios it_in; /* should be in struct tty */ 392177435Sjeff struct termios it_out; 393177435Sjeff 394177435Sjeff /* Lock state. */ 395177435Sjeff struct termios lt_in; /* should be in struct tty */ 396165620Sjeff struct termios lt_out; 397164936Sjulian 398123433Sjeff bool_t do_timestamp; 399177042Sjeff bool_t do_dcd_timestamp; 400177042Sjeff struct timeval timestamp; 401177042Sjeff struct timeval dcd_timestamp; 402177042Sjeff struct pps_state pps; 403165762Sjeff 404165762Sjeff u_long bytes_in; /* statistics */ 405165762Sjeff u_long bytes_out; 406165762Sjeff u_int delta_error_counts[CE_NTYPES]; 407165762Sjeff u_long error_counts[CE_NTYPES]; 408165762Sjeff 409171713Sjeff /* 410165762Sjeff * Data area for output buffers. Someday we should build the output 411165762Sjeff * buffer queue without copying data. 412165766Sjeff */ 413165766Sjeff#ifdef PC98 414165766Sjeff int obufsize; 415165766Sjeff u_char *obuf1; 416165766Sjeff u_char *obuf2; 417165766Sjeff#else 418165766Sjeff u_char obuf1[256]; 419167664Sjeff u_char obuf2[256]; 420165762Sjeff#endif 421165766Sjeff#ifdef DEVFS 422177435Sjeff void *devfs_token_ttyd; 423177042Sjeff void *devfs_token_ttyl; 424165762Sjeff void *devfs_token_ttyi; 425177009Sjeff void *devfs_token_cuaa; 426177435Sjeff void *devfs_token_cual; 427177009Sjeff void *devfs_token_cuai; 428177009Sjeff#endif 429171482Sjeff}; 430171482Sjeff 431171482Sjeff#ifdef COM_ESP 432171482Sjeffstatic int espattach __P((struct com_s *com, Port_t esp_port)); 433171482Sjeff#endif 434122744Sjeffstatic int sioattach __P((device_t dev)); 435177435Sjeff 436122744Sjeffstatic timeout_t siobusycheck; 437177435Sjeffstatic timeout_t siodtrwakeup; 438177435Sjeffstatic void comhardclose __P((struct com_s *com)); 439177435Sjeffstatic void sioinput __P((struct com_s *com)); 440171482Sjeffstatic void siointr1 __P((struct com_s *com)); 441171482Sjeffstatic void siointr __P((void *arg)); 442177435Sjeffstatic int commctl __P((struct com_s *com, int bits, int how)); 443164936Sjulianstatic int comparam __P((struct tty *tp, struct termios *t)); 444165620Sjeffstatic swihand_t siopoll; 445164936Sjulianstatic int sioprobe __P((device_t dev)); 446123433Sjeffstatic void siosettimeout __P((void)); 447165766Sjeffstatic int siosetwater __P((struct com_s *com, speed_t speed)); 448165766Sjeffstatic void comstart __P((struct tty *tp)); 449177435Sjeffstatic timeout_t comwakeup; 450165766Sjeffstatic void disc_optim __P((struct tty *tp, struct termios *t, 451177435Sjeff struct com_s *com)); 452165766Sjeff 453177435Sjeff 454122744Sjeffstatic char driver_name[] = "sio"; 455122744Sjeff 456171482Sjeff/* table and macro for fast conversion from a unit number to its com struct */ 457171482Sjeffstatic devclass_t sio_devclass; 458171482Sjeff#define com_addr(unit) ((struct com_s *) \ 459171482Sjeff devclass_get_softc(sio_devclass, unit)) 460113357Sjeff 461177435Sjeffstatic device_method_t sio_methods[] = { 462113357Sjeff /* Device interface */ 463171482Sjeff DEVMETHOD(device_probe, sioprobe), 464171482Sjeff DEVMETHOD(device_attach, sioattach), 465177435Sjeff 466177902Sjeff { 0, 0 } 467165620Sjeff}; 468177902Sjeff 469177902Sjeffstatic driver_t sio_driver = { 470171713Sjeff driver_name, 471110267Sjeff sio_methods, 472113357Sjeff sizeof(struct com_s), 473171482Sjeff}; 474171482Sjeff 475171482Sjeffstatic d_open_t sioopen; 476171482Sjeffstatic d_close_t sioclose; 477112994Sjeffstatic d_read_t sioread; 478177435Sjeffstatic d_write_t siowrite; 479110267Sjeffstatic d_ioctl_t sioioctl; 480171482Sjeffstatic d_stop_t siostop; 481177435Sjeffstatic d_devtotty_t siodevtotty; 482171482Sjeff 483171482Sjeff#define CDEV_MAJOR 28 484171713Sjeffstatic struct cdevsw sio_cdevsw = { 485177902Sjeff /* open */ sioopen, 486165620Sjeff /* close */ sioclose, 487177902Sjeff /* read */ sioread, 488177902Sjeff /* write */ siowrite, 489165620Sjeff /* ioctl */ sioioctl, 490110267Sjeff /* stop */ siostop, 491110267Sjeff /* reset */ noreset, 492176735Sjeff /* devtotty */ siodevtotty, 493176735Sjeff /* poll */ ttpoll, 494176735Sjeff /* mmap */ nommap, 495176735Sjeff /* strategy */ nostrategy, 496176735Sjeff /* name */ driver_name, 497176735Sjeff /* parms */ noparms, 498176735Sjeff /* maj */ CDEV_MAJOR, 499176735Sjeff /* dump */ nodump, 500176735Sjeff /* psize */ nopsize, 501176735Sjeff /* flags */ D_TTY, 502176735Sjeff /* maxio */ 0, 503176735Sjeff /* bmaj */ -1 504177435Sjeff}; 505177435Sjeff 506176735Sjeffint comconsole = -1; 507176735Sjeffstatic volatile speed_t comdefaultrate = CONSPEED; 508176735Sjeff#ifdef __alpha__ 509176735Sjeffstatic volatile speed_t gdbdefaultrate = CONSPEED; 510176735Sjeff#endif 511113357Sjeffstatic u_int com_events; /* input chars + weighted output completions */ 512176735Sjeffstatic Port_t siocniobase; 513176735Sjeffstatic int siocnunit; 514176735Sjeffstatic Port_t siogdbiobase; 515176735Sjeffstatic int siogdbunit = -1; 516176735Sjeffstatic bool_t sio_registered; 517176735Sjeffstatic int sio_timeout; 518176735Sjeffstatic int sio_timeouts_until_log; 519176735Sjeffstatic struct callout_handle sio_timeout_handle 520176735Sjeff = CALLOUT_HANDLE_INITIALIZER(&sio_timeout_handle); 521176735Sjeff#if 0 /* XXX */ 522176735Sjeffstatic struct tty *sio_tty[NSIOTOT]; 523176735Sjeff#else 524176735Sjeffstatic struct tty sio_tty[NSIOTOT]; 525176735Sjeff#endif 526176735Sjeffstatic const int nsio_tty = NSIOTOT; 527177169Sjhb 528176735Sjeff#ifdef PC98 529176735Sjeffstruct siodev { 530176735Sjeff short if_type; 531176735Sjeff short irq; 532176735Sjeff Port_t cmd, sts, ctrl, mod; 533176735Sjeff}; 534116069Sjeffstatic int sysclock; 535176735Sjeff 536176735Sjeff#define COM_INT_DISABLE {int previpri; previpri=spltty(); 537176735Sjeff#define COM_INT_ENABLE splx(previpri);} 538176735Sjeff#define IEN_TxFLAG IEN_Tx 539176735Sjeff 540176735Sjeff#define COM_CARRIER_DETECT_EMULATE 0 541176735Sjeff#define PC98_CHECK_MODEM_INTERVAL (hz/10) 542176735Sjeff#define DCD_OFF_TOLERANCE 2 543176735Sjeff#define DCD_ON_RECOGNITION 2 544176735Sjeff#define IS_8251(if_type) (!(if_type & 0x10)) 545176735Sjeff#define COM1_EXT_CLOCK 0x40000 546176735Sjeff 547176735Sjeffstatic void commint __P((dev_t dev)); 548176735Sjeffstatic void com_tiocm_set __P((struct com_s *com, int msr)); 549176735Sjeffstatic void com_tiocm_bis __P((struct com_s *com, int msr)); 550176735Sjeffstatic void com_tiocm_bic __P((struct com_s *com, int msr)); 551176735Sjeffstatic int com_tiocm_get __P((struct com_s *com)); 552176735Sjeffstatic int com_tiocm_get_delta __P((struct com_s *com)); 553176735Sjeffstatic void pc98_msrint_start __P((dev_t dev)); 554176735Sjeffstatic void com_cflag_and_speed_set __P((struct com_s *com, int cflag, int speed)); 555176735Sjeffstatic int pc98_ttspeedtab __P((struct com_s *com, int speed)); 556176735Sjeffstatic int pc98_get_modem_status __P((struct com_s *com)); 557176735Sjeffstatic timeout_t pc98_check_msr; 558176735Sjeffstatic void pc98_set_baud_rate __P((struct com_s *com, int count)); 559176735Sjeffstatic void pc98_i8251_reset __P((struct com_s *com, int mode, int command)); 560176735Sjeffstatic void pc98_disable_i8251_interrupt __P((struct com_s *com, int mod)); 561176735Sjeffstatic void pc98_enable_i8251_interrupt __P((struct com_s *com, int mod)); 562176735Sjeffstatic int pc98_check_i8251_interrupt __P((struct com_s *com)); 563176735Sjeffstatic int pc98_i8251_get_cmd __P((struct com_s *com)); 564176735Sjeffstatic int pc98_i8251_get_mod __P((struct com_s *com)); 565176735Sjeffstatic void pc98_i8251_set_cmd __P((struct com_s *com, int x)); 566176735Sjeffstatic void pc98_i8251_or_cmd __P((struct com_s *com, int x)); 567176735Sjeffstatic void pc98_i8251_clear_cmd __P((struct com_s *com, int x)); 568176735Sjeffstatic void pc98_i8251_clear_or_cmd __P((struct com_s *com, int clr, int x)); 569176735Sjeffstatic int pc98_check_if_type __P((device_t dev, struct siodev *iod)); 570116069Sjeffstatic void pc98_check_sysclock __P((void)); 571176735Sjeffstatic int pc98_set_ioport __P((struct com_s *com, int id_flags)); 572176735Sjeff 573176735Sjeff#define com_int_Tx_disable(com) \ 574116069Sjeff pc98_disable_i8251_interrupt(com,IEN_Tx|IEN_TxEMP) 575177169Sjhb#define com_int_Tx_enable(com) \ 576176735Sjeff pc98_enable_i8251_interrupt(com,IEN_TxFLAG) 577176735Sjeff#define com_int_Rx_disable(com) \ 578176735Sjeff pc98_disable_i8251_interrupt(com,IEN_Rx) 579176735Sjeff#define com_int_Rx_enable(com) \ 580176735Sjeff pc98_enable_i8251_interrupt(com,IEN_Rx) 581176735Sjeff#define com_int_TxRx_disable(com) \ 582176735Sjeff pc98_disable_i8251_interrupt(com,IEN_Tx|IEN_TxEMP|IEN_Rx) 583176735Sjeff#define com_int_TxRx_enable(com) \ 584176735Sjeff pc98_enable_i8251_interrupt(com,IEN_TxFLAG|IEN_Rx) 585176735Sjeff#define com_send_break_on(com) \ 586176735Sjeff pc98_i8251_or_cmd(com,CMD8251_SBRK) 587176735Sjeff#define com_send_break_off(com) \ 588176735Sjeff pc98_i8251_clear_cmd(com,CMD8251_SBRK) 589176735Sjeff 590176735Sjeffstatic struct speedtab pc98speedtab[] = { /* internal RS232C interface */ 591176735Sjeff { 0, 0, }, 592176735Sjeff { 50, 50, }, 593176735Sjeff { 75, 75, }, 594176735Sjeff { 150, 150, }, 595176735Sjeff { 200, 200, }, 596176735Sjeff { 300, 300, }, 597176735Sjeff { 600, 600, }, 598176735Sjeff { 1200, 1200, }, 599176735Sjeff { 2400, 2400, }, 600176735Sjeff { 4800, 4800, }, 601176735Sjeff { 9600, 9600, }, 602176735Sjeff { 19200, 19200, }, 603176735Sjeff { 38400, 38400, }, 604176735Sjeff { 51200, 51200, }, 605176735Sjeff { 76800, 76800, }, 606176735Sjeff { 20800, 20800, }, 607176735Sjeff { 31200, 31200, }, 608176735Sjeff { 41600, 41600, }, 609176735Sjeff { 62400, 62400, }, 610176735Sjeff { -1, -1 } 611176735Sjeff}; 612176735Sjeffstatic struct speedtab pc98fast_speedtab[] = { 613176735Sjeff { 9600, 0x80 | COMBRD(9600), }, 614176735Sjeff { 19200, 0x80 | COMBRD(19200), }, 615176735Sjeff { 38400, 0x80 | COMBRD(38400), }, 616176735Sjeff { 57600, 0x80 | COMBRD(57600), }, 617176735Sjeff { 115200, 0x80 | COMBRD(115200), }, 618176735Sjeff { -1, -1 } 619176735Sjeff}; 620176735Sjeffstatic struct speedtab comspeedtab_pio9032b[] = { 621176735Sjeff { 300, 6, }, 622176735Sjeff { 600, 5, }, 623176735Sjeff { 1200, 4, }, 624176735Sjeff { 2400, 3, }, 625176735Sjeff { 4800, 2, }, 626176735Sjeff { 9600, 1, }, 627176735Sjeff { 19200, 0, }, 628176735Sjeff { 38400, 7, }, 629176735Sjeff { -1, -1 } 630176735Sjeff}; 631176735Sjeffstatic struct speedtab comspeedtab_b98_01[] = { 632176735Sjeff { 75, 11, }, 633176735Sjeff { 150, 10, }, 634176735Sjeff { 300, 9, }, 635176735Sjeff { 600, 8, }, 636176735Sjeff { 1200, 7, }, 637176735Sjeff { 2400, 6, }, 638176735Sjeff { 4800, 5, }, 639176735Sjeff { 9600, 4, }, 640176735Sjeff { 19200, 3, }, 641176735Sjeff { 38400, 2, }, 642176735Sjeff { 76800, 1, }, 643176735Sjeff { 153600, 0, }, 644176735Sjeff { -1, -1 } 645176735Sjeff}; 646176735Sjeffstatic struct speedtab comspeedtab_mc16550[] = { 647176735Sjeff { 300, 1536, }, 648176735Sjeff { 600, 768, }, 649176735Sjeff { 1200, 384, }, 650176735Sjeff { 2400, 192, }, 651176735Sjeff { 4800, 96, }, 652176735Sjeff { 9600, 48, }, 653176735Sjeff { 19200, 24, }, 654176735Sjeff { 38400, 12, }, 655176735Sjeff { 57600, 8, }, 656176735Sjeff { 115200, 4, }, 657176735Sjeff { 153600, 3, }, 658176735Sjeff { 230400, 2, }, 659176735Sjeff { 460800, 1, }, 660176735Sjeff { -1, -1 } 661176735Sjeff}; 662176735Sjeffstatic struct speedtab comspeedtab_rsb384[] = { 663176735Sjeff { 300, 3840, }, 664176735Sjeff { 600, 1920, }, 665176735Sjeff { 1200, 960, }, 666176735Sjeff { 2400, 480, }, 667176735Sjeff { 4800, 240, }, 668176735Sjeff { 9600, 120, }, 669176735Sjeff { 19200, 60, }, 670176735Sjeff { 38400, 30, }, 671176735Sjeff { 57600, 20, }, 672176735Sjeff { 115200, 10, }, 673176735Sjeff { 128000, 9, }, 674176735Sjeff { 144000, 8, }, 675176735Sjeff { 192000, 6, }, 676176735Sjeff { 230400, 5, }, 677176735Sjeff { 288000, 4, }, 678176735Sjeff { 384000, 3, }, 679176735Sjeff { 576000, 2, }, 680176735Sjeff { 1152000, 1, }, 681176735Sjeff { -1, -1 } 682176735Sjeff}; 683176735Sjeffstatic struct speedtab comspeedtab_rsa[] = { 684176735Sjeff { 0, 0 }, 685176735Sjeff { 50, COMBRD_RSA(50) }, 686176735Sjeff { 75, COMBRD_RSA(75) }, 687176735Sjeff { 110, COMBRD_RSA(110) }, 688176735Sjeff { 134, COMBRD_RSA(134) }, 689176735Sjeff { 150, COMBRD_RSA(150) }, 690176735Sjeff { 200, COMBRD_RSA(200) }, 691176735Sjeff { 300, COMBRD_RSA(300) }, 692176735Sjeff { 600, COMBRD_RSA(600) }, 693176735Sjeff { 1200, COMBRD_RSA(1200) }, 694176735Sjeff { 1800, COMBRD_RSA(1800) }, 695176735Sjeff { 2400, COMBRD_RSA(2400) }, 696176735Sjeff { 4800, COMBRD_RSA(4800) }, 697176735Sjeff { 9600, COMBRD_RSA(9600) }, 698176735Sjeff { 19200, COMBRD_RSA(19200) }, 699176735Sjeff { 38400, COMBRD_RSA(38400) }, 700176735Sjeff { 57600, COMBRD_RSA(57600) }, 701176735Sjeff { 115200, COMBRD_RSA(115200) }, 702176735Sjeff { 230400, COMBRD_RSA(230400) }, 703176735Sjeff { 460800, COMBRD_RSA(460800) }, 704176735Sjeff { 921600, COMBRD_RSA(921600) }, 705176735Sjeff { -1, -1 } 706176735Sjeff}; 707176735Sjeff#endif /* PC98 */ 708176735Sjeff 709176735Sjeffstatic struct speedtab comspeedtab[] = { 710176735Sjeff { 0, 0 }, 711176735Sjeff { 50, COMBRD(50) }, 712176735Sjeff { 75, COMBRD(75) }, 713176735Sjeff { 110, COMBRD(110) }, 714176735Sjeff { 134, COMBRD(134) }, 715176735Sjeff { 150, COMBRD(150) }, 716121790Sjeff { 200, COMBRD(200) }, 717176735Sjeff { 300, COMBRD(300) }, 718116069Sjeff { 600, COMBRD(600) }, 719176735Sjeff { 1200, COMBRD(1200) }, 720176735Sjeff { 1800, COMBRD(1800) }, 721176735Sjeff { 2400, COMBRD(2400) }, 722123487Sjeff { 4800, COMBRD(4800) }, 723123487Sjeff { 9600, COMBRD(9600) }, 724176735Sjeff { 19200, COMBRD(19200) }, 725176735Sjeff { 38400, COMBRD(38400) }, 726176735Sjeff { 57600, COMBRD(57600) }, 727176735Sjeff { 115200, COMBRD(115200) }, 728176735Sjeff { -1, -1 } 729176735Sjeff}; 730176735Sjeff 731123487Sjeff#ifdef PC98 732176735Sjeffstruct { 733176735Sjeff char *name; 734176735Sjeff short port_table[7]; 735176735Sjeff short irr_mask; 736176735Sjeff struct speedtab *speedtab; 737176735Sjeff short check_irq; 738176735Sjeff} if_8251_type[] = { 739123487Sjeff /* COM_IF_INTERNAL */ 740176735Sjeff { " (internal)", {0x30, 0x32, 0x32, 0x33, 0x35, -1, -1}, 741176735Sjeff -1, pc98speedtab, 1 }, 742176735Sjeff /* COM_IF_PC9861K_1 */ 743123487Sjeff { " (PC9861K)", {0xb1, 0xb3, 0xb3, 0xb0, 0xb0, -1, -1}, 744123487Sjeff 3, NULL, 1 }, 745123487Sjeff /* COM_IF_PC9861K_2 */ 746176735Sjeff { " (PC9861K)", {0xb9, 0xbb, 0xbb, 0xb2, 0xb2, -1, -1}, 747123487Sjeff 3, NULL, 1 }, 748172409Sjeff /* COM_IF_IND_SS_1 */ 749123487Sjeff { " (IND-SS)", {0xb1, 0xb3, 0xb3, 0xb0, 0xb0, 0xb3, -1}, 750172409Sjeff 3, comspeedtab_mc16550, 1 }, 751172409Sjeff /* COM_IF_IND_SS_2 */ 752172409Sjeff { " (IND-SS)", {0xb9, 0xbb, 0xbb, 0xb2, 0xb2, 0xbb, -1}, 753172409Sjeff 3, comspeedtab_mc16550, 1 }, 754176735Sjeff /* COM_IF_PIO9032B_1 */ 755176735Sjeff { " (PIO9032B)", {0xb1, 0xb3, 0xb3, 0xb0, 0xb0, 0xb8, -1}, 756171482Sjeff 7, comspeedtab_pio9032b, 1 }, 757171482Sjeff /* COM_IF_PIO9032B_2 */ 758172409Sjeff { " (PIO9032B)", {0xb9, 0xbb, 0xbb, 0xb2, 0xb2, 0xba, -1}, 759172409Sjeff 7, comspeedtab_pio9032b, 1 }, 760176735Sjeff /* COM_IF_B98_01_1 */ 761172409Sjeff { " (B98-01)", {0xb1, 0xb3, 0xb3, 0xb0, 0xb0, 0xd1, 0xd3}, 762123487Sjeff 7, comspeedtab_b98_01, 0 }, 763123487Sjeff /* COM_IF_B98_01_2 */ 764171482Sjeff { " (B98-01)", {0xb9, 0xbb, 0xbb, 0xb2, 0xb2, 0xd5, 0xd7}, 765171482Sjeff 7, comspeedtab_b98_01, 0 }, 766171482Sjeff}; 767123487Sjeff#define PC98SIO_data_port(type) (if_8251_type[type].port_table[0]) 768171482Sjeff#define PC98SIO_cmd_port(type) (if_8251_type[type].port_table[1]) 769171482Sjeff#define PC98SIO_sts_port(type) (if_8251_type[type].port_table[2]) 770171482Sjeff#define PC98SIO_in_modem_port(type) (if_8251_type[type].port_table[3]) 771171482Sjeff#define PC98SIO_intr_ctrl_port(type) (if_8251_type[type].port_table[4]) 772171482Sjeff#define PC98SIO_baud_rate_port(type) (if_8251_type[type].port_table[5]) 773171482Sjeff#define PC98SIO_func_port(type) (if_8251_type[type].port_table[6]) 774171482Sjeff 775171482Sjeffstruct { 776171482Sjeff char *name; 777171482Sjeff short irr_read; 778171482Sjeff short irr_write; 779171482Sjeff short port_shift; 780172409Sjeff short io_size; 781172409Sjeff struct speedtab *speedtab; 782172409Sjeff} if_16550a_type[] = { 783172409Sjeff /* COM_IF_RSA98 */ 784172409Sjeff { " (RSA-98)", -1, -1, 0, IO_COMSIZE, comspeedtab }, 785172409Sjeff /* COM_IF_NS16550 */ 786172409Sjeff { "", -1, -1, 0, IO_COMSIZE, comspeedtab }, 787172409Sjeff /* COM_IF_SECOND_CCU */ 788172409Sjeff { "", -1, -1, 0, IO_COMSIZE, comspeedtab }, 789172409Sjeff /* COM_IF_MC16550II */ 790171482Sjeff { " (MC16550II)", -1, 0x1000, 8, 1, comspeedtab_mc16550 }, 791171482Sjeff /* COM_IF_MCRS98 */ 792176735Sjeff { " (MC-RS98)", -1, 0x1000, 8, 1, comspeedtab_mc16550 }, 793164936Sjulian /* COM_IF_RSB3000 */ 794123487Sjeff { " (RSB-3000)", 0xbf, -1, 1, 1, comspeedtab_rsb384 }, 795123433Sjeff /* COM_IF_RSB384 */ 796116069Sjeff { " (RSB-384)", 0xbf, -1, 1, 1, comspeedtab_rsb384 }, 797116069Sjeff /* COM_IF_MODEM_CARD */ 798176735Sjeff { "", -1, -1, 0, IO_COMSIZE, comspeedtab }, 799116069Sjeff /* COM_IF_RSA98III */ 800116069Sjeff { " (RSA-98III)", -1, -1, 0, 16, comspeedtab_rsa }, 801116069Sjeff /* COM_IF_ESP98 */ 802116069Sjeff { " (ESP98)", -1, -1, 1, 1, comspeedtab_mc16550 }, 803171482Sjeff}; 804176735Sjeff#endif /* PC98 */ 805176735Sjeff 806176735Sjeff#ifdef COM_ESP 807176735Sjeff#ifdef PC98 808116069Sjeff 809122744Sjeff/* XXX configure this properly. */ 810165620Sjeffstatic Port_t likely_com_ports[] = { 0, 0xb0, 0xb1, 0 }; 811122744Sjeffstatic Port_t likely_esp_ports[] = { 0xc0d0, 0 }; 812171482Sjeff 813171482Sjeff#define ESP98_CMD1 (ESP_CMD1 * 0x100) 814171482Sjeff#define ESP98_CMD2 (ESP_CMD2 * 0x100) 815171482Sjeff#define ESP98_STATUS1 (ESP_STATUS1 * 0x100) 816171482Sjeff#define ESP98_STATUS2 (ESP_STATUS2 * 0x100) 817171482Sjeff 818171482Sjeff#else /* PC98 */ 819176735Sjeff 820172293Sjeff/* XXX configure this properly. */ 821172293Sjeffstatic Port_t likely_com_ports[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, }; 822172293Sjeffstatic Port_t likely_esp_ports[] = { 0x140, 0x180, 0x280, 0 }; 823172293Sjeff 824172293Sjeff#endif /* PC98 */ 825171482Sjeff#endif 826172409Sjeff 827176735Sjeff/* 828116069Sjeff * handle sysctl read/write requests for console speed 829116069Sjeff * 830171482Sjeff * In addition to setting comdefaultrate for I/O through /dev/console, 831171482Sjeff * also set the initial and lock values for the /dev/ttyXX device 832171482Sjeff * if there is one associated with the console. Finally, if the /dev/tty 833176735Sjeff * device has already been open, change the speed on the open running port 834171482Sjeff * itself. 835116069Sjeff */ 836171482Sjeff 837171482Sjeffstatic int 838164936Sjuliansysctl_machdep_comdefaultrate SYSCTL_HANDLER_ARGS 839171482Sjeff{ 840116069Sjeff int error, s; 841172409Sjeff speed_t newspeed; 842172409Sjeff struct com_s *com; 843172409Sjeff struct tty *tp; 844164936Sjulian 845171482Sjeff newspeed = comdefaultrate; 846177435Sjeff 847177435Sjeff error = sysctl_handle_opaque(oidp, &newspeed, sizeof newspeed, req); 848176735Sjeff if (error || !req->newptr) 849177435Sjeff return (error); 850171482Sjeff 851171482Sjeff comdefaultrate = newspeed; 852172409Sjeff 853171482Sjeff if (comconsole < 0) /* serial console not selected? */ 854171482Sjeff return (0); 855172409Sjeff 856171482Sjeff com = com_addr(comconsole); 857171482Sjeff if (!com) 858166108Sjeff return (ENXIO); 859171482Sjeff 860171482Sjeff /* 861176735Sjeff * set the initial and lock rates for /dev/ttydXX and /dev/cuaXX 862116069Sjeff * (note, the lock rates really are boolean -- if non-zero, disallow 863110267Sjeff * speed changes) 864171482Sjeff */ 865171482Sjeff com->it_in.c_ispeed = com->it_in.c_ospeed = 866171482Sjeff com->lt_in.c_ispeed = com->lt_in.c_ospeed = 867171482Sjeff com->it_out.c_ispeed = com->it_out.c_ospeed = 868123433Sjeff com->lt_out.c_ispeed = com->lt_out.c_ospeed = comdefaultrate; 869164936Sjulian 870121790Sjeff /* 871176735Sjeff * if we're open, change the running rate too 872164936Sjulian */ 873176735Sjeff tp = com->tp; 874176735Sjeff if (tp && (tp->t_state & TS_ISOPEN)) { 875171482Sjeff tp->t_termios.c_ispeed = 876123433Sjeff tp->t_termios.c_ospeed = comdefaultrate; 877172484Sjeff s = spltty(); 878172484Sjeff error = comparam(tp, &tp->t_termios); 879176735Sjeff splx(s); 880176735Sjeff } 881176735Sjeff return error; 882171482Sjeff} 883176735Sjeff 884176735SjeffSYSCTL_PROC(_machdep, OID_AUTO, conspeed, CTLTYPE_INT | CTLFLAG_RW, 885176735Sjeff 0, 0, sysctl_machdep_comdefaultrate, "I", ""); 886176735Sjeff 887176735Sjeff#if NCARD > 0 888176735Sjeff/* 889176735Sjeff * PC-Card (PCMCIA) specific code. 890176735Sjeff */ 891176735Sjeffstatic int sioinit __P((struct pccard_devinfo *)); 892166108Sjeffstatic void siounload __P((struct pccard_devinfo *)); 893176735Sjeffstatic int card_intr __P((struct pccard_devinfo *)); 894176735Sjeff 895176735SjeffPCCARD_MODULE(sio, sioinit, siounload, card_intr, 0, tty_imask); 896176735Sjeff 897176735Sjeff/* 898176735Sjeff * Initialize the device - called from Slot manager. 899171482Sjeff */ 900176735Sjeffint 901176735Sjeffsioinit(struct pccard_devinfo *devi) 902176735Sjeff{ 903176735Sjeff 904176735Sjeff /* validate unit number. */ 905176735Sjeff if (devi->isahd.id_unit >= (NSIOTOT)) 906176735Sjeff return(ENODEV); 907176735Sjeff /* Make sure it isn't already probed. */ 908176735Sjeff if (com_addr(devi->isahd.id_unit)) 909176735Sjeff return(EBUSY); 910176735Sjeff 911176735Sjeff /* It's already probed as serial by Upper */ 912176735Sjeff devi->isahd.id_flags |= COM_C_NOPROBE; 913176735Sjeff 914176735Sjeff /* 915176735Sjeff * Probe the device. If a value is returned, the 916123433Sjeff * device was found at the location. 917171482Sjeff */ 918123433Sjeff if (sioprobe(&devi->isahd) == 0) 919121790Sjeff return(ENXIO); 920121790Sjeff if (sioattach(&devi->isahd) == 0) 921171482Sjeff return(ENXIO); 922171482Sjeff 923171482Sjeff return(0); 924121790Sjeff} 925177435Sjeff 926121790Sjeff/* 927166247Sjeff * siounload - unload the driver and clear the table. 928166247Sjeff * XXX TODO: 929166108Sjeff * This is usually called when the card is ejected, but 930121790Sjeff * can be caused by a modunload of a controller driver. 931177005Sjeff * The idea is to reset the driver's view of the device 932177005Sjeff * and ensure that any driver entry points such as 933177435Sjeff * read and write do not hang. 934177435Sjeff */ 935177005Sjeffstatic void 936177005Sjeffsiounload(struct pccard_devinfo *devi) 937166137Sjeff{ 938177005Sjeff struct com_s *com; 939171482Sjeff 940121790Sjeff if (!devi) { 941121790Sjeff printf("NULL devi in siounload\n"); 942171482Sjeff return; 943171482Sjeff } 944171482Sjeff com = com_addr(devi->isahd.id_unit); 945171482Sjeff if (!com) { 946177435Sjeff printf("NULL com in siounload\n"); 947176735Sjeff return; 948171482Sjeff } 949171482Sjeff if (!com->iobase) { 950171482Sjeff printf("sio%d already unloaded!\n",devi->isahd.id_unit); 951177435Sjeff return; 952171482Sjeff } 953171482Sjeff if (com->tp && (com->tp->t_state & TS_ISOPEN)) { 954171482Sjeff com->gone = 1; 955171482Sjeff printf("sio%d: unload\n", devi->isahd.id_unit); 956171482Sjeff com->tp->t_gen++; 957171482Sjeff ttyclose(com->tp); 958171482Sjeff ttwakeup(com->tp); 959171482Sjeff ttwwakeup(com->tp); 960171482Sjeff } else { 961171482Sjeff if (com->ibuf != NULL) 962171482Sjeff free(com->ibuf, M_DEVBUF); 963171482Sjeff free(com, M_DEVBUF); 964171482Sjeff printf("sio%d: unload,gone\n", devi->isahd.id_unit); 965171482Sjeff } 966171482Sjeff} 967171482Sjeff 968171482Sjeff/* 969171482Sjeff * card_intr - Shared interrupt called from 970171482Sjeff * front end of PC-Card handler. 971171482Sjeff */ 972171482Sjeffstatic int 973171482Sjeffcard_intr(struct pccard_devinfo *devi) 974171482Sjeff{ 975177435Sjeff struct com_s *com; 976177435Sjeff 977177435Sjeff COM_LOCK(); 978177435Sjeff com = com_addr(devi->isahd.id_unit); 979171482Sjeff if (com && !com->gone) 980171482Sjeff siointr1(com_addr(devi->isahd.id_unit)); 981171482Sjeff COM_UNLOCK(); 982171482Sjeff return(1); 983171482Sjeff} 984171482Sjeff#endif /* NCARD > 0 */ 985171482Sjeff 986171482Sjeff#define SET_FLAG(dev, bit) isa_set_flags(dev, isa_get_flags(dev) | (bit)) 987171482Sjeff#define CLR_FLAG(dev, bit) isa_set_flags(dev, isa_get_flags(dev) & ~(bit)) 988171482Sjeff 989171482Sjeffstatic int 990171482Sjeffsioprobe(dev) 991171482Sjeff device_t dev; 992171482Sjeff{ 993177435Sjeff static bool_t already_init; 994176735Sjeff bool_t failures[10]; 995121790Sjeff int fn; 996121790Sjeff device_t idev; 997121790Sjeff Port_t iobase; 998177435Sjeff intrmask_t irqmap[4]; 999121790Sjeff intrmask_t irqs; 1000121790Sjeff u_char mcr_image; 1001121790Sjeff int result; 1002121790Sjeff device_t xdev; 1003121790Sjeff u_int flags = isa_get_flags(dev); 1004121790Sjeff#ifdef PC98 1005121790Sjeff int irqout=0; 1006121790Sjeff int tmp; 1007123231Speter int port_shift = 0; 1008121790Sjeff struct siodev iod; 1009121790Sjeff Port_t rsabase = NULL; 1010177435Sjeff#endif 1011177435Sjeff 1012177435Sjeff if (!already_init) { 1013177435Sjeff /* 1014121790Sjeff * Turn off MCR_IENABLE for all likely serial ports. An unused 1015121790Sjeff * port with its MCR_IENABLE gate open will inhibit interrupts 1016121790Sjeff * from any used port that shares the interrupt vector. 1017121790Sjeff * XXX the gate enable is elsewhere for some multiports. 1018121790Sjeff */ 1019171482Sjeff device_t *devs; 1020171482Sjeff int count, i; 1021171482Sjeff 1022177435Sjeff devclass_get_devices(sio_devclass, &devs, &count); 1023176735Sjeff#ifdef PC98 1024121790Sjeff for (i = 0; i < count; i++) { 1025177435Sjeff xdev = devs[i]; 1026121790Sjeff tmp = (flags >> 24) & 0xff; 1027171482Sjeff if (IS_8251(tmp)) 1028177435Sjeff outb((isa_get_port(xdev) & 0xff00) | PC98SIO_cmd_port(tmp & 0x0f), 0xf2); 1029177435Sjeff else 1030177435Sjeff if (tmp == COM_IF_RSA98III) { 1031177435Sjeff rsabase = isa_get_port(xdev) & 0xfff0; 1032177435Sjeff outb(isa_get_port(xdev) + 8 + (com_mcr << if_16550a_type[tmp & 0x0f].port_shift), 0); 1033176735Sjeff } else 1034121790Sjeff outb(isa_get_port(xdev) + (com_mcr << if_16550a_type[tmp & 0x0f].port_shift), 0); 1035123433Sjeff } 1036171482Sjeff#else 1037171482Sjeff for (i = 0; i < count; i++) { 1038172409Sjeff xdev = devs[i]; 1039171482Sjeff outb(isa_get_port(xdev) + com_mcr, 0); 1040171482Sjeff } 1041177435Sjeff#endif 1042123433Sjeff free(devs, M_TEMP); 1043177435Sjeff already_init = TRUE; 1044171482Sjeff } 1045123433Sjeff 1046177435Sjeff if (COM_LLCONSOLE(flags)) { 1047171482Sjeff printf("sio%d: reserved for low-level i/o\n", 1048177435Sjeff device_get_unit(dev)); 1049177435Sjeff return (ENXIO); 1050177435Sjeff } 1051177435Sjeff 1052171482Sjeff#ifdef PC98 1053171482Sjeff DELAY(10); 1054171482Sjeff 1055123433Sjeff /* 1056172293Sjeff * If the port is i8251 UART (internal, B98_01) 1057171482Sjeff */ 1058171482Sjeff if (pc98_check_if_type(dev, &iod) == -1) 1059123685Sjeff return ENXIO; 1060171482Sjeff if (iod.irq > 0) 1061171482Sjeff isa_set_irq(dev, iod.irq); 1062171482Sjeff if (IS_8251(iod.if_type)) { 1063171482Sjeff outb(iod.cmd, 0); 1064171482Sjeff DELAY(10); 1065171482Sjeff outb(iod.cmd, 0); 1066166108Sjeff DELAY(10); 1067171482Sjeff outb(iod.cmd, 0); 1068171482Sjeff DELAY(10); 1069166108Sjeff outb(iod.cmd, CMD8251_RESET); 1070171482Sjeff DELAY(1000); /* for a while...*/ 1071171482Sjeff outb(iod.cmd, 0xf2); /* MODE (dummy) */ 1072171713Sjeff DELAY(10); 1073171482Sjeff outb(iod.cmd, 0x01); /* CMD (dummy) */ 1074166108Sjeff DELAY(1000); /* for a while...*/ 1075166108Sjeff if (( inb(iod.sts) & STS8251_TxEMP ) == 0 ) { 1076166108Sjeff result = ENXIO; 1077177435Sjeff } 1078171482Sjeff if (if_8251_type[iod.if_type & 0x0f].check_irq) { 1079176735Sjeff COM_INT_DISABLE 1080177435Sjeff tmp = ( inb( iod.ctrl ) & ~(IEN_Rx|IEN_TxEMP|IEN_Tx)); 1081171482Sjeff outb( iod.ctrl, tmp|IEN_TxEMP ); 1082176735Sjeff DELAY(10); 1083166108Sjeff result = isa_irq_pending() ? 0 : ENXIO; 1084166108Sjeff outb( iod.ctrl, tmp ); 1085166108Sjeff COM_INT_ENABLE 1086166108Sjeff } else { 1087176735Sjeff /* 1088177435Sjeff * B98_01 doesn't activate TxEMP interrupt line 1089166108Sjeff * when being reset, so we can't check irq pending. 1090166108Sjeff */ 1091171506Sjeff result = 0; 1092171506Sjeff } 1093171506Sjeff if (epson_machine_id==0x20) { /* XXX */ 1094176735Sjeff result = 0; 1095176735Sjeff } 1096166108Sjeff isa_set_portsize(dev, 4); 1097176735Sjeff return result; 1098176735Sjeff } 1099166108Sjeff#endif /* PC98 */ 1100176735Sjeff /* 1101176735Sjeff * If the device is on a multiport card and has an AST/4 1102176735Sjeff * compatible interrupt control register, initialize this 1103166108Sjeff * register and prepare to leave MCR_IENABLE clear in the mcr. 1104176735Sjeff * Otherwise, prepare to set MCR_IENABLE in the mcr. 1105176735Sjeff * Point idev to the device struct giving the correct id_irq. 1106166108Sjeff * This is the struct for the master device if there is one. 1107176735Sjeff */ 1108176735Sjeff idev = dev; 1109176735Sjeff mcr_image = MCR_IENABLE; 1110176735Sjeff#ifdef PC98 1111176735Sjeff if (iod.if_type == COM_IF_RSA98III) { 1112176735Sjeff mcr_image = 0; 1113176735Sjeff rsabase = isa_get_port(idev) & 0xfff0; 1114139334Sjeff if (rsabase != isa_get_port(idev)) 1115123433Sjeff return(0); 1116176735Sjeff outb(rsabase + rsa_msr, 0x04); 1117123433Sjeff outb(rsabase + rsa_frr, 0x00); 1118176735Sjeff if ((inb(rsabase + rsa_srr) & 0x36) != 0x36) 1119176735Sjeff return (0); 1120176735Sjeff outb(rsabase + rsa_ier, 0x00); 1121176735Sjeff outb(rsabase + rsa_frr, 0x00); 1122176735Sjeff outb(rsabase + rsa_tivsr, 0x00); 1123176735Sjeff outb(rsabase + rsa_tcr, 0x00); 1124176735Sjeff } 1125176735Sjeff#endif /* PC98 */ 1126176735Sjeff#ifdef COM_MULTIPORT 1127176735Sjeff if (COM_ISMULTIPORT(flags)) { 1128171506Sjeff idev = devclass_get_device(sio_devclass, COM_MPMASTER(flags)); 1129176735Sjeff if (idev == NULL) { 1130171506Sjeff printf("sio%d: master device %d not configured\n", 1131177005Sjeff device_get_unit(dev), COM_MPMASTER(flags)); 1132177005Sjeff isa_set_irq(dev, 0); 1133177005Sjeff idev = dev; 1134177005Sjeff } 1135171482Sjeff#ifndef PC98 1136123433Sjeff if (!COM_NOTAST4(flags)) { 1137176735Sjeff outb(isa_get_port(idev) + com_scr, 1138123433Sjeff isa_get_irq(idev) >= 0 ? 0x80 : 0); 1139117326Sjeff mcr_image = 0; 1140121790Sjeff } 1141117326Sjeff#endif /* !PC98 */ 1142177435Sjeff } 1143164936Sjulian#endif /* COM_MULTIPORT */ 1144110267Sjeff if (isa_get_irq(idev) < 0) 1145177435Sjeff mcr_image = 0; 1146110267Sjeff 1147171482Sjeff#ifdef PC98 1148177435Sjeff tmp = if_16550a_type[iod.if_type & 0x0f].irr_write; 1149177435Sjeff if (tmp != -1) { 1150177435Sjeff /* MC16550II */ 1151177435Sjeff switch (isa_get_irq(idev)) { 1152177435Sjeff case 3: irqout = 4; break; 1153177435Sjeff case 5: irqout = 5; break; 1154165762Sjeff case 6: irqout = 6; break; 1155177435Sjeff case 12: irqout = 7; break; 1156177435Sjeff default: 1157165762Sjeff printf("sio%d: irq configuration error\n", 1158177435Sjeff device_get_unit(dev)); 1159177435Sjeff return (0); 1160177435Sjeff } 1161165762Sjeff outb((isa_get_port(dev) & 0x00ff) | tmp, irqout); 1162177435Sjeff } 1163177435Sjeff port_shift = if_16550a_type[iod.if_type & 0x0f].port_shift; 1164165762Sjeff#endif 1165165762Sjeff bzero(failures, sizeof failures); 1166165762Sjeff iobase = isa_get_port(dev); 1167110267Sjeff#ifdef PC98 1168110267Sjeff if (iod.if_type == COM_IF_RSA98III) 1169171482Sjeff iobase += 8; 1170171482Sjeff#endif 1171171482Sjeff 1172109864Sjeff /* 1173164936Sjulian * We don't want to get actual interrupts, just masked ones. 1174110028Sjeff * Interrupts from this line should already be masked in the ICU, 1175171482Sjeff * but mask them in the processor as well in case there are some 1176171713Sjeff * (misconfigured) shared interrupts. 1177171713Sjeff */ 1178165762Sjeff disable_intr(); 1179165762Sjeff/* EXTRA DELAY? */ 1180165620Sjeff 1181176735Sjeff /* 1182176735Sjeff * Initialize the speed and the word size and wait long enough to 1183176735Sjeff * drain the maximum of 16 bytes of junk in device output queues. 1184176735Sjeff * The speed is undefined after a master reset and must be set 1185110028Sjeff * before relying on anything related to output. There may be 1186110028Sjeff * junk after a (very fast) soft reboot and (apparently) after 1187171713Sjeff * master reset. 1188110028Sjeff * XXX what about the UART bug avoided by waiting in comparam()? 1189171713Sjeff * We don't want to to wait long enough to drain at 2 bps. 1190171713Sjeff */ 1191171713Sjeff if (iobase == siocniobase) 1192171713Sjeff DELAY((16 + 1) * 1000000 / (comdefaultrate / 10)); 1193171713Sjeff else { 1194176735Sjeff#ifdef PC98 1195176735Sjeff tmp = ttspeedtab(SIO_TEST_SPEED, 1196171713Sjeff if_16550a_type[iod.if_type & 0x0f].speedtab); 1197171713Sjeff outb(iobase + (com_cfcr << port_shift), CFCR_DLAB|CFCR_8BITS); 1198176735Sjeff outb(iobase + (com_dlbl << port_shift), tmp & 0xff); 1199171713Sjeff outb(iobase + (com_dlbh << port_shift), (tmp >> 8) & 0xff); 1200176735Sjeff outb(iobase + (com_cfcr << port_shift), CFCR_8BITS); 1201176735Sjeff#else 1202176735Sjeff outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS); 1203123433Sjeff outb(iobase + com_dlbl, COMBRD(SIO_TEST_SPEED) & 0xff); 1204176735Sjeff outb(iobase + com_dlbh, (u_int) COMBRD(SIO_TEST_SPEED) >> 8); 1205176735Sjeff outb(iobase + com_cfcr, CFCR_8BITS); 1206171713Sjeff#endif 1207171713Sjeff DELAY((16 + 1) * 1000000 / (SIO_TEST_SPEED / 10)); 1208171713Sjeff } 1209171713Sjeff 1210171713Sjeff /* 1211171713Sjeff * Enable the interrupt gate and disable device interupts. This 1212171713Sjeff * should leave the device driving the interrupt line low and 1213171713Sjeff * guarantee an edge trigger if an interrupt can be generated. 1214171713Sjeff */ 1215171713Sjeff/* EXTRA DELAY? */ 1216171713Sjeff#ifdef PC98 1217171713Sjeff outb(iobase + (com_mcr << port_shift), mcr_image); 1218171713Sjeff outb(iobase + (com_ier << port_shift), 0); 1219171713Sjeff#else 1220176734Sjeff outb(iobase + com_mcr, mcr_image); 1221117237Sjeff outb(iobase + com_ier, 0); 1222171713Sjeff#endif 1223116069Sjeff DELAY(1000); /* XXX */ 1224171482Sjeff irqmap[0] = isa_irq_pending(); 1225171482Sjeff 1226171482Sjeff /* 1227171482Sjeff * Attempt to set loopback mode so that we can send a null byte 1228171482Sjeff * without annoying any external device. 1229171482Sjeff */ 1230171482Sjeff/* EXTRA DELAY? */ 1231171482Sjeff#ifdef PC98 1232171482Sjeff outb(iobase + (com_mcr << port_shift), mcr_image | MCR_LOOPBACK); 1233171482Sjeff#else 1234171713Sjeff outb(iobase + com_mcr, mcr_image | MCR_LOOPBACK); 1235177435Sjeff#endif 1236176735Sjeff 1237171482Sjeff /* 1238109864Sjeff * Attempt to generate an output interrupt. On 8250's, setting 1239109864Sjeff * IER_ETXRDY generates an interrupt independent of the current 1240171482Sjeff * setting and independent of whether the THR is empty. On 16450's, 1241171482Sjeff * setting IER_ETXRDY generates an interrupt independent of the 1242171482Sjeff * current setting. On 16550A's, setting IER_ETXRDY only 1243153533Sdavidxu * generates an interrupt when IER_ETXRDY is not already set. 1244153533Sdavidxu */ 1245153533Sdavidxu#ifdef PC98 1246153533Sdavidxu outb(iobase + (com_ier << port_shift), IER_ETXRDY); 1247171482Sjeff if (iod.if_type == COM_IF_RSA98III) 1248171482Sjeff outb(rsabase + rsa_ier, 0x04); 1249153533Sdavidxu#else 1250166229Sjeff outb(iobase + com_ier, IER_ETXRDY); 1251153533Sdavidxu#endif /* PC98 */ 1252153533Sdavidxu 1253165762Sjeff /* 1254165766Sjeff * On some 16x50 incompatibles, setting IER_ETXRDY doesn't generate 1255153533Sdavidxu * an interrupt. They'd better generate one for actually doing 1256171482Sjeff * output. Loopback may be broken on the same incompatibles but 1257165762Sjeff * it's unlikely to do more than allow the null byte out. 1258165762Sjeff */ 1259165762Sjeff#ifdef PC98 1260165762Sjeff outb(iobase + (com_data << port_shift), 0); 1261171482Sjeff#else 1262171482Sjeff outb(iobase + com_data, 0); 1263171482Sjeff#endif 1264166108Sjeff DELAY((1 + 2) * 1000000 / (SIO_TEST_SPEED / 10)); 1265171899Sjeff 1266172409Sjeff /* 1267172409Sjeff * Turn off loopback mode so that the interrupt gate works again 1268172409Sjeff * (MCR_IENABLE was hidden). This should leave the device driving 1269172409Sjeff * an interrupt line high. It doesn't matter if the interrupt 1270172409Sjeff * line oscillates while we are not looking at it, since interrupts 1271171899Sjeff * are disabled. 1272171899Sjeff */ 1273171899Sjeff/* EXTRA DELAY? */ 1274171899Sjeff#ifdef PC98 1275176735Sjeff outb(iobase + (com_mcr << port_shift), mcr_image); 1276166108Sjeff#else 1277166108Sjeff outb(iobase + com_mcr, mcr_image); 1278153533Sdavidxu#endif /* PC98 */ 1279153533Sdavidxu 1280153533Sdavidxu /* 1281109864Sjeff * It's a definitly Serial PCMCIA(16550A), but still be required 1282171482Sjeff * for IIR_TXRDY implementation ( Palido 321s, DC-1S... ) 1283171482Sjeff */ 1284171482Sjeff if ( COM_NOPROBE(flags) ) { 1285171482Sjeff /* Reading IIR register twice */ 1286171482Sjeff for ( fn = 0; fn < 2; fn ++ ) { 1287171482Sjeff DELAY(10000); 1288171482Sjeff#ifdef PC98 1289171482Sjeff failures[6] = inb(iobase + (com_iir << port_shift)); 1290171482Sjeff#else 1291171482Sjeff failures[6] = inb(iobase + com_iir); 1292171482Sjeff#endif 1293171482Sjeff } 1294171482Sjeff /* Check IIR_TXRDY clear ? */ 1295171482Sjeff#ifdef PC98 1296171482Sjeff isa_set_portsize(dev, 1297171482Sjeff if_16550a_type[iod.if_type & 0x0f].io_size); 1298171482Sjeff#else 1299171482Sjeff isa_set_portsize(dev, IO_COMSIZE); 1300171482Sjeff#endif 1301171482Sjeff result = 0; 1302171482Sjeff if ( failures[6] & IIR_TXRDY ) { 1303171482Sjeff /* Nop, Double check with clearing IER */ 1304171482Sjeff#ifdef PC98 1305171482Sjeff outb(iobase + (com_ier << port_shift), 0); 1306171482Sjeff if (inb(iobase + 1307171482Sjeff (com_iir << port_shift)) & IIR_NOPEND) { 1308171482Sjeff#else 1309171482Sjeff outb(iobase + com_ier, 0); 1310171482Sjeff if ( inb(iobase + com_iir) & IIR_NOPEND ) { 1311171482Sjeff#endif 1312171482Sjeff /* Ok. we're familia this gang */ 1313171482Sjeff SET_FLAG(dev, COM_C_IIR_TXRDYBUG); /* Set IIR_TXRDYBUG */ 1314171482Sjeff } else { 1315171482Sjeff /* Unknow, Just omit this chip.. XXX*/ 1316171482Sjeff result = ENXIO; 1317171482Sjeff } 1318171482Sjeff } else { 1319171482Sjeff /* OK. this is well-known guys */ 1320171482Sjeff CLR_FLAG(dev, COM_C_IIR_TXRDYBUG); /*Clear IIR_TXRDYBUG*/ 1321171482Sjeff } 1322171482Sjeff#ifdef PC98 1323171482Sjeff outb(iobase + (com_cfcr << port_shift), CFCR_8BITS); 1324171482Sjeff#else 1325109864Sjeff outb(iobase + com_cfcr, CFCR_8BITS); 1326109864Sjeff#endif 1327109864Sjeff enable_intr(); 1328113357Sjeff return (iobase == siocniobase ? 0 : result); 1329163709Sjb } 1330109864Sjeff 1331165762Sjeff /* 1332109864Sjeff * Check that 1333109864Sjeff * o the CFCR, IER and MCR in UART hold the values written to them 1334163709Sjb * (the values happen to be all distinct - this is good for 1335113357Sjeff * avoiding false positive tests from bus echoes). 1336112966Sjeff * o an output interrupt is generated and its vector is correct. 1337165762Sjeff * o the interrupt goes away when the IIR in the UART is read. 1338165762Sjeff */ 1339165762Sjeff/* EXTRA DELAY? */ 1340112966Sjeff#ifdef PC98 1341171482Sjeff failures[0] = inb(iobase + (com_cfcr << port_shift)) - CFCR_8BITS; 1342165762Sjeff failures[1] = inb(iobase + (com_ier << port_shift)) - IER_ETXRDY; 1343165762Sjeff failures[2] = inb(iobase + (com_mcr << port_shift)) - mcr_image; 1344172293Sjeff#else 1345172293Sjeff failures[0] = inb(iobase + com_cfcr) - CFCR_8BITS; 1346172293Sjeff failures[1] = inb(iobase + com_ier) - IER_ETXRDY; 1347172293Sjeff failures[2] = inb(iobase + com_mcr) - mcr_image; 1348112966Sjeff#endif 1349172308Sjeff DELAY(10000); /* Some internal modems need this time */ 1350165762Sjeff irqmap[1] = isa_irq_pending(); 1351165762Sjeff#ifdef PC98 1352165762Sjeff failures[4] = (inb(iobase + (com_iir << port_shift)) & IIR_IMASK) 1353165762Sjeff - IIR_TXRDY; 1354165762Sjeff if (iod.if_type == COM_IF_RSA98III) 1355166208Sjeff inb(rsabase + rsa_srr); 1356166208Sjeff#else 1357165762Sjeff failures[4] = (inb(iobase + com_iir) & IIR_IMASK) - IIR_TXRDY; 1358165762Sjeff#endif 1359165762Sjeff DELAY(1000); /* XXX */ 1360165762Sjeff irqmap[2] = isa_irq_pending(); 1361165762Sjeff#ifdef PC98 1362171482Sjeff failures[6] = (inb(iobase + (com_iir << port_shift)) & IIR_IMASK) 1363171482Sjeff - IIR_NOPEND; 1364171482Sjeff if (iod.if_type == COM_IF_RSA98III) 1365171482Sjeff inb(rsabase + rsa_srr); 1366171482Sjeff#else 1367171482Sjeff failures[6] = (inb(iobase + com_iir) & IIR_IMASK) - IIR_NOPEND; 1368165762Sjeff#endif 1369165762Sjeff 1370112966Sjeff /* 1371112966Sjeff * Turn off all device interrupts and check that they go off properly. 1372109864Sjeff * Leave MCR_IENABLE alone. For ports without a master port, it gates 1373109864Sjeff * the OUT2 output of the UART to 1374121868Sjeff * the ICU input. Closing the gate would give a floating ICU input 1375121868Sjeff * (unless there is another device driving it) and spurious interrupts. 1376171482Sjeff * (On the system that this was first tested on, the input floats high 1377171482Sjeff * and gives a (masked) interrupt as soon as the gate is closed.) 1378121868Sjeff */ 1379116463Sjeff#ifdef PC98 1380163709Sjb outb(iobase + (com_ier << port_shift), 0); 1381116463Sjeff outb(iobase + (com_cfcr << port_shift), CFCR_8BITS); 1382165819Sjeff failures[7] = inb(iobase + (com_ier << port_shift)); 1383166208Sjeff if (iod.if_type == COM_IF_RSA98III) 1384121605Sjeff outb(rsabase + rsa_ier, 0x00); 1385165819Sjeff#else 1386171482Sjeff outb(iobase + com_ier, 0); 1387121868Sjeff outb(iobase + com_cfcr, CFCR_8BITS); /* dummy to avoid bus echo */ 1388121868Sjeff failures[7] = inb(iobase + com_ier); 1389121868Sjeff#endif 1390165819Sjeff DELAY(1000); /* XXX */ 1391165819Sjeff irqmap[3] = isa_irq_pending(); 1392165819Sjeff#ifdef PC98 1393165819Sjeff failures[9] = (inb(iobase + (com_iir << port_shift)) & IIR_IMASK) 1394165819Sjeff - IIR_NOPEND; 1395171482Sjeff if (iod.if_type == COM_IF_RSA98III) { 1396171482Sjeff inb(rsabase + rsa_srr); 1397171482Sjeff outb(rsabase + rsa_frr, 0x00); 1398165819Sjeff } 1399171482Sjeff#else 1400171482Sjeff failures[9] = (inb(iobase + com_iir) & IIR_IMASK) - IIR_NOPEND; 1401165819Sjeff#endif 1402165819Sjeff 1403165819Sjeff enable_intr(); 1404165819Sjeff 1405121868Sjeff irqs = irqmap[1] & ~irqmap[0]; 1406121868Sjeff if (isa_get_irq(idev) >= 0 && ((1 << isa_get_irq(idev)) & irqs) == 0) 1407133427Sjeff printf( 1408121868Sjeff "sio%d: configured irq %d not in bitmap of probed irqs %#x\n", 1409127850Sjeff device_get_unit(dev), isa_get_irq(idev), irqs); 1410171482Sjeff if (bootverbose) 1411171482Sjeff printf("sio%d: irq maps: %#x %#x %#x %#x\n", 1412121868Sjeff device_get_unit(dev), 1413116463Sjeff irqmap[0], irqmap[1], irqmap[2], irqmap[3]); 1414171482Sjeff 1415171482Sjeff#ifdef PC98 1416116463Sjeff isa_set_portsize(dev, if_16550a_type[iod.if_type & 0x0f].io_size); 1417116463Sjeff#else 1418171482Sjeff isa_set_portsize(dev, IO_COMSIZE); 1419171482Sjeff#endif 1420171482Sjeff result = 0; 1421171482Sjeff for (fn = 0; fn < sizeof failures; ++fn) 1422171482Sjeff if (failures[fn]) { 1423171482Sjeff#ifdef PC98 1424121868Sjeff outb(iobase + (com_mcr << port_shift), 0); 1425163709Sjb#else 1426121868Sjeff outb(iobase + com_mcr, 0); 1427121868Sjeff#endif 1428121868Sjeff result = ENXIO; 1429121868Sjeff if (bootverbose) { 1430171482Sjeff printf("sio%d: probe failed test(s):", 1431121868Sjeff device_get_unit(dev)); 1432121868Sjeff for (fn = 0; fn < sizeof failures; ++fn) 1433171482Sjeff if (failures[fn]) 1434171482Sjeff printf(" %d", fn); 1435121868Sjeff printf("\n"); 1436121868Sjeff } 1437121868Sjeff break; 1438113357Sjeff } 1439171482Sjeff return (iobase == siocniobase ? 0 : result); 1440134791Sjulian} 1441134791Sjulian 1442134791Sjulian#ifdef COM_ESP 1443134791Sjulianstatic int 1444165762Sjeffespattach(com, esp_port) 1445134791Sjulian struct com_s *com; 1446134791Sjulian Port_t esp_port; 1447134791Sjulian{ 1448136167Sjulian u_char dips; 1449164936Sjulian u_char val; 1450165762Sjeff 1451165796Sjeff /* 1452177009Sjeff * Check the ESP-specific I/O port to see if we're an ESP 1453134791Sjulian * card. If not, return failure immediately. 1454134791Sjulian */ 1455134791Sjulian if ((inb(esp_port) & 0xf3) == 0) { 1456113357Sjeff printf(" port 0x%x is not an ESP board?\n", esp_port); 1457113357Sjeff return (0); 1458165762Sjeff } 1459113357Sjeff 1460109864Sjeff /* 1461109864Sjeff * We've got something that claims to be a Hayes ESP card. 1462109864Sjeff * Let's hope so. 1463165762Sjeff */ 1464165762Sjeff 1465165762Sjeff /* Get the dip-switch configuration */ 1466109864Sjeff#ifdef PC98 1467109864Sjeff outb(esp_port + ESP98_CMD1, ESP_GETDIPS); 1468171482Sjeff dips = inb(esp_port + ESP98_STATUS1); 1469171482Sjeff#else 1470171482Sjeff outb(esp_port + ESP_CMD1, ESP_GETDIPS); 1471171482Sjeff dips = inb(esp_port + ESP_STATUS1); 1472171482Sjeff#endif 1473171482Sjeff 1474121790Sjeff /* 1475164936Sjulian * Bits 0,1 of dips say which COM port we are. 1476109864Sjeff */ 1477165762Sjeff#ifdef PC98 1478165762Sjeff if ((com->iobase & 0xff) == likely_com_ports[dips & 0x03]) 1479165762Sjeff#else 1480165796Sjeff if (com->iobase == likely_com_ports[dips & 0x03]) 1481165796Sjeff#endif 1482165796Sjeff printf(" : ESP"); 1483109864Sjeff else { 1484109864Sjeff printf(" esp_port has com %d\n", dips & 0x03); 1485116365Sjeff return (0); 1486165762Sjeff } 1487164936Sjulian 1488165762Sjeff /* 1489165762Sjeff * Check for ESP version 2.0 or later: bits 4,5,6 = 010. 1490164936Sjulian */ 1491164936Sjulian#ifdef PC98 1492165762Sjeff outb(esp_port + ESP98_CMD1, ESP_GETTEST); 1493109864Sjeff val = inb(esp_port + ESP98_STATUS1); /* clear reg 1 */ 1494109864Sjeff val = inb(esp_port + ESP98_STATUS2); 1495171482Sjeff#else 1496171482Sjeff outb(esp_port + ESP_CMD1, ESP_GETTEST); 1497171482Sjeff val = inb(esp_port + ESP_STATUS1); /* clear reg 1 */ 1498171482Sjeff val = inb(esp_port + ESP_STATUS2); 1499171482Sjeff#endif 1500165762Sjeff if ((val & 0x70) < 0x20) { 1501139453Sjhb printf("-old (%o)", val & 0x70); 1502109864Sjeff return (0); 1503164936Sjulian } 1504177009Sjeff 1505177009Sjeff /* 1506109864Sjeff * Check for ability to emulate 16550: bit 7 == 1 1507139316Sjeff */ 1508173600Sjulian if ((dips & 0x80) == 0) { 1509173600Sjulian printf(" slave"); 1510164936Sjulian return (0); 1511170293Sjeff } 1512139453Sjhb 1513139453Sjhb /* 1514177376Sjeff * Okay, we seem to be a Hayes ESP card. Whee. 1515177376Sjeff */ 1516177376Sjeff com->esp = TRUE; 1517177376Sjeff com->esp_port = esp_port; 1518177376Sjeff return (1); 1519177376Sjeff} 1520165766Sjeff#endif /* COM_ESP */ 1521165762Sjeff 1522165762Sjeffstatic int 1523171482Sjeffsioattach(dev) 1524177009Sjeff device_t dev; 1525177009Sjeff{ 1526177376Sjeff struct com_s *com; 1527177376Sjeff#ifdef COM_ESP 1528177376Sjeff Port_t *espp; 1529177376Sjeff#endif 1530177009Sjeff Port_t iobase; 1531177376Sjeff int unit; 1532177376Sjeff void *ih; 1533177376Sjeff struct resource *res; 1534176735Sjeff int zero = 0; 1535171482Sjeff u_int flags = isa_get_flags(dev); 1536176735Sjeff#ifdef PC98 1537176735Sjeff int port_shift = 0; 1538177376Sjeff u_char *obuf; 1539177009Sjeff u_long obufsize; 1540177376Sjeff#endif 1541109864Sjeff 1542109864Sjeff iobase = isa_get_port(dev); 1543139453Sjhb#ifdef PC98 1544139453Sjhb if (((flags >> 24) & 0xff) == COM_IF_RSA98III) 1545139453Sjhb iobase += 8; 1546139453Sjhb#endif 1547109864Sjeff unit = device_get_unit(dev); 1548139453Sjhb com = device_get_softc(dev); 1549139453Sjhb#ifdef PC98 1550139453Sjhb obufsize = 256; 1551139453Sjhb if (((flags >> 24) & 0xff) == COM_IF_RSA98III) 1552139453Sjhb obufsize = 2048; 1553139453Sjhb if ((obuf = malloc(obufsize * 2, M_DEVBUF, M_NOWAIT)) == NULL) 1554139453Sjhb return (0); 1555139453Sjhb bzero(obuf, obufsize * 2); 1556139453Sjhb#endif 1557139453Sjhb 1558139453Sjhb /* 1559139453Sjhb * sioprobe() has initialized the device registers as follows: 1560139453Sjhb * o cfcr = CFCR_8BITS. 1561139453Sjhb * It is most important that CFCR_DLAB is off, so that the 1562139453Sjhb * data port is not hidden when we enable interrupts. 1563139453Sjhb * o ier = 0. 1564139453Sjhb * Interrupts are only enabled when the line is open. 1565139453Sjhb * o mcr = MCR_IENABLE, or 0 if the port has AST/4 compatible 1566139453Sjhb * interrupt control register or the config specifies no irq. 1567139453Sjhb * Keeping MCR_DTR and MCR_RTS off might stop the external 1568139453Sjhb * device from sending before we are ready. 1569139453Sjhb */ 1570163709Sjb bzero(com, sizeof *com); 1571139453Sjhb#ifdef PC98 1572139453Sjhb com->obufsize = obufsize; 1573139453Sjhb com->obuf1 = obuf; 1574139455Sjhb com->obuf2 = obuf + obufsize; 1575139453Sjhb#endif 1576139453Sjhb com->unit = unit; 1577139453Sjhb com->cfcr_image = CFCR_8BITS; 1578139453Sjhb com->dtr_wait = 3 * hz; 1579139453Sjhb com->loses_outints = COM_LOSESOUTINTS(flags) != 0; 1580171482Sjeff com->no_irq = isa_get_irq(dev) < 0; 1581171482Sjeff com->tx_fifo_size = 1; 1582171482Sjeff com->obufs[0].l_head = com->obuf1; 1583139453Sjhb com->obufs[1].l_head = com->obuf2; 1584139453Sjhb 1585139453Sjhb com->iobase = iobase; 1586139453Sjhb#ifdef PC98 1587139453Sjhb if (pc98_set_ioport(com, isa_get_flags(dev)) == -1) { 1588139453Sjhb com->pc98_if_type = (isa_get_flags(dev) >> 24) & 0xff; 1589139453Sjhb port_shift = if_16550a_type[com->pc98_if_type & 0x0f].port_shift; 1590139453Sjhb com->data_port = iobase + (com_data << port_shift); 1591139453Sjhb com->int_id_port = iobase + (com_iir << port_shift); 1592139455Sjhb com->modem_ctl_port = iobase + (com_mcr << port_shift); 1593139453Sjhb com->mcr_image = inb(com->modem_ctl_port); 1594139453Sjhb com->line_status_port = iobase + (com_lsr << port_shift); 1595139453Sjhb com->modem_status_port = iobase + (com_msr << port_shift); 1596139453Sjhb com->intr_ctl_port = iobase + (com_ier << port_shift); 1597139453Sjhb } 1598139453Sjhb#else /* not PC98 */ 1599139453Sjhb com->data_port = iobase + com_data; 1600139453Sjhb com->int_id_port = iobase + com_iir; 1601139453Sjhb com->modem_ctl_port = iobase + com_mcr; 1602139453Sjhb com->mcr_image = inb(com->modem_ctl_port); 1603139453Sjhb com->line_status_port = iobase + com_lsr; 1604139453Sjhb com->modem_status_port = iobase + com_msr; 1605139453Sjhb com->intr_ctl_port = iobase + com_ier; 1606139453Sjhb#endif 1607139453Sjhb 1608139453Sjhb /* 1609139455Sjhb * We don't use all the flags from <sys/ttydefaults.h> since they 1610171482Sjeff * are only relevant for logins. It's important to have echo off 1611171482Sjeff * initially so that the line doesn't start blathering before the 1612171482Sjeff * echo flag can be turned off. 1613139453Sjhb */ 1614163709Sjb com->it_in.c_iflag = 0; 1615161599Sdavidxu com->it_in.c_oflag = 0; 1616161599Sdavidxu com->it_in.c_cflag = TTYDEF_CFLAG; 1617161599Sdavidxu com->it_in.c_lflag = 0; 1618163709Sjb if (unit == comconsole) { 1619164939Sjulian#ifdef PC98 1620164939Sjulian if (IS_8251(com->pc98_if_type)) 1621163709Sjb DELAY(100000); 1622163709Sjb#endif 1623161599Sdavidxu com->it_in.c_iflag = TTYDEF_IFLAG; 1624161599Sdavidxu com->it_in.c_oflag = TTYDEF_OFLAG; 1625161599Sdavidxu com->it_in.c_cflag = TTYDEF_CFLAG | CLOCAL; 1626161599Sdavidxu com->it_in.c_lflag = TTYDEF_LFLAG; 1627161599Sdavidxu com->lt_out.c_cflag = com->lt_in.c_cflag = CLOCAL; 1628161599Sdavidxu com->lt_out.c_ispeed = com->lt_out.c_ospeed = 1629161599Sdavidxu com->lt_in.c_ispeed = com->lt_in.c_ospeed = 1630174536Sdavidxu com->it_in.c_ispeed = com->it_in.c_ospeed = comdefaultrate; 1631161599Sdavidxu } else 1632164091Smaxim com->it_in.c_ispeed = com->it_in.c_ospeed = TTYDEF_SPEED; 1633163709Sjb if (siosetwater(com, com->it_in.c_ispeed) != 0) { 1634161599Sdavidxu enable_intr(); 1635161599Sdavidxu free(com, M_DEVBUF); 1636161599Sdavidxu return (0); 1637161599Sdavidxu } 1638161599Sdavidxu enable_intr(); 1639161599Sdavidxu termioschars(&com->it_in); 1640161599Sdavidxu com->it_out = com->it_in; 1641174536Sdavidxu 1642163709Sjb /* attempt to determine UART type */ 1643161599Sdavidxu printf("sio%d: type", unit); 1644161599Sdavidxu 1645163709Sjb 1646174536Sdavidxu#ifndef PC98 1647161599Sdavidxu#ifdef COM_MULTIPORT 1648174536Sdavidxu if (!COM_ISMULTIPORT(flags) && !COM_IIR_TXRDYBUG(flags)) 1649161599Sdavidxu#else 1650161599Sdavidxu if (!COM_IIR_TXRDYBUG(flags)) 1651171482Sjeff#endif 1652174847Swkoszek { 1653174847Swkoszek u_char scr; 1654174847Swkoszek u_char scr1; 1655174847Swkoszek u_char scr2; 1656174847Swkoszek 1657174847Swkoszek scr = inb(iobase + com_scr); 1658174847Swkoszek outb(iobase + com_scr, 0xa5); 1659174847Swkoszek scr1 = inb(iobase + com_scr); 1660174847Swkoszek outb(iobase + com_scr, 0x5a); 1661174847Swkoszek scr2 = inb(iobase + com_scr); 1662174847Swkoszek outb(iobase + com_scr, scr); 1663174847Swkoszek if (scr1 != 0xa5 || scr2 != 0x5a) { 1664174847Swkoszek printf(" 8250"); 1665174847Swkoszek goto determined_type; 1666174847Swkoszek } 1667174847Swkoszek } 1668174847Swkoszek#endif /* !PC98 */ 1669171713Sjeff#ifdef PC98 1670171713Sjeff if (IS_8251(com->pc98_if_type)) { 1671171713Sjeff com_int_TxRx_disable( com ); 1672171713Sjeff com_cflag_and_speed_set( com, com->it_in.c_cflag, comdefaultrate ); 1673171713Sjeff com_tiocm_bic( com, TIOCM_DTR|TIOCM_RTS|TIOCM_LE ); 1674171713Sjeff com_send_break_off( com ); 1675171713Sjeff printf(" 8251%s", if_8251_type[com->pc98_if_type & 0x0f].name); 1676171713Sjeff } else { 1677171713Sjeff outb(iobase + (com_fifo << port_shift), FIFO_ENABLE | FIFO_RX_HIGH); 1678171713Sjeff#else 1679177435Sjeff outb(iobase + com_fifo, FIFO_ENABLE | FIFO_RX_HIGH); 1680171713Sjeff#endif /* PC98 */ 1681171713Sjeff DELAY(100); 1682171713Sjeff com->st16650a = 0; 1683171713Sjeff switch (inb(com->int_id_port) & IIR_FIFO_MASK) { 1684171713Sjeff case FIFO_RX_LOW: 1685171713Sjeff printf(" 16450"); 1686171713Sjeff break; 1687171713Sjeff case FIFO_RX_MEDL: 1688171713Sjeff printf(" 16450?"); 1689177435Sjeff break; 1690171713Sjeff case FIFO_RX_MEDH: 1691171713Sjeff printf(" 16550?"); 1692171713Sjeff break; 1693171713Sjeff case FIFO_RX_HIGH: 1694171713Sjeff if (COM_NOFIFO(flags)) { 1695171713Sjeff printf(" 16550A fifo disabled"); 1696171713Sjeff } else { 1697171713Sjeff com->hasfifo = TRUE; 1698171713Sjeff#ifdef PC98 1699171713Sjeff com->tx_fifo_size = 0; /* XXX flag conflicts. */ 1700171713Sjeff printf(" 16550A"); 1701171713Sjeff#else 1702171713Sjeff if (COM_ST16650A(flags)) { 1703171713Sjeff com->st16650a = 1; 1704171713Sjeff com->tx_fifo_size = 32; 1705171713Sjeff printf(" ST16650A"); 1706171482Sjeff } else { 1707171482Sjeff com->tx_fifo_size = COM_FIFOSIZE(flags); 1708171482Sjeff printf(" 16550A"); 1709171482Sjeff } 1710171482Sjeff#endif 1711171482Sjeff } 1712171482Sjeff#ifdef PC98 1713171482Sjeff if (com->pc98_if_type == COM_IF_RSA98III) { 1714171482Sjeff com->tx_fifo_size = 2048; 1715171482Sjeff com->rsabase = isa_get_port(dev); 1716171482Sjeff outb(com->rsabase + rsa_ier, 0x00); 1717171482Sjeff outb(com->rsabase + rsa_frr, 0x00); 1718171482Sjeff } 1719171482Sjeff#endif 1720171482Sjeff 1721161599Sdavidxu#ifdef COM_ESP 1722135051Sjulian#ifdef PC98 1723109864Sjeff if (com->pc98_if_type == COM_IF_ESP98) 1724165627Sjeff#endif 1725164936Sjulian for (espp = likely_esp_ports; *espp != 0; espp++) 1726171482Sjeff if (espattach(com, *espp)) { 1727171713Sjeff com->tx_fifo_size = 1024; 1728171482Sjeff break; 1729109864Sjeff } 1730170293Sjeff#endif 1731177376Sjeff if (!com->st16650a) { 1732109864Sjeff if (!com->tx_fifo_size) 1733171482Sjeff com->tx_fifo_size = 16; 1734171482Sjeff else 1735164936Sjulian printf(" lookalike with %d bytes FIFO", 1736171713Sjeff com->tx_fifo_size); 1737171482Sjeff } 1738133555Sjeff 1739113339Sjulian break; 1740132266Sjhb } 1741144777Sups 1742123434Sjeff#ifdef PC98 1743171482Sjeff if (com->pc98_if_type == COM_IF_RSB3000) { 1744171482Sjeff /* Set RSB-2000/3000 Extended Buffer mode. */ 1745123434Sjeff u_char lcr; 1746167327Sjulian lcr = inb(iobase + (com_cfcr << port_shift)); 1747171482Sjeff outb(iobase + (com_cfcr << port_shift), lcr | CFCR_DLAB); 1748139334Sjeff outb(iobase + (com_emr << port_shift), EMR_EXBUFF | EMR_EFMODE); 1749170293Sjeff outb(iobase + (com_cfcr << port_shift), lcr); 1750171482Sjeff } 1751171713Sjeff#endif 1752170293Sjeff 1753171713Sjeff#ifdef COM_ESP 1754171713Sjeff if (com->esp) { 1755177435Sjeff /* 1756171713Sjeff * Set 16550 compatibility mode. 1757171713Sjeff * We don't use the ESP_MODE_SCALE bit to increase the 1758171482Sjeff * fifo trigger levels because we can't handle large 1759171482Sjeff * bursts of input. 1760171482Sjeff * XXX flow control should be set in comparam(), not here. 1761171482Sjeff */ 1762177435Sjeff#ifdef PC98 1763171482Sjeff outb(com->esp_port + ESP98_CMD1, ESP_SETMODE); 1764171482Sjeff outb(com->esp_port + ESP98_CMD2, ESP_MODE_RTS | ESP_MODE_FIFO); 1765171482Sjeff#else 1766171482Sjeff outb(com->esp_port + ESP_CMD1, ESP_SETMODE); 1767171482Sjeff outb(com->esp_port + ESP_CMD2, ESP_MODE_RTS | ESP_MODE_FIFO); 1768171482Sjeff#endif 1769171482Sjeff 1770171482Sjeff /* Set RTS/CTS flow control. */ 1771171482Sjeff#ifdef PC98 1772171482Sjeff outb(com->esp_port + ESP98_CMD1, ESP_SETFLOWTYPE); 1773171482Sjeff outb(com->esp_port + ESP98_CMD2, ESP_FLOW_RTS); 1774145256Sjkoshy outb(com->esp_port + ESP98_CMD2, ESP_FLOW_CTS); 1775145256Sjkoshy#else 1776145256Sjkoshy outb(com->esp_port + ESP_CMD1, ESP_SETFLOWTYPE); 1777145256Sjkoshy outb(com->esp_port + ESP_CMD2, ESP_FLOW_RTS); 1778145256Sjkoshy outb(com->esp_port + ESP_CMD2, ESP_FLOW_CTS); 1779174629Sjeff#endif 1780172411Sjeff 1781171482Sjeff /* Set flow-control levels. */ 1782171482Sjeff#ifdef PC98 1783171482Sjeff outb(com->esp_port + ESP98_CMD1, ESP_SETRXFLOW); 1784171482Sjeff outb(com->esp_port + ESP98_CMD2, HIBYTE(768)); 1785171482Sjeff outb(com->esp_port + ESP98_CMD2, LOBYTE(768)); 1786171482Sjeff outb(com->esp_port + ESP98_CMD2, HIBYTE(512)); 1787171482Sjeff outb(com->esp_port + ESP98_CMD2, LOBYTE(512)); 1788171482Sjeff#else 1789174629Sjeff outb(com->esp_port + ESP_CMD1, ESP_SETRXFLOW); 1790174629Sjeff outb(com->esp_port + ESP_CMD2, HIBYTE(768)); 1791145256Sjkoshy outb(com->esp_port + ESP_CMD2, LOBYTE(768)); 1792145256Sjkoshy outb(com->esp_port + ESP_CMD2, HIBYTE(512)); 1793145256Sjkoshy outb(com->esp_port + ESP_CMD2, LOBYTE(512)); 1794145256Sjkoshy#endif 1795171482Sjeff 1796171482Sjeff#ifdef PC98 1797171482Sjeff /* Set UART clock prescaler. */ 1798171482Sjeff outb(com->esp_port + ESP98_CMD1, ESP_SETCLOCK); 1799171482Sjeff outb(com->esp_port + ESP98_CMD2, 2); /* 4 times */ 1800171482Sjeff#endif 1801171482Sjeff } 1802171482Sjeff#endif /* COM_ESP */ 1803109864Sjeff#ifdef PC98 1804109864Sjeff printf("%s", if_16550a_type[com->pc98_if_type & 0x0f].name); 1805171482Sjeff outb(iobase + (com_fifo << port_shift), 0); 1806171482Sjeff#else 1807171482Sjeff outb(iobase + com_fifo, 0); 1808109864Sjeffdetermined_type: ; 1809130551Sjulian#endif 1810109864Sjeff 1811109864Sjeff#ifdef COM_MULTIPORT 1812109864Sjeff if (COM_ISMULTIPORT(flags)) { 1813130551Sjulian com->multiport = TRUE; 1814165762Sjeff printf(" (multiport"); 1815130551Sjulian if (unit == COM_MPMASTER(flags)) 1816163709Sjb printf(" master"); 1817170293Sjeff printf(")"); 1818163709Sjb com->no_irq = 1819165762Sjeff isa_get_irq(devclass_get_device 1820170293Sjeff (sio_devclass, COM_MPMASTER(flags))) < 0; 1821130551Sjulian } 1822109864Sjeff#endif /* COM_MULTIPORT */ 1823109864Sjeff#ifdef PC98 1824171482Sjeff } 1825171482Sjeff#endif 1826171482Sjeff if (unit == comconsole) 1827109864Sjeff printf(", console"); 1828177085Sjeff if ( COM_IIR_TXRDYBUG(flags) ) 1829109864Sjeff printf(" with a bogus IIR_TXRDY register"); 1830165762Sjeff printf("\n"); 1831170293Sjeff 1832109864Sjeff if (!sio_registered) { 1833172264Sjeff register_swi(SWI_TTY, siopoll); 1834177085Sjeff sio_registered = TRUE; 1835177085Sjeff } 1836177085Sjeff#ifdef DEVFS 1837177085Sjeff com->devfs_token_ttyd = devfs_add_devswf(&sio_cdevsw, 1838109864Sjeff unit, DV_CHR, 1839109864Sjeff UID_ROOT, GID_WHEEL, 0600, "ttyd%r", unit); 1840171482Sjeff com->devfs_token_ttyi = devfs_add_devswf(&sio_cdevsw, 1841171482Sjeff unit | CONTROL_INIT_STATE, DV_CHR, 1842171482Sjeff UID_ROOT, GID_WHEEL, 0600, "ttyid%r", unit); 1843171482Sjeff com->devfs_token_ttyl = devfs_add_devswf(&sio_cdevsw, 1844109864Sjeff unit | CONTROL_LOCK_STATE, DV_CHR, 1845109864Sjeff UID_ROOT, GID_WHEEL, 0600, "ttyld%r", unit); 1846109864Sjeff com->devfs_token_cuaa = devfs_add_devswf(&sio_cdevsw, 1847166229Sjeff unit | CALLOUT_MASK, DV_CHR, 1848171482Sjeff UID_UUCP, GID_DIALER, 0660, "cuaa%r", unit); 1849165762Sjeff com->devfs_token_cuai = devfs_add_devswf(&sio_cdevsw, 1850170293Sjeff unit | CALLOUT_MASK | CONTROL_INIT_STATE, DV_CHR, 1851166229Sjeff UID_UUCP, GID_DIALER, 0660, "cuaia%r", unit); 1852177085Sjeff com->devfs_token_cual = devfs_add_devswf(&sio_cdevsw, 1853109864Sjeff unit | CALLOUT_MASK | CONTROL_LOCK_STATE, DV_CHR, 1854165762Sjeff UID_UUCP, GID_DIALER, 0660, "cuala%r", unit); 1855165762Sjeff#endif 1856109864Sjeff com->flags = isa_get_flags(dev); /* Heritate id_flags for later */ 1857172264Sjeff com->pps.ppscap = PPS_CAPTUREASSERT | PPS_CAPTURECLEAR; 1858172264Sjeff pps_init(&com->pps); 1859171482Sjeff 1860166208Sjeff res = bus_alloc_resource(dev, SYS_RES_IRQ, &zero, 0ul, ~0ul, 1, 1861109864Sjeff RF_SHAREABLE | RF_ACTIVE); 1862171482Sjeff BUS_SETUP_INTR(device_get_parent(dev), dev, res, 1863171482Sjeff INTR_TYPE_TTY | INTR_TYPE_FAST, 1864165819Sjeff siointr, com, &ih); 1865166229Sjeff 1866109864Sjeff return (0); 1867166229Sjeff} 1868166229Sjeff 1869166190Sjeffstatic int 1870109864Sjeffsioopen(dev, flag, mode, p) 1871109864Sjeff dev_t dev; 1872109864Sjeff int flag; 1873109864Sjeff int mode; 1874109864Sjeff struct proc *p; 1875109864Sjeff{ 1876109864Sjeff struct com_s *com; 1877163709Sjb int error; 1878109864Sjeff Port_t iobase; 1879170293Sjeff int mynor; 1880164936Sjulian int s; 1881165762Sjeff struct tty *tp; 1882165762Sjeff int unit; 1883165762Sjeff#ifdef PC98 1884165762Sjeff int port_shift = 0; 1885165762Sjeff#endif 1886171482Sjeff 1887165762Sjeff mynor = minor(dev); 1888165762Sjeff unit = MINOR_TO_UNIT(mynor); 1889164936Sjulian if ((u_int) unit >= NSIOTOT || (com = com_addr(unit)) == NULL) 1890109864Sjeff return (ENXIO); 1891171482Sjeff if (com->gone) 1892171482Sjeff return (ENXIO); 1893171482Sjeff if (mynor & CONTROL_MASK) 1894164936Sjulian return (0); 1895164936Sjulian#if 0 /* XXX */ 1896164936Sjulian tp = com->tp = sio_tty[unit] = ttymalloc(sio_tty[unit]); 1897164936Sjulian#else 1898164936Sjulian tp = com->tp = &sio_tty[unit]; 1899164936Sjulian#endif 1900177426Sjeff s = spltty(); 1901165762Sjeff 1902165762Sjeff#ifdef PC98 1903165762Sjeff if (!IS_8251(com->pc98_if_type)) 1904177426Sjeff port_shift = if_16550a_type[com->pc98_if_type & 0x0f].port_shift; 1905177426Sjeff#endif 1906171482Sjeff /* 1907176735Sjeff * We jump to this label after all non-interrupted sleeps to pick 1908164936Sjulian * up any changes of the device state. 1909177426Sjeff */ 1910165762Sjeffopen_top: 1911165762Sjeff while (com->state & CS_DTR_OFF) { 1912165762Sjeff error = tsleep(&com->dtr_wait, TTIPRI | PCATCH, "siodtr", 0); 1913164936Sjulian if (com_addr(unit) == NULL) 1914164936Sjulian return (ENXIO); 1915164936Sjulian if (error != 0 || com->gone) 1916165762Sjeff goto out; 1917165762Sjeff } 1918165762Sjeff if (tp->t_state & TS_ISOPEN) { 1919165762Sjeff /* 1920165762Sjeff * The device is open, so everything has been initialized. 1921171482Sjeff * Handle conflicts. 1922171482Sjeff */ 1923165762Sjeff if (mynor & CALLOUT_MASK) { 1924113357Sjeff if (!com->active_out) { 1925113357Sjeff error = EBUSY; 1926171482Sjeff goto out; 1927171482Sjeff } 1928171482Sjeff } else { 1929113357Sjeff if (com->active_out) { 1930163709Sjb if (flag & O_NONBLOCK) { 1931113357Sjeff error = EBUSY; 1932113357Sjeff goto out; 1933170293Sjeff } 1934163709Sjb error = tsleep(&com->active_out, 1935113357Sjeff TTIPRI | PCATCH, "siobi", 0); 1936163709Sjb if (com_addr(unit) == NULL) 1937109864Sjeff return (ENXIO); 1938109864Sjeff if (error != 0 || com->gone) 1939109864Sjeff goto out; 1940109864Sjeff goto open_top; 1941109864Sjeff } 1942109864Sjeff } 1943164939Sjulian if (tp->t_state & TS_XCLUDE && 1944109864Sjeff suser(p)) { 1945165762Sjeff error = EBUSY; 1946164939Sjulian goto out; 1947163709Sjb } 1948173600Sjulian } else { 1949113372Sjeff /* 1950177368Sjeff * The device isn't open, so there are no conflicts. 1951165762Sjeff * Initialize it. Initialization is done twice in many 1952165762Sjeff * cases: to preempt sleeping callin opens if we are 1953113372Sjeff * callout, and to complete a callin open after DCD rises. 1954113372Sjeff */ 1955171482Sjeff tp->t_oproc = comstart; 1956171482Sjeff tp->t_param = comparam; 1957171482Sjeff tp->t_dev = dev; 1958171482Sjeff tp->t_termios = mynor & CALLOUT_MASK 1959171482Sjeff ? com->it_out : com->it_in; 1960171482Sjeff#ifdef PC98 1961113372Sjeff if (!IS_8251(com->pc98_if_type)) 1962164939Sjulian#endif 1963164936Sjulian (void)commctl(com, TIOCM_DTR | TIOCM_RTS, DMSET); 1964165762Sjeff com->poll = com->no_irq; 1965164939Sjulian com->poll_output = com->loses_outints; 1966173600Sjulian ++com->wopeners; 1967164939Sjulian error = comparam(tp, &tp->t_termios); 1968165762Sjeff --com->wopeners; 1969165762Sjeff if (error != 0) 1970165762Sjeff goto out; 1971165762Sjeff#ifdef PC98 1972165762Sjeff if (IS_8251(com->pc98_if_type)) { 1973170293Sjeff com_tiocm_bis(com, TIOCM_DTR|TIOCM_RTS); 1974171482Sjeff pc98_msrint_start(dev); 1975164939Sjulian } 1976165762Sjeff#endif 1977170293Sjeff /* 1978164936Sjulian * XXX we should goto open_top if comparam() slept. 1979164936Sjulian */ 1980177005Sjeff iobase = com->iobase; 1981177005Sjeff if (com->hasfifo) { 1982177005Sjeff /* 1983177005Sjeff * (Re)enable and drain fifos. 1984177005Sjeff * 1985177005Sjeff * Certain SMC chips cause problems if the fifos 1986177005Sjeff * are enabled while input is ready. Turn off the 1987177005Sjeff * fifo if necessary to clear the input. We test 1988177005Sjeff * the input ready bit after enabling the fifos 1989177005Sjeff * since we've already enabled them in comparam() 1990177005Sjeff * and to handle races between enabling and fresh 1991177005Sjeff * input. 1992177005Sjeff */ 1993177005Sjeff while (TRUE) { 1994177005Sjeff#ifdef PC98 1995177005Sjeff outb(iobase + (com_fifo << port_shift), 1996177005Sjeff FIFO_RCV_RST | FIFO_XMT_RST 1997177005Sjeff | com->fifo_image); 1998171482Sjeff if (com->pc98_if_type == COM_IF_RSA98III) 1999171482Sjeff outb(com->rsabase + rsa_frr , 0x00); 2000171482Sjeff#else 2001171482Sjeff outb(iobase + com_fifo, 2002164936Sjulian FIFO_RCV_RST | FIFO_XMT_RST 2003164936Sjulian | com->fifo_image); 2004164936Sjulian#endif 2005164936Sjulian /* 2006164936Sjulian * XXX the delays are for superstitious 2007164936Sjulian * historical reasons. It must be less than 2008164936Sjulian * the character time at the maximum 2009164936Sjulian * supported speed (87 usec at 115200 bps 2010164936Sjulian * 8N1). Otherwise we might loop endlessly 2011164936Sjulian * if data is streaming in. We used to use 2012164936Sjulian * delays of 100. That usually worked 2013164936Sjulian * because DELAY(100) used to usually delay 2014164936Sjulian * for about 85 usec instead of 100. 2015164936Sjulian */ 2016164936Sjulian DELAY(50); 2017170293Sjeff#ifndef PC98 2018164936Sjulian if (!(inb(com->line_status_port) & LSR_RXRDY)) 2019164936Sjulian#else 2020177005Sjeff if (com->pc98_if_type == COM_IF_RSA98III 2021170293Sjeff ? !(inb(com->rsabase + rsa_srr) & 0x08) 2022164936Sjulian : !(inb(com->line_status_port) & LSR_RXRDY)) 2023164936Sjulian#endif 2024164936Sjulian break; 2025171482Sjeff#ifdef PC98 2026171482Sjeff outb(iobase + (com_fifo << port_shift), 0); 2027171482Sjeff#else 2028171482Sjeff outb(iobase + com_fifo, 0); 2029164936Sjulian#endif 2030121127Sjeff DELAY(50); 2031109864Sjeff (void) inb(com->data_port); 2032164936Sjulian } 2033164936Sjulian } 2034109864Sjeff 2035171482Sjeff disable_intr(); 2036164936Sjulian#ifdef PC98 2037172409Sjeff if (IS_8251(com->pc98_if_type)) { 2038133427Sjeff com_tiocm_bis(com, TIOCM_LE); 2039172409Sjeff com->pc98_prev_modem_status = pc98_get_modem_status(com); 2040172409Sjeff com_int_Rx_enable(com); 2041172409Sjeff } else { 2042172409Sjeff#endif 2043172409Sjeff (void) inb(com->line_status_port); 2044172409Sjeff (void) inb(com->data_port); 2045172409Sjeff com->prev_modem_status = com->last_modem_status 2046172409Sjeff = inb(com->modem_status_port); 2047165766Sjeff if (COM_IIR_TXRDYBUG(com->flags)) { 2048165766Sjeff outb(com->intr_ctl_port, IER_ERXRDY | IER_ERLS 2049133427Sjeff | IER_EMSC); 2050165766Sjeff } else { 2051165766Sjeff outb(com->intr_ctl_port, IER_ERXRDY | IER_ETXRDY 2052165766Sjeff | IER_ERLS | IER_EMSC); 2053165766Sjeff } 2054165766Sjeff#ifdef PC98 2055165766Sjeff if (com->pc98_if_type == COM_IF_RSA98III) { 2056175104Sjeff outb(com->rsabase + rsa_ier, 0x1d); 2057113357Sjeff outb(com->intr_ctl_port, IER_ERLS | IER_EMSC); 2058175104Sjeff } 2059175104Sjeff#endif 2060175104Sjeff#ifdef PC98 2061175104Sjeff } 2062175104Sjeff#endif 2063175104Sjeff enable_intr(); 2064175104Sjeff /* 2065177009Sjeff * Handle initial DCD. Callout devices get a fake initial 2066175104Sjeff * DCD (trapdoor DCD). If we are callout, then any sleeping 2067113357Sjeff * callin opens get woken up and resume sleeping on "siobi" 2068109864Sjeff * instead of "siodcd". 2069109864Sjeff */ 2070164936Sjulian /* 2071113357Sjeff * XXX `mynor & CALLOUT_MASK' should be 2072109864Sjeff * `tp->t_cflag & (SOFT_CARRIER | TRAPDOOR_CARRIER) where 2073177009Sjeff * TRAPDOOR_CARRIER is the default initial state for callout 2074109864Sjeff * devices and SOFT_CARRIER is like CLOCAL except it hides 2075177009Sjeff * the true carrier. 2076113357Sjeff */ 2077109864Sjeff#ifdef PC98 2078109864Sjeff if ((IS_8251(com->pc98_if_type) && 2079171482Sjeff (pc98_get_modem_status(com) & TIOCM_CAR)) || 2080171482Sjeff (!IS_8251(com->pc98_if_type) && 2081171482Sjeff (com->prev_modem_status & MSR_DCD)) || 2082171482Sjeff mynor & CALLOUT_MASK) 2083171482Sjeff#else 2084171482Sjeff if (com->prev_modem_status & MSR_DCD || mynor & CALLOUT_MASK) 2085171482Sjeff#endif 2086171482Sjeff (*linesw[tp->t_line].l_modem)(tp, 1); 2087171482Sjeff } 2088171482Sjeff /* 2089171482Sjeff * Wait for DCD if necessary. 2090171482Sjeff */ 2091171482Sjeff if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK) 2092171482Sjeff && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) { 2093171482Sjeff ++com->wopeners; 2094171482Sjeff error = tsleep(TSA_CARR_ON(tp), TTIPRI | PCATCH, "siodcd", 0); 2095171482Sjeff if (com_addr(unit) == NULL) 2096171482Sjeff return (ENXIO); 2097171482Sjeff --com->wopeners; 2098171482Sjeff if (error != 0 || com->gone) 2099171482Sjeff goto out; 2100171482Sjeff goto open_top; 2101171482Sjeff } 2102171482Sjeff error = (*linesw[tp->t_line].l_open)(dev, tp); 2103171482Sjeff disc_optim(tp, &tp->t_termios, com); 2104109864Sjeff if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK) 2105109864Sjeff com->active_out = TRUE; 2106109864Sjeff siosettimeout(); 2107164936Sjulianout: 2108115998Sjeff splx(s); 2109109864Sjeff if (!(tp->t_state & TS_ISOPEN) && com->wopeners == 0) 2110115998Sjeff comhardclose(com); 2111115998Sjeff return (error); 2112164936Sjulian} 2113121605Sjeff 2114165620Sjeffstatic int 2115121605Sjeffsioclose(dev, flag, mode, p) 2116121605Sjeff dev_t dev; 2117165620Sjeff int flag; 2118121605Sjeff int mode; 2119115998Sjeff struct proc *p; 2120115998Sjeff{ 2121115998Sjeff struct com_s *com; 2122109864Sjeff int mynor; 2123109864Sjeff int s; 2124171482Sjeff struct tty *tp; 2125171482Sjeff 2126171482Sjeff mynor = minor(dev); 2127171482Sjeff if (mynor & CONTROL_MASK) 2128171482Sjeff return (0); 2129166190Sjeff com = com_addr(MINOR_TO_UNIT(mynor)); 2130109970Sjeff tp = com->tp; 2131109970Sjeff s = spltty(); 2132177435Sjeff (*linesw[tp->t_line].l_close)(tp, flag); 2133164936Sjulian#ifdef PC98 2134109970Sjeff com->modem_checking = 0; 2135164936Sjulian#endif 2136171482Sjeff disc_optim(tp, &tp->t_termios, com); 2137177435Sjeff siostop(tp, FREAD | FWRITE); 2138177435Sjeff comhardclose(com); 2139177435Sjeff ttyclose(tp); 2140177435Sjeff siosettimeout(); 2141177435Sjeff splx(s); 2142109864Sjeff if (com->gone) { 2143176735Sjeff printf("sio%d: gone\n", com->unit); 2144109864Sjeff s = spltty(); 2145109864Sjeff if (com->ibuf != NULL) 2146171482Sjeff free(com->ibuf, M_DEVBUF); 2147171482Sjeff bzero(tp, sizeof *tp); 2148171482Sjeff free(com, M_DEVBUF); 2149171482Sjeff splx(s); 2150171482Sjeff } 2151171482Sjeff return (0); 2152166190Sjeff} 2153166190Sjeff 2154166190Sjeffstatic void 2155166190Sjeffcomhardclose(com) 2156166190Sjeff struct com_s *com; 2157177005Sjeff{ 2158177005Sjeff Port_t iobase; 2159166190Sjeff int s; 2160166190Sjeff struct tty *tp; 2161166190Sjeff int unit; 2162177005Sjeff#ifdef PC98 2163177005Sjeff int port_shift = 0; 2164166190Sjeff#endif 2165171482Sjeff 2166177005Sjeff unit = com->unit; 2167171482Sjeff iobase = com->iobase; 2168171482Sjeff s = spltty(); 2169166190Sjeff com->poll = FALSE; 2170166190Sjeff com->poll_output = FALSE; 2171171482Sjeff com->do_timestamp = FALSE; 2172177009Sjeff com->do_dcd_timestamp = FALSE; 2173177009Sjeff com->pps.ppsparam.mode = 0; 2174177009Sjeff#ifdef PC98 2175171482Sjeff if (IS_8251(com->pc98_if_type)) 2176109864Sjeff com_send_break_off(com); 2177171482Sjeff else { 2178109864Sjeff port_shift = if_16550a_type[com->pc98_if_type & 0x0f].port_shift; 2179109864Sjeff outb(iobase + (com_cfcr << port_shift), 2180171482Sjeff com->cfcr_image &= ~CFCR_SBREAK); 2181166190Sjeff } 2182166190Sjeff#else 2183166190Sjeff outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK); 2184166190Sjeff#endif 2185172207Sjeff { 2186172207Sjeff#ifdef PC98 2187171482Sjeff int tmp; 2188171482Sjeff if (IS_8251(com->pc98_if_type)) 2189171482Sjeff com_int_TxRx_disable(com); 2190177435Sjeff else 2191177435Sjeff outb(iobase + (com_ier << port_shift), 0); 2192171482Sjeff if (com->pc98_if_type == COM_IF_RSA98III) { 2193171482Sjeff outb(com->rsabase + rsa_ier, 0x00); 2194171482Sjeff } 2195171482Sjeff#else 2196171482Sjeff outb(iobase + com_ier, 0); 2197171482Sjeff#endif 2198171482Sjeff tp = com->tp; 2199171482Sjeff#ifdef PC98 2200171482Sjeff if (IS_8251(com->pc98_if_type)) 2201171482Sjeff tmp = pc98_get_modem_status(com) & TIOCM_CAR; 2202171482Sjeff else 2203171482Sjeff tmp = com->prev_modem_status & MSR_DCD; 2204171482Sjeff#endif 2205171482Sjeff if (tp->t_cflag & HUPCL 2206173600Sjulian /* 2207173600Sjulian * XXX we will miss any carrier drop between here and the 2208171482Sjeff * next open. Perhaps we should watch DCD even when the 2209166108Sjeff * port is closed; it is not sufficient to check it at 2210171482Sjeff * the next open because it might go up and down while 2211171482Sjeff * we're not watching. 2212166108Sjeff */ 2213171482Sjeff || (!com->active_out 2214171482Sjeff#ifdef PC98 2215171482Sjeff && !(tmp) 2216171482Sjeff#else 2217171482Sjeff && !(com->prev_modem_status & MSR_DCD) 2218171482Sjeff#endif 2219171482Sjeff && !(com->it_in.c_cflag & CLOCAL)) 2220177435Sjeff || !(tp->t_state & TS_ISOPEN)) { 2221177435Sjeff#ifdef PC98 2222171482Sjeff if (IS_8251(com->pc98_if_type)) 2223177009Sjeff com_tiocm_bic(com, TIOCM_DTR|TIOCM_RTS|TIOCM_LE); 2224177435Sjeff else 2225166108Sjeff#endif 2226166108Sjeff (void)commctl(com, TIOCM_DTR, DMBIC); 2227171482Sjeff if (com->dtr_wait != 0 && !(com->state & CS_DTR_OFF)) { 2228171482Sjeff timeout(siodtrwakeup, com, com->dtr_wait); 2229171482Sjeff com->state |= CS_DTR_OFF; 2230171482Sjeff } 2231171482Sjeff } 2232171482Sjeff#ifdef PC98 2233171482Sjeff else { 2234171482Sjeff if (IS_8251(com->pc98_if_type)) 2235171482Sjeff com_tiocm_bic(com, TIOCM_LE ); 2236166108Sjeff } 2237171482Sjeff#endif 2238171482Sjeff } 2239109864Sjeff if (com->hasfifo) { 2240109864Sjeff /* 2241171482Sjeff * Disable fifos so that they are off after controlled 2242171482Sjeff * reboots. Some BIOSes fail to detect 16550s when the 2243171482Sjeff * fifos are enabled. 2244171482Sjeff */ 2245171482Sjeff#ifdef PC98 2246109864Sjeff outb(iobase + (com_fifo << port_shift), 0); 2247121127Sjeff#else 2248109864Sjeff outb(iobase + com_fifo, 0); 2249164936Sjulian#endif 2250113357Sjeff } 2251139316Sjeff com->active_out = FALSE; 2252173600Sjulian wakeup(&com->active_out); 2253173600Sjulian wakeup(TSA_CARR_ON(tp)); /* restart any wopeners */ 2254177435Sjeff splx(s); 2255171482Sjeff} 2256171482Sjeff 2257166190Sjeffstatic int 2258164936Sjuliansioread(dev, uio, flag) 2259177435Sjeff dev_t dev; 2260177435Sjeff struct uio *uio; 2261166190Sjeff int flag; 2262176735Sjeff{ 2263176735Sjeff int mynor; 2264109864Sjeff struct com_s *com; 2265109864Sjeff 2266171482Sjeff mynor = minor(dev); 2267171482Sjeff if (mynor & CONTROL_MASK) 2268171482Sjeff return (ENODEV); 2269109864Sjeff com = com_addr(MINOR_TO_UNIT(mynor)); 2270121127Sjeff if (com->gone) 2271109864Sjeff return (ENODEV); 2272109864Sjeff return ((*linesw[com->tp->t_line].l_read)(com->tp, uio, flag)); 2273164936Sjulian} 2274109864Sjeff 2275109864Sjeffstatic int 2276164936Sjuliansiowrite(dev, uio, flag) 2277164936Sjulian dev_t dev; 2278121290Sjeff struct uio *uio; 2279109864Sjeff int flag; 2280170293Sjeff{ 2281164936Sjulian int mynor; 2282109864Sjeff struct com_s *com; 2283109864Sjeff int unit; 2284165796Sjeff 2285109864Sjeff mynor = minor(dev); 2286165762Sjeff if (mynor & CONTROL_MASK) 2287165762Sjeff return (ENODEV); 2288109864Sjeff 2289170293Sjeff unit = MINOR_TO_UNIT(mynor); 2290109864Sjeff com = com_addr(unit); 2291109864Sjeff if (com->gone) 2292109864Sjeff return (ENODEV); 2293109864Sjeff /* 2294176735Sjeff * (XXX) We disallow virtual consoles if the physical console is 2295176735Sjeff * a serial port. This is in case there is a display attached that 2296176735Sjeff * is not the console. In that situation we don't need/want the X 2297176735Sjeff * server taking over the console. 2298176729Sjeff */ 2299176729Sjeff if (constty != NULL && unit == comconsole) 2300176729Sjeff constty = NULL; 2301176735Sjeff return ((*linesw[com->tp->t_line].l_write)(com->tp, uio, flag)); 2302176735Sjeff} 2303176735Sjeff 2304176735Sjeffstatic void 2305176735Sjeffsiobusycheck(chan) 2306176735Sjeff void *chan; 2307176735Sjeff{ 2308176735Sjeff struct com_s *com; 2309176735Sjeff int s; 2310176735Sjeff 2311176735Sjeff com = (struct com_s *)chan; 2312176735Sjeff 2313176735Sjeff /* 2314176735Sjeff * Clear TS_BUSY if low-level output is complete. 2315176735Sjeff * spl locking is sufficient because siointr1() does not set CS_BUSY. 2316176735Sjeff * If siointr1() clears CS_BUSY after we look at it, then we'll get 2317176735Sjeff * called again. Reading the line status port outside of siointr1() 2318176735Sjeff * is safe because CS_BUSY is clear so there are no output interrupts 2319176735Sjeff * to lose. 2320177435Sjeff */ 2321176735Sjeff s = spltty(); 2322176735Sjeff if (com->state & CS_BUSY) 2323176735Sjeff com->extra_state &= ~CSE_BUSYCHECK; /* False alarm. */ 2324176729Sjeff#ifdef PC98 2325176729Sjeff else if ((IS_8251(com->pc98_if_type) && 2326171482Sjeff (inb(com->sts_port) & (STS8251_TxRDY | STS8251_TxEMP)) 2327171482Sjeff == (STS8251_TxRDY | STS8251_TxEMP)) || 2328171482Sjeff (inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY)) 2329122038Sjeff == (LSR_TSRE | LSR_TXRDY)) { 2330122038Sjeff#else 2331122038Sjeff else if ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY)) 2332164936Sjulian == (LSR_TSRE | LSR_TXRDY)) { 2333122038Sjeff#endif 2334171713Sjeff com->tp->t_state &= ~TS_BUSY; 2335164936Sjulian ttwwakeup(com->tp); 2336166137Sjeff com->extra_state &= ~CSE_BUSYCHECK; 2337166152Sjeff } else 2338164936Sjulian timeout(siobusycheck, com, hz / 100); 2339166137Sjeff splx(s); 2340123433Sjeff} 2341122038Sjeff 2342166137Sjeffstatic void 2343122038Sjeffsiodtrwakeup(chan) 2344131527Sphk void *chan; 2345122038Sjeff{ 2346122038Sjeff struct com_s *com; 2347171482Sjeff 2348171482Sjeff com = (struct com_s *)chan; 2349171482Sjeff com->state &= ~CS_DTR_OFF; 2350122038Sjeff wakeup(&com->dtr_wait); 2351122038Sjeff} 2352122038Sjeff 2353165762Sjeffstatic void 2354165762Sjeffsioinput(com) 2355170293Sjeff struct com_s *com; 2356165762Sjeff{ 2357166137Sjeff u_char *buf; 2358166137Sjeff int incc; 2359165762Sjeff u_char line_status; 2360165762Sjeff int recv_data; 2361122038Sjeff struct tty *tp; 2362122038Sjeff#ifdef PC98 2363109864Sjeff u_char tmp; 2364145256Sjkoshy#endif 2365145256Sjkoshy 2366170293Sjeff buf = com->ibuf; 2367164936Sjulian tp = com->tp; 2368145256Sjkoshy if (!(tp->t_state & TS_ISOPEN) || !(tp->t_cflag & CREAD)) { 2369145256Sjkoshy com_events -= (com->iptr - com->ibuf); 2370171482Sjeff com->iptr = com->ibuf; 2371171482Sjeff return; 2372171482Sjeff } 2373159630Sdavidxu if (tp->t_state & TS_CAN_BYPASS_L_RINT) { 2374159630Sdavidxu /* 2375159630Sdavidxu * Avoid the grotesquely inefficient lineswitch routine 2376170293Sjeff * (ttyinput) in "raw" mode. It usually takes about 450 2377170293Sjeff * instructions (that's without canonical processing or echo!). 2378159630Sdavidxu * slinput is reasonably fast (usually 40 instructions plus 2379170293Sjeff * call overhead). 2380159630Sdavidxu */ 2381159630Sdavidxu do { 2382171482Sjeff enable_intr(); 2383171482Sjeff incc = com->iptr - buf; 2384171482Sjeff if (tp->t_rawq.c_cc + incc > tp->t_ihiwat 2385145256Sjkoshy && (com->state & CS_RTS_IFLOW 2386125289Sjeff || tp->t_iflag & IXOFF) 2387125289Sjeff && !(tp->t_state & TS_TBLOCK)) 2388125289Sjeff ttyblock(tp); 2389125289Sjeff com->delta_error_counts[CE_TTY_BUF_OVERFLOW] 2390125289Sjeff += b_to_q((char *)buf, incc, &tp->t_rawq); 2391125289Sjeff buf += incc; 2392125289Sjeff tk_nin += incc; 2393176735Sjeff tk_rawcc += incc; 2394176735Sjeff tp->t_rawcc += incc; 2395125289Sjeff ttwakeup(tp); 2396125289Sjeff if (tp->t_state & TS_TTSTOP 2397165620Sjeff && (tp->t_iflag & IXANY 2398125289Sjeff || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) { 2399125289Sjeff tp->t_state &= ~TS_TTSTOP; 2400125289Sjeff tp->t_lflag &= ~FLUSHO; 2401125289Sjeff comstart(tp); 2402109864Sjeff } 2403109864Sjeff disable_intr(); 2404109864Sjeff } while (buf < com->iptr); 2405109864Sjeff } else { 2406109864Sjeff do { 2407109864Sjeff enable_intr(); 2408109864Sjeff line_status = buf[com->ierroff]; 2409109864Sjeff recv_data = *buf++; 2410109864Sjeff if (line_status 2411109864Sjeff & (LSR_BI | LSR_FE | LSR_OE | LSR_PE)) { 2412159570Sdavidxu if (line_status & LSR_BI) 2413166190Sjeff recv_data |= TTY_BI; 2414166190Sjeff if (line_status & LSR_FE) 2415166190Sjeff recv_data |= TTY_FE; 2416166190Sjeff if (line_status & LSR_OE) 2417166190Sjeff recv_data |= TTY_OE; 2418166190Sjeff if (line_status & LSR_PE) 2419166190Sjeff recv_data |= TTY_PE; 2420171482Sjeff } 2421166190Sjeff (*linesw[tp->t_line].l_rint)(recv_data, tp); 2422166190Sjeff disable_intr(); 2423171482Sjeff } while (buf < com->iptr); 2424166190Sjeff } 2425171482Sjeff com_events -= (com->iptr - com->ibuf); 2426171482Sjeff com->iptr = com->ibuf; 2427171482Sjeff 2428171482Sjeff /* 2429171482Sjeff * There is now room for another low-level buffer full of input, 2430171482Sjeff * so enable RTS if it is now disabled and there is room in the 2431166190Sjeff * high-level buffer. 2432171482Sjeff */ 2433171482Sjeff#ifdef PC98 2434166190Sjeff if (IS_8251(com->pc98_if_type)) 2435166190Sjeff tmp = com_tiocm_get(com) & TIOCM_RTS; 2436170293Sjeff else 2437170293Sjeff tmp = com->mcr_image & MCR_RTS; 2438170293Sjeff if ((com->state & CS_RTS_IFLOW) && !(tmp) && 2439170293Sjeff !(tp->t_state & TS_TBLOCK)) 2440170293Sjeff if (IS_8251(com->pc98_if_type)) 2441170293Sjeff com_tiocm_bis(com, TIOCM_RTS); 2442172411Sjeff else 2443171482Sjeff outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS); 2444171482Sjeff#else 2445171482Sjeff if ((com->state & CS_RTS_IFLOW) && !(com->mcr_image & MCR_RTS) && 2446170293Sjeff !(tp->t_state & TS_TBLOCK)) 2447171482Sjeff outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS); 2448171482Sjeff#endif 2449170293Sjeff} 2450170293Sjeff 2451171482Sjeffvoid 2452177435Sjeffsiointr(arg) 2453174629Sjeff void *arg; 2454170293Sjeff{ 2455170293Sjeff#ifndef COM_MULTIPORT 2456172411Sjeff COM_LOCK(); 2457172411Sjeff siointr1((struct com_s *) arg); 2458170293Sjeff COM_UNLOCK(); 2459170293Sjeff#else /* COM_MULTIPORT */ 2460172411Sjeff bool_t possibly_more_intrs; 2461170293Sjeff int unit; 2462170293Sjeff struct com_s *com; 2463171482Sjeff#ifdef PC98 2464171482Sjeff u_char rsa_buf_status; 2465171482Sjeff#endif 2466171482Sjeff 2467170293Sjeff /* 2468170600Sjeff * Loop until there is no activity on any port. This is necessary 2469170293Sjeff * to get an interrupt edge more than to avoid another interrupt. 2470171482Sjeff * If the IRQ signal is just an OR of the IRQ signals from several 2471171482Sjeff * devices, then the edge from one may be lost because another is 2472171482Sjeff * on. 2473170293Sjeff */ 2474170293Sjeff COM_LOCK(); 2475170293Sjeff do { 2476171482Sjeff possibly_more_intrs = FALSE; 2477170293Sjeff for (unit = 0; unit < NSIOTOT; ++unit) { 2478171482Sjeff com = com_addr(unit); 2479171482Sjeff /* 2480171482Sjeff * XXX COM_LOCK(); 2481171482Sjeff * would it work here, or be counter-productive? 2482171482Sjeff */ 2483171482Sjeff#ifdef PC98 2484171482Sjeff if (com != NULL 2485172411Sjeff && !com->gone 2486174629Sjeff && IS_8251(com->pc98_if_type)){ 2487174629Sjeff siointr1(com); 2488170293Sjeff } else 2489170293Sjeff#endif /* PC98 */ 2490177435Sjeff#ifdef PC98 2491171482Sjeff if (com != NULL 2492165762Sjeff && !com->gone 2493171482Sjeff && com->pc98_if_type == COM_IF_RSA98III) { 2494171482Sjeff rsa_buf_status = inb(com->rsabase + rsa_srr) & 0xc9; 2495171482Sjeff if ((rsa_buf_status & 0xc8) 2496171482Sjeff || !(rsa_buf_status & 0x01)) { 2497171482Sjeff siointr1(com); 2498171482Sjeff if(rsa_buf_status 2499177085Sjeff != (inb(com->rsabase + rsa_srr) & 0xc9)) 2500177085Sjeff possibly_more_intrs = TRUE; 2501166108Sjeff } 2502171482Sjeff } else 2503171482Sjeff#endif 2504171482Sjeff if (com != NULL 2505171482Sjeff && !com->gone 2506172409Sjeff && (inb(com->int_id_port) & IIR_IMASK) 2507172409Sjeff != IIR_NOPEND) { 2508172409Sjeff siointr1(com); 2509171482Sjeff possibly_more_intrs = TRUE; 2510171482Sjeff } 2511171482Sjeff /* XXX COM_UNLOCK(); */ 2512171482Sjeff } 2513171506Sjeff } while (possibly_more_intrs); 2514171506Sjeff COM_UNLOCK(); 2515166108Sjeff#endif /* COM_MULTIPORT */ 2516165762Sjeff} 2517172264Sjeff 2518172293Sjeffstatic void 2519165762Sjeffsiointr1(com) 2520 struct com_s *com; 2521{ 2522 u_char line_status; 2523 u_char modem_status; 2524 u_char *ioptr; 2525 u_char recv_data; 2526 u_char int_ctl; 2527 u_char int_ctl_new; 2528 struct timecounter *tc; 2529 u_int count; 2530 2531#ifdef PC98 2532 u_char tmp=0; 2533 u_char rsa_buf_status = 0; 2534 int rsa_tx_fifo_size=0; 2535 recv_data=0; 2536#endif /* PC98 */ 2537 2538 int_ctl = inb(com->intr_ctl_port); 2539 int_ctl_new = int_ctl; 2540 2541 while (!com->gone) { 2542#ifdef PC98 2543status_read:; 2544 if (IS_8251(com->pc98_if_type)) { 2545 tmp = inb(com->sts_port); 2546more_intr: 2547 line_status = 0; 2548 if (tmp & STS8251_TxRDY) line_status |= LSR_TXRDY; 2549 if (tmp & STS8251_RxRDY) line_status |= LSR_RXRDY; 2550 if (tmp & STS8251_TxEMP) line_status |= LSR_TSRE; 2551 if (tmp & STS8251_PE) line_status |= LSR_PE; 2552 if (tmp & STS8251_OE) line_status |= LSR_OE; 2553 if (tmp & STS8251_FE) line_status |= LSR_FE; 2554 if (tmp & STS8251_BD_SD) line_status |= LSR_BI; 2555 } else { 2556#endif /* PC98 */ 2557 if (com->pps.ppsparam.mode & PPS_CAPTUREBOTH) { 2558 modem_status = inb(com->modem_status_port); 2559 if ((modem_status ^ com->last_modem_status) & MSR_DCD) { 2560 tc = timecounter; 2561 count = tc->tc_get_timecount(tc); 2562 pps_event(&com->pps, tc, count, 2563 (modem_status & MSR_DCD) ? 2564 PPS_CAPTURECLEAR : PPS_CAPTUREASSERT); 2565 } 2566 } 2567 line_status = inb(com->line_status_port); 2568#ifdef PC98 2569 } 2570 if (com->pc98_if_type == COM_IF_RSA98III) 2571 rsa_buf_status = inb(com->rsabase + rsa_srr); 2572#endif /* PC98 */ 2573 2574 /* input event? (check first to help avoid overruns) */ 2575#ifndef PC98 2576 while (line_status & LSR_RCV_MASK) { 2577#else 2578 while ((line_status & LSR_RCV_MASK) 2579 || (com->pc98_if_type == COM_IF_RSA98III 2580 && (rsa_buf_status & 0x08))) { 2581#endif /* PC98 */ 2582 /* break/unnattached error bits or real input? */ 2583#ifdef PC98 2584 if (IS_8251(com->pc98_if_type)) { 2585 recv_data = inb(com->data_port); 2586 if (tmp & 0x78) { 2587 pc98_i8251_or_cmd(com,CMD8251_ER); 2588 recv_data = 0; 2589 } 2590 } else { 2591#endif /* PC98 */ 2592#ifdef PC98 2593 if (com->pc98_if_type == COM_IF_RSA98III) { 2594 if (!(rsa_buf_status & 0x08)) 2595 recv_data = 0; 2596 else { 2597 recv_data = inb(com->data_port); 2598 } 2599 } else 2600#endif 2601 if (!(line_status & LSR_RXRDY)) 2602 recv_data = 0; 2603 else 2604 recv_data = inb(com->data_port); 2605#ifdef PC98 2606 } 2607#endif 2608 if (line_status & (LSR_BI | LSR_FE | LSR_PE)) { 2609 /* 2610 * Don't store BI if IGNBRK or FE/PE if IGNPAR. 2611 * Otherwise, push the work to a higher level 2612 * (to handle PARMRK) if we're bypassing. 2613 * Otherwise, convert BI/FE and PE+INPCK to 0. 2614 * 2615 * This makes bypassing work right in the 2616 * usual "raw" case (IGNBRK set, and IGNPAR 2617 * and INPCK clear). 2618 * 2619 * Note: BI together with FE/PE means just BI. 2620 */ 2621 if (line_status & LSR_BI) { 2622#if defined(DDB) && defined(BREAK_TO_DEBUGGER) 2623 if (com->unit == comconsole) { 2624 breakpoint(); 2625 goto cont; 2626 } 2627#endif 2628 if (com->tp == NULL 2629 || com->tp->t_iflag & IGNBRK) 2630 goto cont; 2631 } else { 2632 if (com->tp == NULL 2633 || com->tp->t_iflag & IGNPAR) 2634 goto cont; 2635 } 2636 if (com->tp->t_state & TS_CAN_BYPASS_L_RINT 2637 && (line_status & (LSR_BI | LSR_FE) 2638 || com->tp->t_iflag & INPCK)) 2639 recv_data = 0; 2640 } 2641 ++com->bytes_in; 2642 if (com->hotchar != 0 && recv_data == com->hotchar) 2643 setsofttty(); 2644 ioptr = com->iptr; 2645 if (ioptr >= com->ibufend) 2646 CE_RECORD(com, CE_INTERRUPT_BUF_OVERFLOW); 2647 else { 2648 if (com->do_timestamp) 2649 microtime(&com->timestamp); 2650 ++com_events; 2651 schedsofttty(); 2652#if 0 /* for testing input latency vs efficiency */ 2653if (com->iptr - com->ibuf == 8) 2654 setsofttty(); 2655#endif 2656 ioptr[0] = recv_data; 2657 ioptr[com->ierroff] = line_status; 2658 com->iptr = ++ioptr; 2659 if (ioptr == com->ihighwater 2660 && com->state & CS_RTS_IFLOW) 2661#ifdef PC98 2662 if (IS_8251(com->pc98_if_type)) 2663 com_tiocm_bic(com, TIOCM_RTS); 2664 else 2665#endif 2666 outb(com->modem_ctl_port, 2667 com->mcr_image &= ~MCR_RTS); 2668 if (line_status & LSR_OE) 2669 CE_RECORD(com, CE_OVERRUN); 2670 } 2671cont: 2672 /* 2673 * "& 0x7F" is to avoid the gcc-1.40 generating a slow 2674 * jump from the top of the loop to here 2675 */ 2676#ifdef PC98 2677 if (IS_8251(com->pc98_if_type)) 2678 goto status_read; 2679 else 2680#endif 2681 line_status = inb(com->line_status_port) & 0x7F; 2682#ifdef PC98 2683 if (com->pc98_if_type == COM_IF_RSA98III) 2684 rsa_buf_status = inb(com->rsabase + rsa_srr); 2685#endif /* PC98 */ 2686 } 2687 2688 /* modem status change? (always check before doing output) */ 2689#ifdef PC98 2690 if (!IS_8251(com->pc98_if_type)) { 2691#endif 2692 modem_status = inb(com->modem_status_port); 2693 if (modem_status != com->last_modem_status) { 2694 if (com->do_dcd_timestamp 2695 && !(com->last_modem_status & MSR_DCD) 2696 && modem_status & MSR_DCD) 2697 microtime(&com->dcd_timestamp); 2698 2699 /* 2700 * Schedule high level to handle DCD changes. Note 2701 * that we don't use the delta bits anywhere. Some 2702 * UARTs mess them up, and it's easy to remember the 2703 * previous bits and calculate the delta. 2704 */ 2705 com->last_modem_status = modem_status; 2706 if (!(com->state & CS_CHECKMSR)) { 2707 com_events += LOTS_OF_EVENTS; 2708 com->state |= CS_CHECKMSR; 2709 setsofttty(); 2710 } 2711 2712 /* handle CTS change immediately for crisp flow ctl */ 2713 if (com->state & CS_CTS_OFLOW) { 2714 if (modem_status & MSR_CTS) 2715 com->state |= CS_ODEVREADY; 2716 else 2717 com->state &= ~CS_ODEVREADY; 2718 } 2719 } 2720#ifdef PC98 2721 } 2722#endif 2723 2724 /* output queued and everything ready? */ 2725#ifndef PC98 2726 if (line_status & LSR_TXRDY 2727 && com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) { 2728#else 2729 if (((com->pc98_if_type == COM_IF_RSA98III) 2730 ? (rsa_buf_status & 0x02) 2731 : (line_status & LSR_TXRDY)) 2732 && com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) { 2733#endif 2734 ioptr = com->obufq.l_head; 2735 if (com->tx_fifo_size > 1) { 2736 u_int ocount; 2737 2738 ocount = com->obufq.l_tail - ioptr; 2739#ifdef PC98 2740 if (com->pc98_if_type == COM_IF_RSA98III) { 2741 rsa_buf_status = inb(com->rsabase + rsa_srr); 2742 rsa_tx_fifo_size = 1024; 2743 if (!(rsa_buf_status & 0x01)) 2744 rsa_tx_fifo_size = 2048; 2745 if (ocount > rsa_tx_fifo_size) 2746 ocount = rsa_tx_fifo_size; 2747 } else 2748#endif 2749 if (ocount > com->tx_fifo_size) 2750 ocount = com->tx_fifo_size; 2751 com->bytes_out += ocount; 2752 do 2753 outb(com->data_port, *ioptr++); 2754 while (--ocount != 0); 2755 } else { 2756 outb(com->data_port, *ioptr++); 2757 ++com->bytes_out; 2758 } 2759#ifdef PC98 2760 if (IS_8251(com->pc98_if_type)) 2761 if (!(pc98_check_i8251_interrupt(com) & IEN_TxFLAG)) 2762 com_int_Tx_enable(com); 2763#endif 2764 com->obufq.l_head = ioptr; 2765 if (COM_IIR_TXRDYBUG(com->flags)) { 2766 int_ctl_new = int_ctl | IER_ETXRDY; 2767 } 2768 if (ioptr >= com->obufq.l_tail) { 2769 struct lbq *qp; 2770 2771 qp = com->obufq.l_next; 2772 qp->l_queued = FALSE; 2773 qp = qp->l_next; 2774 if (qp != NULL) { 2775 com->obufq.l_head = qp->l_head; 2776 com->obufq.l_tail = qp->l_tail; 2777 com->obufq.l_next = qp; 2778 } else { 2779 /* output just completed */ 2780 if ( COM_IIR_TXRDYBUG(com->flags) ) { 2781 int_ctl_new = int_ctl & ~IER_ETXRDY; 2782 } 2783 com->state &= ~CS_BUSY; 2784#if defined(PC98) 2785 if (IS_8251(com->pc98_if_type)) 2786 if ( pc98_check_i8251_interrupt(com) & IEN_TxFLAG ) 2787 com_int_Tx_disable(com); 2788#endif 2789 } 2790 if (!(com->state & CS_ODONE)) { 2791 com_events += LOTS_OF_EVENTS; 2792 com->state |= CS_ODONE; 2793 setsofttty(); /* handle at high level ASAP */ 2794 } 2795 } 2796 if ( COM_IIR_TXRDYBUG(com->flags) && (int_ctl != int_ctl_new)) { 2797#ifdef PC98 2798 if (com->pc98_if_type == COM_IF_RSA98III) { 2799 int_ctl_new &= ~(IER_ETXRDY | IER_ERXRDY); 2800 outb(com->intr_ctl_port, int_ctl_new); 2801 outb(com->rsabase + rsa_ier, 0x1d); 2802 } else 2803#endif 2804 outb(com->intr_ctl_port, int_ctl_new); 2805 } 2806 } 2807#ifdef PC98 2808 else if (line_status & LSR_TXRDY) { 2809 if (IS_8251(com->pc98_if_type)) 2810 if ( pc98_check_i8251_interrupt(com) & IEN_TxFLAG ) 2811 com_int_Tx_disable(com); 2812 } 2813 if (IS_8251(com->pc98_if_type)) 2814 if ((tmp = inb(com->sts_port)) & STS8251_RxRDY) 2815 goto more_intr; 2816#endif 2817 2818 /* finished? */ 2819#ifndef COM_MULTIPORT 2820#ifdef PC98 2821 if (IS_8251(com->pc98_if_type)) 2822 return; 2823#endif 2824 if ((inb(com->int_id_port) & IIR_IMASK) == IIR_NOPEND) 2825#endif /* COM_MULTIPORT */ 2826 return; 2827 } 2828} 2829 2830static int 2831sioioctl(dev, cmd, data, flag, p) 2832 dev_t dev; 2833 u_long cmd; 2834 caddr_t data; 2835 int flag; 2836 struct proc *p; 2837{ 2838 struct com_s *com; 2839 int error; 2840 Port_t iobase; 2841 int mynor; 2842 int s; 2843 struct tty *tp; 2844#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 2845 u_long oldcmd; 2846 struct termios term; 2847#endif 2848 2849 mynor = minor(dev); 2850 com = com_addr(MINOR_TO_UNIT(mynor)); 2851 if (com->gone) 2852 return (ENODEV); 2853 iobase = com->iobase; 2854 if (mynor & CONTROL_MASK) { 2855 struct termios *ct; 2856 2857 switch (mynor & CONTROL_MASK) { 2858 case CONTROL_INIT_STATE: 2859 ct = mynor & CALLOUT_MASK ? &com->it_out : &com->it_in; 2860 break; 2861 case CONTROL_LOCK_STATE: 2862 ct = mynor & CALLOUT_MASK ? &com->lt_out : &com->lt_in; 2863 break; 2864 default: 2865 return (ENODEV); /* /dev/nodev */ 2866 } 2867 switch (cmd) { 2868 case TIOCSETA: 2869 error = suser(p); 2870 if (error != 0) 2871 return (error); 2872 *ct = *(struct termios *)data; 2873 return (0); 2874 case TIOCGETA: 2875 *(struct termios *)data = *ct; 2876 return (0); 2877 case TIOCGETD: 2878 *(int *)data = TTYDISC; 2879 return (0); 2880 case TIOCGWINSZ: 2881 bzero(data, sizeof(struct winsize)); 2882 return (0); 2883 default: 2884 return (ENOTTY); 2885 } 2886 } 2887 tp = com->tp; 2888#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 2889 term = tp->t_termios; 2890 oldcmd = cmd; 2891 error = ttsetcompat(tp, &cmd, data, &term); 2892 if (error != 0) 2893 return (error); 2894 if (cmd != oldcmd) 2895 data = (caddr_t)&term; 2896#endif 2897 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) { 2898 int cc; 2899 struct termios *dt = (struct termios *)data; 2900 struct termios *lt = mynor & CALLOUT_MASK 2901 ? &com->lt_out : &com->lt_in; 2902 2903 dt->c_iflag = (tp->t_iflag & lt->c_iflag) 2904 | (dt->c_iflag & ~lt->c_iflag); 2905 dt->c_oflag = (tp->t_oflag & lt->c_oflag) 2906 | (dt->c_oflag & ~lt->c_oflag); 2907 dt->c_cflag = (tp->t_cflag & lt->c_cflag) 2908 | (dt->c_cflag & ~lt->c_cflag); 2909 dt->c_lflag = (tp->t_lflag & lt->c_lflag) 2910 | (dt->c_lflag & ~lt->c_lflag); 2911 for (cc = 0; cc < NCCS; ++cc) 2912 if (lt->c_cc[cc] != 0) 2913 dt->c_cc[cc] = tp->t_cc[cc]; 2914 if (lt->c_ispeed != 0) 2915 dt->c_ispeed = tp->t_ispeed; 2916 if (lt->c_ospeed != 0) 2917 dt->c_ospeed = tp->t_ospeed; 2918 } 2919 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 2920 if (error != ENOIOCTL) 2921 return (error); 2922 s = spltty(); 2923 error = ttioctl(tp, cmd, data, flag); 2924 disc_optim(tp, &tp->t_termios, com); 2925 if (error != ENOIOCTL) { 2926 splx(s); 2927 return (error); 2928 } 2929#ifdef PC98 2930 if (IS_8251(com->pc98_if_type)) { 2931 switch (cmd) { 2932 case TIOCSBRK: 2933 com_send_break_on( com ); 2934 break; 2935 case TIOCCBRK: 2936 com_send_break_off( com ); 2937 break; 2938 case TIOCSDTR: 2939 com_tiocm_bis(com, TIOCM_DTR | TIOCM_RTS ); 2940 break; 2941 case TIOCCDTR: 2942 com_tiocm_bic(com, TIOCM_DTR); 2943 break; 2944 /* 2945 * XXX should disallow changing MCR_RTS if CS_RTS_IFLOW is set. The 2946 * changes get undone on the next call to comparam(). 2947 */ 2948 case TIOCMSET: 2949 com_tiocm_set( com, *(int *)data ); 2950 break; 2951 case TIOCMBIS: 2952 com_tiocm_bis( com, *(int *)data ); 2953 break; 2954 case TIOCMBIC: 2955 com_tiocm_bic( com, *(int *)data ); 2956 break; 2957 case TIOCMGET: 2958 *(int *)data = com_tiocm_get(com); 2959 break; 2960 case TIOCMSDTRWAIT: 2961 /* must be root since the wait applies to following logins */ 2962 error = suser(p); 2963 if (error != 0) { 2964 splx(s); 2965 return (error); 2966 } 2967 com->dtr_wait = *(int *)data * hz / 100; 2968 break; 2969 case TIOCMGDTRWAIT: 2970 *(int *)data = com->dtr_wait * 100 / hz; 2971 break; 2972 case TIOCTIMESTAMP: 2973 com->do_timestamp = TRUE; 2974 *(struct timeval *)data = com->timestamp; 2975 break; 2976 case TIOCDCDTIMESTAMP: 2977 com->do_dcd_timestamp = TRUE; 2978 *(struct timeval *)data = com->dcd_timestamp; 2979 break; 2980 default: 2981 splx(s); 2982 return (ENOTTY); 2983 } 2984 } else { 2985 int port_shift; 2986 port_shift = if_16550a_type[com->pc98_if_type & 0x0f].port_shift; 2987#endif 2988 switch (cmd) { 2989 case TIOCSBRK: 2990#ifdef PC98 2991 outb(iobase + (com_cfcr << port_shift), 2992 com->cfcr_image |= CFCR_SBREAK); 2993#else 2994 outb(iobase + com_cfcr, com->cfcr_image |= CFCR_SBREAK); 2995#endif 2996 break; 2997 case TIOCCBRK: 2998#ifdef PC98 2999 outb(iobase + (com_cfcr << port_shift), 3000 com->cfcr_image &= ~CFCR_SBREAK); 3001#else 3002 outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK); 3003#endif 3004 break; 3005 case TIOCSDTR: 3006 (void)commctl(com, TIOCM_DTR, DMBIS); 3007 break; 3008 case TIOCCDTR: 3009 (void)commctl(com, TIOCM_DTR, DMBIC); 3010 break; 3011 /* 3012 * XXX should disallow changing MCR_RTS if CS_RTS_IFLOW is set. The 3013 * changes get undone on the next call to comparam(). 3014 */ 3015 case TIOCMSET: 3016 (void)commctl(com, *(int *)data, DMSET); 3017 break; 3018 case TIOCMBIS: 3019 (void)commctl(com, *(int *)data, DMBIS); 3020 break; 3021 case TIOCMBIC: 3022 (void)commctl(com, *(int *)data, DMBIC); 3023 break; 3024 case TIOCMGET: 3025 *(int *)data = commctl(com, 0, DMGET); 3026 break; 3027 case TIOCMSDTRWAIT: 3028 /* must be root since the wait applies to following logins */ 3029 error = suser(p); 3030 if (error != 0) { 3031 splx(s); 3032 return (error); 3033 } 3034 com->dtr_wait = *(int *)data * hz / 100; 3035 break; 3036 case TIOCMGDTRWAIT: 3037 *(int *)data = com->dtr_wait * 100 / hz; 3038 break; 3039 case TIOCTIMESTAMP: 3040 com->do_timestamp = TRUE; 3041 *(struct timeval *)data = com->timestamp; 3042 break; 3043 case TIOCDCDTIMESTAMP: 3044 com->do_dcd_timestamp = TRUE; 3045 *(struct timeval *)data = com->dcd_timestamp; 3046 break; 3047 default: 3048 splx(s); 3049 error = pps_ioctl(cmd, data, &com->pps); 3050 if (error == ENODEV) 3051 error = ENOTTY; 3052 return (error); 3053 } 3054#ifdef PC98 3055 } 3056#endif 3057 splx(s); 3058 return (0); 3059} 3060 3061static void 3062siopoll() 3063{ 3064 int unit; 3065 3066 if (com_events == 0) 3067 return; 3068repeat: 3069 for (unit = 0; unit < NSIOTOT; ++unit) { 3070 struct com_s *com; 3071 int incc; 3072 struct tty *tp; 3073 3074 com = com_addr(unit); 3075 if (com == NULL) 3076 continue; 3077 tp = com->tp; 3078 if (tp == NULL || com->gone) { 3079 /* 3080 * Discard any events related to never-opened or 3081 * going-away devices. 3082 */ 3083 disable_intr(); 3084 incc = com->iptr - com->ibuf; 3085 com->iptr = com->ibuf; 3086 if (com->state & CS_CHECKMSR) { 3087 incc += LOTS_OF_EVENTS; 3088 com->state &= ~CS_CHECKMSR; 3089 } 3090 com_events -= incc; 3091 enable_intr(); 3092 continue; 3093 } 3094 if (com->iptr != com->ibuf) { 3095 disable_intr(); 3096 sioinput(com); 3097 enable_intr(); 3098 } 3099 if (com->state & CS_CHECKMSR) { 3100 u_char delta_modem_status; 3101 3102#ifdef PC98 3103 if (!IS_8251(com->pc98_if_type)) { 3104#endif 3105 disable_intr(); 3106 delta_modem_status = com->last_modem_status 3107 ^ com->prev_modem_status; 3108 com->prev_modem_status = com->last_modem_status; 3109 com_events -= LOTS_OF_EVENTS; 3110 com->state &= ~CS_CHECKMSR; 3111 enable_intr(); 3112 if (delta_modem_status & MSR_DCD) 3113 (*linesw[tp->t_line].l_modem) 3114 (tp, com->prev_modem_status & MSR_DCD); 3115#ifdef PC98 3116 } 3117#endif 3118 } 3119 if (com->state & CS_ODONE) { 3120 disable_intr(); 3121 com_events -= LOTS_OF_EVENTS; 3122 com->state &= ~CS_ODONE; 3123 enable_intr(); 3124 if (!(com->state & CS_BUSY) 3125 && !(com->extra_state & CSE_BUSYCHECK)) { 3126 timeout(siobusycheck, com, hz / 100); 3127 com->extra_state |= CSE_BUSYCHECK; 3128 } 3129 (*linesw[tp->t_line].l_start)(tp); 3130 } 3131 if (com_events == 0) 3132 break; 3133 } 3134 if (com_events >= LOTS_OF_EVENTS) 3135 goto repeat; 3136} 3137 3138static int 3139comparam(tp, t) 3140 struct tty *tp; 3141 struct termios *t; 3142{ 3143 u_int cfcr; 3144 int cflag; 3145 struct com_s *com; 3146 int divisor; 3147 u_char dlbh; 3148 u_char dlbl; 3149 Port_t iobase; 3150 int s; 3151 int unit; 3152#ifdef PC98 3153 int port_shift = 0; 3154 u_char param = 0; 3155#endif 3156 3157#ifdef PC98 3158 cfcr = 0; 3159 unit = DEV_TO_UNIT(tp->t_dev); 3160 com = com_addr(unit); 3161 iobase = com->iobase; 3162 if (IS_8251(com->pc98_if_type)) { 3163 divisor = pc98_ttspeedtab(com, t->c_ospeed); 3164 } else { 3165 port_shift = if_16550a_type[com->pc98_if_type & 0x0f].port_shift; 3166 3167 /* do historical conversions */ 3168 if (t->c_ispeed == 0) 3169 t->c_ispeed = t->c_ospeed; 3170 3171 /* check requested parameters */ 3172 divisor = ttspeedtab(t->c_ospeed, 3173 if_16550a_type[com->pc98_if_type & 0x0f].speedtab); 3174 } 3175#else 3176 /* do historical conversions */ 3177 if (t->c_ispeed == 0) 3178 t->c_ispeed = t->c_ospeed; 3179 3180 /* check requested parameters */ 3181 divisor = ttspeedtab(t->c_ospeed, comspeedtab); 3182#endif 3183 if (divisor < 0 || divisor > 0 && t->c_ispeed != t->c_ospeed) 3184 return (EINVAL); 3185 3186 /* parameters are OK, convert them to the com struct and the device */ 3187#ifndef PC98 3188 unit = DEV_TO_UNIT(tp->t_dev); 3189 com = com_addr(unit); 3190 iobase = com->iobase; 3191#endif 3192 s = spltty(); 3193#ifdef PC98 3194 if (IS_8251(com->pc98_if_type)) { 3195 if (divisor == 0) 3196 com_tiocm_bic( com, TIOCM_DTR|TIOCM_RTS|TIOCM_LE ); 3197 else 3198 com_tiocm_bis( com, TIOCM_DTR|TIOCM_RTS|TIOCM_LE ); 3199 } else { 3200#endif 3201 if (divisor == 0) 3202 (void)commctl(com, TIOCM_DTR, DMBIC); /* hang up line */ 3203 else 3204 (void)commctl(com, TIOCM_DTR, DMBIS); 3205#ifdef PC98 3206 } 3207#endif 3208 cflag = t->c_cflag; 3209#ifdef PC98 3210 if (!IS_8251(com->pc98_if_type)) { 3211#endif 3212 switch (cflag & CSIZE) { 3213 case CS5: 3214 cfcr = CFCR_5BITS; 3215 break; 3216 case CS6: 3217 cfcr = CFCR_6BITS; 3218 break; 3219 case CS7: 3220 cfcr = CFCR_7BITS; 3221 break; 3222 default: 3223 cfcr = CFCR_8BITS; 3224 break; 3225 } 3226 if (cflag & PARENB) { 3227 cfcr |= CFCR_PENAB; 3228 if (!(cflag & PARODD)) 3229 cfcr |= CFCR_PEVEN; 3230 } 3231 if (cflag & CSTOPB) 3232 cfcr |= CFCR_STOPB; 3233 3234 if (com->hasfifo && divisor != 0) { 3235 /* 3236 * Use a fifo trigger level low enough so that the input 3237 * latency from the fifo is less than about 16 msec and 3238 * the total latency is less than about 30 msec. These 3239 * latencies are reasonable for humans. Serial comms 3240 * protocols shouldn't expect anything better since modem 3241 * latencies are larger. 3242 */ 3243 com->fifo_image = t->c_ospeed <= 4800 3244 ? FIFO_ENABLE : FIFO_ENABLE | FIFO_RX_HIGH; 3245#ifdef COM_ESP 3246 /* 3247 * The Hayes ESP card needs the fifo DMA mode bit set 3248 * in compatibility mode. If not, it will interrupt 3249 * for each character received. 3250 */ 3251 if (com->esp) 3252 com->fifo_image |= FIFO_DMA_MODE; 3253#endif 3254#ifdef PC98 3255 outb(iobase + (com_fifo << port_shift), com->fifo_image); 3256#else 3257 outb(iobase + com_fifo, com->fifo_image); 3258#endif 3259 } 3260#ifdef PC98 3261 } 3262#endif 3263 3264 /* 3265 * This returns with interrupts disabled so that we can complete 3266 * the speed change atomically. Keeping interrupts disabled is 3267 * especially important while com_data is hidden. 3268 */ 3269 (void) siosetwater(com, t->c_ispeed); 3270 3271#ifdef PC98 3272 if (IS_8251(com->pc98_if_type)) 3273 com_cflag_and_speed_set(com, cflag, t->c_ospeed); 3274 else { 3275#endif 3276 if (divisor != 0) { 3277#ifdef PC98 3278 outb(iobase + (com_cfcr << port_shift), cfcr | CFCR_DLAB); 3279#else 3280 outb(iobase + com_cfcr, cfcr | CFCR_DLAB); 3281#endif 3282 /* 3283 * Only set the divisor registers if they would change, 3284 * since on some 16550 incompatibles (UMC8669F), setting 3285 * them while input is arriving them loses sync until 3286 * data stops arriving. 3287 */ 3288 dlbl = divisor & 0xFF; 3289#ifdef PC98 3290 if (inb(iobase + (com_dlbl << port_shift)) != dlbl) 3291 outb(iobase + (com_dlbl << port_shift), dlbl); 3292 dlbh = (u_int) divisor >> 8; 3293 if (inb(iobase + (com_dlbh << port_shift)) != dlbh) 3294 outb(iobase + (com_dlbh << port_shift), dlbh); 3295#else 3296 if (inb(iobase + com_dlbl) != dlbl) 3297 outb(iobase + com_dlbl, dlbl); 3298 dlbh = (u_int) divisor >> 8; 3299 if (inb(iobase + com_dlbh) != dlbh) 3300 outb(iobase + com_dlbh, dlbh); 3301#endif 3302 } 3303 3304 3305#ifdef PC98 3306 } 3307 outb(iobase + (com_cfcr << port_shift), com->cfcr_image = cfcr); 3308#else 3309 outb(iobase + com_cfcr, com->cfcr_image = cfcr); 3310#endif 3311 3312 if (!(tp->t_state & TS_TTSTOP)) 3313 com->state |= CS_TTGO; 3314 3315 if (cflag & CRTS_IFLOW) { 3316 if (com->st16650a) { 3317 outb(iobase + com_cfcr, 0xbf); 3318 outb(iobase + com_fifo, inb(iobase + com_fifo) | 0x40); 3319 } 3320 com->state |= CS_RTS_IFLOW; 3321 /* 3322 * If CS_RTS_IFLOW just changed from off to on, the change 3323 * needs to be propagated to MCR_RTS. This isn't urgent, 3324 * so do it later by calling comstart() instead of repeating 3325 * a lot of code from comstart() here. 3326 */ 3327 } else if (com->state & CS_RTS_IFLOW) { 3328 com->state &= ~CS_RTS_IFLOW; 3329 /* 3330 * CS_RTS_IFLOW just changed from on to off. Force MCR_RTS 3331 * on here, since comstart() won't do it later. 3332 */ 3333#ifdef PC98 3334 if (IS_8251(com->pc98_if_type)) 3335 com_tiocm_bis(com, TIOCM_RTS); 3336 else 3337#endif 3338 outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS); 3339 if (com->st16650a) { 3340 outb(iobase + com_cfcr, 0xbf); 3341 outb(iobase + com_fifo, inb(iobase + com_fifo) & ~0x40); 3342 } 3343 } 3344 3345 3346 /* 3347 * Set up state to handle output flow control. 3348 * XXX - worth handling MDMBUF (DCD) flow control at the lowest level? 3349 * Now has 10+ msec latency, while CTS flow has 50- usec latency. 3350 */ 3351 com->state |= CS_ODEVREADY; 3352 com->state &= ~CS_CTS_OFLOW; 3353#ifdef PC98 3354 if (com->pc98_if_type == COM_IF_RSA98III) { 3355 param = inb(com->rsabase + rsa_msr); 3356 outb(com->rsabase + rsa_msr, param & 0x14); 3357 } 3358#endif 3359 if (cflag & CCTS_OFLOW) { 3360 com->state |= CS_CTS_OFLOW; 3361#ifdef PC98 3362 if (IS_8251(com->pc98_if_type)) { 3363 if (!(pc98_get_modem_status(com) & TIOCM_CTS)) 3364 com->state &= ~CS_ODEVREADY; 3365 } else { 3366#endif 3367#ifdef PC98 3368 if (com->pc98_if_type == COM_IF_RSA98III) { 3369 /* Set automatic flow control mode */ 3370 outb(com->rsabase + rsa_msr, param | 0x08); 3371 } else 3372#endif 3373 if (!(com->last_modem_status & MSR_CTS)) 3374 com->state &= ~CS_ODEVREADY; 3375 if (com->st16650a) { 3376 outb(iobase + com_cfcr, 0xbf); 3377 outb(iobase + com_fifo, inb(iobase + com_fifo) | 0x80); 3378 } 3379#ifdef PC98 3380 } 3381#endif 3382 } else { 3383 if (com->st16650a) { 3384 outb(iobase + com_cfcr, 0xbf); 3385 outb(iobase + com_fifo, inb(iobase + com_fifo) & ~0x80); 3386 } 3387 } 3388 3389 3390#ifdef PC98 3391 outb(iobase + (com_cfcr << port_shift), com->cfcr_image); 3392#else 3393 outb(iobase + com_cfcr, com->cfcr_image); 3394#endif 3395 3396 3397 /* XXX shouldn't call functions while intrs are disabled. */ 3398 disc_optim(tp, t, com); 3399 /* 3400 * Recover from fiddling with CS_TTGO. We used to call siointr1() 3401 * unconditionally, but that defeated the careful discarding of 3402 * stale input in sioopen(). 3403 */ 3404 if (com->state >= (CS_BUSY | CS_TTGO)) 3405 siointr1(com); 3406 3407 enable_intr(); 3408 splx(s); 3409 comstart(tp); 3410 if (com->ibufold != NULL) { 3411 free(com->ibufold, M_DEVBUF); 3412 com->ibufold = NULL; 3413 } 3414 return (0); 3415} 3416 3417static int 3418siosetwater(com, speed) 3419 struct com_s *com; 3420 speed_t speed; 3421{ 3422 int cp4ticks; 3423 u_char *ibuf; 3424 int ibufsize; 3425 struct tty *tp; 3426 3427 /* 3428 * Make the buffer size large enough to handle a softtty interrupt 3429 * latency of about 2 ticks without loss of throughput or data 3430 * (about 3 ticks if input flow control is not used or not honoured, 3431 * but a bit less for CS5-CS7 modes). 3432 */ 3433 cp4ticks = speed / 10 / hz * 4; 3434 for (ibufsize = 128; ibufsize < cp4ticks;) 3435 ibufsize <<= 1; 3436#ifdef PC98 3437 if (com->pc98_if_type == COM_IF_RSA98III) 3438 ibufsize = 2048; 3439#endif 3440 if (ibufsize == com->ibufsize) { 3441 disable_intr(); 3442 return (0); 3443 } 3444 3445 /* 3446 * Allocate input buffer. The extra factor of 2 in the size is 3447 * to allow for an error byte for each input byte. 3448 */ 3449 ibuf = malloc(2 * ibufsize, M_DEVBUF, M_NOWAIT); 3450 if (ibuf == NULL) { 3451 disable_intr(); 3452 return (ENOMEM); 3453 } 3454 3455 /* Initialize non-critical variables. */ 3456 com->ibufold = com->ibuf; 3457 com->ibufsize = ibufsize; 3458 tp = com->tp; 3459 if (tp != NULL) { 3460 tp->t_ififosize = 2 * ibufsize; 3461 tp->t_ispeedwat = (speed_t)-1; 3462 tp->t_ospeedwat = (speed_t)-1; 3463 } 3464 3465 /* 3466 * Read current input buffer, if any. Continue with interrupts 3467 * disabled. 3468 */ 3469 disable_intr(); 3470 if (com->iptr != com->ibuf) 3471 sioinput(com); 3472 3473 /*- 3474 * Initialize critical variables, including input buffer watermarks. 3475 * The external device is asked to stop sending when the buffer 3476 * exactly reaches high water, or when the high level requests it. 3477 * The high level is notified immediately (rather than at a later 3478 * clock tick) when this watermark is reached. 3479 * The buffer size is chosen so the watermark should almost never 3480 * be reached. 3481 * The low watermark is invisibly 0 since the buffer is always 3482 * emptied all at once. 3483 */ 3484 com->iptr = com->ibuf = ibuf; 3485 com->ibufend = ibuf + ibufsize; 3486 com->ierroff = ibufsize; 3487 com->ihighwater = ibuf + 3 * ibufsize / 4; 3488 return (0); 3489} 3490 3491static void 3492comstart(tp) 3493 struct tty *tp; 3494{ 3495 struct com_s *com; 3496 int s; 3497 int unit; 3498#ifdef PC98 3499 int tmp; 3500#endif 3501 3502 unit = DEV_TO_UNIT(tp->t_dev); 3503 com = com_addr(unit); 3504 s = spltty(); 3505 disable_intr(); 3506 if (tp->t_state & TS_TTSTOP) 3507 com->state &= ~CS_TTGO; 3508 else 3509 com->state |= CS_TTGO; 3510 if (tp->t_state & TS_TBLOCK) { 3511#ifdef PC98 3512 if (IS_8251(com->pc98_if_type)) 3513 tmp = com_tiocm_get(com) & TIOCM_RTS; 3514 else 3515 tmp = com->mcr_image & MCR_RTS; 3516 if (tmp && (com->state & CS_RTS_IFLOW)) 3517#else 3518 if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW) 3519#endif 3520#ifdef PC98 3521 if (IS_8251(com->pc98_if_type)) 3522 com_tiocm_bic(com, TIOCM_RTS); 3523 else 3524#endif 3525 outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS); 3526 } else { 3527#ifdef PC98 3528 if (IS_8251(com->pc98_if_type)) 3529 tmp = com_tiocm_get(com) & TIOCM_RTS; 3530 else 3531 tmp = com->mcr_image & MCR_RTS; 3532 if (!(tmp) && com->iptr < com->ihighwater 3533 && com->state & CS_RTS_IFLOW) 3534#else 3535 if (!(com->mcr_image & MCR_RTS) && com->iptr < com->ihighwater 3536 && com->state & CS_RTS_IFLOW) 3537#endif 3538#ifdef PC98 3539 if (IS_8251(com->pc98_if_type)) 3540 com_tiocm_bis(com, TIOCM_RTS); 3541 else 3542#endif 3543 outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS); 3544 } 3545 enable_intr(); 3546 if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) { 3547 ttwwakeup(tp); 3548#ifdef PC98 3549/* if(IS_8251(com->pc98_if_type)) 3550 com_int_Tx_enable(com); */ 3551#endif 3552 splx(s); 3553 return; 3554 } 3555 if (tp->t_outq.c_cc != 0) { 3556 struct lbq *qp; 3557 struct lbq *next; 3558 3559 if (!com->obufs[0].l_queued) { 3560 com->obufs[0].l_tail 3561 = com->obuf1 + q_to_b(&tp->t_outq, com->obuf1, 3562#ifndef PC98 3563 sizeof com->obuf1); 3564#else 3565 com->obufsize); 3566#endif 3567 com->obufs[0].l_next = NULL; 3568 com->obufs[0].l_queued = TRUE; 3569 disable_intr(); 3570 if (com->state & CS_BUSY) { 3571 qp = com->obufq.l_next; 3572 while ((next = qp->l_next) != NULL) 3573 qp = next; 3574 qp->l_next = &com->obufs[0]; 3575 } else { 3576 com->obufq.l_head = com->obufs[0].l_head; 3577 com->obufq.l_tail = com->obufs[0].l_tail; 3578 com->obufq.l_next = &com->obufs[0]; 3579 com->state |= CS_BUSY; 3580 } 3581 enable_intr(); 3582 } 3583 if (tp->t_outq.c_cc != 0 && !com->obufs[1].l_queued) { 3584 com->obufs[1].l_tail 3585 = com->obuf2 + q_to_b(&tp->t_outq, com->obuf2, 3586#ifndef PC98 3587 sizeof com->obuf2); 3588#else 3589 com->obufsize); 3590#endif 3591 com->obufs[1].l_next = NULL; 3592 com->obufs[1].l_queued = TRUE; 3593 disable_intr(); 3594 if (com->state & CS_BUSY) { 3595 qp = com->obufq.l_next; 3596 while ((next = qp->l_next) != NULL) 3597 qp = next; 3598 qp->l_next = &com->obufs[1]; 3599 } else { 3600 com->obufq.l_head = com->obufs[1].l_head; 3601 com->obufq.l_tail = com->obufs[1].l_tail; 3602 com->obufq.l_next = &com->obufs[1]; 3603 com->state |= CS_BUSY; 3604 } 3605 enable_intr(); 3606 } 3607 tp->t_state |= TS_BUSY; 3608 } 3609 disable_intr(); 3610 if (com->state >= (CS_BUSY | CS_TTGO)) 3611 siointr1(com); /* fake interrupt to start output */ 3612 enable_intr(); 3613#ifdef PC98 3614/* if(IS_8251(com->pc98_if_type)) 3615 com_int_Tx_enable(com); */ 3616#endif 3617 ttwwakeup(tp); 3618 splx(s); 3619} 3620 3621static void 3622siostop(tp, rw) 3623 struct tty *tp; 3624 int rw; 3625{ 3626 struct com_s *com; 3627#ifdef PC98 3628 int port_shift = 0; 3629 int rsa98_tmp = 0; 3630#endif 3631 3632 com = com_addr(DEV_TO_UNIT(tp->t_dev)); 3633 if (com->gone) 3634 return; 3635#ifdef PC98 3636 if (IS_8251(com->pc98_if_type)) 3637 port_shift = if_16550a_type[com->pc98_if_type & 0x0f].port_shift; 3638#endif 3639 disable_intr(); 3640 if (rw & FWRITE) { 3641 if (com->hasfifo) 3642#ifdef COM_ESP 3643 /* XXX avoid h/w bug. */ 3644 if (!com->esp) 3645#endif 3646#ifdef PC98 3647 outb(com->iobase + (com_fifo << port_shift), 3648 FIFO_XMT_RST | com->fifo_image); 3649 if (com->pc98_if_type == COM_IF_RSA98III) 3650 for(rsa98_tmp = 0; rsa98_tmp < 2048; rsa98_tmp++) 3651 outb(com->iobase + (com_fifo << port_shift), 3652 FIFO_XMT_RST | com->fifo_image); 3653#else 3654 outb(com->iobase + com_fifo, 3655 FIFO_XMT_RST | com->fifo_image); 3656#endif 3657 com->obufs[0].l_queued = FALSE; 3658 com->obufs[1].l_queued = FALSE; 3659 if (com->state & CS_ODONE) 3660 com_events -= LOTS_OF_EVENTS; 3661 com->state &= ~(CS_ODONE | CS_BUSY); 3662 com->tp->t_state &= ~TS_BUSY; 3663 } 3664 if (rw & FREAD) { 3665 if (com->hasfifo) 3666#ifdef COM_ESP 3667 /* XXX avoid h/w bug. */ 3668 if (!com->esp) 3669#endif 3670#ifdef PC98 3671 if (com->pc98_if_type == COM_IF_RSA98III) { 3672 for(rsa98_tmp = 0; rsa98_tmp < 2048; rsa98_tmp++) 3673 inb(com->data_port); 3674 } 3675 outb(com->iobase + (com_fifo << port_shift), 3676 FIFO_RCV_RST | com->fifo_image); 3677#else 3678 outb(com->iobase + com_fifo, 3679 FIFO_RCV_RST | com->fifo_image); 3680#endif 3681 com_events -= (com->iptr - com->ibuf); 3682 com->iptr = com->ibuf; 3683 } 3684 enable_intr(); 3685 comstart(tp); 3686} 3687 3688static struct tty * 3689siodevtotty(dev) 3690 dev_t dev; 3691{ 3692 int mynor; 3693 int unit; 3694 3695 mynor = minor(dev); 3696 if (mynor & CONTROL_MASK) 3697 return (NULL); 3698 unit = MINOR_TO_UNIT(mynor); 3699 if ((u_int) unit >= NSIOTOT) 3700 return (NULL); 3701 return (&sio_tty[unit]); 3702} 3703 3704static int 3705commctl(com, bits, how) 3706 struct com_s *com; 3707 int bits; 3708 int how; 3709{ 3710 int mcr; 3711 int msr; 3712 3713 if (how == DMGET) { 3714 bits = TIOCM_LE; /* XXX - always enabled while open */ 3715 mcr = com->mcr_image; 3716 if (mcr & MCR_DTR) 3717 bits |= TIOCM_DTR; 3718 if (mcr & MCR_RTS) 3719 bits |= TIOCM_RTS; 3720 msr = com->prev_modem_status; 3721 if (msr & MSR_CTS) 3722 bits |= TIOCM_CTS; 3723 if (msr & MSR_DCD) 3724 bits |= TIOCM_CD; 3725 if (msr & MSR_DSR) 3726 bits |= TIOCM_DSR; 3727 /* 3728 * XXX - MSR_RI is naturally volatile, and we make MSR_TERI 3729 * more volatile by reading the modem status a lot. Perhaps 3730 * we should latch both bits until the status is read here. 3731 */ 3732 if (msr & (MSR_RI | MSR_TERI)) 3733 bits |= TIOCM_RI; 3734 return (bits); 3735 } 3736 mcr = 0; 3737 if (bits & TIOCM_DTR) 3738 mcr |= MCR_DTR; 3739 if (bits & TIOCM_RTS) 3740 mcr |= MCR_RTS; 3741 if (com->gone) 3742 return(0); 3743 disable_intr(); 3744 switch (how) { 3745 case DMSET: 3746 outb(com->modem_ctl_port, 3747 com->mcr_image = mcr | (com->mcr_image & MCR_IENABLE)); 3748 break; 3749 case DMBIS: 3750 outb(com->modem_ctl_port, com->mcr_image |= mcr); 3751 break; 3752 case DMBIC: 3753 outb(com->modem_ctl_port, com->mcr_image &= ~mcr); 3754 break; 3755 } 3756 enable_intr(); 3757 return (0); 3758} 3759 3760static void 3761siosettimeout() 3762{ 3763 struct com_s *com; 3764 bool_t someopen; 3765 int unit; 3766 3767 /* 3768 * Set our timeout period to 1 second if no polled devices are open. 3769 * Otherwise set it to max(1/200, 1/hz). 3770 * Enable timeouts iff some device is open. 3771 */ 3772 untimeout(comwakeup, (void *)NULL, sio_timeout_handle); 3773 sio_timeout = hz; 3774 someopen = FALSE; 3775 for (unit = 0; unit < NSIOTOT; ++unit) { 3776 com = com_addr(unit); 3777 if (com != NULL && com->tp != NULL 3778 && com->tp->t_state & TS_ISOPEN && !com->gone) { 3779 someopen = TRUE; 3780 if (com->poll || com->poll_output) { 3781 sio_timeout = hz > 200 ? hz / 200 : 1; 3782 break; 3783 } 3784 } 3785 } 3786 if (someopen) { 3787 sio_timeouts_until_log = hz / sio_timeout; 3788 sio_timeout_handle = timeout(comwakeup, (void *)NULL, 3789 sio_timeout); 3790 } else { 3791 /* Flush error messages, if any. */ 3792 sio_timeouts_until_log = 1; 3793 comwakeup((void *)NULL); 3794 untimeout(comwakeup, (void *)NULL, sio_timeout_handle); 3795 } 3796} 3797 3798static void 3799comwakeup(chan) 3800 void *chan; 3801{ 3802 struct com_s *com; 3803 int unit; 3804 3805 sio_timeout_handle = timeout(comwakeup, (void *)NULL, sio_timeout); 3806 3807 /* 3808 * Recover from lost output interrupts. 3809 * Poll any lines that don't use interrupts. 3810 */ 3811 for (unit = 0; unit < NSIOTOT; ++unit) { 3812 com = com_addr(unit); 3813 if (com != NULL && !com->gone 3814 && (com->state >= (CS_BUSY | CS_TTGO) || com->poll)) { 3815 disable_intr(); 3816 siointr1(com); 3817 enable_intr(); 3818 } 3819 } 3820 3821 /* 3822 * Check for and log errors, but not too often. 3823 */ 3824 if (--sio_timeouts_until_log > 0) 3825 return; 3826 sio_timeouts_until_log = hz / sio_timeout; 3827 for (unit = 0; unit < NSIOTOT; ++unit) { 3828 int errnum; 3829 3830 com = com_addr(unit); 3831 if (com == NULL) 3832 continue; 3833 if (com->gone) 3834 continue; 3835 for (errnum = 0; errnum < CE_NTYPES; ++errnum) { 3836 u_int delta; 3837 u_long total; 3838 3839 disable_intr(); 3840 delta = com->delta_error_counts[errnum]; 3841 com->delta_error_counts[errnum] = 0; 3842 enable_intr(); 3843 if (delta == 0) 3844 continue; 3845 total = com->error_counts[errnum] += delta; 3846 log(LOG_ERR, "sio%d: %u more %s%s (total %lu)\n", 3847 unit, delta, error_desc[errnum], 3848 delta == 1 ? "" : "s", total); 3849 } 3850 } 3851} 3852 3853#ifdef PC98 3854/* commint is called when modem control line changes */ 3855static void 3856commint(dev_t dev) 3857{ 3858 register struct tty *tp; 3859 int stat,delta; 3860 struct com_s *com; 3861 int mynor,unit; 3862 3863 mynor = minor(dev); 3864 unit = MINOR_TO_UNIT(mynor); 3865 com = com_addr(unit); 3866 tp = com->tp; 3867 3868 stat = com_tiocm_get(com); 3869 delta = com_tiocm_get_delta(com); 3870 3871 if (com->state & CS_CTS_OFLOW) { 3872 if (stat & TIOCM_CTS) 3873 com->state |= CS_ODEVREADY; 3874 else 3875 com->state &= ~CS_ODEVREADY; 3876 } 3877 if ((delta & TIOCM_CAR) && (mynor & CALLOUT_MASK) == 0) { 3878 if (stat & TIOCM_CAR ) 3879 (void)(*linesw[tp->t_line].l_modem)(tp, 1); 3880 else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) { 3881 /* negate DTR, RTS */ 3882 com_tiocm_bic(com, (tp->t_cflag & HUPCL) ? 3883 TIOCM_DTR|TIOCM_RTS|TIOCM_LE : TIOCM_LE ); 3884 /* disable IENABLE */ 3885 com_int_TxRx_disable( com ); 3886 } 3887 } 3888} 3889#endif 3890 3891static void 3892disc_optim(tp, t, com) 3893 struct tty *tp; 3894 struct termios *t; 3895 struct com_s *com; 3896{ 3897 if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON)) 3898 && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK)) 3899 && (!(t->c_iflag & PARMRK) 3900 || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK)) 3901 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN)) 3902 && linesw[tp->t_line].l_rint == ttyinput) 3903 tp->t_state |= TS_CAN_BYPASS_L_RINT; 3904 else 3905 tp->t_state &= ~TS_CAN_BYPASS_L_RINT; 3906 com->hotchar = linesw[tp->t_line].l_hotchar; 3907} 3908 3909/* 3910 * Following are all routines needed for SIO to act as console 3911 */ 3912#include <machine/cons.h> 3913 3914struct siocnstate { 3915 u_char dlbl; 3916 u_char dlbh; 3917 u_char ier; 3918 u_char cfcr; 3919 u_char mcr; 3920}; 3921 3922static speed_t siocngetspeed __P((Port_t, struct speedtab *)); 3923static void siocnclose __P((struct siocnstate *sp, Port_t iobase)); 3924static void siocnopen __P((struct siocnstate *sp, Port_t iobase, int speed)); 3925static void siocntxwait __P((Port_t iobase)); 3926 3927#ifdef __i386__ 3928static cn_probe_t siocnprobe; 3929static cn_init_t siocninit; 3930static cn_checkc_t siocncheckc; 3931static cn_getc_t siocngetc; 3932static cn_putc_t siocnputc; 3933 3934CONS_DRIVER(sio, siocnprobe, siocninit, NULL, siocngetc, siocncheckc, siocnputc); 3935 3936/* To get the GDB related variables */ 3937#if DDB > 0 3938#include <ddb/ddb.h> 3939#endif 3940#endif 3941 3942static void 3943siocntxwait(iobase) 3944 Port_t iobase; 3945{ 3946 int timo; 3947 3948 /* 3949 * Wait for any pending transmission to finish. Required to avoid 3950 * the UART lockup bug when the speed is changed, and for normal 3951 * transmits. 3952 */ 3953 timo = 100000; 3954 while ((inb(iobase + com_lsr) & (LSR_TSRE | LSR_TXRDY)) 3955 != (LSR_TSRE | LSR_TXRDY) && --timo != 0) 3956 ; 3957} 3958 3959/* 3960 * Read the serial port specified and try to figure out what speed 3961 * it's currently running at. We're assuming the serial port has 3962 * been initialized and is basicly idle. This routine is only intended 3963 * to be run at system startup. 3964 * 3965 * If the value read from the serial port doesn't make sense, return 0. 3966 */ 3967 3968static speed_t 3969siocngetspeed(iobase, table) 3970 Port_t iobase; 3971 struct speedtab *table; 3972{ 3973 int code; 3974 u_char dlbh; 3975 u_char dlbl; 3976 u_char cfcr; 3977 3978 cfcr = inb(iobase + com_cfcr); 3979 outb(iobase + com_cfcr, CFCR_DLAB | cfcr); 3980 3981 dlbl = inb(iobase + com_dlbl); 3982 dlbh = inb(iobase + com_dlbh); 3983 3984 outb(iobase + com_cfcr, cfcr); 3985 3986 code = dlbh << 8 | dlbl; 3987 3988 for ( ; table->sp_speed != -1; table++) 3989 if (table->sp_code == code) 3990 return (table->sp_speed); 3991 3992 return 0; /* didn't match anything sane */ 3993} 3994 3995static void 3996siocnopen(sp, iobase, speed) 3997 struct siocnstate *sp; 3998 Port_t iobase; 3999 int speed; 4000{ 4001 int divisor; 4002 u_char dlbh; 4003 u_char dlbl; 4004 4005 /* 4006 * Save all the device control registers except the fifo register 4007 * and set our default ones (cs8 -parenb speed=comdefaultrate). 4008 * We can't save the fifo register since it is read-only. 4009 */ 4010 sp->ier = inb(iobase + com_ier); 4011 outb(iobase + com_ier, 0); /* spltty() doesn't stop siointr() */ 4012 siocntxwait(iobase); 4013 sp->cfcr = inb(iobase + com_cfcr); 4014 outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS); 4015 sp->dlbl = inb(iobase + com_dlbl); 4016 sp->dlbh = inb(iobase + com_dlbh); 4017 /* 4018 * Only set the divisor registers if they would change, since on 4019 * some 16550 incompatibles (Startech), setting them clears the 4020 * data input register. This also reduces the effects of the 4021 * UMC8669F bug. 4022 */ 4023 divisor = ttspeedtab(speed, comspeedtab); 4024 dlbl = divisor & 0xFF; 4025 if (sp->dlbl != dlbl) 4026 outb(iobase + com_dlbl, dlbl); 4027 dlbh = (u_int) divisor >> 8; 4028 if (sp->dlbh != dlbh) 4029 outb(iobase + com_dlbh, dlbh); 4030 outb(iobase + com_cfcr, CFCR_8BITS); 4031 sp->mcr = inb(iobase + com_mcr); 4032 /* 4033 * We don't want interrupts, but must be careful not to "disable" 4034 * them by clearing the MCR_IENABLE bit, since that might cause 4035 * an interrupt by floating the IRQ line. 4036 */ 4037 outb(iobase + com_mcr, (sp->mcr & MCR_IENABLE) | MCR_DTR | MCR_RTS); 4038} 4039 4040static void 4041siocnclose(sp, iobase) 4042 struct siocnstate *sp; 4043 Port_t iobase; 4044{ 4045 /* 4046 * Restore the device control registers. 4047 */ 4048 siocntxwait(iobase); 4049 outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS); 4050 if (sp->dlbl != inb(iobase + com_dlbl)) 4051 outb(iobase + com_dlbl, sp->dlbl); 4052 if (sp->dlbh != inb(iobase + com_dlbh)) 4053 outb(iobase + com_dlbh, sp->dlbh); 4054 outb(iobase + com_cfcr, sp->cfcr); 4055 /* 4056 * XXX damp oscillations of MCR_DTR and MCR_RTS by not restoring them. 4057 */ 4058 outb(iobase + com_mcr, sp->mcr | MCR_DTR | MCR_RTS); 4059 outb(iobase + com_ier, sp->ier); 4060} 4061 4062#ifdef __i386__ 4063static 4064#endif 4065void 4066siocnprobe(cp) 4067 struct consdev *cp; 4068{ 4069 speed_t boot_speed; 4070 u_char cfcr; 4071 int s, unit; 4072 struct siocnstate sp; 4073 4074 /* 4075 * Find our first enabled console, if any. If it is a high-level 4076 * console device, then initialize it and return successfully. 4077 * If it is a low-level console device, then initialize it and 4078 * return unsuccessfully. It must be initialized in both cases 4079 * for early use by console drivers and debuggers. Initializing 4080 * the hardware is not necessary in all cases, since the i/o 4081 * routines initialize it on the fly, but it is necessary if 4082 * input might arrive while the hardware is switched back to an 4083 * uninitialized state. We can't handle multiple console devices 4084 * yet because our low-level routines don't take a device arg. 4085 * We trust the user to set the console flags properly so that we 4086 * don't need to probe. 4087 */ 4088 cp->cn_pri = CN_DEAD; 4089 4090 for (unit = 0; unit < 16; unit++) { /* XXX need to know how many */ 4091 int flags; 4092 if (resource_int_value("sio", unit, "flags", &flags)) 4093 continue; 4094 if (COM_CONSOLE(flags) || COM_DEBUGGER(flags)) { 4095 int port; 4096 Port_t iobase; 4097 4098 if (resource_int_value("sio", unit, "port", &port)) 4099 continue; 4100 iobase = port; 4101 s = spltty(); 4102 if (boothowto & RB_SERIAL) { 4103 boot_speed = siocngetspeed(iobase, comspeedtab); 4104 if (boot_speed) 4105 comdefaultrate = boot_speed; 4106 } 4107 4108 /* 4109 * Initialize the divisor latch. We can't rely on 4110 * siocnopen() to do this the first time, since it 4111 * avoids writing to the latch if the latch appears 4112 * to have the correct value. Also, if we didn't 4113 * just read the speed from the hardware, then we 4114 * need to set the speed in hardware so that 4115 * switching it later is null. 4116 */ 4117 cfcr = inb(iobase + com_cfcr); 4118 outb(iobase + com_cfcr, CFCR_DLAB | cfcr); 4119 outb(iobase + com_dlbl, 4120 COMBRD(comdefaultrate) & 0xff); 4121 outb(iobase + com_dlbh, 4122 (u_int) COMBRD(comdefaultrate) >> 8); 4123 outb(iobase + com_cfcr, cfcr); 4124 4125 siocnopen(&sp, iobase, comdefaultrate); 4126 4127 splx(s); 4128 if (COM_CONSOLE(flags) && !COM_LLCONSOLE(flags)) { 4129 cp->cn_dev = makedev(CDEV_MAJOR, unit); 4130 cp->cn_pri = COM_FORCECONSOLE(flags) 4131 || boothowto & RB_SERIAL 4132 ? CN_REMOTE : CN_NORMAL; 4133 printf("sio%d: system console\n", unit); 4134 siocniobase = iobase; 4135 siocnunit = unit; 4136 } 4137 if (COM_DEBUGGER(flags) && !COM_LLCONSOLE(flags)) { 4138 printf("sio%d: gdb debugging port\n", unit); 4139 siogdbiobase = iobase; 4140 siogdbunit = unit; 4141#ifdef __i386__ 4142#if DDB > 0 4143 gdbdev = makedev(CDEV_MAJOR, unit); 4144 gdb_getc = siocngetc; 4145 gdb_putc = siocnputc; 4146#endif 4147#endif 4148 } 4149 } 4150 } 4151#ifdef __i386__ 4152#if DDB > 0 4153 /* 4154 * XXX Ugly Compatability. 4155 * If no gdb port has been specified, set it to be the console 4156 * as some configuration files don't specify the gdb port. 4157 */ 4158 if (gdbdev == NODEV && (boothowto & RB_GDB)) { 4159 printf("Warning: no GDB port specified. Defaulting to sio%d.\n", 4160 siocnunit); 4161 printf("Set flag 0x80 on desired GDB port in your\n"); 4162 printf("configuration file (currently sio only).\n"); 4163 siogdbiobase = siocniobase; 4164 siogdbunit = siocnunit; 4165 gdbdev = makedev(CDEV_MAJOR, siocnunit); 4166 gdb_getc = siocngetc; 4167 gdb_putc = siocnputc; 4168 } 4169#endif 4170#endif 4171} 4172 4173#ifdef __alpha__ 4174 4175struct consdev siocons = { 4176 NULL, NULL, siocngetc, siocncheckc, siocnputc, 4177 NULL, 0, CN_NORMAL, 4178}; 4179 4180extern struct consdev *cn_tab; 4181 4182int 4183siocnattach(port, speed) 4184 int port; 4185 int speed; 4186{ 4187 int s; 4188 u_char cfcr; 4189 struct siocnstate sp; 4190 4191 siocniobase = port; 4192 comdefaultrate = speed; 4193 4194 s = spltty(); 4195 4196 /* 4197 * Initialize the divisor latch. We can't rely on 4198 * siocnopen() to do this the first time, since it 4199 * avoids writing to the latch if the latch appears 4200 * to have the correct value. Also, if we didn't 4201 * just read the speed from the hardware, then we 4202 * need to set the speed in hardware so that 4203 * switching it later is null. 4204 */ 4205 cfcr = inb(siocniobase + com_cfcr); 4206 outb(siocniobase + com_cfcr, CFCR_DLAB | cfcr); 4207 outb(siocniobase + com_dlbl, 4208 COMBRD(comdefaultrate) & 0xff); 4209 outb(siocniobase + com_dlbh, 4210 (u_int) COMBRD(comdefaultrate) >> 8); 4211 outb(siocniobase + com_cfcr, cfcr); 4212 4213 siocnopen(&sp, siocniobase, comdefaultrate); 4214 splx(s); 4215 4216 siocons.cn_dev = makedev(CDEV_MAJOR, 0); 4217 cn_tab = &siocons; 4218 return 0; 4219} 4220 4221int 4222siogdbattach(port, speed) 4223 int port; 4224 int speed; 4225{ 4226 int s; 4227 u_char cfcr; 4228 struct siocnstate sp; 4229 4230 siogdbiobase = port; 4231 gdbdefaultrate = speed; 4232 4233 s = spltty(); 4234 4235 /* 4236 * Initialize the divisor latch. We can't rely on 4237 * siocnopen() to do this the first time, since it 4238 * avoids writing to the latch if the latch appears 4239 * to have the correct value. Also, if we didn't 4240 * just read the speed from the hardware, then we 4241 * need to set the speed in hardware so that 4242 * switching it later is null. 4243 */ 4244 cfcr = inb(siogdbiobase + com_cfcr); 4245 outb(siogdbiobase + com_cfcr, CFCR_DLAB | cfcr); 4246 outb(siogdbiobase + com_dlbl, 4247 COMBRD(gdbdefaultrate) & 0xff); 4248 outb(siogdbiobase + com_dlbh, 4249 (u_int) COMBRD(gdbdefaultrate) >> 8); 4250 outb(siogdbiobase + com_cfcr, cfcr); 4251 4252 siocnopen(&sp, siogdbiobase, gdbdefaultrate); 4253 splx(s); 4254 4255 return 0; 4256} 4257 4258#endif 4259 4260#ifdef __i386__ 4261static 4262#endif 4263void 4264siocninit(cp) 4265 struct consdev *cp; 4266{ 4267 comconsole = DEV_TO_UNIT(cp->cn_dev); 4268} 4269 4270#ifdef __i386__ 4271static 4272#endif 4273int 4274siocncheckc(dev) 4275 dev_t dev; 4276{ 4277 int c; 4278 Port_t iobase; 4279 int s; 4280 struct siocnstate sp; 4281 4282 if (minor(dev) == siogdbunit) 4283 iobase = siogdbiobase; 4284 else 4285 iobase = siocniobase; 4286 s = spltty(); 4287 siocnopen(&sp, iobase, comdefaultrate); 4288 if (inb(iobase + com_lsr) & LSR_RXRDY) 4289 c = inb(iobase + com_data); 4290 else 4291 c = -1; 4292 siocnclose(&sp, iobase); 4293 splx(s); 4294 return (c); 4295} 4296 4297 4298int 4299siocngetc(dev) 4300 dev_t dev; 4301{ 4302 int c; 4303 Port_t iobase; 4304 int s; 4305 struct siocnstate sp; 4306 4307 if (minor(dev) == siogdbunit) 4308 iobase = siogdbiobase; 4309 else 4310 iobase = siocniobase; 4311 s = spltty(); 4312 siocnopen(&sp, iobase, comdefaultrate); 4313 while (!(inb(iobase + com_lsr) & LSR_RXRDY)) 4314 ; 4315 c = inb(iobase + com_data); 4316 siocnclose(&sp, iobase); 4317 splx(s); 4318 return (c); 4319} 4320 4321void 4322siocnputc(dev, c) 4323 dev_t dev; 4324 int c; 4325{ 4326 int s; 4327 struct siocnstate sp; 4328 Port_t iobase; 4329 4330 if (minor(dev) == siogdbunit) 4331 iobase = siogdbiobase; 4332 else 4333 iobase = siocniobase; 4334 s = spltty(); 4335 siocnopen(&sp, iobase, comdefaultrate); 4336 siocntxwait(iobase); 4337 outb(iobase + com_data, c); 4338 siocnclose(&sp, iobase); 4339 splx(s); 4340} 4341 4342#ifdef __alpha__ 4343int 4344siogdbgetc() 4345{ 4346 int c; 4347 Port_t iobase; 4348 int s; 4349 struct siocnstate sp; 4350 4351 iobase = siogdbiobase; 4352 s = spltty(); 4353 siocnopen(&sp, iobase, gdbdefaultrate); 4354 while (!(inb(iobase + com_lsr) & LSR_RXRDY)) 4355 ; 4356 c = inb(iobase + com_data); 4357 siocnclose(&sp, iobase); 4358 splx(s); 4359 return (c); 4360} 4361 4362void 4363siogdbputc(c) 4364 int c; 4365{ 4366 int s; 4367 struct siocnstate sp; 4368 4369 s = spltty(); 4370 siocnopen(&sp, siogdbiobase, gdbdefaultrate); 4371 siocntxwait(siogdbiobase); 4372 outb(siogdbiobase + com_data, c); 4373 siocnclose(&sp, siogdbiobase); 4374 splx(s); 4375} 4376#endif 4377 4378 4379/* 4380 * support PnP cards if we are using 'em 4381 */ 4382 4383#if NPNP > 0 4384 4385static pnpid_t siopnp_ids[] = { 4386 { 0x5015f435, "MOT1550"}, 4387 { 0x8113b04e, "Supra1381"}, 4388 { 0x9012b04e, "Supra1290"}, 4389 { 0x7121b04e, "SupraExpress 56i Sp"}, 4390 { 0x11007256, "USR0011"}, 4391 { 0x30207256, "USR2030"}, 4392 { 0x31307256, "USR3031"}, 4393 { 0x90307256, "USR3090"}, 4394 { 0x0100440e, "Cardinal MVP288IV"}, 4395 { 0 } 4396}; 4397 4398static char *siopnp_probe(u_long csn, u_long vend_id); 4399static void siopnp_attach(u_long csn, u_long vend_id, char *name, 4400 struct isa_device *dev); 4401static u_long nsiopnp = NSIO; 4402 4403static struct pnp_device siopnp = { 4404 "siopnp", 4405 siopnp_probe, 4406 siopnp_attach, 4407 &nsiopnp, 4408 &tty_imask 4409}; 4410DATA_SET (pnpdevice_set, siopnp); 4411 4412static char * 4413siopnp_probe(u_long csn, u_long vend_id) 4414{ 4415 pnpid_t *id; 4416 char *s = NULL; 4417 4418 for(id = siopnp_ids; id->vend_id != 0; id++) { 4419 if (vend_id == id->vend_id) { 4420 s = id->id_str; 4421 break; 4422 } 4423 } 4424 4425 if (s) { 4426 struct pnp_cinfo d; 4427 read_pnp_parms(&d, 0); 4428 if (d.enable == 0 || d.flags & 1) { 4429 printf("CSN %lu is disabled.\n", csn); 4430 return (NULL); 4431 } 4432 4433 } 4434 4435 return (s); 4436} 4437 4438static void 4439siopnp_attach(u_long csn, u_long vend_id, char *name, struct isa_device *dev) 4440{ 4441 struct pnp_cinfo d; 4442 4443 if (dev->id_unit >= NSIOTOT) 4444 return; 4445 4446 if (read_pnp_parms(&d, 0) == 0) { 4447 printf("failed to read pnp parms\n"); 4448 return; 4449 } 4450 4451 write_pnp_parms(&d, 0); 4452 4453 enable_pnp_card(); 4454 4455 dev->id_iobase = d.port[0]; 4456 dev->id_irq = (1 << d.irq[0]); 4457 dev->id_ointr = siointr; 4458 dev->id_ri_flags = RI_FAST; 4459 dev->id_drq = -1; 4460 4461 if (dev->id_driver == NULL) { 4462 dev->id_driver = &siodriver; 4463 dev->id_id = isa_compat_nextid(); 4464 } 4465 4466 if ((dev->id_alive = sioprobe(dev)) != 0) 4467 sioattach(dev); 4468 else 4469 printf("sio%d: probe failed\n", dev->id_unit); 4470} 4471#endif 4472 4473DEV_DRIVER_MODULE(sio, isa, sio_driver, sio_devclass, sio_cdevsw, 0, 0); 4474 4475#ifdef PC98 4476/* 4477 * pc98 local function 4478 */ 4479 4480static void 4481com_tiocm_set(struct com_s *com, int msr) 4482{ 4483 int s; 4484 int tmp = 0; 4485 int mask = CMD8251_TxEN|CMD8251_RxEN|CMD8251_DTR|CMD8251_RTS; 4486 4487 s=spltty(); 4488 com->pc98_prev_modem_status = ( msr & (TIOCM_LE|TIOCM_DTR|TIOCM_RTS) ) 4489 | ( com->pc98_prev_modem_status & ~(TIOCM_LE|TIOCM_DTR|TIOCM_RTS) ); 4490 tmp |= (CMD8251_TxEN|CMD8251_RxEN); 4491 if ( msr & TIOCM_DTR ) tmp |= CMD8251_DTR; 4492 if ( msr & TIOCM_RTS ) tmp |= CMD8251_RTS; 4493 pc98_i8251_clear_or_cmd( com, mask, tmp ); 4494 splx(s); 4495} 4496 4497static void 4498com_tiocm_bis(struct com_s *com, int msr) 4499{ 4500 int s; 4501 int tmp = 0; 4502 4503 s=spltty(); 4504 com->pc98_prev_modem_status |= ( msr & (TIOCM_LE|TIOCM_DTR|TIOCM_RTS) ); 4505 tmp |= CMD8251_TxEN|CMD8251_RxEN; 4506 if ( msr & TIOCM_DTR ) tmp |= CMD8251_DTR; 4507 if ( msr & TIOCM_RTS ) tmp |= CMD8251_RTS; 4508 4509 pc98_i8251_or_cmd( com, tmp ); 4510 splx(s); 4511} 4512 4513static void 4514com_tiocm_bic(struct com_s *com, int msr) 4515{ 4516 int s; 4517 int tmp = msr; 4518 4519 s=spltty(); 4520 com->pc98_prev_modem_status &= ~( msr & (TIOCM_LE|TIOCM_DTR|TIOCM_RTS) ); 4521 if ( msr & TIOCM_DTR ) tmp |= CMD8251_DTR; 4522 if ( msr & TIOCM_RTS ) tmp |= CMD8251_RTS; 4523 4524 pc98_i8251_clear_cmd( com, tmp ); 4525 splx(s); 4526} 4527 4528static int 4529com_tiocm_get(struct com_s *com) 4530{ 4531 return( com->pc98_prev_modem_status ); 4532} 4533 4534static int 4535com_tiocm_get_delta(struct com_s *com) 4536{ 4537 int tmp; 4538 4539 tmp = com->pc98_modem_delta; 4540 com->pc98_modem_delta = 0; 4541 return( tmp ); 4542} 4543 4544/* convert to TIOCM_?? ( ioctl.h ) */ 4545static int 4546pc98_get_modem_status(struct com_s *com) 4547{ 4548 int stat, stat2; 4549 register int msr; 4550 4551 stat = inb(com->sts_port); 4552 stat2 = inb(com->in_modem_port); 4553 msr = com->pc98_prev_modem_status 4554 & ~(TIOCM_CAR|TIOCM_RI|TIOCM_DSR|TIOCM_CTS); 4555 if ( !(stat2 & CICSCD_CD) ) msr |= TIOCM_CAR; 4556 if ( !(stat2 & CICSCD_CI) ) msr |= TIOCM_RI; 4557 if ( stat & STS8251_DSR ) msr |= TIOCM_DSR; 4558 if ( !(stat2 & CICSCD_CS) ) msr |= TIOCM_CTS; 4559#if COM_CARRIER_DETECT_EMULATE 4560 if ( msr & (TIOCM_DSR|TIOCM_CTS) ) { 4561 msr |= TIOCM_CAR; 4562 } 4563#endif 4564 return(msr); 4565} 4566 4567static void 4568pc98_check_msr(void* chan) 4569{ 4570 int msr, delta; 4571 int s; 4572 register struct tty *tp; 4573 struct com_s *com; 4574 int mynor; 4575 int unit; 4576 dev_t dev; 4577 4578 dev=(dev_t)chan; 4579 mynor = minor(dev); 4580 unit = MINOR_TO_UNIT(mynor); 4581 com = com_addr(unit); 4582 tp = com->tp; 4583 4584 s = spltty(); 4585 msr = pc98_get_modem_status(com); 4586 /* make change flag */ 4587 delta = msr ^ com->pc98_prev_modem_status; 4588 if ( delta & TIOCM_CAR ) { 4589 if ( com->modem_car_chg_timer ) { 4590 if ( -- com->modem_car_chg_timer ) 4591 msr ^= TIOCM_CAR; 4592 } else { 4593 if ((com->modem_car_chg_timer = (msr & TIOCM_CAR) ? 4594 DCD_ON_RECOGNITION : DCD_OFF_TOLERANCE) != 0) 4595 msr ^= TIOCM_CAR; 4596 } 4597 } else 4598 com->modem_car_chg_timer = 0; 4599 delta = ( msr ^ com->pc98_prev_modem_status ) & 4600 (TIOCM_CAR|TIOCM_RI|TIOCM_DSR|TIOCM_CTS); 4601 com->pc98_prev_modem_status = msr; 4602 delta = ( com->pc98_modem_delta |= delta ); 4603 splx(s); 4604 if ( com->modem_checking || (tp->t_state & (TS_ISOPEN)) ) { 4605 if ( delta ) { 4606 commint(dev); 4607 } 4608 timeout(pc98_check_msr, (caddr_t)dev, 4609 PC98_CHECK_MODEM_INTERVAL); 4610 } else { 4611 com->modem_checking = 0; 4612 } 4613} 4614 4615static void 4616pc98_msrint_start(dev_t dev) 4617{ 4618 struct com_s *com; 4619 int mynor; 4620 int unit; 4621 int s = spltty(); 4622 4623 mynor = minor(dev); 4624 unit = MINOR_TO_UNIT(mynor); 4625 com = com_addr(unit); 4626 /* modem control line check routine envoke interval is 1/10 sec */ 4627 if ( com->modem_checking == 0 ) { 4628 com->pc98_prev_modem_status = pc98_get_modem_status(com); 4629 com->pc98_modem_delta = 0; 4630 timeout(pc98_check_msr, (caddr_t)dev, 4631 PC98_CHECK_MODEM_INTERVAL); 4632 com->modem_checking = 1; 4633 } 4634 splx(s); 4635} 4636 4637static void 4638pc98_disable_i8251_interrupt(struct com_s *com, int mod) 4639{ 4640 /* disable interrupt */ 4641 register int tmp; 4642 4643 mod |= ~(IEN_Tx|IEN_TxEMP|IEN_Rx); 4644 COM_INT_DISABLE 4645 tmp = inb( com->intr_ctrl_port ) & ~(IEN_Tx|IEN_TxEMP|IEN_Rx); 4646 outb( com->intr_ctrl_port, (com->intr_enable&=~mod) | tmp ); 4647 COM_INT_ENABLE 4648} 4649 4650static void 4651pc98_enable_i8251_interrupt(struct com_s *com, int mod) 4652{ 4653 register int tmp; 4654 4655 COM_INT_DISABLE 4656 tmp = inb( com->intr_ctrl_port ) & ~(IEN_Tx|IEN_TxEMP|IEN_Rx); 4657 outb( com->intr_ctrl_port, (com->intr_enable|=mod) | tmp ); 4658 COM_INT_ENABLE 4659} 4660 4661static int 4662pc98_check_i8251_interrupt(struct com_s *com) 4663{ 4664 return ( com->intr_enable & 0x07 ); 4665} 4666 4667static void 4668pc98_i8251_clear_cmd(struct com_s *com, int x) 4669{ 4670 int tmp; 4671 4672 COM_INT_DISABLE 4673 tmp = com->pc98_prev_siocmd & ~(x); 4674 outb(com->cmd_port, tmp); 4675 com->pc98_prev_siocmd = tmp & ~(CMD8251_ER|CMD8251_RESET|CMD8251_EH); 4676 COM_INT_ENABLE 4677} 4678 4679static void 4680pc98_i8251_or_cmd(struct com_s *com, int x) 4681{ 4682 int tmp; 4683 4684 COM_INT_DISABLE 4685 tmp = com->pc98_prev_siocmd | (x); 4686 outb(com->cmd_port, tmp); 4687 com->pc98_prev_siocmd = tmp & ~(CMD8251_ER|CMD8251_RESET|CMD8251_EH); 4688 COM_INT_ENABLE 4689} 4690 4691static void 4692pc98_i8251_set_cmd(struct com_s *com, int x) 4693{ 4694 int tmp; 4695 4696 COM_INT_DISABLE 4697 tmp = (x); 4698 outb(com->cmd_port, tmp); 4699 com->pc98_prev_siocmd = tmp & ~(CMD8251_ER|CMD8251_RESET|CMD8251_EH); 4700 COM_INT_ENABLE 4701} 4702 4703static void 4704pc98_i8251_clear_or_cmd(struct com_s *com, int clr, int x) 4705{ 4706 int tmp; 4707 COM_INT_DISABLE 4708 tmp = com->pc98_prev_siocmd & ~(clr); 4709 tmp |= (x); 4710 outb(com->cmd_port, tmp); 4711 com->pc98_prev_siocmd = tmp & ~(CMD8251_ER|CMD8251_RESET|CMD8251_EH); 4712 COM_INT_ENABLE 4713} 4714 4715static int 4716pc98_i8251_get_cmd(struct com_s *com) 4717{ 4718 return com->pc98_prev_siocmd; 4719} 4720 4721static int 4722pc98_i8251_get_mod(struct com_s *com) 4723{ 4724 return com->pc98_prev_siomod; 4725} 4726 4727static void 4728pc98_i8251_reset(struct com_s *com, int mode, int command) 4729{ 4730 outb(com->cmd_port, 0); /* dummy */ 4731 DELAY(2); 4732 outb(com->cmd_port, 0); /* dummy */ 4733 DELAY(2); 4734 outb(com->cmd_port, 0); /* dummy */ 4735 DELAY(2); 4736 outb(com->cmd_port, CMD8251_RESET); /* internal reset */ 4737 DELAY(2); 4738 outb(com->cmd_port, mode ); /* mode register */ 4739 com->pc98_prev_siomod = mode; 4740 DELAY(2); 4741 pc98_i8251_set_cmd( com, (command|CMD8251_ER) ); 4742} 4743 4744static void 4745pc98_check_sysclock(void) 4746{ 4747 /* get system clock from port */ 4748 if ( pc98_machine_type & M_8M ) { 4749 /* 8 MHz system & H98 */ 4750 sysclock = 8; 4751 } else { 4752 /* 5 MHz system */ 4753 sysclock = 5; 4754 } 4755} 4756 4757static void 4758com_cflag_and_speed_set( struct com_s *com, int cflag, int speed) 4759{ 4760 int cfcr=0, count; 4761 int previnterrupt; 4762 4763 count = pc98_ttspeedtab( com, speed ); 4764 if ( count < 0 ) return; 4765 4766 previnterrupt = pc98_check_i8251_interrupt(com); 4767 pc98_disable_i8251_interrupt( com, IEN_Tx|IEN_TxEMP|IEN_Rx ); 4768 4769 switch ( cflag&CSIZE ) { 4770 case CS5: 4771 cfcr = MOD8251_5BITS; break; 4772 case CS6: 4773 cfcr = MOD8251_6BITS; break; 4774 case CS7: 4775 cfcr = MOD8251_7BITS; break; 4776 case CS8: 4777 cfcr = MOD8251_8BITS; break; 4778 } 4779 if ( cflag&PARENB ) { 4780 if ( cflag&PARODD ) 4781 cfcr |= MOD8251_PODD; 4782 else 4783 cfcr |= MOD8251_PEVEN; 4784 } else 4785 cfcr |= MOD8251_PDISAB; 4786 4787 if ( cflag&CSTOPB ) 4788 cfcr |= MOD8251_STOP2; 4789 else 4790 cfcr |= MOD8251_STOP1; 4791 4792 if ( count & 0x10000 ) 4793 cfcr |= MOD8251_CLKX1; 4794 else 4795 cfcr |= MOD8251_CLKX16; 4796 4797 if (epson_machine_id != 0x20) { /* XXX */ 4798 int tmp; 4799 while (!((tmp = inb(com->sts_port)) & STS8251_TxEMP)) 4800 ; 4801 } 4802 /* set baud rate from ospeed */ 4803 pc98_set_baud_rate( com, count ); 4804 4805 if ( cfcr != pc98_i8251_get_mod(com) ) 4806 pc98_i8251_reset(com, cfcr, pc98_i8251_get_cmd(com) ); 4807 4808 pc98_enable_i8251_interrupt( com, previnterrupt ); 4809} 4810 4811static int 4812pc98_ttspeedtab(struct com_s *com, int speed) 4813{ 4814 int if_type, effect_sp, count = -1, mod; 4815 4816 if_type = com->pc98_if_type & 0x0f; 4817 4818 switch (com->pc98_if_type) { 4819 case COM_IF_INTERNAL: 4820 if (PC98SIO_baud_rate_port(if_type) != -1) { 4821 count = ttspeedtab(speed, if_8251_type[if_type].speedtab); 4822 if (count > 0) { 4823 count |= COM1_EXT_CLOCK; 4824 break; 4825 } 4826 } 4827 4828 /* for *1CLK asynchronous! mode, TEFUTEFU */ 4829 mod = (sysclock == 5) ? 2457600 : 1996800; 4830 effect_sp = ttspeedtab( speed, pc98speedtab ); 4831 if ( effect_sp < 0 ) /* XXX */ 4832 effect_sp = ttspeedtab( (speed - 1), pc98speedtab ); 4833 if ( effect_sp <= 0 ) 4834 return effect_sp; 4835 if ( effect_sp == speed ) 4836 mod /= 16; 4837 if ( mod % effect_sp ) 4838 return(-1); 4839 count = mod / effect_sp; 4840 if ( count > 65535 ) 4841 return(-1); 4842 if ( effect_sp != speed ) 4843 count |= 0x10000; 4844 break; 4845 case COM_IF_PC9861K_1: 4846 case COM_IF_PC9861K_2: 4847 count = 1; 4848 break; 4849 case COM_IF_IND_SS_1: 4850 case COM_IF_IND_SS_2: 4851 case COM_IF_PIO9032B_1: 4852 case COM_IF_PIO9032B_2: 4853 if ( speed == 0 ) return 0; 4854 count = ttspeedtab( speed, if_8251_type[if_type].speedtab ); 4855 break; 4856 case COM_IF_B98_01_1: 4857 case COM_IF_B98_01_2: 4858 if ( speed == 0 ) return 0; 4859 count = ttspeedtab( speed, if_8251_type[if_type].speedtab ); 4860#ifdef B98_01_OLD 4861 if (count == 0 || count == 1) { 4862 count += 4; 4863 count |= 0x20000; /* x1 mode for 76800 and 153600 */ 4864 } 4865#endif 4866 break; 4867 } 4868 4869 return count; 4870} 4871 4872static void 4873pc98_set_baud_rate( struct com_s *com, int count ) 4874{ 4875 int if_type, io, s; 4876 4877 if_type = com->pc98_if_type & 0x0f; 4878 io = com->iobase & 0xff00; 4879 4880 switch (com->pc98_if_type) { 4881 case COM_IF_INTERNAL: 4882 if (PC98SIO_baud_rate_port(if_type) != -1) { 4883 if (count & COM1_EXT_CLOCK) { 4884 outb((Port_t)PC98SIO_baud_rate_port(if_type), count & 0xff); 4885 break; 4886 } else { 4887 outb((Port_t)PC98SIO_baud_rate_port(if_type), 0x09); 4888 } 4889 } 4890 4891 if ( count < 0 ) { 4892 printf( "[ Illegal count : %d ]", count ); 4893 return; 4894 } else if ( count == 0 ) 4895 return; 4896 /* set i8253 */ 4897 s = splclock(); 4898 if (count != 3) 4899 outb( 0x77, 0xb6 ); 4900 else 4901 outb( 0x77, 0xb4 ); 4902 outb( 0x5f, 0); 4903 outb( 0x75, count & 0xff ); 4904 outb( 0x5f, 0); 4905 outb( 0x75, (count >> 8) & 0xff ); 4906 splx(s); 4907 break; 4908 case COM_IF_IND_SS_1: 4909 case COM_IF_IND_SS_2: 4910 outb(io | PC98SIO_intr_ctrl_port(if_type), 0); 4911 outb(io | PC98SIO_baud_rate_port(if_type), 0); 4912 outb(io | PC98SIO_baud_rate_port(if_type), 0xc0); 4913 outb(io | PC98SIO_baud_rate_port(if_type), (count >> 8) | 0x80); 4914 outb(io | PC98SIO_baud_rate_port(if_type), count & 0xff); 4915 break; 4916 case COM_IF_PIO9032B_1: 4917 case COM_IF_PIO9032B_2: 4918 outb(io | PC98SIO_baud_rate_port(if_type), count); 4919 break; 4920 case COM_IF_B98_01_1: 4921 case COM_IF_B98_01_2: 4922 outb(io | PC98SIO_baud_rate_port(if_type), count & 0x0f); 4923#ifdef B98_01_OLD 4924 /* 4925 * Some old B98_01 board should be controlled 4926 * in different way, but this hasn't been tested yet. 4927 */ 4928 outb(io | PC98SIO_func_port(if_type), 4929 (count & 0x20000) ? 0xf0 : 0xf2); 4930#endif 4931 break; 4932 } 4933} 4934static int 4935pc98_check_if_type(device_t dev, struct siodev *iod) 4936{ 4937 int irr, io, if_type, tmp; 4938 static short irq_tab[2][8] = { 4939 { 3, 5, 6, 9, 10, 12, 13, -1}, 4940 { 3, 10, 12, 13, 5, 6, 9, -1} 4941 }; 4942 4943 iod->if_type = if_type = (isa_get_flags(dev) >> 24) & 0xff; 4944 if ((if_type < 0 || if_type > COM_IF_END1) && 4945 (if_type < 0x10 || if_type > COM_IF_END2)) 4946 return(-1); 4947 if_type &= 0x0f; 4948 iod->irq = 0; 4949 io = isa_get_port(dev) & 0xff00; 4950 4951 if (IS_8251(iod->if_type)) { 4952 if (PC98SIO_func_port(if_type) != -1) { 4953 outb(io | PC98SIO_func_port(if_type), 0xf2); 4954 tmp = ttspeedtab(9600, if_8251_type[if_type].speedtab); 4955 if (tmp != -1 && PC98SIO_baud_rate_port(if_type) != -1) 4956 outb(io | PC98SIO_baud_rate_port(if_type), tmp); 4957 } 4958 4959 iod->cmd = io | PC98SIO_cmd_port(if_type); 4960 iod->sts = io | PC98SIO_sts_port(if_type); 4961 iod->mod = io | PC98SIO_in_modem_port(if_type); 4962 iod->ctrl = io | PC98SIO_intr_ctrl_port(if_type); 4963 4964 if (iod->if_type == COM_IF_INTERNAL) { 4965 iod->irq = 4; 4966 4967 /* XXX check new internal port. */ 4968 outb(0x138, 0); 4969 DELAY(10); 4970 for (tmp = 0; tmp < 100; tmp++) { 4971 if ((inb(0x138) & 1) == 0) { 4972 PC98SIO_baud_rate_port(if_type) = 0x13a; 4973 if_8251_type[if_type].name = " (internal fast)"; 4974 if_8251_type[if_type].speedtab = pc98fast_speedtab; 4975 break; 4976 } 4977 DELAY(1); 4978 } 4979 } else { 4980 tmp = inb( iod->mod ) & if_8251_type[if_type].irr_mask; 4981 if ((isa_get_port(dev) & 0xff) == IO_COM2) 4982 iod->irq = irq_tab[0][tmp]; 4983 else 4984 iod->irq = irq_tab[1][tmp]; 4985 } 4986 } else { 4987 irr = if_16550a_type[if_type].irr_read; 4988#ifdef COM_MULTIPORT 4989 if (!COM_ISMULTIPORT(isa_get_flags(dev)) || 4990 device_get_unit(dev) == COM_MPMASTER(isa_get_flags(dev))) 4991#endif 4992 if (irr != -1) { 4993 tmp = inb(io | irr); 4994 if (isa_get_port(dev) & 0x01) /* XXX depend on RSB-384 */ 4995 iod->irq = irq_tab[1][tmp >> 3]; 4996 else 4997 iod->irq = irq_tab[0][tmp & 0x07]; 4998 } 4999 } 5000 if ( iod->irq == -1 ) return -1; 5001 5002 return 0; 5003} 5004static int 5005pc98_set_ioport( struct com_s *com, int id_flags ) 5006{ 5007 int io, if_type; 5008 5009 if_type = (id_flags >> 24) & 0xff; 5010 if (IS_8251(if_type)) { 5011 pc98_check_sysclock(); 5012 io = com->iobase & 0xff00; 5013 com->pc98_if_type = if_type; 5014 if_type &= 0x0f; 5015 com->data_port = io | PC98SIO_data_port(if_type); 5016 com->cmd_port = io | PC98SIO_cmd_port(if_type); 5017 com->sts_port = io | PC98SIO_sts_port(if_type); 5018 com->in_modem_port = io | PC98SIO_in_modem_port(if_type); 5019 com->intr_ctrl_port = io | PC98SIO_intr_ctrl_port(if_type); 5020 return 0; 5021 } 5022 5023 return -1; 5024} 5025#endif /* PC98 defined */ 5026