sio.c revision 36762
11541Srgrimes/*- 21541Srgrimes * Copyright (c) 1991 The Regents of the University of California. 31541Srgrimes * All rights reserved. 45455Sdg * 55455Sdg * Redistribution and use in source and binary forms, with or without 61541Srgrimes * modification, are permitted provided that the following conditions 71541Srgrimes * are met: 81541Srgrimes * 1. Redistributions of source code must retain the above copyright 91541Srgrimes * notice, this list of conditions and the following disclaimer. 101541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111541Srgrimes * notice, this list of conditions and the following disclaimer in the 121541Srgrimes * documentation and/or other materials provided with the distribution. 131541Srgrimes * 3. All advertising materials mentioning features or use of this software 141541Srgrimes * must display the following acknowledgement: 151541Srgrimes * This product includes software developed by the University of 161541Srgrimes * California, Berkeley and its contributors. 171541Srgrimes * 4. Neither the name of the University nor the names of its contributors 181541Srgrimes * may be used to endorse or promote products derived from this software 191541Srgrimes * without specific prior written permission. 201541Srgrimes * 211541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311541Srgrimes * SUCH DAMAGE. 321541Srgrimes * 331541Srgrimes * from: @(#)com.c 7.5 (Berkeley) 5/16/91 341541Srgrimes * $Id: sio.c,v 1.59 1998/06/05 08:31:01 kato Exp $ 351541Srgrimes */ 367164Sdg 371541Srgrimes#include "opt_comconsole.h" 381541Srgrimes#include "opt_compat.h" 391541Srgrimes#include "opt_ddb.h" 401549Srgrimes#include "opt_devfs.h" 411541Srgrimes#include "opt_sio.h" 421541Srgrimes#include "sio.h" 431541Srgrimes#include "pnp.h" 441541Srgrimes 451541Srgrimes#ifndef EXTRA_SIO 461541Srgrimes#if NPNP > 0 475455Sdg#define EXTRA_SIO 2 485455Sdg#else 496621Sdg#define EXTRA_SIO 0 506621Sdg#endif 511541Srgrimes#endif 521541Srgrimes 531541Srgrimes#define NSIOTOT (NSIO + EXTRA_SIO) 541541Srgrimes 553055Sdg/* 565455Sdg * Serial driver, based on 386BSD-0.1 com driver. 575455Sdg * Mostly rewritten to use pseudo-DMA. 581541Srgrimes * Works for National Semiconductor NS8250-NS16550AF UARTs. 591541Srgrimes * COM driver, based on HP dca driver. 603055Sdg * 611541Srgrimes * Changes for PC-Card integration: 621541Srgrimes * - Added PC-Card driver table and handlers 631541Srgrimes */ 641541Srgrimes/*=============================================================== 651541Srgrimes * 386BSD(98),FreeBSD-1.1x(98) com driver. 661541Srgrimes * ----- 675455Sdg * modified for PC9801 by M.Ishii 681541Srgrimes * Kyoto University Microcomputer Club (KMC) 691541Srgrimes * Chou "TEFUTEFU" Hirotomi 705455Sdg * Kyoto Univ. the faculty of medicine 715455Sdg *=============================================================== 725455Sdg * FreeBSD-2.0.1(98) sio driver. 731541Srgrimes * ----- 741541Srgrimes * modified for pc98 Internal i8251 and MICRO CORE MC16550II 751541Srgrimes * T.Koike(hfc01340@niftyserve.or.jp) 761541Srgrimes * implement kernel device configuration 771541Srgrimes * aizu@orient.center.nitech.ac.jp 781541Srgrimes * 791541Srgrimes * Notes. 801541Srgrimes * ----- 811541Srgrimes * PC98 localization based on 386BSD(98) com driver. Using its PC98 local 821541Srgrimes * functions. 831541Srgrimes * This driver is under debugging,has bugs. 841541Srgrimes * 851541Srgrimes * 1) config 865455Sdg * options COM_MULTIPORT #if using MC16550II 875455Sdg * device sio0 at nec? port 0x30 tty irq 4 vector siointr #internal 881541Srgrimes * device sio1 at nec? port 0xd2 tty irq 5 flags 0x101 vector siointr #mc1 891541Srgrimes * device sio2 at nec? port 0x8d2 tty flags 0x101 vector siointr #mc2 901541Srgrimes * # ~~~~~iobase ~~multi port flag 911541Srgrimes * # ~ master device is sio1 921541Srgrimes * 2) device 935839Sdg * cd /dev; MAKEDEV ttyd0 ttyd1 .. 941541Srgrimes * 3) /etc/rc.serial 951541Srgrimes * 57600bps is too fast for sio0(internal8251) 961541Srgrimes * my ex. 971541Srgrimes * #set default speed 9600 981541Srgrimes * modem() 991541Srgrimes * : 1001541Srgrimes * stty </dev/ttyid$i crtscts 9600 1011541Srgrimes * : # ~~~~ default speed(can change after init.) 1021541Srgrimes * modem 0 1 2 1031541Srgrimes * 4) COMCONSOLE 1041541Srgrimes * not changed. 1051549Srgrimes * 5) PC9861K,PIO9032B,B98_01 1061541Srgrimes * not tested. 1071541Srgrimes */ 1081541Srgrimes/* 1091541Srgrimes * modified for AIWA B98-01 1101541Srgrimes * by T.Hatanou <hatanou@yasuda.comm.waseda.ac.jp> last update: 15 Sep.1995 1111541Srgrimes * 1121541Srgrimes * How to configure... 1131541Srgrimes * # options COM_MULTIPORT # support for MICROCORE MC16550II 1141541Srgrimes * ... comment-out this line, which will conflict with B98_01. 1155455Sdg * options "B98_01" # support for AIWA B98-01 1161541Srgrimes * device sio1 at nec? port 0x00d1 tty irq ? vector siointr 1171541Srgrimes * device sio2 at nec? port 0x00d5 tty irq ? vector siointr 1181541Srgrimes * ... you can leave these lines `irq ?', irq will be autodetected. 1195455Sdg */ 1201541Srgrimes#ifdef PC98 1215455Sdg#define MC16550 0 1225455Sdg#define COM_IF_INTERNAL 1 1235455Sdg#if 0 1241541Srgrimes#define COM_IF_PC9861K 2 1255455Sdg#define COM_IF_PIO9032B 3 1265455Sdg#endif 1275455Sdg#ifdef B98_01 1285455Sdg#undef COM_MULTIPORT /* COM_MULTIPORT will conflict with B98_01 */ 1295455Sdg#define COM_IF_B98_01 4 1301541Srgrimes#endif /* B98_01 */ 1315455Sdg#endif /* PC98 */ 1325455Sdg 1335455Sdg#include <sys/param.h> 1346621Sdg#include <sys/systm.h> 1355455Sdg#include <sys/reboot.h> 1365455Sdg#include <sys/malloc.h> 1376621Sdg#include <sys/tty.h> 1385839Sdg#include <sys/proc.h> 1395839Sdg#include <sys/conf.h> 1406621Sdg#include <sys/dkstat.h> 1415839Sdg#include <sys/fcntl.h> 1426621Sdg#include <sys/kernel.h> 1435839Sdg#include <sys/syslog.h> 1445455Sdg#include <sys/sysctl.h> 1455455Sdg#ifdef DEVFS 1461541Srgrimes#include <sys/devfsext.h> 1475455Sdg#endif 1485455Sdg 1491541Srgrimes#include <machine/clock.h> 1501541Srgrimes 1515455Sdg#ifdef PC98 1525455Sdg#include <pc98/pc98/pc98.h> 1531541Srgrimes#include <pc98/pc98/pc98_machdep.h> 1541541Srgrimes#include <i386/isa/icu.h> 1555455Sdg#include <i386/isa/isa_device.h> 1561541Srgrimes#include <pc98/pc98/sioreg.h> 1575455Sdg#include <i386/isa/ic/i8251.h> 1585455Sdg#else 1595455Sdg#include <i386/isa/isa.h> 1605455Sdg#include <i386/isa/isa_device.h> 1615455Sdg#include <i386/isa/sioreg.h> 1625455Sdg#endif 1635455Sdg#include <i386/isa/intr_machdep.h> 1645455Sdg 1655455Sdg#ifdef COM_ESP 1665455Sdg#include <i386/isa/ic/esp.h> 1675455Sdg#endif 1685455Sdg#include <i386/isa/ic/ns16550.h> 1695455Sdg 1705455Sdg#include "card.h" 1711541Srgrimes#if NCARD > 0 1725455Sdg#include <pccard/cardinfo.h> 1735455Sdg#include <pccard/slot.h> 1745455Sdg#endif 1755455Sdg 1761541Srgrimes#if NPNP > 0 1775455Sdg#include <i386/isa/pnp.h> 1785455Sdg#endif 1795455Sdg 1805455Sdg#ifdef SMP 1815455Sdg#define disable_intr() COM_DISABLE_INTR() 1825455Sdg#define enable_intr() COM_ENABLE_INTR() 1835455Sdg#endif /* SMP */ 1845455Sdg 1855455Sdg#define LOTS_OF_EVENTS 64 /* helps separate urgent events from input */ 1866621Sdg#define RB_I_HIGH_WATER (TTYHOG - 2 * RS_IBUFSIZE) 1876621Sdg#define RS_IBUFSIZE 256 1886621Sdg 1895455Sdg#define CALLOUT_MASK 0x80 1906621Sdg#define CONTROL_MASK 0x60 1915455Sdg#define CONTROL_INIT_STATE 0x20 1925455Sdg#define CONTROL_LOCK_STATE 0x40 1935455Sdg#define DEV_TO_UNIT(dev) (MINOR_TO_UNIT(minor(dev))) 1945455Sdg#define MINOR_MAGIC_MASK (CALLOUT_MASK | CONTROL_MASK) 1956621Sdg#define MINOR_TO_UNIT(mynor) ((mynor) & ~MINOR_MAGIC_MASK) 1966621Sdg 1975455Sdg#ifdef COM_MULTIPORT 1981541Srgrimes/* checks in flags for multiport and which is multiport "master chip" 1995455Sdg * for a given card 2005455Sdg */ 2015455Sdg#define COM_ISMULTIPORT(dev) ((dev)->id_flags & 0x01) 2025455Sdg#define COM_MPMASTER(dev) (((dev)->id_flags >> 8) & 0x0ff) 2035455Sdg#define COM_NOTAST4(dev) ((dev)->id_flags & 0x04) 2045455Sdg#endif /* COM_MULTIPORT */ 2055455Sdg 2065455Sdg#define COM_CONSOLE(dev) ((dev)->id_flags & 0x10) 2075455Sdg#define COM_FORCECONSOLE(dev) ((dev)->id_flags & 0x20) 2085839Sdg#define COM_LLCONSOLE(dev) ((dev)->id_flags & 0x40) 2095839Sdg#define COM_LOSESOUTINTS(dev) ((dev)->id_flags & 0x08) 2105455Sdg#define COM_NOFIFO(dev) ((dev)->id_flags & 0x02) 2115455Sdg#define COM_ST16650A(dev) ((dev)->id_flags & 0x20000) 2121541Srgrimes#define COM_C_NOPROBE (0x40000) 2136621Sdg#define COM_NOPROBE(dev) ((dev)->id_flags & COM_C_NOPROBE) 2141541Srgrimes#define COM_C_IIR_TXRDYBUG (0x80000) 2155455Sdg#define COM_IIR_TXRDYBUG(dev) ((dev)->id_flags & COM_C_IIR_TXRDYBUG) 2161541Srgrimes#define COM_FIFOSIZE(dev) (((dev)->id_flags & 0xff000000) >> 24) 2175455Sdg 2185455Sdg#ifndef PC98 2191541Srgrimes#define com_scr 7 /* scratch register for 16450-16550 (R/W) */ 2201541Srgrimes#endif /* !PC98 */ 2211541Srgrimes 2225839Sdg/* 2235455Sdg * Input buffer watermarks. 2245455Sdg * The external device is asked to stop sending when the buffer exactly reaches 2255455Sdg * high water, or when the high level requests it. 2265455Sdg * The high level is notified immediately (rather than at a later clock tick) 2275455Sdg * when this watermark is reached. 2281541Srgrimes * The buffer size is chosen so the watermark should almost never be reached. 2291541Srgrimes * The low watermark is invisibly 0 since the buffer is always emptied all at 2305455Sdg * once. 2315455Sdg */ 2321541Srgrimes#define RS_IHIGHWATER (3 * RS_IBUFSIZE / 4) 2335455Sdg 2345455Sdg/* 2355455Sdg * com state bits. 2365455Sdg * (CS_BUSY | CS_TTGO) and (CS_BUSY | CS_TTGO | CS_ODEVREADY) must be higher 2375455Sdg * than the other bits so that they can be tested as a group without masking 2385455Sdg * off the low bits. 2395455Sdg * 2405455Sdg * The following com and tty flags correspond closely: 2415455Sdg * CS_BUSY = TS_BUSY (maintained by comstart(), siopoll() and 2425455Sdg * siostop()) 2436621Sdg * CS_TTGO = ~TS_TTSTOP (maintained by comparam() and comstart()) 2445455Sdg * CS_CTS_OFLOW = CCTS_OFLOW (maintained by comparam()) 2451541Srgrimes * CS_RTS_IFLOW = CRTS_IFLOW (maintained by comparam()) 2461541Srgrimes * TS_FLUSH is not used. 2475455Sdg * XXX I think TIOCSETA doesn't clear TS_TTSTOP when it clears IXON. 2485455Sdg * XXX CS_*FLOW should be CF_*FLOW in com->flags (control flags not state). 2491541Srgrimes */ 2505455Sdg#define CS_BUSY 0x80 /* output in progress */ 2515455Sdg#define CS_TTGO 0x40 /* output not stopped by XOFF */ 2525455Sdg#define CS_ODEVREADY 0x20 /* external device h/w ready (CTS) */ 2535455Sdg#define CS_CHECKMSR 1 /* check of MSR scheduled */ 2545455Sdg#define CS_CTS_OFLOW 2 /* use CTS output flow control */ 2555839Sdg#define CS_DTR_OFF 0x10 /* DTR held off */ 2565455Sdg#define CS_ODONE 4 /* output completed */ 2575455Sdg#define CS_RTS_IFLOW 8 /* use RTS input flow control */ 2581541Srgrimes#define CSE_BUSYCHECK 1 /* siobusycheck() scheduled */ 2591541Srgrimes 2601541Srgrimesstatic char const * const error_desc[] = { 2611541Srgrimes#define CE_OVERRUN 0 2621541Srgrimes "silo overflow", 2631541Srgrimes#define CE_INTERRUPT_BUF_OVERFLOW 1 2641541Srgrimes "interrupt-level buffer overflow", 2651541Srgrimes#define CE_TTY_BUF_OVERFLOW 2 2661541Srgrimes "tty-level buffer overflow", 2671541Srgrimes}; 2681541Srgrimes 2691541Srgrimes#define CE_NTYPES 3 2701541Srgrimes#define CE_RECORD(com, errnum) (++(com)->delta_error_counts[errnum]) 2711541Srgrimes 2721541Srgrimes/* types. XXX - should be elsewhere */ 2731541Srgrimestypedef u_int Port_t; /* hardware port */ 2741541Srgrimestypedef u_char bool_t; /* boolean */ 2751541Srgrimes 2761541Srgrimes/* queue of linear buffers */ 2771541Srgrimesstruct lbq { 2781541Srgrimes u_char *l_head; /* next char to process */ 2795455Sdg u_char *l_tail; /* one past the last char to process */ 2801541Srgrimes struct lbq *l_next; /* next in queue */ 2811541Srgrimes bool_t l_queued; /* nonzero if queued */ 2821541Srgrimes}; 2831541Srgrimes 2845455Sdg/* com device structure */ 2851541Srgrimesstruct com_s { 2861541Srgrimes u_int id_flags; /* Copy isa device falgas */ 2871541Srgrimes u_char state; /* miscellaneous flag bits */ 2881541Srgrimes bool_t active_out; /* nonzero if the callout device is open */ 2891541Srgrimes u_char cfcr_image; /* copy of value written to CFCR */ 2901541Srgrimes#ifdef COM_ESP 2911541Srgrimes bool_t esp; /* is this unit a hayes esp board? */ 2921541Srgrimes#endif 2931541Srgrimes u_char extra_state; /* more flag bits, separate for order trick */ 2945455Sdg u_char fifo_image; /* copy of value written to FIFO */ 2951541Srgrimes bool_t hasfifo; /* nonzero for 16550 UARTs */ 2965455Sdg bool_t st16650a; /* Is a Startech 16650A or RTS/CTS compat */ 2975455Sdg bool_t loses_outints; /* nonzero if device loses output interrupts */ 2985455Sdg u_char mcr_image; /* copy of value written to MCR */ 2995455Sdg#ifdef COM_MULTIPORT 3005455Sdg bool_t multiport; /* is this unit part of a multiport device? */ 3015455Sdg#endif /* COM_MULTIPORT */ 3025455Sdg bool_t no_irq; /* nonzero if irq is not attached */ 3035455Sdg bool_t gone; /* hardware disappeared */ 3045455Sdg bool_t poll; /* nonzero if polling is required */ 3055455Sdg bool_t poll_output; /* nonzero if polling for output is required */ 3065455Sdg int unit; /* unit number */ 3075455Sdg int dtr_wait; /* time to hold DTR down on close (* 1/hz) */ 3085455Sdg u_int tx_fifo_size; 3095455Sdg u_int wopeners; /* # processes waiting for DCD in open() */ 3105455Sdg 3111541Srgrimes /* 3125142Sdg * The high level of the driver never reads status registers directly 3131541Srgrimes * because there would be too many side effects to handle conveniently. 3141541Srgrimes * Instead, it reads copies of the registers stored here by the 3155455Sdg * interrupt handler. 3165455Sdg */ 3171541Srgrimes u_char last_modem_status; /* last MSR read by intr handler */ 3185455Sdg u_char prev_modem_status; /* last MSR handled by high level */ 3195455Sdg 3205455Sdg u_char hotchar; /* ldisc-specific char to be handled ASAP */ 3215455Sdg u_char *ibuf; /* start of input buffer */ 3225455Sdg u_char *ibufend; /* end of input buffer */ 3235455Sdg u_char *ihighwater; /* threshold in input buffer */ 3245455Sdg u_char *iptr; /* next free spot in input buffer */ 3251541Srgrimes 3265455Sdg struct lbq obufq; /* head of queue of output buffers */ 3275455Sdg struct lbq obufs[2]; /* output buffers */ 3285455Sdg 3295455Sdg#ifdef PC98 3305455Sdg Port_t cmd_port; 3315455Sdg Port_t sts_port; 3325455Sdg Port_t in_modem_port; 3335455Sdg Port_t intr_ctrl_port; 3345455Sdg int intr_enable; 3355455Sdg int pc98_prev_modem_status; 3365455Sdg int pc98_modem_delta; 3375455Sdg int modem_car_chg_timer; 3381541Srgrimes int pc98_prev_siocmd; 3391541Srgrimes int pc98_prev_siomod; 3405455Sdg int modem_checking; 3415455Sdg int pc98_if_type; 3425455Sdg#endif /* PC98 */ 3431541Srgrimes Port_t data_port; /* i/o ports */ 3445455Sdg#ifdef COM_ESP 3455455Sdg Port_t esp_port; 3465455Sdg#endif 3471541Srgrimes Port_t int_id_port; 3486621Sdg Port_t iobase; 3495455Sdg Port_t modem_ctl_port; 3501541Srgrimes Port_t line_status_port; 3511541Srgrimes Port_t modem_status_port; 3521541Srgrimes Port_t intr_ctl_port; /* Ports of IIR register */ 3531541Srgrimes 3541541Srgrimes struct tty *tp; /* cross reference */ 3551541Srgrimes 3561541Srgrimes /* Initial state. */ 3571541Srgrimes struct termios it_in; /* should be in struct tty */ 3581541Srgrimes struct termios it_out; 3591541Srgrimes 3601541Srgrimes /* Lock state. */ 3611541Srgrimes struct termios lt_in; /* should be in struct tty */ 3621541Srgrimes struct termios lt_out; 3631541Srgrimes 3641541Srgrimes bool_t do_timestamp; 3651541Srgrimes bool_t do_dcd_timestamp; 3661541Srgrimes struct timeval timestamp; 3671541Srgrimes struct timeval dcd_timestamp; 3681541Srgrimes 3691541Srgrimes u_long bytes_in; /* statistics */ 3701541Srgrimes u_long bytes_out; 3711541Srgrimes u_int delta_error_counts[CE_NTYPES]; 3721541Srgrimes u_long error_counts[CE_NTYPES]; 3735455Sdg 3746621Sdg /* 3751541Srgrimes * Ping-pong input buffers. The extra factor of 2 in the sizes is 3761541Srgrimes * to allow for an error byte for each input byte. 3771541Srgrimes */ 3781541Srgrimes#define CE_INPUT_OFFSET RS_IBUFSIZE 3791541Srgrimes u_char ibuf1[2 * RS_IBUFSIZE]; 3801541Srgrimes u_char ibuf2[2 * RS_IBUFSIZE]; 3811541Srgrimes 3821541Srgrimes /* 3831541Srgrimes * Data area for output buffers. Someday we should build the output 3841541Srgrimes * buffer queue without copying data. 3851541Srgrimes */ 3861541Srgrimes u_char obuf1[256]; 3871541Srgrimes u_char obuf2[256]; 3885455Sdg#ifdef DEVFS 3891541Srgrimes void *devfs_token_ttyd; 3901541Srgrimes void *devfs_token_ttyl; 3911541Srgrimes void *devfs_token_ttyi; 3921541Srgrimes void *devfs_token_cuaa; 3931541Srgrimes void *devfs_token_cual; 3941541Srgrimes void *devfs_token_cuai; 3951541Srgrimes#endif 3961541Srgrimes}; 3971541Srgrimes 3981541Srgrimes/* 3991541Srgrimes * XXX public functions in drivers should be declared in headers produced 4001541Srgrimes * by `config', not here. 4011541Srgrimes */ 4021541Srgrimes 4035455Sdg/* Interrupt handling entry point. */ 4041541Srgrimesvoid siopoll __P((void)); 4051541Srgrimes 4065455Sdg/* Device switch entry points. */ 4075455Sdg#define sioreset noreset 4085455Sdg#define siommap nommap 4095455Sdg#define siostrategy nostrategy 4101541Srgrimes 4115455Sdg#ifdef COM_ESP 4125455Sdgstatic int espattach __P((struct isa_device *isdp, struct com_s *com, 4135455Sdg Port_t esp_port)); 4141541Srgrimes#endif 4151541Srgrimesstatic int sioattach __P((struct isa_device *dev)); 4161541Srgrimesstatic timeout_t siobusycheck; 4171541Srgrimesstatic timeout_t siodtrwakeup; 4181541Srgrimesstatic void comhardclose __P((struct com_s *com)); 4195455Sdgstatic void siointr1 __P((struct com_s *com)); 4205455Sdgstatic int commctl __P((struct com_s *com, int bits, int how)); 4215839Sdgstatic int comparam __P((struct tty *tp, struct termios *t)); 4221541Srgrimesstatic int sioprobe __P((struct isa_device *dev)); 4231541Srgrimesstatic void siosettimeout __P((void)); 4241541Srgrimesstatic void comstart __P((struct tty *tp)); 4255455Sdgstatic timeout_t comwakeup; 4261541Srgrimesstatic void disc_optim __P((struct tty *tp, struct termios *t, 4275455Sdg struct com_s *com)); 4285455Sdg 4295455Sdg#ifdef DSI_SOFT_MODEM 4305455Sdgstatic int LoadSoftModem __P((int unit,int base_io, u_long size, u_char *ptr)); 4311541Srgrimes#endif /* DSI_SOFT_MODEM */ 4321541Srgrimes 4335455Sdgstatic char driver_name[] = "sio"; 4345455Sdg 4351541Srgrimes/* table and macro for fast conversion from a unit number to its com struct */ 4361541Srgrimesstatic struct com_s *p_com_addr[NSIOTOT]; 4375455Sdg#define com_addr(unit) (p_com_addr[unit]) 4385455Sdg 4395455Sdgstruct isa_driver siodriver = { 4401541Srgrimes sioprobe, sioattach, driver_name 4415455Sdg}; 4421541Srgrimes 4435455Sdgstatic d_open_t sioopen; 4441541Srgrimesstatic d_close_t sioclose; 4451541Srgrimesstatic d_read_t sioread; 4461541Srgrimesstatic d_write_t siowrite; 4471541Srgrimesstatic d_ioctl_t sioioctl; 4481541Srgrimesstatic d_stop_t siostop; 4491541Srgrimesstatic d_devtotty_t siodevtotty; 4501541Srgrimes 4515455Sdg#define CDEV_MAJOR 28 4525455Sdgstatic struct cdevsw sio_cdevsw = { 4531541Srgrimes sioopen, sioclose, sioread, siowrite, 4545455Sdg sioioctl, siostop, noreset, siodevtotty, 4555455Sdg ttpoll, nommap, NULL, driver_name, 4561541Srgrimes NULL, -1, 4575455Sdg}; 4581541Srgrimes 4591541Srgrimesstatic int comconsole = -1; 4601541Srgrimesstatic volatile speed_t comdefaultrate = CONSPEED; 4611541Srgrimesstatic u_int com_events; /* input chars + weighted output completions */ 4621541Srgrimesstatic Port_t siocniobase; 4631541Srgrimesstatic int sio_timeout; 4641541Srgrimesstatic int sio_timeouts_until_log; 4651541Srgrimesstatic struct callout_handle sio_timeout_handle 4661541Srgrimes = CALLOUT_HANDLE_INITIALIZER(&sio_timeout_handle); 4671541Srgrimes#if 0 /* XXX */ 4681541Srgrimesstatic struct tty *sio_tty[NSIOTOT]; 4695455Sdg#else 4701541Srgrimesstatic struct tty sio_tty[NSIOTOT]; 4711541Srgrimes#endif 4721541Srgrimesstatic const int nsio_tty = NSIOTOT; 4731541Srgrimes 4741541Srgrimes#ifdef PC98 4751541Srgrimesstruct siodev { 4761541Srgrimes short if_type; 4771541Srgrimes short irq; 4781541Srgrimes Port_t cmd, sts, ctrl, mod; 4791541Srgrimes }; 4801541Srgrimesstatic int sysclock; 4811541Srgrimesstatic short port_table[5][3] = { 4821541Srgrimes {0x30, 0xb1, 0xb9}, 4831541Srgrimes {0x32, 0xb3, 0xbb}, 4841541Srgrimes {0x32, 0xb3, 0xbb}, 4851541Srgrimes {0x33, 0xb0, 0xb2}, 4861541Srgrimes {0x35, 0xb0, 0xb2} 4871541Srgrimes }; 4881541Srgrimes#define PC98SIO_data_port(ch) port_table[0][ch] 4891541Srgrimes#define PC98SIO_cmd_port(ch) port_table[1][ch] 4905455Sdg#define PC98SIO_sts_port(ch) port_table[2][ch] 4911541Srgrimes#define PC98SIO_in_modem_port(ch) port_table[3][ch] 4921541Srgrimes#define PC98SIO_intr_ctrl_port(ch) port_table[4][ch] 4935839Sdg#ifdef COM_IF_PIO9032B 4945455Sdg#define IO_COM_PIO9032B_2 0x0b8 4955455Sdg#define IO_COM_PIO9032B_3 0x0ba 4961541Srgrimes#endif /* COM_IF_PIO9032B */ 4971541Srgrimes#ifdef COM_IF_B98_01 4981541Srgrimes#define IO_COM_B98_01_2 0x0d1 4991541Srgrimes#define IO_COM_B98_01_3 0x0d5 5005455Sdg#endif /* COM_IF_B98_01 */ 5011541Srgrimes#define COM_INT_DISABLE {int previpri; previpri=spltty(); 5021541Srgrimes#define COM_INT_ENABLE splx(previpri);} 5036837Sdg#define IEN_TxFLAG IEN_Tx 5046837Sdg 5056837Sdg#define COM_CARRIER_DETECT_EMULATE 0 5066837Sdg#define PC98_CHECK_MODEM_INTERVAL (hz/10) 5076837Sdg#define DCD_OFF_TOLERANCE 2 5086837Sdg#define DCD_ON_RECOGNITION 2 5091541Srgrimes#define IS_8251(type) (type != MC16550) 5107090Sbde#define IS_PC98IN(adr) (adr == 0x30) 5116837Sdg 5127164Sdgstatic void commint __P((dev_t dev)); 5137164Sdgstatic void com_tiocm_set __P((struct com_s *com, int msr)); 5147164Sdgstatic void com_tiocm_bis __P((struct com_s *com, int msr)); 5156837Sdgstatic void com_tiocm_bic __P((struct com_s *com, int msr)); 5166837Sdgstatic int com_tiocm_get __P((struct com_s *com)); 5176837Sdgstatic int com_tiocm_get_delta __P((struct com_s *com)); 5186837Sdgstatic void pc98_msrint_start __P((dev_t dev)); 5196837Sdgstatic void com_cflag_and_speed_set __P((struct com_s *com, int cflag, int speed)); 5206837Sdgstatic int pc98_ttspeedtab __P((struct com_s *com, int speed)); 5216837Sdgstatic int pc98_get_modem_status __P((struct com_s *com)); 5221541Srgrimesstatic timeout_t pc98_check_msr; 5236837Sdgstatic void pc98_set_baud_rate __P((struct com_s *com, int count)); 5246837Sdgstatic void pc98_i8251_reset __P((struct com_s *com, int mode, int command)); 5256837Sdgstatic void pc98_disable_i8251_interrupt __P((struct com_s *com, int mod)); 5266837Sdgstatic void pc98_enable_i8251_interrupt __P((struct com_s *com, int mod)); 5276837Sdgstatic int pc98_check_i8251_interrupt __P((struct com_s *com)); 5286837Sdgstatic int pc98_i8251_get_cmd __P((struct com_s *com)); 5296837Sdgstatic int pc98_i8251_get_mod __P((struct com_s *com)); 5306837Sdgstatic void pc98_i8251_set_cmd __P((struct com_s *com, int x)); 5317090Sbdestatic void pc98_i8251_or_cmd __P((struct com_s *com, int x)); 5327164Sdgstatic void pc98_i8251_clear_cmd __P((struct com_s *com, int x)); 5336837Sdgstatic void pc98_i8251_clear_or_cmd __P((struct com_s *com, int clr, int x)); 5346837Sdgstatic int pc98_check_if_type __P((int iobase, struct siodev *iod)); 5356837Sdgstatic void pc98_check_sysclock __P((void)); 5361541Srgrimesstatic int pc98_set_ioport __P((struct com_s *com, int io_base)); 5376837Sdg 5385455Sdg#define com_int_Tx_disable(com) \ 5395839Sdg pc98_disable_i8251_interrupt(com,IEN_Tx|IEN_TxEMP) 5401541Srgrimes#define com_int_Tx_enable(com) \ 5411541Srgrimes pc98_enable_i8251_interrupt(com,IEN_TxFLAG) 5425455Sdg#define com_int_Rx_disable(com) \ 5431541Srgrimes pc98_disable_i8251_interrupt(com,IEN_Rx) 5441541Srgrimes#define com_int_Rx_enable(com) \ 5451541Srgrimes pc98_enable_i8251_interrupt(com,IEN_Rx) 5465455Sdg#define com_int_TxRx_disable(com) \ 5475455Sdg pc98_disable_i8251_interrupt(com,IEN_Tx|IEN_TxEMP|IEN_Rx) 5485455Sdg#define com_int_TxRx_enable(com) \ 5495455Sdg pc98_enable_i8251_interrupt(com,IEN_TxFLAG|IEN_Rx) 5505455Sdg#define com_send_break_on(com) \ 5511541Srgrimes pc98_i8251_or_cmd(com,CMD8251_SBRK) 5525455Sdg#define com_send_break_off(com) \ 5535839Sdg pc98_i8251_clear_cmd(com,CMD8251_SBRK) 5541541Srgrimes 5551541Srgrimesstruct speedtab pc98speedtab[] = { /* internal RS232C interface */ 5565455Sdg 0, 0, 5571541Srgrimes 50, 50, 5581541Srgrimes 75, 75, 5595839Sdg 150, 150, 5605455Sdg 200, 200, 5611541Srgrimes 300, 300, 5621541Srgrimes 600, 600, 5635455Sdg 1200, 1200, 5645455Sdg 2400, 2400, 5655455Sdg 4800, 4800, 5665455Sdg 9600, 9600, 5675455Sdg 19200, 19200, 5681541Srgrimes 38400, 38400, 5695455Sdg 76800, 76800, 5705455Sdg 20800, 20800, 5715455Sdg 41600, 41600, 5725455Sdg 15600, 15600, 5735455Sdg 31200, 31200, 5745455Sdg 62400, 62400, 5751541Srgrimes -1, -1 5765455Sdg}; 5771541Srgrimes#ifdef COM_IF_PIO9032B 5785455Sdgstruct speedtab comspeedtab_pio9032b[] = { 5795455Sdg 300, 6, 5805455Sdg 600, 5, 5815455Sdg 1200, 4, 5825455Sdg 2400, 3, 5835455Sdg 4800, 2, 5845455Sdg 9600, 1, 5855455Sdg 19200, 0, 5865455Sdg 38400, 7, 5871541Srgrimes -1, -1 5881541Srgrimes}; 5895839Sdg#endif 5905455Sdg 5911541Srgrimes#ifdef COM_IF_B98_01 5926837Sdgstruct speedtab comspeedtab_b98_01[] = { 5936837Sdg 0, 0, 5946837Sdg 75, 15, 5955455Sdg 150, 14, 5965455Sdg 300, 13, 5975455Sdg 600, 12, 5985455Sdg 1200, 11, 5995455Sdg 2400, 10, 6005455Sdg 4800, 9, 6015839Sdg 9600, 8, 6025839Sdg 19200, 7, 6035455Sdg 38400, 6, 6045455Sdg 76800, 5, 6055455Sdg 153600, 4, 6065455Sdg -1, -1 6075455Sdg}; 6085455Sdg#endif 6095455Sdg#endif /* PC98 */ 6105455Sdg 6111541Srgrimesstatic struct speedtab comspeedtab[] = { 6125455Sdg { 0, 0 }, 6135455Sdg { 50, COMBRD(50) }, 6145455Sdg { 75, COMBRD(75) }, 6155455Sdg { 110, COMBRD(110) }, 6161541Srgrimes { 134, COMBRD(134) }, 6171541Srgrimes { 150, COMBRD(150) }, 6181541Srgrimes { 200, COMBRD(200) }, 6191541Srgrimes { 300, COMBRD(300) }, 6201937Sdg { 600, COMBRD(600) }, 6211541Srgrimes { 1200, COMBRD(1200) }, 6225455Sdg { 1800, COMBRD(1800) }, 6231541Srgrimes { 2400, COMBRD(2400) }, 6241541Srgrimes { 4800, COMBRD(4800) }, 6251541Srgrimes { 9600, COMBRD(9600) }, 6261541Srgrimes { 19200, COMBRD(19200) }, 6275455Sdg { 38400, COMBRD(38400) }, 6286621Sdg { 57600, COMBRD(57600) }, 6295455Sdg { 115200, COMBRD(115200) }, 6301541Srgrimes { -1, -1 } 6311541Srgrimes}; 6325455Sdg 6331541Srgrimes#ifdef COM_ESP 6341541Srgrimes/* XXX configure this properly. */ 6351541Srgrimesstatic Port_t likely_com_ports[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, }; 6361541Srgrimesstatic Port_t likely_esp_ports[] = { 0x140, 0x180, 0x280, 0 }; 6371541Srgrimes#endif 6381541Srgrimes 6391541Srgrimes/* 6401541Srgrimes * handle sysctl read/write requests for console speed 6411541Srgrimes * 6421541Srgrimes * In addition to setting comdefaultrate for I/O through /dev/console, 6431541Srgrimes * also set the initial and lock values for the /dev/ttyXX device 6441541Srgrimes * if there is one associated with the console. Finally, if the /dev/tty 6451541Srgrimes * device has already been open, change the speed on the open running port 6461541Srgrimes * itself. 6475455Sdg */ 6481541Srgrimes 6491541Srgrimesstatic int 6501541Srgrimessysctl_machdep_comdefaultrate SYSCTL_HANDLER_ARGS 6511541Srgrimes{ 6521541Srgrimes int error, s; 6531541Srgrimes speed_t newspeed; 6545455Sdg struct com_s *com; 6551541Srgrimes struct tty *tp; 6565455Sdg 6575455Sdg newspeed = comdefaultrate; 6581541Srgrimes 6591541Srgrimes error = sysctl_handle_opaque(oidp, &newspeed, sizeof newspeed, req); 6601541Srgrimes if (error || !req->newptr) 6611541Srgrimes return (error); 662 663 comdefaultrate = newspeed; 664 665 if (comconsole < 0) /* serial console not selected? */ 666 return (0); 667 668 com = com_addr(comconsole); 669 if (!com) 670 return (ENXIO); 671 672 /* 673 * set the initial and lock rates for /dev/ttydXX and /dev/cuaXX 674 * (note, the lock rates really are boolean -- if non-zero, disallow 675 * speed changes) 676 */ 677 com->it_in.c_ispeed = com->it_in.c_ospeed = 678 com->lt_in.c_ispeed = com->lt_in.c_ospeed = 679 com->it_out.c_ispeed = com->it_out.c_ospeed = 680 com->lt_out.c_ispeed = com->lt_out.c_ospeed = comdefaultrate; 681 682 /* 683 * if we're open, change the running rate too 684 */ 685 tp = com->tp; 686 if (tp && (tp->t_state & TS_ISOPEN)) { 687 tp->t_termios.c_ispeed = 688 tp->t_termios.c_ospeed = comdefaultrate; 689 s = spltty(); 690 error = comparam(tp, &tp->t_termios); 691 splx(s); 692 } 693 return error; 694} 695 696SYSCTL_PROC(_machdep, OID_AUTO, conspeed, CTLTYPE_INT | CTLFLAG_RW, 697 0, 0, sysctl_machdep_comdefaultrate, "I", ""); 698 699#if NCARD > 0 700/* 701 * PC-Card (PCMCIA) specific code. 702 */ 703static int sioinit __P((struct pccard_devinfo *)); 704static void siounload __P((struct pccard_devinfo *)); 705static int card_intr __P((struct pccard_devinfo *)); 706 707static struct pccard_device sio_info = { 708 driver_name, 709 sioinit, 710 siounload, 711 card_intr, 712 0, /* Attributes - presently unused */ 713 &tty_imask /* Interrupt mask for device */ 714 /* XXX - Should this also include net_imask? */ 715}; 716 717DATA_SET(pccarddrv_set, sio_info); 718 719/* 720 * Initialize the device - called from Slot manager. 721 */ 722int 723sioinit(struct pccard_devinfo *devi) 724{ 725 726 /* validate unit number. */ 727 if (devi->isahd.id_unit >= (NSIOTOT)) 728 return(ENODEV); 729 /* Make sure it isn't already probed. */ 730 if (com_addr(devi->isahd.id_unit)) 731 return(EBUSY); 732 733 /* It's already probed as serial by Upper */ 734 devi->isahd.id_flags |= COM_C_NOPROBE; 735 736 /* 737 * Probe the device. If a value is returned, the 738 * device was found at the location. 739 */ 740 if (sioprobe(&devi->isahd) == 0) 741 return(ENXIO); 742 if (sioattach(&devi->isahd) == 0) 743 return(ENXIO); 744 745 return(0); 746} 747 748/* 749 * siounload - unload the driver and clear the table. 750 * XXX TODO: 751 * This is usually called when the card is ejected, but 752 * can be caused by a modunload of a controller driver. 753 * The idea is to reset the driver's view of the device 754 * and ensure that any driver entry points such as 755 * read and write do not hang. 756 */ 757static void 758siounload(struct pccard_devinfo *devi) 759{ 760 struct com_s *com; 761 762 com = com_addr(devi->isahd.id_unit); 763 if (!com->iobase) { 764 printf("sio%d already unloaded!\n",devi->isahd.id_unit); 765 return; 766 } 767 if (com->tp && (com->tp->t_state & TS_ISOPEN)) { 768 com->gone = 1; 769 printf("sio%d: unload\n", devi->isahd.id_unit); 770 com->tp->t_gen++; 771 ttyclose(com->tp); 772 ttwakeup(com->tp); 773 ttwwakeup(com->tp); 774 } else { 775 com_addr(com->unit) = NULL; 776 bzero(com, sizeof *com); 777 free(com,M_TTYS); 778 printf("sio%d: unload,gone\n", devi->isahd.id_unit); 779 } 780} 781 782/* 783 * card_intr - Shared interrupt called from 784 * front end of PC-Card handler. 785 */ 786static int 787card_intr(struct pccard_devinfo *devi) 788{ 789 struct com_s *com; 790 791 COM_LOCK(); 792 com = com_addr(devi->isahd.id_unit); 793 if (com && !com->gone) 794 siointr1(com_addr(devi->isahd.id_unit)); 795 COM_UNLOCK(); 796 return(1); 797} 798#endif /* NCARD > 0 */ 799 800static int 801sioprobe(dev) 802 struct isa_device *dev; 803{ 804 static bool_t already_init; 805 bool_t failures[10]; 806 int fn; 807 struct isa_device *idev; 808 Port_t iobase; 809 intrmask_t irqmap[4]; 810 intrmask_t irqs; 811 u_char mcr_image; 812 int result; 813 struct isa_device *xdev; 814#ifdef PC98 815 int irqout=0; 816 int ret = 0; 817 int tmp; 818 struct siodev iod; 819#endif 820 821 if (!already_init) { 822 /* 823 * Turn off MCR_IENABLE for all likely serial ports. An unused 824 * port with its MCR_IENABLE gate open will inhibit interrupts 825 * from any used port that shares the interrupt vector. 826 * XXX the gate enable is elsewhere for some multiports. 827 */ 828 for (xdev = isa_devtab_tty; xdev->id_driver != NULL; xdev++) 829 if (xdev->id_driver == &siodriver && xdev->id_enabled) 830#ifdef PC98 831 if (IS_PC98IN(xdev->id_iobase)) 832 outb(xdev->id_iobase + 2, 0xf2); 833 else 834#endif 835 outb(xdev->id_iobase + com_mcr, 0); 836 already_init = TRUE; 837 } 838 839 if (COM_LLCONSOLE(dev)) { 840 printf("sio%d: reserved for low-level i/o\n", dev->id_unit); 841 return (0); 842 } 843 844#ifdef PC98 845 DELAY(10); 846 /* 847 * If the port is i8251 UART (internal, B98_01) 848 */ 849 if(pc98_check_if_type(dev->id_iobase, &iod) == -1) 850 return 0; 851 if(IS_8251(iod.if_type)){ 852 if ( iod.irq > 0 ) 853 dev->id_irq = (1 << iod.irq); 854 outb(iod.cmd, 0); 855 DELAY(10); 856 outb(iod.cmd, 0); 857 DELAY(10); 858 outb(iod.cmd, 0); 859 DELAY(10); 860 outb(iod.cmd, CMD8251_RESET); 861 DELAY(1000); /* for a while...*/ 862 outb(iod.cmd, 0xf2); /* MODE (dummy) */ 863 DELAY(10); 864 outb(iod.cmd, 0x01); /* CMD (dummy) */ 865 DELAY(1000); /* for a while...*/ 866 if (( inb(iod.sts) & STS8251_TxEMP ) == 0 ) { 867 ret = 0; 868 } 869 switch (iod.if_type) { 870 case COM_IF_INTERNAL: 871 COM_INT_DISABLE 872 tmp = ( inb( iod.ctrl ) & ~(IEN_Rx|IEN_TxEMP|IEN_Tx)); 873 outb( iod.ctrl, tmp|IEN_TxEMP ); 874 DELAY(10); 875 ret = isa_irq_pending() ? 4 : 0; 876 outb( iod.ctrl, tmp ); 877 COM_INT_ENABLE 878 break; 879#ifdef COM_IF_B98_01 880 case COM_IF_B98_01: 881 /* B98_01 doesn't activate TxEMP interrupt line 882 when being reset, so we can't check irq pending.*/ 883 ret = 4; 884 break; 885#endif 886 } 887 if (epson_machine_id==0x20) { /* XXX */ 888 ret = 4; 889 } 890 return ret; 891 } 892#endif /* PC98 */ 893 /* 894 * If the device is on a multiport card and has an AST/4 895 * compatible interrupt control register, initialize this 896 * register and prepare to leave MCR_IENABLE clear in the mcr. 897 * Otherwise, prepare to set MCR_IENABLE in the mcr. 898 * Point idev to the device struct giving the correct id_irq. 899 * This is the struct for the master device if there is one. 900 */ 901 idev = dev; 902 mcr_image = MCR_IENABLE; 903#ifdef COM_MULTIPORT 904 if (COM_ISMULTIPORT(dev)) { 905 idev = find_isadev(isa_devtab_tty, &siodriver, 906 COM_MPMASTER(dev)); 907 if (idev == NULL) { 908 printf("sio%d: master device %d not configured\n", 909 dev->id_unit, COM_MPMASTER(dev)); 910 dev->id_irq = 0; 911 idev = dev; 912 } 913#ifndef PC98 914 if (!COM_NOTAST4(dev)) { 915 outb(idev->id_iobase + com_scr, 916 idev->id_irq ? 0x80 : 0); 917 mcr_image = 0; 918 } 919#endif /* !PC98 */ 920 } 921#endif /* COM_MULTIPORT */ 922 if (idev->id_irq == 0) 923 mcr_image = 0; 924 925#ifdef PC98 926 switch(idev->id_irq){ 927 case IRQ3: irqout = 4; break; 928 case IRQ5: irqout = 5; break; 929 case IRQ6: irqout = 6; break; 930 case IRQ12: irqout = 7; break; 931 default: 932 printf("sio%d: irq configuration error\n",dev->id_unit); 933 return (0); 934 } 935 outb(dev->id_iobase+0x1000, irqout); 936#endif 937 bzero(failures, sizeof failures); 938 iobase = dev->id_iobase; 939 940 /* 941 * We don't want to get actual interrupts, just masked ones. 942 * Interrupts from this line should already be masked in the ICU, 943 * but mask them in the processor as well in case there are some 944 * (misconfigured) shared interrupts. 945 */ 946 disable_intr(); 947/* EXTRA DELAY? */ 948 949 /* 950 * Initialize the speed and the word size and wait long enough to 951 * drain the maximum of 16 bytes of junk in device output queues. 952 * The speed is undefined after a master reset and must be set 953 * before relying on anything related to output. There may be 954 * junk after a (very fast) soft reboot and (apparently) after 955 * master reset. 956 * XXX what about the UART bug avoided by waiting in comparam()? 957 * We don't want to to wait long enough to drain at 2 bps. 958 */ 959 if (iobase == siocniobase) 960 DELAY((16 + 1) * 1000000 / (comdefaultrate / 10)); 961 else { 962 outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS); 963 outb(iobase + com_dlbl, COMBRD(SIO_TEST_SPEED) & 0xff); 964 outb(iobase + com_dlbh, (u_int) COMBRD(SIO_TEST_SPEED) >> 8); 965 outb(iobase + com_cfcr, CFCR_8BITS); 966 DELAY((16 + 1) * 1000000 / (SIO_TEST_SPEED / 10)); 967 } 968 969 /* 970 * Enable the interrupt gate and disable device interupts. This 971 * should leave the device driving the interrupt line low and 972 * guarantee an edge trigger if an interrupt can be generated. 973 */ 974/* EXTRA DELAY? */ 975 outb(iobase + com_mcr, mcr_image); 976 outb(iobase + com_ier, 0); 977 DELAY(1000); /* XXX */ 978 irqmap[0] = isa_irq_pending(); 979 980 /* 981 * Attempt to set loopback mode so that we can send a null byte 982 * without annoying any external device. 983 */ 984/* EXTRA DELAY? */ 985 outb(iobase + com_mcr, mcr_image | MCR_LOOPBACK); 986 987 /* 988 * Attempt to generate an output interrupt. On 8250's, setting 989 * IER_ETXRDY generates an interrupt independent of the current 990 * setting and independent of whether the THR is empty. On 16450's, 991 * setting IER_ETXRDY generates an interrupt independent of the 992 * current setting. On 16550A's, setting IER_ETXRDY only 993 * generates an interrupt when IER_ETXRDY is not already set. 994 */ 995 outb(iobase + com_ier, IER_ETXRDY); 996 997 /* 998 * On some 16x50 incompatibles, setting IER_ETXRDY doesn't generate 999 * an interrupt. They'd better generate one for actually doing 1000 * output. Loopback may be broken on the same incompatibles but 1001 * it's unlikely to do more than allow the null byte out. 1002 */ 1003 outb(iobase + com_data, 0); 1004 DELAY((1 + 2) * 1000000 / (SIO_TEST_SPEED / 10)); 1005 1006 /* 1007 * Turn off loopback mode so that the interrupt gate works again 1008 * (MCR_IENABLE was hidden). This should leave the device driving 1009 * an interrupt line high. It doesn't matter if the interrupt 1010 * line oscillates while we are not looking at it, since interrupts 1011 * are disabled. 1012 */ 1013/* EXTRA DELAY? */ 1014 outb(iobase + com_mcr, mcr_image); 1015 1016 /* 1017 * It's a definitly Serial PCMCIA(16550A), but still be required 1018 * for IIR_TXRDY implementation ( Palido 321s, DC-1S... ) 1019 */ 1020 if ( COM_NOPROBE(dev) ) { 1021 /* Reading IIR register twice */ 1022 for ( fn = 0; fn < 2; fn ++ ) { 1023 DELAY(10000); 1024 failures[6] = inb(iobase + com_iir); 1025 } 1026 /* Check IIR_TXRDY clear ? */ 1027 result = IO_COMSIZE; 1028 if ( failures[6] & IIR_TXRDY ) { 1029 /* Nop, Double check with clearing IER */ 1030 outb(iobase + com_ier, 0); 1031 if ( inb(iobase + com_iir) & IIR_NOPEND ) { 1032 /* Ok. we're familia this gang */ 1033 dev->id_flags |= COM_C_IIR_TXRDYBUG; /* Set IIR_TXRDYBUG */ 1034 } else { 1035 /* Unknow, Just omit this chip.. XXX*/ 1036 result = 0; 1037 } 1038 } else { 1039 /* OK. this is well-known guys */ 1040 dev->id_flags &= ~COM_C_IIR_TXRDYBUG; /*Clear IIR_TXRDYBUG*/ 1041 } 1042 outb(iobase + com_cfcr, CFCR_8BITS); 1043 enable_intr(); 1044 return (iobase == siocniobase ? IO_COMSIZE : result); 1045 } 1046 1047 /* 1048 * Check that 1049 * o the CFCR, IER and MCR in UART hold the values written to them 1050 * (the values happen to be all distinct - this is good for 1051 * avoiding false positive tests from bus echoes). 1052 * o an output interrupt is generated and its vector is correct. 1053 * o the interrupt goes away when the IIR in the UART is read. 1054 */ 1055/* EXTRA DELAY? */ 1056 failures[0] = inb(iobase + com_cfcr) - CFCR_8BITS; 1057 failures[1] = inb(iobase + com_ier) - IER_ETXRDY; 1058 failures[2] = inb(iobase + com_mcr) - mcr_image; 1059 DELAY(10000); /* Some internal modems need this time */ 1060 irqmap[1] = isa_irq_pending(); 1061 failures[4] = (inb(iobase + com_iir) & IIR_IMASK) - IIR_TXRDY; 1062 DELAY(1000); /* XXX */ 1063 irqmap[2] = isa_irq_pending(); 1064 failures[6] = (inb(iobase + com_iir) & IIR_IMASK) - IIR_NOPEND; 1065 1066 /* 1067 * Turn off all device interrupts and check that they go off properly. 1068 * Leave MCR_IENABLE alone. For ports without a master port, it gates 1069 * the OUT2 output of the UART to 1070 * the ICU input. Closing the gate would give a floating ICU input 1071 * (unless there is another device driving at) and spurious interrupts. 1072 * (On the system that this was first tested on, the input floats high 1073 * and gives a (masked) interrupt as soon as the gate is closed.) 1074 */ 1075 outb(iobase + com_ier, 0); 1076 outb(iobase + com_cfcr, CFCR_8BITS); /* dummy to avoid bus echo */ 1077 failures[7] = inb(iobase + com_ier); 1078 DELAY(1000); /* XXX */ 1079 irqmap[3] = isa_irq_pending(); 1080 failures[9] = (inb(iobase + com_iir) & IIR_IMASK) - IIR_NOPEND; 1081 1082 enable_intr(); 1083 1084 irqs = irqmap[1] & ~irqmap[0]; 1085 if (idev->id_irq != 0 && (idev->id_irq & irqs) == 0) 1086 printf( 1087 "sio%d: configured irq %d not in bitmap of probed irqs %#x\n", 1088 dev->id_unit, ffs(idev->id_irq) - 1, irqs); 1089 if (bootverbose) 1090 printf("sio%d: irq maps: %#x %#x %#x %#x\n", 1091 dev->id_unit, irqmap[0], irqmap[1], irqmap[2], irqmap[3]); 1092 1093 result = IO_COMSIZE; 1094 for (fn = 0; fn < sizeof failures; ++fn) 1095 if (failures[fn]) { 1096 outb(iobase + com_mcr, 0); 1097 result = 0; 1098 if (bootverbose) { 1099 printf("sio%d: probe failed test(s):", 1100 dev->id_unit); 1101 for (fn = 0; fn < sizeof failures; ++fn) 1102 if (failures[fn]) 1103 printf(" %d", fn); 1104 printf("\n"); 1105 } 1106 break; 1107 } 1108 return (iobase == siocniobase ? IO_COMSIZE : result); 1109} 1110 1111#ifdef COM_ESP 1112static int 1113espattach(isdp, com, esp_port) 1114 struct isa_device *isdp; 1115 struct com_s *com; 1116 Port_t esp_port; 1117{ 1118 u_char dips; 1119 u_char val; 1120 1121 /* 1122 * Check the ESP-specific I/O port to see if we're an ESP 1123 * card. If not, return failure immediately. 1124 */ 1125 if ((inb(esp_port) & 0xf3) == 0) { 1126 printf(" port 0x%x is not an ESP board?\n", esp_port); 1127 return (0); 1128 } 1129 1130 /* 1131 * We've got something that claims to be a Hayes ESP card. 1132 * Let's hope so. 1133 */ 1134 1135 /* Get the dip-switch configuration */ 1136 outb(esp_port + ESP_CMD1, ESP_GETDIPS); 1137 dips = inb(esp_port + ESP_STATUS1); 1138 1139 /* 1140 * Bits 0,1 of dips say which COM port we are. 1141 */ 1142 if (com->iobase == likely_com_ports[dips & 0x03]) 1143 printf(" : ESP"); 1144 else { 1145 printf(" esp_port has com %d\n", dips & 0x03); 1146 return (0); 1147 } 1148 1149 /* 1150 * Check for ESP version 2.0 or later: bits 4,5,6 = 010. 1151 */ 1152 outb(esp_port + ESP_CMD1, ESP_GETTEST); 1153 val = inb(esp_port + ESP_STATUS1); /* clear reg 1 */ 1154 val = inb(esp_port + ESP_STATUS2); 1155 if ((val & 0x70) < 0x20) { 1156 printf("-old (%o)", val & 0x70); 1157 return (0); 1158 } 1159 1160 /* 1161 * Check for ability to emulate 16550: bit 7 == 1 1162 */ 1163 if ((dips & 0x80) == 0) { 1164 printf(" slave"); 1165 return (0); 1166 } 1167 1168 /* 1169 * Okay, we seem to be a Hayes ESP card. Whee. 1170 */ 1171 com->esp = TRUE; 1172 com->esp_port = esp_port; 1173 return (1); 1174} 1175#endif /* COM_ESP */ 1176 1177static int 1178sioattach(isdp) 1179 struct isa_device *isdp; 1180{ 1181 struct com_s *com; 1182 dev_t dev; 1183#ifdef COM_ESP 1184 Port_t *espp; 1185#endif 1186 Port_t iobase; 1187 int s; 1188 int unit; 1189 1190 isdp->id_ri_flags |= RI_FAST; 1191 iobase = isdp->id_iobase; 1192 unit = isdp->id_unit; 1193 com = malloc(sizeof *com, M_TTYS, M_NOWAIT); 1194 if (com == NULL) 1195 return (0); 1196 1197 /* 1198 * sioprobe() has initialized the device registers as follows: 1199 * o cfcr = CFCR_8BITS. 1200 * It is most important that CFCR_DLAB is off, so that the 1201 * data port is not hidden when we enable interrupts. 1202 * o ier = 0. 1203 * Interrupts are only enabled when the line is open. 1204 * o mcr = MCR_IENABLE, or 0 if the port has AST/4 compatible 1205 * interrupt control register or the config specifies no irq. 1206 * Keeping MCR_DTR and MCR_RTS off might stop the external 1207 * device from sending before we are ready. 1208 */ 1209 bzero(com, sizeof *com); 1210 com->unit = unit; 1211 com->cfcr_image = CFCR_8BITS; 1212 com->dtr_wait = 3 * hz; 1213 com->loses_outints = COM_LOSESOUTINTS(isdp) != 0; 1214 com->no_irq = isdp->id_irq == 0; 1215 com->tx_fifo_size = 1; 1216 com->iptr = com->ibuf = com->ibuf1; 1217 com->ibufend = com->ibuf1 + RS_IBUFSIZE; 1218 com->ihighwater = com->ibuf1 + RS_IHIGHWATER; 1219 com->obufs[0].l_head = com->obuf1; 1220 com->obufs[1].l_head = com->obuf2; 1221 1222 com->iobase = iobase; 1223#ifdef PC98 1224 if(pc98_set_ioport(com, iobase) == -1) 1225 if((iobase & 0x0f0) == 0xd0) { 1226 com->pc98_if_type = MC16550; 1227 com->data_port = iobase + com_data; 1228 com->int_id_port = iobase + com_iir; 1229 com->modem_ctl_port = iobase + com_mcr; 1230 com->mcr_image = inb(com->modem_ctl_port); 1231 com->line_status_port = iobase + com_lsr; 1232 com->modem_status_port = iobase + com_msr; 1233 com->intr_ctl_port = iobase + com_ier; 1234 } 1235#else /* not PC98 */ 1236 com->data_port = iobase + com_data; 1237 com->int_id_port = iobase + com_iir; 1238 com->modem_ctl_port = iobase + com_mcr; 1239 com->mcr_image = inb(com->modem_ctl_port); 1240 com->line_status_port = iobase + com_lsr; 1241 com->modem_status_port = iobase + com_msr; 1242 com->intr_ctl_port = iobase + com_ier; 1243#endif 1244 1245 /* 1246 * We don't use all the flags from <sys/ttydefaults.h> since they 1247 * are only relevant for logins. It's important to have echo off 1248 * initially so that the line doesn't start blathering before the 1249 * echo flag can be turned off. 1250 */ 1251 com->it_in.c_iflag = 0; 1252 com->it_in.c_oflag = 0; 1253 com->it_in.c_cflag = TTYDEF_CFLAG; 1254 com->it_in.c_lflag = 0; 1255 if (unit == comconsole) { 1256#ifdef PC98 1257 if(IS_8251(com->pc98_if_type)) 1258 DELAY(100000); 1259#endif 1260 com->it_in.c_iflag = TTYDEF_IFLAG; 1261 com->it_in.c_oflag = TTYDEF_OFLAG; 1262 com->it_in.c_cflag = TTYDEF_CFLAG | CLOCAL; 1263 com->it_in.c_lflag = TTYDEF_LFLAG; 1264 com->lt_out.c_cflag = com->lt_in.c_cflag = CLOCAL; 1265 com->lt_out.c_ispeed = com->lt_out.c_ospeed = 1266 com->lt_in.c_ispeed = com->lt_in.c_ospeed = 1267 com->it_in.c_ispeed = com->it_in.c_ospeed = comdefaultrate; 1268 } else 1269 com->it_in.c_ispeed = com->it_in.c_ospeed = TTYDEF_SPEED; 1270 termioschars(&com->it_in); 1271 com->it_out = com->it_in; 1272 1273 /* attempt to determine UART type */ 1274 printf("sio%d: type", unit); 1275 1276#ifdef DSI_SOFT_MODEM 1277 if((inb(iobase+7) ^ inb(iobase+7)) & 0x80) { 1278 printf(" Digicom Systems, Inc. SoftModem"); 1279 goto determined_type; 1280 } 1281#endif /* DSI_SOFT_MODEM */ 1282 1283#ifndef PC98 1284#ifdef COM_MULTIPORT 1285 if (!COM_ISMULTIPORT(isdp) && !COM_IIR_TXRDYBUG(isdp)) 1286#else 1287 if (!COM_IIR_TXRDYBUG(isdp)) 1288#endif 1289 { 1290 u_char scr; 1291 u_char scr1; 1292 u_char scr2; 1293 1294 scr = inb(iobase + com_scr); 1295 outb(iobase + com_scr, 0xa5); 1296 scr1 = inb(iobase + com_scr); 1297 outb(iobase + com_scr, 0x5a); 1298 scr2 = inb(iobase + com_scr); 1299 outb(iobase + com_scr, scr); 1300 if (scr1 != 0xa5 || scr2 != 0x5a) { 1301 printf(" 8250"); 1302 goto determined_type; 1303 } 1304 } 1305#endif /* !PC98 */ 1306#ifdef PC98 1307 if(IS_8251(com->pc98_if_type)){ 1308 com_int_TxRx_disable( com ); 1309 com_cflag_and_speed_set( com, com->it_in.c_cflag, 1310 comdefaultrate ); 1311 com_tiocm_bic( com, TIOCM_DTR|TIOCM_RTS|TIOCM_LE ); 1312 com_send_break_off( com ); 1313 switch(com->pc98_if_type){ 1314 case COM_IF_INTERNAL: 1315 printf(" 8251 (internal)"); 1316 break; 1317#ifdef COM_IF_PC9861K 1318 case COM_IF_PC9861K: 1319 printf(" 8251 (PC9861K)"); 1320 break; 1321#endif 1322#ifdef COM_IF_PIO9032B 1323 case COM_IF_PIO9032B: 1324 printf(" 8251 (PIO9032B)"); 1325 break; 1326#endif 1327#ifdef COM_IF_B98_01 1328 case COM_IF_B98_01: 1329 printf(" 8251 (B98_01)"); 1330 break; 1331#endif 1332 } 1333 } else { 1334#endif /* PC98 */ 1335 outb(iobase + com_fifo, FIFO_ENABLE | FIFO_RX_HIGH); 1336 DELAY(100); 1337 com->st16650a = 0; 1338 switch (inb(com->int_id_port) & IIR_FIFO_MASK) { 1339 case FIFO_RX_LOW: 1340 printf(" 16450"); 1341 break; 1342 case FIFO_RX_MEDL: 1343 printf(" 16450?"); 1344 break; 1345 case FIFO_RX_MEDH: 1346 printf(" 16550?"); 1347 break; 1348 case FIFO_RX_HIGH: 1349 if (COM_NOFIFO(isdp)) { 1350 printf(" 16550A fifo disabled"); 1351 } else { 1352 com->hasfifo = TRUE; 1353 if (COM_ST16650A(isdp)) { 1354 com->st16650a = 1; 1355 com->tx_fifo_size = 32; 1356 printf(" ST16650A"); 1357 } else { 1358 com->tx_fifo_size = COM_FIFOSIZE(isdp); 1359 printf(" 16550A"); 1360 } 1361 } 1362#ifdef COM_ESP 1363 for (espp = likely_esp_ports; *espp != 0; espp++) 1364 if (espattach(isdp, com, *espp)) { 1365 com->tx_fifo_size = 1024; 1366 break; 1367 } 1368#endif 1369 if (!com->st16650a) { 1370 if (!com->tx_fifo_size) 1371 com->tx_fifo_size = 16; 1372 else 1373 printf(" lookalike with %d bytes FIFO", 1374 com->tx_fifo_size); 1375 } 1376 1377 break; 1378 } 1379 1380#ifdef COM_ESP 1381 if (com->esp) { 1382 /* 1383 * Set 16550 compatibility mode. 1384 * We don't use the ESP_MODE_SCALE bit to increase the 1385 * fifo trigger levels because we can't handle large 1386 * bursts of input. 1387 * XXX flow control should be set in comparam(), not here. 1388 */ 1389 outb(com->esp_port + ESP_CMD1, ESP_SETMODE); 1390 outb(com->esp_port + ESP_CMD2, ESP_MODE_RTS | ESP_MODE_FIFO); 1391 1392 /* Set RTS/CTS flow control. */ 1393 outb(com->esp_port + ESP_CMD1, ESP_SETFLOWTYPE); 1394 outb(com->esp_port + ESP_CMD2, ESP_FLOW_RTS); 1395 outb(com->esp_port + ESP_CMD2, ESP_FLOW_CTS); 1396 1397 /* Set flow-control levels. */ 1398 outb(com->esp_port + ESP_CMD1, ESP_SETRXFLOW); 1399 outb(com->esp_port + ESP_CMD2, HIBYTE(768)); 1400 outb(com->esp_port + ESP_CMD2, LOBYTE(768)); 1401 outb(com->esp_port + ESP_CMD2, HIBYTE(512)); 1402 outb(com->esp_port + ESP_CMD2, LOBYTE(512)); 1403 } 1404#endif /* COM_ESP */ 1405 outb(iobase + com_fifo, 0); 1406determined_type: ; 1407 1408#ifdef COM_MULTIPORT 1409 if (COM_ISMULTIPORT(isdp)) { 1410 com->multiport = TRUE; 1411 printf(" (multiport"); 1412 if (unit == COM_MPMASTER(isdp)) 1413 printf(" master"); 1414 printf(")"); 1415 com->no_irq = find_isadev(isa_devtab_tty, &siodriver, 1416 COM_MPMASTER(isdp))->id_irq == 0; 1417 } 1418#endif /* COM_MULTIPORT */ 1419#ifdef PC98 1420 } 1421#endif 1422 if (unit == comconsole) 1423 printf(", console"); 1424 if ( COM_IIR_TXRDYBUG(isdp) ) 1425 printf(" with a bogus IIR_TXRDY register"); 1426 printf("\n"); 1427 1428 s = spltty(); 1429 com_addr(unit) = com; 1430 splx(s); 1431 1432 dev = makedev(CDEV_MAJOR, 0); 1433 cdevsw_add(&dev, &sio_cdevsw, NULL); 1434#ifdef DEVFS 1435 com->devfs_token_ttyd = devfs_add_devswf(&sio_cdevsw, 1436 unit, DV_CHR, 1437 UID_ROOT, GID_WHEEL, 0600, "ttyd%n", unit); 1438 com->devfs_token_ttyi = devfs_add_devswf(&sio_cdevsw, 1439 unit | CONTROL_INIT_STATE, DV_CHR, 1440 UID_ROOT, GID_WHEEL, 0600, "ttyid%n", unit); 1441 com->devfs_token_ttyl = devfs_add_devswf(&sio_cdevsw, 1442 unit | CONTROL_LOCK_STATE, DV_CHR, 1443 UID_ROOT, GID_WHEEL, 0600, "ttyld%n", unit); 1444 com->devfs_token_cuaa = devfs_add_devswf(&sio_cdevsw, 1445 unit | CALLOUT_MASK, DV_CHR, 1446 UID_UUCP, GID_DIALER, 0660, "cuaa%n", unit); 1447 com->devfs_token_cuai = devfs_add_devswf(&sio_cdevsw, 1448 unit | CALLOUT_MASK | CONTROL_INIT_STATE, DV_CHR, 1449 UID_UUCP, GID_DIALER, 0660, "cuaia%n", unit); 1450 com->devfs_token_cual = devfs_add_devswf(&sio_cdevsw, 1451 unit | CALLOUT_MASK | CONTROL_LOCK_STATE, DV_CHR, 1452 UID_UUCP, GID_DIALER, 0660, "cuala%n", unit); 1453#endif 1454 com->id_flags = isdp->id_flags; /* Heritate id_flags for later */ 1455 return (1); 1456} 1457 1458static int 1459sioopen(dev, flag, mode, p) 1460 dev_t dev; 1461 int flag; 1462 int mode; 1463 struct proc *p; 1464{ 1465 struct com_s *com; 1466 int error; 1467 Port_t iobase; 1468 int mynor; 1469 int s; 1470 struct tty *tp; 1471 int unit; 1472 1473 mynor = minor(dev); 1474 unit = MINOR_TO_UNIT(mynor); 1475 if ((u_int) unit >= NSIOTOT || (com = com_addr(unit)) == NULL) 1476 return (ENXIO); 1477 if (com->gone) 1478 return (ENXIO); 1479 if (mynor & CONTROL_MASK) 1480 return (0); 1481#if 0 /* XXX */ 1482 tp = com->tp = sio_tty[unit] = ttymalloc(sio_tty[unit]); 1483#else 1484 tp = com->tp = &sio_tty[unit]; 1485#endif 1486 s = spltty(); 1487 /* 1488 * We jump to this label after all non-interrupted sleeps to pick 1489 * up any changes of the device state. 1490 */ 1491open_top: 1492 while (com->state & CS_DTR_OFF) { 1493 error = tsleep(&com->dtr_wait, TTIPRI | PCATCH, "siodtr", 0); 1494 if (com_addr(unit) == NULL) 1495 return (ENXIO); 1496 if (error != 0 || com->gone) 1497 goto out; 1498 } 1499 if (tp->t_state & TS_ISOPEN) { 1500 /* 1501 * The device is open, so everything has been initialized. 1502 * Handle conflicts. 1503 */ 1504 if (mynor & CALLOUT_MASK) { 1505 if (!com->active_out) { 1506 error = EBUSY; 1507 goto out; 1508 } 1509 } else { 1510 if (com->active_out) { 1511 if (flag & O_NONBLOCK) { 1512 error = EBUSY; 1513 goto out; 1514 } 1515 error = tsleep(&com->active_out, 1516 TTIPRI | PCATCH, "siobi", 0); 1517 if (com_addr(unit) == NULL) 1518 return (ENXIO); 1519 if (error != 0 || com->gone) 1520 goto out; 1521 goto open_top; 1522 } 1523 } 1524 if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) { 1525 error = EBUSY; 1526 goto out; 1527 } 1528 } else { 1529 /* 1530 * The device isn't open, so there are no conflicts. 1531 * Initialize it. Initialization is done twice in many 1532 * cases: to preempt sleeping callin opens if we are 1533 * callout, and to complete a callin open after DCD rises. 1534 */ 1535 tp->t_oproc = comstart; 1536 tp->t_param = comparam; 1537 tp->t_dev = dev; 1538 tp->t_termios = mynor & CALLOUT_MASK 1539 ? com->it_out : com->it_in; 1540#ifdef PC98 1541 if(!IS_8251(com->pc98_if_type)) 1542#endif 1543 (void)commctl(com, TIOCM_DTR | TIOCM_RTS, DMSET); 1544 com->poll = com->no_irq; 1545 com->poll_output = com->loses_outints; 1546 ++com->wopeners; 1547 error = comparam(tp, &tp->t_termios); 1548 --com->wopeners; 1549 if (error != 0) 1550 goto out; 1551#ifdef PC98 1552 if(IS_8251(com->pc98_if_type)){ 1553 com_tiocm_bis(com, TIOCM_DTR|TIOCM_RTS); 1554 pc98_msrint_start(dev); 1555 } 1556#endif 1557 /* 1558 * XXX we should goto open_top if comparam() slept. 1559 */ 1560 ttsetwater(tp); 1561 iobase = com->iobase; 1562 if (com->hasfifo) { 1563 /* 1564 * (Re)enable and drain fifos. 1565 * 1566 * Certain SMC chips cause problems if the fifos 1567 * are enabled while input is ready. Turn off the 1568 * fifo if necessary to clear the input. We test 1569 * the input ready bit after enabling the fifos 1570 * since we've already enabled them in comparam() 1571 * and to handle races between enabling and fresh 1572 * input. 1573 */ 1574 while (TRUE) { 1575 outb(iobase + com_fifo, 1576 FIFO_RCV_RST | FIFO_XMT_RST 1577 | com->fifo_image); 1578 /* 1579 * XXX the delays are for superstitious 1580 * historical reasons. It must be less than 1581 * the character time at the maximum 1582 * supported speed (87 usec at 115200 bps 1583 * 8N1). Otherwise we might loop endlessly 1584 * if data is streaming in. We used to use 1585 * delays of 100. That usually worked 1586 * because DELAY(100) used to usually delay 1587 * for about 85 usec instead of 100. 1588 */ 1589 DELAY(50); 1590 if (!(inb(com->line_status_port) & LSR_RXRDY)) 1591 break; 1592 outb(iobase + com_fifo, 0); 1593 DELAY(50); 1594 (void) inb(com->data_port); 1595 } 1596 } 1597 1598 disable_intr(); 1599#ifdef PC98 1600 if(IS_8251(com->pc98_if_type)){ 1601 com_tiocm_bis(com, TIOCM_LE); 1602 com->pc98_prev_modem_status = 1603 pc98_get_modem_status(com); 1604 com_int_Rx_enable(com); 1605 } else { 1606#endif 1607 (void) inb(com->line_status_port); 1608 (void) inb(com->data_port); 1609 com->prev_modem_status = com->last_modem_status 1610 = inb(com->modem_status_port); 1611 if (COM_IIR_TXRDYBUG(com)) { 1612 outb(com->intr_ctl_port, IER_ERXRDY | IER_ERLS 1613 | IER_EMSC); 1614 } else { 1615 outb(com->intr_ctl_port, IER_ERXRDY | IER_ETXRDY 1616 | IER_ERLS | IER_EMSC); 1617 } 1618#ifdef PC98 1619 } 1620#endif 1621 enable_intr(); 1622 /* 1623 * Handle initial DCD. Callout devices get a fake initial 1624 * DCD (trapdoor DCD). If we are callout, then any sleeping 1625 * callin opens get woken up and resume sleeping on "siobi" 1626 * instead of "siodcd". 1627 */ 1628 /* 1629 * XXX `mynor & CALLOUT_MASK' should be 1630 * `tp->t_cflag & (SOFT_CARRIER | TRAPDOOR_CARRIER) where 1631 * TRAPDOOR_CARRIER is the default initial state for callout 1632 * devices and SOFT_CARRIER is like CLOCAL except it hides 1633 * the true carrier. 1634 */ 1635#ifdef PC98 1636 if ((IS_8251(com->pc98_if_type) && 1637 (pc98_get_modem_status(com) & TIOCM_CAR)) || 1638 (!IS_8251(com->pc98_if_type) && 1639 (com->prev_modem_status & MSR_DCD)) || 1640 mynor & CALLOUT_MASK) 1641#else 1642 if (com->prev_modem_status & MSR_DCD || mynor & CALLOUT_MASK) 1643#endif 1644 (*linesw[tp->t_line].l_modem)(tp, 1); 1645 } 1646 /* 1647 * Wait for DCD if necessary. 1648 */ 1649 if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK) 1650 && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) { 1651 ++com->wopeners; 1652 error = tsleep(TSA_CARR_ON(tp), TTIPRI | PCATCH, "siodcd", 0); 1653 if (com_addr(unit) == NULL) 1654 return (ENXIO); 1655 --com->wopeners; 1656 if (error != 0 || com->gone) 1657 goto out; 1658 goto open_top; 1659 } 1660 error = (*linesw[tp->t_line].l_open)(dev, tp); 1661 disc_optim(tp, &tp->t_termios, com); 1662 if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK) 1663 com->active_out = TRUE; 1664 siosettimeout(); 1665out: 1666 splx(s); 1667 if (!(tp->t_state & TS_ISOPEN) && com->wopeners == 0) 1668 comhardclose(com); 1669 return (error); 1670} 1671 1672static int 1673sioclose(dev, flag, mode, p) 1674 dev_t dev; 1675 int flag; 1676 int mode; 1677 struct proc *p; 1678{ 1679 struct com_s *com; 1680 int mynor; 1681 int s; 1682 struct tty *tp; 1683 1684 mynor = minor(dev); 1685 if (mynor & CONTROL_MASK) 1686 return (0); 1687 com = com_addr(MINOR_TO_UNIT(mynor)); 1688 tp = com->tp; 1689 s = spltty(); 1690 (*linesw[tp->t_line].l_close)(tp, flag); 1691#ifdef PC98 1692 com->modem_checking = 0; 1693#endif 1694 disc_optim(tp, &tp->t_termios, com); 1695 siostop(tp, FREAD | FWRITE); 1696 comhardclose(com); 1697 ttyclose(tp); 1698 siosettimeout(); 1699 splx(s); 1700 if (com->gone) { 1701 printf("sio%d: gone\n", com->unit); 1702 s = spltty(); 1703 com_addr(com->unit) = 0; 1704 bzero(tp,sizeof *tp); 1705 bzero(com,sizeof *com); 1706 free(com,M_TTYS); 1707 splx(s); 1708 } 1709 return (0); 1710} 1711 1712static void 1713comhardclose(com) 1714 struct com_s *com; 1715{ 1716 Port_t iobase; 1717 int s; 1718 struct tty *tp; 1719 int unit; 1720 1721 unit = com->unit; 1722 iobase = com->iobase; 1723 s = spltty(); 1724 com->poll = FALSE; 1725 com->poll_output = FALSE; 1726 com->do_timestamp = FALSE; 1727 com->do_dcd_timestamp = FALSE; 1728#ifdef PC98 1729 if(IS_8251(com->pc98_if_type)) 1730 com_send_break_off(com); 1731 else 1732#endif 1733 outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK); 1734 { 1735#ifdef PC98 1736 int tmp; 1737 if(IS_8251(com->pc98_if_type)) 1738 com_int_TxRx_disable(com); 1739 else 1740#endif 1741 outb(iobase + com_ier, 0); 1742 tp = com->tp; 1743#ifdef PC98 1744 if(IS_8251(com->pc98_if_type)) 1745 tmp = pc98_get_modem_status(com) & TIOCM_CAR; 1746 else 1747 tmp = com->prev_modem_status & MSR_DCD; 1748#endif 1749 if (tp->t_cflag & HUPCL 1750 /* 1751 * XXX we will miss any carrier drop between here and the 1752 * next open. Perhaps we should watch DCD even when the 1753 * port is closed; it is not sufficient to check it at 1754 * the next open because it might go up and down while 1755 * we're not watching. 1756 */ 1757 || !com->active_out 1758#ifdef PC98 1759 && !(tmp) 1760#else 1761 && !(com->prev_modem_status & MSR_DCD) 1762#endif 1763 && !(com->it_in.c_cflag & CLOCAL) 1764 || !(tp->t_state & TS_ISOPEN)) { 1765#ifdef PC98 1766 if(IS_8251(com->pc98_if_type)) 1767 com_tiocm_bic(com, TIOCM_DTR|TIOCM_RTS|TIOCM_LE); 1768 else 1769#endif 1770 (void)commctl(com, TIOCM_DTR, DMBIC); 1771 if (com->dtr_wait != 0 && !(com->state & CS_DTR_OFF)) { 1772 timeout(siodtrwakeup, com, com->dtr_wait); 1773 com->state |= CS_DTR_OFF; 1774 } 1775 } 1776#ifdef PC98 1777 else { 1778 if(IS_8251(com->pc98_if_type)) 1779 com_tiocm_bic(com, TIOCM_LE ); 1780 } 1781#endif 1782 } 1783 if (com->hasfifo) { 1784 /* 1785 * Disable fifos so that they are off after controlled 1786 * reboots. Some BIOSes fail to detect 16550s when the 1787 * fifos are enabled. 1788 */ 1789 outb(iobase + com_fifo, 0); 1790 } 1791 com->active_out = FALSE; 1792 wakeup(&com->active_out); 1793 wakeup(TSA_CARR_ON(tp)); /* restart any wopeners */ 1794 splx(s); 1795} 1796 1797static int 1798sioread(dev, uio, flag) 1799 dev_t dev; 1800 struct uio *uio; 1801 int flag; 1802{ 1803 int mynor; 1804 int unit; 1805 struct tty *tp; 1806 1807 mynor = minor(dev); 1808 if (mynor & CONTROL_MASK) 1809 return (ENODEV); 1810 unit = MINOR_TO_UNIT(mynor); 1811 if (com_addr(unit)->gone) 1812 return (ENODEV); 1813 tp = com_addr(unit)->tp; 1814 return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 1815} 1816 1817static int 1818siowrite(dev, uio, flag) 1819 dev_t dev; 1820 struct uio *uio; 1821 int flag; 1822{ 1823 int mynor; 1824 struct tty *tp; 1825 int unit; 1826 1827 mynor = minor(dev); 1828 if (mynor & CONTROL_MASK) 1829 return (ENODEV); 1830 1831 unit = MINOR_TO_UNIT(mynor); 1832 if (com_addr(unit)->gone) 1833 return (ENODEV); 1834 tp = com_addr(unit)->tp; 1835 /* 1836 * (XXX) We disallow virtual consoles if the physical console is 1837 * a serial port. This is in case there is a display attached that 1838 * is not the console. In that situation we don't need/want the X 1839 * server taking over the console. 1840 */ 1841 if (constty != NULL && unit == comconsole) 1842 constty = NULL; 1843 return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 1844} 1845 1846static void 1847siobusycheck(chan) 1848 void *chan; 1849{ 1850 struct com_s *com; 1851 int s; 1852 1853 com = (struct com_s *)chan; 1854 1855 /* 1856 * Clear TS_BUSY if low-level output is complete. 1857 * spl locking is sufficient because siointr1() does not set CS_BUSY. 1858 * If siointr1() clears CS_BUSY after we look at it, then we'll get 1859 * called again. Reading the line status port outside of siointr1() 1860 * is safe because CS_BUSY is clear so there are no output interrupts 1861 * to lose. 1862 */ 1863 s = spltty(); 1864 if (com->state & CS_BUSY) 1865 com->extra_state &= ~CSE_BUSYCHECK; /* False alarm. */ 1866#ifdef PC98 1867 else if (IS_8251(com->pc98_if_type) && 1868 (inb(com->sts_port) & (STS8251_TxRDY | STS8251_TxEMP)) 1869 == (STS8251_TxRDY | STS8251_TxEMP) || 1870 (inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY)) 1871 == (LSR_TSRE | LSR_TXRDY)) { 1872#else 1873 else if ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY)) 1874 == (LSR_TSRE | LSR_TXRDY)) { 1875#endif 1876 com->tp->t_state &= ~TS_BUSY; 1877 ttwwakeup(com->tp); 1878 com->extra_state &= ~CSE_BUSYCHECK; 1879 } else 1880 timeout(siobusycheck, com, hz / 100); 1881 splx(s); 1882} 1883 1884static void 1885siodtrwakeup(chan) 1886 void *chan; 1887{ 1888 struct com_s *com; 1889 1890 com = (struct com_s *)chan; 1891 com->state &= ~CS_DTR_OFF; 1892 wakeup(&com->dtr_wait); 1893} 1894 1895void 1896siointr(unit) 1897 int unit; 1898{ 1899#ifndef COM_MULTIPORT 1900 COM_LOCK(); 1901 siointr1(com_addr(unit)); 1902 COM_UNLOCK(); 1903#else /* COM_MULTIPORT */ 1904 struct com_s *com; 1905 bool_t possibly_more_intrs; 1906 1907 /* 1908 * Loop until there is no activity on any port. This is necessary 1909 * to get an interrupt edge more than to avoid another interrupt. 1910 * If the IRQ signal is just an OR of the IRQ signals from several 1911 * devices, then the edge from one may be lost because another is 1912 * on. 1913 */ 1914 COM_LOCK(); 1915 do { 1916 possibly_more_intrs = FALSE; 1917 for (unit = 0; unit < NSIOTOT; ++unit) { 1918 com = com_addr(unit); 1919 /* 1920 * XXX COM_LOCK(); 1921 * would it work here, or be counter-productive? 1922 */ 1923#ifdef PC98 1924 if (com != NULL 1925 && !com->gone 1926 && IS_8251(com->pc98_if_type)){ 1927 siointr1(com); 1928 } else 1929#endif /* PC98 */ 1930 if (com != NULL 1931 && !com->gone 1932 && (inb(com->int_id_port) & IIR_IMASK) 1933 != IIR_NOPEND) { 1934 siointr1(com); 1935 possibly_more_intrs = TRUE; 1936 } 1937 /* XXX COM_UNLOCK(); */ 1938 } 1939 } while (possibly_more_intrs); 1940 COM_UNLOCK(); 1941#endif /* COM_MULTIPORT */ 1942} 1943 1944static void 1945siointr1(com) 1946 struct com_s *com; 1947{ 1948 u_char line_status; 1949 u_char modem_status; 1950 u_char *ioptr; 1951 u_char recv_data; 1952 u_char int_ident; 1953 u_char int_ctl; 1954 u_char int_ctl_new; 1955 1956#ifdef PC98 1957 u_char tmp=0; 1958recv_data=0; 1959#endif /* PC98 */ 1960 1961 int_ctl = inb(com->intr_ctl_port); 1962 int_ctl_new = int_ctl; 1963 1964 while (!com->gone) { 1965#ifdef PC98 1966status_read:; 1967 if (IS_8251(com->pc98_if_type)) { 1968 tmp = inb(com->sts_port); 1969more_intr: 1970 line_status = 0; 1971 if (tmp & STS8251_TxRDY) line_status |= LSR_TXRDY; 1972 if (tmp & STS8251_RxRDY) line_status |= LSR_RXRDY; 1973 if (tmp & STS8251_TxEMP) line_status |= LSR_TSRE; 1974 if (tmp & STS8251_PE) line_status |= LSR_PE; 1975 if (tmp & STS8251_OE) line_status |= LSR_OE; 1976 if (tmp & STS8251_FE) line_status |= LSR_FE; 1977 if (tmp & STS8251_BD_SD) line_status |= LSR_BI; 1978 } else 1979#endif /* PC98 */ 1980 line_status = inb(com->line_status_port); 1981 1982 /* input event? (check first to help avoid overruns) */ 1983 while (line_status & LSR_RCV_MASK) { 1984 /* break/unnattached error bits or real input? */ 1985#ifdef PC98 1986 if(IS_8251(com->pc98_if_type)){ 1987 recv_data = inb(com->data_port); 1988 if(tmp & 0x78){ 1989 pc98_i8251_or_cmd(com,CMD8251_ER); 1990 recv_data = 0; 1991 } 1992 } else { 1993#endif /* PC98 */ 1994 if (!(line_status & LSR_RXRDY)) 1995 recv_data = 0; 1996 else 1997 recv_data = inb(com->data_port); 1998#ifdef PC98 1999 } 2000#endif 2001 if (line_status & (LSR_BI | LSR_FE | LSR_PE)) { 2002 /* 2003 * Don't store BI if IGNBRK or FE/PE if IGNPAR. 2004 * Otherwise, push the work to a higher level 2005 * (to handle PARMRK) if we're bypassing. 2006 * Otherwise, convert BI/FE and PE+INPCK to 0. 2007 * 2008 * This makes bypassing work right in the 2009 * usual "raw" case (IGNBRK set, and IGNPAR 2010 * and INPCK clear). 2011 * 2012 * Note: BI together with FE/PE means just BI. 2013 */ 2014 if (line_status & LSR_BI) { 2015#if defined(DDB) && defined(BREAK_TO_DEBUGGER) 2016 if (com->unit == comconsole) { 2017 breakpoint(); 2018 goto cont; 2019 } 2020#endif 2021 if (com->tp == NULL 2022 || com->tp->t_iflag & IGNBRK) 2023 goto cont; 2024 } else { 2025 if (com->tp == NULL 2026 || com->tp->t_iflag & IGNPAR) 2027 goto cont; 2028 } 2029 if (com->tp->t_state & TS_CAN_BYPASS_L_RINT 2030 && (line_status & (LSR_BI | LSR_FE) 2031 || com->tp->t_iflag & INPCK)) 2032 recv_data = 0; 2033 } 2034 ++com->bytes_in; 2035 if (com->hotchar != 0 && recv_data == com->hotchar) 2036 setsofttty(); 2037 ioptr = com->iptr; 2038 if (ioptr >= com->ibufend) 2039 CE_RECORD(com, CE_INTERRUPT_BUF_OVERFLOW); 2040 else { 2041 if (com->do_timestamp) 2042 microtime(&com->timestamp); 2043 ++com_events; 2044 schedsofttty(); 2045#if 0 /* for testing input latency vs efficiency */ 2046if (com->iptr - com->ibuf == 8) 2047 setsofttty(); 2048#endif 2049 ioptr[0] = recv_data; 2050 ioptr[CE_INPUT_OFFSET] = line_status; 2051 com->iptr = ++ioptr; 2052 if (ioptr == com->ihighwater 2053 && com->state & CS_RTS_IFLOW) 2054#ifdef PC98 2055 if(IS_8251(com->pc98_if_type)) 2056 com_tiocm_bic(com, TIOCM_RTS); 2057 else 2058#endif 2059 outb(com->modem_ctl_port, 2060 com->mcr_image &= ~MCR_RTS); 2061 if (line_status & LSR_OE) 2062 CE_RECORD(com, CE_OVERRUN); 2063 } 2064cont: 2065 /* 2066 * "& 0x7F" is to avoid the gcc-1.40 generating a slow 2067 * jump from the top of the loop to here 2068 */ 2069#ifdef PC98 2070 if(IS_8251(com->pc98_if_type)) 2071 goto status_read; 2072 else 2073#endif 2074 line_status = inb(com->line_status_port) & 0x7F; 2075 } 2076 2077 /* modem status change? (always check before doing output) */ 2078#ifdef PC98 2079 if(!IS_8251(com->pc98_if_type)){ 2080#endif 2081 modem_status = inb(com->modem_status_port); 2082 if (modem_status != com->last_modem_status) { 2083 if (com->do_dcd_timestamp 2084 && !(com->last_modem_status & MSR_DCD) 2085 && modem_status & MSR_DCD) 2086 microtime(&com->dcd_timestamp); 2087 2088 /* 2089 * Schedule high level to handle DCD changes. Note 2090 * that we don't use the delta bits anywhere. Some 2091 * UARTs mess them up, and it's easy to remember the 2092 * previous bits and calculate the delta. 2093 */ 2094 com->last_modem_status = modem_status; 2095 if (!(com->state & CS_CHECKMSR)) { 2096 com_events += LOTS_OF_EVENTS; 2097 com->state |= CS_CHECKMSR; 2098 setsofttty(); 2099 } 2100 2101 /* handle CTS change immediately for crisp flow ctl */ 2102 if (com->state & CS_CTS_OFLOW) { 2103 if (modem_status & MSR_CTS) 2104 com->state |= CS_ODEVREADY; 2105 else 2106 com->state &= ~CS_ODEVREADY; 2107 } 2108 } 2109#ifdef PC98 2110 } 2111#endif 2112 2113 /* output queued and everything ready? */ 2114 if (line_status & LSR_TXRDY 2115 && com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) { 2116 ioptr = com->obufq.l_head; 2117 if (com->tx_fifo_size > 1) { 2118 u_int ocount; 2119 2120 ocount = com->obufq.l_tail - ioptr; 2121 if (ocount > com->tx_fifo_size) 2122 ocount = com->tx_fifo_size; 2123 com->bytes_out += ocount; 2124 do 2125 outb(com->data_port, *ioptr++); 2126 while (--ocount != 0); 2127 } else { 2128 outb(com->data_port, *ioptr++); 2129 ++com->bytes_out; 2130 } 2131#ifdef PC98 2132 if(IS_8251(com->pc98_if_type)) 2133 if ( !(pc98_check_i8251_interrupt(com) & IEN_TxFLAG) ) 2134 com_int_Tx_enable(com); 2135#endif 2136 com->obufq.l_head = ioptr; 2137 if (COM_IIR_TXRDYBUG(com)) { 2138 int_ctl_new = int_ctl | IER_ETXRDY; 2139 } 2140 if (ioptr >= com->obufq.l_tail) { 2141 struct lbq *qp; 2142 2143 qp = com->obufq.l_next; 2144 qp->l_queued = FALSE; 2145 qp = qp->l_next; 2146 if (qp != NULL) { 2147 com->obufq.l_head = qp->l_head; 2148 com->obufq.l_tail = qp->l_tail; 2149 com->obufq.l_next = qp; 2150 } else { 2151 /* output just completed */ 2152 if ( COM_IIR_TXRDYBUG(com) ) { 2153 int_ctl_new = int_ctl & ~IER_ETXRDY; 2154 } 2155 com->state &= ~CS_BUSY; 2156#if defined(PC98) 2157 if(IS_8251(com->pc98_if_type)) 2158 if ( pc98_check_i8251_interrupt(com) & IEN_TxFLAG ) 2159 com_int_Tx_disable(com); 2160#endif 2161 } 2162 if (!(com->state & CS_ODONE)) { 2163 com_events += LOTS_OF_EVENTS; 2164 com->state |= CS_ODONE; 2165 setsofttty(); /* handle at high level ASAP */ 2166 } 2167 } 2168 if ( COM_IIR_TXRDYBUG(com) && (int_ctl != int_ctl_new)) { 2169 outb(com->intr_ctl_port, int_ctl_new); 2170 } 2171 } 2172#ifdef PC98 2173 else if (line_status & LSR_TXRDY) { 2174 if(IS_8251(com->pc98_if_type)) 2175 if ( pc98_check_i8251_interrupt(com) & IEN_TxFLAG ) 2176 com_int_Tx_disable(com); 2177 } 2178 if(IS_8251(com->pc98_if_type)) 2179 if ((tmp = inb(com->sts_port)) & STS8251_RxRDY) 2180 goto more_intr; 2181#endif 2182 2183 /* finished? */ 2184#ifndef COM_MULTIPORT 2185#ifdef PC98 2186 if(IS_8251(com->pc98_if_type)) 2187 return; 2188#endif 2189 if ((inb(com->int_id_port) & IIR_IMASK) == IIR_NOPEND) 2190#endif /* COM_MULTIPORT */ 2191 return; 2192 } 2193} 2194 2195static int 2196sioioctl(dev, cmd, data, flag, p) 2197 dev_t dev; 2198 u_long cmd; 2199 caddr_t data; 2200 int flag; 2201 struct proc *p; 2202{ 2203 struct com_s *com; 2204 int error; 2205 Port_t iobase; 2206 int mynor; 2207 int s; 2208 struct tty *tp; 2209#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 2210 int oldcmd; 2211 struct termios term; 2212#endif 2213 2214 mynor = minor(dev); 2215 com = com_addr(MINOR_TO_UNIT(mynor)); 2216 if (com->gone) 2217 return (ENODEV); 2218 iobase = com->iobase; 2219 if (mynor & CONTROL_MASK) { 2220 struct termios *ct; 2221 2222 switch (mynor & CONTROL_MASK) { 2223 case CONTROL_INIT_STATE: 2224 ct = mynor & CALLOUT_MASK ? &com->it_out : &com->it_in; 2225 break; 2226 case CONTROL_LOCK_STATE: 2227 ct = mynor & CALLOUT_MASK ? &com->lt_out : &com->lt_in; 2228 break; 2229 default: 2230 return (ENODEV); /* /dev/nodev */ 2231 } 2232 switch (cmd) { 2233 case TIOCSETA: 2234 error = suser(p->p_ucred, &p->p_acflag); 2235 if (error != 0) 2236 return (error); 2237 *ct = *(struct termios *)data; 2238 return (0); 2239 case TIOCGETA: 2240 *(struct termios *)data = *ct; 2241 return (0); 2242 case TIOCGETD: 2243 *(int *)data = TTYDISC; 2244 return (0); 2245 case TIOCGWINSZ: 2246 bzero(data, sizeof(struct winsize)); 2247 return (0); 2248#ifdef DSI_SOFT_MODEM 2249 /* 2250 * Download micro-code to Digicom modem. 2251 */ 2252 case TIOCDSIMICROCODE: 2253 { 2254 u_long l; 2255 u_char *p,*pi; 2256 2257 pi = (u_char*)(*(caddr_t*)data); 2258 error = copyin(pi,&l,sizeof l); 2259 if(error) 2260 {return error;}; 2261 pi += sizeof l; 2262 2263 p = malloc(l,M_TEMP,M_NOWAIT); 2264 if(!p) 2265 {return ENOBUFS;} 2266 error = copyin(pi,p,l); 2267 if(error) 2268 {free(p,M_TEMP); return error;}; 2269 if(error = LoadSoftModem( 2270 MINOR_TO_UNIT(mynor),iobase,l,p)) 2271 {free(p,M_TEMP); return error;} 2272 free(p,M_TEMP); 2273 return(0); 2274 } 2275#endif /* DSI_SOFT_MODEM */ 2276 default: 2277 return (ENOTTY); 2278 } 2279 } 2280 tp = com->tp; 2281#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 2282 term = tp->t_termios; 2283 oldcmd = cmd; 2284 error = ttsetcompat(tp, &cmd, data, &term); 2285 if (error != 0) 2286 return (error); 2287 if (cmd != oldcmd) 2288 data = (caddr_t)&term; 2289#endif 2290 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) { 2291 int cc; 2292 struct termios *dt = (struct termios *)data; 2293 struct termios *lt = mynor & CALLOUT_MASK 2294 ? &com->lt_out : &com->lt_in; 2295 2296 dt->c_iflag = (tp->t_iflag & lt->c_iflag) 2297 | (dt->c_iflag & ~lt->c_iflag); 2298 dt->c_oflag = (tp->t_oflag & lt->c_oflag) 2299 | (dt->c_oflag & ~lt->c_oflag); 2300 dt->c_cflag = (tp->t_cflag & lt->c_cflag) 2301 | (dt->c_cflag & ~lt->c_cflag); 2302 dt->c_lflag = (tp->t_lflag & lt->c_lflag) 2303 | (dt->c_lflag & ~lt->c_lflag); 2304 for (cc = 0; cc < NCCS; ++cc) 2305 if (lt->c_cc[cc] != 0) 2306 dt->c_cc[cc] = tp->t_cc[cc]; 2307 if (lt->c_ispeed != 0) 2308 dt->c_ispeed = tp->t_ispeed; 2309 if (lt->c_ospeed != 0) 2310 dt->c_ospeed = tp->t_ospeed; 2311 } 2312 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 2313 if (error != ENOIOCTL) 2314 return (error); 2315 s = spltty(); 2316 error = ttioctl(tp, cmd, data, flag); 2317 disc_optim(tp, &tp->t_termios, com); 2318 if (error != ENOIOCTL) { 2319 splx(s); 2320 return (error); 2321 } 2322#ifdef PC98 2323 if(IS_8251(com->pc98_if_type)){ 2324 switch (cmd) { 2325 case TIOCSBRK: 2326 com_send_break_on( com ); 2327 break; 2328 case TIOCCBRK: 2329 com_send_break_off( com ); 2330 break; 2331 case TIOCSDTR: 2332 com_tiocm_bis(com, TIOCM_DTR | TIOCM_RTS ); 2333 break; 2334 case TIOCCDTR: 2335 com_tiocm_bic(com, TIOCM_DTR); 2336 break; 2337 /* 2338 * XXX should disallow changing MCR_RTS if CS_RTS_IFLOW is set. The 2339 * changes get undone on the next call to comparam(). 2340 */ 2341 case TIOCMSET: 2342 com_tiocm_set( com, *(int *)data ); 2343 break; 2344 case TIOCMBIS: 2345 com_tiocm_bis( com, *(int *)data ); 2346 break; 2347 case TIOCMBIC: 2348 com_tiocm_bic( com, *(int *)data ); 2349 break; 2350 case TIOCMGET: 2351 *(int *)data = com_tiocm_get(com); 2352 break; 2353 case TIOCMSDTRWAIT: 2354 /* must be root since the wait applies to following logins */ 2355 error = suser(p->p_ucred, &p->p_acflag); 2356 if (error != 0) { 2357 splx(s); 2358 return (error); 2359 } 2360 com->dtr_wait = *(int *)data * hz / 100; 2361 break; 2362 case TIOCMGDTRWAIT: 2363 *(int *)data = com->dtr_wait * 100 / hz; 2364 break; 2365 case TIOCTIMESTAMP: 2366 com->do_timestamp = TRUE; 2367 *(struct timeval *)data = com->timestamp; 2368 break; 2369 case TIOCDCDTIMESTAMP: 2370 com->do_dcd_timestamp = TRUE; 2371 *(struct timeval *)data = com->dcd_timestamp; 2372 break; 2373 default: 2374 splx(s); 2375 return (ENOTTY); 2376 } 2377 } else { 2378#endif 2379 switch (cmd) { 2380 case TIOCSBRK: 2381 outb(iobase + com_cfcr, com->cfcr_image |= CFCR_SBREAK); 2382 break; 2383 case TIOCCBRK: 2384 outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK); 2385 break; 2386 case TIOCSDTR: 2387 (void)commctl(com, TIOCM_DTR, DMBIS); 2388 break; 2389 case TIOCCDTR: 2390 (void)commctl(com, TIOCM_DTR, DMBIC); 2391 break; 2392 /* 2393 * XXX should disallow changing MCR_RTS if CS_RTS_IFLOW is set. The 2394 * changes get undone on the next call to comparam(). 2395 */ 2396 case TIOCMSET: 2397 (void)commctl(com, *(int *)data, DMSET); 2398 break; 2399 case TIOCMBIS: 2400 (void)commctl(com, *(int *)data, DMBIS); 2401 break; 2402 case TIOCMBIC: 2403 (void)commctl(com, *(int *)data, DMBIC); 2404 break; 2405 case TIOCMGET: 2406 *(int *)data = commctl(com, 0, DMGET); 2407 break; 2408 case TIOCMSDTRWAIT: 2409 /* must be root since the wait applies to following logins */ 2410 error = suser(p->p_ucred, &p->p_acflag); 2411 if (error != 0) { 2412 splx(s); 2413 return (error); 2414 } 2415 com->dtr_wait = *(int *)data * hz / 100; 2416 break; 2417 case TIOCMGDTRWAIT: 2418 *(int *)data = com->dtr_wait * 100 / hz; 2419 break; 2420 case TIOCTIMESTAMP: 2421 com->do_timestamp = TRUE; 2422 *(struct timeval *)data = com->timestamp; 2423 break; 2424 case TIOCDCDTIMESTAMP: 2425 com->do_dcd_timestamp = TRUE; 2426 *(struct timeval *)data = com->dcd_timestamp; 2427 break; 2428 default: 2429 splx(s); 2430 return (ENOTTY); 2431 } 2432#ifdef PC98 2433 } 2434#endif 2435 splx(s); 2436 return (0); 2437} 2438 2439void 2440siopoll() 2441{ 2442 int unit; 2443 2444 if (com_events == 0) 2445 return; 2446repeat: 2447 for (unit = 0; unit < NSIOTOT; ++unit) { 2448 u_char *buf; 2449 struct com_s *com; 2450 u_char *ibuf; 2451 int incc; 2452 struct tty *tp; 2453#ifdef PC98 2454 int tmp; 2455#endif 2456 2457 com = com_addr(unit); 2458 if (com == NULL) 2459 continue; 2460 if (com->gone) 2461 continue; 2462 tp = com->tp; 2463 if (tp == NULL) { 2464 /* 2465 * XXX forget any events related to closed devices 2466 * (actually never opened devices) so that we don't 2467 * loop. 2468 */ 2469 disable_intr(); 2470 incc = com->iptr - com->ibuf; 2471 com->iptr = com->ibuf; 2472 if (com->state & CS_CHECKMSR) { 2473 incc += LOTS_OF_EVENTS; 2474 com->state &= ~CS_CHECKMSR; 2475 } 2476 com_events -= incc; 2477 enable_intr(); 2478 if (incc != 0) 2479 log(LOG_DEBUG, 2480 "sio%d: %d events for device with no tp\n", 2481 unit, incc); 2482 continue; 2483 } 2484 2485 /* switch the role of the low-level input buffers */ 2486 if (com->iptr == (ibuf = com->ibuf)) { 2487 buf = NULL; /* not used, but compiler can't tell */ 2488 incc = 0; 2489 } else { 2490 buf = ibuf; 2491 disable_intr(); 2492 incc = com->iptr - buf; 2493 com_events -= incc; 2494 if (ibuf == com->ibuf1) 2495 ibuf = com->ibuf2; 2496 else 2497 ibuf = com->ibuf1; 2498 com->ibufend = ibuf + RS_IBUFSIZE; 2499 com->ihighwater = ibuf + RS_IHIGHWATER; 2500 com->iptr = ibuf; 2501 2502 /* 2503 * There is now room for another low-level buffer full 2504 * of input, so enable RTS if it is now disabled and 2505 * there is room in the high-level buffer. 2506 */ 2507#ifdef PC98 2508 if(IS_8251(com->pc98_if_type)) 2509 tmp = com_tiocm_get(com) & TIOCM_RTS; 2510 else 2511 tmp = com->mcr_image & MCR_RTS; 2512#endif 2513 if ((com->state & CS_RTS_IFLOW) 2514#ifdef PC98 2515 && !(tmp) 2516#else 2517 && !(com->mcr_image & MCR_RTS) 2518#endif 2519 && !(tp->t_state & TS_TBLOCK)) 2520#ifdef PC98 2521 if(IS_8251(com->pc98_if_type)) 2522 com_tiocm_bis(com, TIOCM_RTS); 2523 else 2524#endif 2525 outb(com->modem_ctl_port, 2526 com->mcr_image |= MCR_RTS); 2527 enable_intr(); 2528 com->ibuf = ibuf; 2529 } 2530 2531 if (com->state & CS_CHECKMSR) { 2532 u_char delta_modem_status; 2533 2534#ifdef PC98 2535 if(!IS_8251(com->pc98_if_type)){ 2536#endif 2537 disable_intr(); 2538 delta_modem_status = com->last_modem_status 2539 ^ com->prev_modem_status; 2540 com->prev_modem_status = com->last_modem_status; 2541 com_events -= LOTS_OF_EVENTS; 2542 com->state &= ~CS_CHECKMSR; 2543 enable_intr(); 2544 if (delta_modem_status & MSR_DCD) 2545 (*linesw[tp->t_line].l_modem) 2546 (tp, com->prev_modem_status & MSR_DCD); 2547#ifdef PC98 2548 } 2549#endif 2550 } 2551 if (com->state & CS_ODONE) { 2552 disable_intr(); 2553 com_events -= LOTS_OF_EVENTS; 2554 com->state &= ~CS_ODONE; 2555 enable_intr(); 2556 if (!(com->state & CS_BUSY) 2557 && !(com->extra_state & CSE_BUSYCHECK)) { 2558 timeout(siobusycheck, com, hz / 100); 2559 com->extra_state |= CSE_BUSYCHECK; 2560 } 2561 (*linesw[tp->t_line].l_start)(tp); 2562 } 2563 if (incc <= 0 || !(tp->t_state & TS_ISOPEN) || 2564 !(tp->t_cflag & CREAD)) 2565 continue; 2566 /* 2567 * Avoid the grotesquely inefficient lineswitch routine 2568 * (ttyinput) in "raw" mode. It usually takes about 450 2569 * instructions (that's without canonical processing or echo!). 2570 * slinput is reasonably fast (usually 40 instructions plus 2571 * call overhead). 2572 */ 2573 if (tp->t_state & TS_CAN_BYPASS_L_RINT) { 2574 if (tp->t_rawq.c_cc + incc >= RB_I_HIGH_WATER 2575 && (com->state & CS_RTS_IFLOW 2576 || tp->t_iflag & IXOFF) 2577 && !(tp->t_state & TS_TBLOCK)) 2578 ttyblock(tp); 2579 tk_nin += incc; 2580 tk_rawcc += incc; 2581 tp->t_rawcc += incc; 2582 com->delta_error_counts[CE_TTY_BUF_OVERFLOW] 2583 += b_to_q((char *)buf, incc, &tp->t_rawq); 2584 ttwakeup(tp); 2585 if (tp->t_state & TS_TTSTOP 2586 && (tp->t_iflag & IXANY 2587 || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) { 2588 tp->t_state &= ~TS_TTSTOP; 2589 tp->t_lflag &= ~FLUSHO; 2590 comstart(tp); 2591 } 2592 } else { 2593 do { 2594 u_char line_status; 2595 int recv_data; 2596 2597 line_status = (u_char) buf[CE_INPUT_OFFSET]; 2598 recv_data = (u_char) *buf++; 2599 if (line_status 2600 & (LSR_BI | LSR_FE | LSR_OE | LSR_PE)) { 2601 if (line_status & LSR_BI) 2602 recv_data |= TTY_BI; 2603 if (line_status & LSR_FE) 2604 recv_data |= TTY_FE; 2605 if (line_status & LSR_OE) 2606 recv_data |= TTY_OE; 2607 if (line_status & LSR_PE) 2608 recv_data |= TTY_PE; 2609 } 2610 (*linesw[tp->t_line].l_rint)(recv_data, tp); 2611 } while (--incc > 0); 2612 } 2613 if (com_events == 0) 2614 break; 2615 } 2616 if (com_events >= LOTS_OF_EVENTS) 2617 goto repeat; 2618} 2619 2620static int 2621comparam(tp, t) 2622 struct tty *tp; 2623 struct termios *t; 2624{ 2625 u_int cfcr; 2626 int cflag; 2627 struct com_s *com; 2628 int divisor; 2629 u_char dlbh; 2630 u_char dlbl; 2631 int error; 2632 Port_t iobase; 2633 int s; 2634 int unit; 2635 int txtimeout; 2636#ifdef PC98 2637 Port_t tmp_port; 2638 int tmp_flg; 2639#endif 2640 2641#ifdef PC98 2642 cfcr = 0; 2643 unit = DEV_TO_UNIT(tp->t_dev); 2644 com = com_addr(unit); 2645 iobase = com->iobase; 2646 if(IS_8251(com->pc98_if_type)) { 2647 divisor = pc98_ttspeedtab(com, t->c_ospeed); 2648 } else 2649#endif 2650 /* do historical conversions */ 2651 if (t->c_ispeed == 0) 2652 t->c_ispeed = t->c_ospeed; 2653 2654 /* check requested parameters */ 2655 divisor = ttspeedtab(t->c_ospeed, comspeedtab); 2656 if (divisor < 0 || divisor > 0 && t->c_ispeed != t->c_ospeed) 2657 return (EINVAL); 2658 2659 /* parameters are OK, convert them to the com struct and the device */ 2660#ifndef PC98 2661 unit = DEV_TO_UNIT(tp->t_dev); 2662 com = com_addr(unit); 2663 iobase = com->iobase; 2664#endif 2665 s = spltty(); 2666#ifdef PC98 2667 if(IS_8251(com->pc98_if_type)){ 2668 if(divisor == 0) 2669 com_tiocm_bic( com, TIOCM_DTR|TIOCM_RTS|TIOCM_LE ); 2670 else 2671 com_tiocm_bis( com, TIOCM_DTR|TIOCM_RTS|TIOCM_LE ); 2672 } else { 2673#endif 2674 if (divisor == 0) 2675 (void)commctl(com, TIOCM_DTR, DMBIC); /* hang up line */ 2676 else 2677 (void)commctl(com, TIOCM_DTR, DMBIS); 2678#ifdef PC98 2679 } 2680#endif 2681 cflag = t->c_cflag; 2682#ifdef PC98 2683 if(!IS_8251(com->pc98_if_type)){ 2684#endif 2685 switch (cflag & CSIZE) { 2686 case CS5: 2687 cfcr = CFCR_5BITS; 2688 break; 2689 case CS6: 2690 cfcr = CFCR_6BITS; 2691 break; 2692 case CS7: 2693 cfcr = CFCR_7BITS; 2694 break; 2695 default: 2696 cfcr = CFCR_8BITS; 2697 break; 2698 } 2699 if (cflag & PARENB) { 2700 cfcr |= CFCR_PENAB; 2701 if (!(cflag & PARODD)) 2702 cfcr |= CFCR_PEVEN; 2703 } 2704 if (cflag & CSTOPB) 2705 cfcr |= CFCR_STOPB; 2706 2707 if (com->hasfifo && divisor != 0) { 2708 /* 2709 * Use a fifo trigger level low enough so that the input 2710 * latency from the fifo is less than about 16 msec and 2711 * the total latency is less than about 30 msec. These 2712 * latencies are reasonable for humans. Serial comms 2713 * protocols shouldn't expect anything better since modem 2714 * latencies are larger. 2715 */ 2716 com->fifo_image = t->c_ospeed <= 4800 2717 ? FIFO_ENABLE : FIFO_ENABLE | FIFO_RX_HIGH; 2718#ifdef COM_ESP 2719 /* 2720 * The Hayes ESP card needs the fifo DMA mode bit set 2721 * in compatibility mode. If not, it will interrupt 2722 * for each character received. 2723 */ 2724 if (com->esp) 2725 com->fifo_image |= FIFO_DMA_MODE; 2726#endif 2727 outb(iobase + com_fifo, com->fifo_image); 2728 } 2729 2730 /* 2731 * Some UARTs lock up if the divisor latch registers are selected 2732 * while the UART is doing output (they refuse to transmit anything 2733 * more until given a hard reset). Fix this by stopping filling 2734 * the device buffers and waiting for them to drain. Reading the 2735 * line status port outside of siointr1() might lose some receiver 2736 * error bits, but that is acceptable here. 2737 */ 2738#ifdef PC98 2739 } 2740#endif 2741 disable_intr(); 2742retry: 2743 com->state &= ~CS_TTGO; 2744 txtimeout = tp->t_timeout; 2745 enable_intr(); 2746#ifdef PC98 2747 if(IS_8251(com->pc98_if_type)){ 2748 tmp_port = com->sts_port; 2749 tmp_flg = (STS8251_TxRDY|STS8251_TxEMP); 2750 } else { 2751 tmp_port = com->line_status_port; 2752 tmp_flg = (LSR_TSRE|LSR_TXRDY); 2753 } 2754 while ((inb(tmp_port) & tmp_flg) != tmp_flg) { 2755#else 2756 while ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY)) 2757 != (LSR_TSRE | LSR_TXRDY)) { 2758#endif 2759 tp->t_state |= TS_SO_OCOMPLETE; 2760 error = ttysleep(tp, TSA_OCOMPLETE(tp), TTIPRI | PCATCH, 2761 "siotx", hz / 100); 2762 if ( txtimeout != 0 2763 && (!error || error == EAGAIN) 2764 && (txtimeout -= hz / 100) <= 0 2765 ) 2766 error = EIO; 2767 if (com->gone) 2768 error = ENODEV; 2769 if (error != 0 && error != EAGAIN) { 2770 if (!(tp->t_state & TS_TTSTOP)) { 2771 disable_intr(); 2772 com->state |= CS_TTGO; 2773 enable_intr(); 2774 } 2775 splx(s); 2776 return (error); 2777 } 2778 } 2779 2780 disable_intr(); /* very important while com_data is hidden */ 2781 2782 /* 2783 * XXX - clearing CS_TTGO is not sufficient to stop further output, 2784 * because siopoll() calls comstart() which usually sets it again 2785 * because TS_TTSTOP is clear. Setting TS_TTSTOP would not be 2786 * sufficient, for similar reasons. 2787 */ 2788#ifdef PC98 2789 if ((inb(tmp_port) & tmp_flg) != tmp_flg) 2790#else 2791 if ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY)) 2792 != (LSR_TSRE | LSR_TXRDY)) 2793#endif 2794 goto retry; 2795 2796#ifdef PC98 2797 if(!IS_8251(com->pc98_if_type)){ 2798#endif 2799 if (divisor != 0) { 2800 outb(iobase + com_cfcr, cfcr | CFCR_DLAB); 2801 /* 2802 * Only set the divisor registers if they would change, 2803 * since on some 16550 incompatibles (UMC8669F), setting 2804 * them while input is arriving them loses sync until 2805 * data stops arriving. 2806 */ 2807 dlbl = divisor & 0xFF; 2808 if (inb(iobase + com_dlbl) != dlbl) 2809 outb(iobase + com_dlbl, dlbl); 2810 dlbh = (u_int) divisor >> 8; 2811 if (inb(iobase + com_dlbh) != dlbh) 2812 outb(iobase + com_dlbh, dlbh); 2813 } 2814 2815 2816 outb(iobase + com_cfcr, com->cfcr_image = cfcr); 2817 2818#ifdef PC98 2819 } else 2820 com_cflag_and_speed_set(com, cflag, t->c_ospeed); 2821#endif 2822 if (!(tp->t_state & TS_TTSTOP)) 2823 com->state |= CS_TTGO; 2824 2825 if (cflag & CRTS_IFLOW) { 2826 if (com->st16650a) { 2827 outb(iobase + com_cfcr, 0xbf); 2828 outb(iobase + com_fifo, inb(iobase + com_fifo) | 0x40); 2829 } 2830 com->state |= CS_RTS_IFLOW; 2831 /* 2832 * If CS_RTS_IFLOW just changed from off to on, the change 2833 * needs to be propagated to MCR_RTS. This isn't urgent, 2834 * so do it later by calling comstart() instead of repeating 2835 * a lot of code from comstart() here. 2836 */ 2837 } else if (com->state & CS_RTS_IFLOW) { 2838 com->state &= ~CS_RTS_IFLOW; 2839 /* 2840 * CS_RTS_IFLOW just changed from on to off. Force MCR_RTS 2841 * on here, since comstart() won't do it later. 2842 */ 2843#ifdef PC98 2844 if(IS_8251(com->pc98_if_type)) 2845 com_tiocm_bis(com, TIOCM_RTS); 2846 else 2847#endif 2848 outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS); 2849 if (com->st16650a) { 2850 outb(iobase + com_cfcr, 0xbf); 2851 outb(iobase + com_fifo, inb(iobase + com_fifo) & ~0x40); 2852 } 2853 } 2854 2855 2856 /* 2857 * Set up state to handle output flow control. 2858 * XXX - worth handling MDMBUF (DCD) flow control at the lowest level? 2859 * Now has 10+ msec latency, while CTS flow has 50- usec latency. 2860 */ 2861 com->state |= CS_ODEVREADY; 2862 com->state &= ~CS_CTS_OFLOW; 2863 if (cflag & CCTS_OFLOW) { 2864 com->state |= CS_CTS_OFLOW; 2865#ifdef PC98 2866 if(IS_8251(com->pc98_if_type)){ 2867 if (!(pc98_get_modem_status(com) & TIOCM_CTS)) 2868 com->state &= ~CS_ODEVREADY; 2869 } else { 2870#endif 2871 if (!(com->last_modem_status & MSR_CTS)) 2872 com->state &= ~CS_ODEVREADY; 2873 if (com->st16650a) { 2874 outb(iobase + com_cfcr, 0xbf); 2875 outb(iobase + com_fifo, inb(iobase + com_fifo) | 0x80); 2876 } 2877#ifdef PC98 2878 } 2879#endif 2880 } else { 2881 if (com->st16650a) { 2882 outb(iobase + com_cfcr, 0xbf); 2883 outb(iobase + com_fifo, inb(iobase + com_fifo) & ~0x80); 2884 } 2885 } 2886 2887 2888 outb(iobase + com_cfcr, com->cfcr_image); 2889 2890 2891 /* XXX shouldn't call functions while intrs are disabled. */ 2892 disc_optim(tp, t, com); 2893 /* 2894 * Recover from fiddling with CS_TTGO. We used to call siointr1() 2895 * unconditionally, but that defeated the careful discarding of 2896 * stale input in sioopen(). 2897 */ 2898 if (com->state >= (CS_BUSY | CS_TTGO)) 2899 siointr1(com); 2900 2901 enable_intr(); 2902 splx(s); 2903 comstart(tp); 2904 return (0); 2905} 2906 2907static void 2908comstart(tp) 2909 struct tty *tp; 2910{ 2911 struct com_s *com; 2912 int s; 2913 int unit; 2914#ifdef PC98 2915 int tmp; 2916#endif 2917 2918 unit = DEV_TO_UNIT(tp->t_dev); 2919 com = com_addr(unit); 2920 s = spltty(); 2921 disable_intr(); 2922 if (tp->t_state & TS_TTSTOP) 2923 com->state &= ~CS_TTGO; 2924 else 2925 com->state |= CS_TTGO; 2926 if (tp->t_state & TS_TBLOCK) { 2927#ifdef PC98 2928 if(IS_8251(com->pc98_if_type)) 2929 tmp = com_tiocm_get(com) & TIOCM_RTS; 2930 else 2931 tmp = com->mcr_image & MCR_RTS; 2932 if (tmp && (com->state & CS_RTS_IFLOW)) 2933#else 2934 if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW) 2935#endif 2936#ifdef PC98 2937 if(IS_8251(com->pc98_if_type)) 2938 com_tiocm_bic(com, TIOCM_RTS); 2939 else 2940#endif 2941 outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS); 2942 } else { 2943#ifdef PC98 2944 if(IS_8251(com->pc98_if_type)) 2945 tmp = com_tiocm_get(com) & TIOCM_RTS; 2946 else 2947 tmp = com->mcr_image & MCR_RTS; 2948 if (!(tmp) && com->iptr < com->ihighwater 2949 && com->state & CS_RTS_IFLOW) 2950#else 2951 if (!(com->mcr_image & MCR_RTS) && com->iptr < com->ihighwater 2952 && com->state & CS_RTS_IFLOW) 2953#endif 2954#ifdef PC98 2955 if(IS_8251(com->pc98_if_type)) 2956 com_tiocm_bis(com, TIOCM_RTS); 2957 else 2958#endif 2959 outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS); 2960 } 2961 enable_intr(); 2962 if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) { 2963 ttwwakeup(tp); 2964#ifdef PC98 2965/* if(IS_8251(com->pc98_if_type)) 2966 com_int_Tx_enable(com); */ 2967#endif 2968 splx(s); 2969 return; 2970 } 2971 if (tp->t_outq.c_cc != 0) { 2972 struct lbq *qp; 2973 struct lbq *next; 2974 2975 if (!com->obufs[0].l_queued) { 2976 com->obufs[0].l_tail 2977 = com->obuf1 + q_to_b(&tp->t_outq, com->obuf1, 2978 sizeof com->obuf1); 2979 com->obufs[0].l_next = NULL; 2980 com->obufs[0].l_queued = TRUE; 2981 disable_intr(); 2982 if (com->state & CS_BUSY) { 2983 qp = com->obufq.l_next; 2984 while ((next = qp->l_next) != NULL) 2985 qp = next; 2986 qp->l_next = &com->obufs[0]; 2987 } else { 2988 com->obufq.l_head = com->obufs[0].l_head; 2989 com->obufq.l_tail = com->obufs[0].l_tail; 2990 com->obufq.l_next = &com->obufs[0]; 2991 com->state |= CS_BUSY; 2992 } 2993 enable_intr(); 2994 } 2995 if (tp->t_outq.c_cc != 0 && !com->obufs[1].l_queued) { 2996 com->obufs[1].l_tail 2997 = com->obuf2 + q_to_b(&tp->t_outq, com->obuf2, 2998 sizeof com->obuf2); 2999 com->obufs[1].l_next = NULL; 3000 com->obufs[1].l_queued = TRUE; 3001 disable_intr(); 3002 if (com->state & CS_BUSY) { 3003 qp = com->obufq.l_next; 3004 while ((next = qp->l_next) != NULL) 3005 qp = next; 3006 qp->l_next = &com->obufs[1]; 3007 } else { 3008 com->obufq.l_head = com->obufs[1].l_head; 3009 com->obufq.l_tail = com->obufs[1].l_tail; 3010 com->obufq.l_next = &com->obufs[1]; 3011 com->state |= CS_BUSY; 3012 } 3013 enable_intr(); 3014 } 3015 tp->t_state |= TS_BUSY; 3016 } 3017 disable_intr(); 3018 if (com->state >= (CS_BUSY | CS_TTGO)) 3019 siointr1(com); /* fake interrupt to start output */ 3020 enable_intr(); 3021#ifdef PC98 3022/* if(IS_8251(com->pc98_if_type)) 3023 com_int_Tx_enable(com); */ 3024#endif 3025 ttwwakeup(tp); 3026 splx(s); 3027} 3028 3029static void 3030siostop(tp, rw) 3031 struct tty *tp; 3032 int rw; 3033{ 3034 struct com_s *com; 3035 3036 com = com_addr(DEV_TO_UNIT(tp->t_dev)); 3037 if (com->gone) 3038 return; 3039 disable_intr(); 3040 if (rw & FWRITE) { 3041 if (com->hasfifo) 3042#ifdef COM_ESP 3043 /* XXX avoid h/w bug. */ 3044 if (!com->esp) 3045#endif 3046 /* XXX does this flush everything? */ 3047 outb(com->iobase + com_fifo, 3048 FIFO_XMT_RST | com->fifo_image); 3049 com->obufs[0].l_queued = FALSE; 3050 com->obufs[1].l_queued = FALSE; 3051 if (com->state & CS_ODONE) 3052 com_events -= LOTS_OF_EVENTS; 3053 com->state &= ~(CS_ODONE | CS_BUSY); 3054 com->tp->t_state &= ~TS_BUSY; 3055 } 3056 if (rw & FREAD) { 3057 if (com->hasfifo) 3058#ifdef COM_ESP 3059 /* XXX avoid h/w bug. */ 3060 if (!com->esp) 3061#endif 3062 /* XXX does this flush everything? */ 3063 outb(com->iobase + com_fifo, 3064 FIFO_RCV_RST | com->fifo_image); 3065 com_events -= (com->iptr - com->ibuf); 3066 com->iptr = com->ibuf; 3067 } 3068 enable_intr(); 3069 comstart(tp); 3070} 3071 3072static struct tty * 3073siodevtotty(dev) 3074 dev_t dev; 3075{ 3076 int mynor; 3077 int unit; 3078 3079 mynor = minor(dev); 3080 if (mynor & CONTROL_MASK) 3081 return (NULL); 3082 unit = MINOR_TO_UNIT(mynor); 3083 if ((u_int) unit >= NSIOTOT) 3084 return (NULL); 3085 return (&sio_tty[unit]); 3086} 3087 3088static int 3089commctl(com, bits, how) 3090 struct com_s *com; 3091 int bits; 3092 int how; 3093{ 3094 int mcr; 3095 int msr; 3096 3097 if (how == DMGET) { 3098 bits = TIOCM_LE; /* XXX - always enabled while open */ 3099 mcr = com->mcr_image; 3100 if (mcr & MCR_DTR) 3101 bits |= TIOCM_DTR; 3102 if (mcr & MCR_RTS) 3103 bits |= TIOCM_RTS; 3104 msr = com->prev_modem_status; 3105 if (msr & MSR_CTS) 3106 bits |= TIOCM_CTS; 3107 if (msr & MSR_DCD) 3108 bits |= TIOCM_CD; 3109 if (msr & MSR_DSR) 3110 bits |= TIOCM_DSR; 3111 /* 3112 * XXX - MSR_RI is naturally volatile, and we make MSR_TERI 3113 * more volatile by reading the modem status a lot. Perhaps 3114 * we should latch both bits until the status is read here. 3115 */ 3116 if (msr & (MSR_RI | MSR_TERI)) 3117 bits |= TIOCM_RI; 3118 return (bits); 3119 } 3120 mcr = 0; 3121 if (bits & TIOCM_DTR) 3122 mcr |= MCR_DTR; 3123 if (bits & TIOCM_RTS) 3124 mcr |= MCR_RTS; 3125 if (com->gone) 3126 return(0); 3127 disable_intr(); 3128 switch (how) { 3129 case DMSET: 3130 outb(com->modem_ctl_port, 3131 com->mcr_image = mcr | (com->mcr_image & MCR_IENABLE)); 3132 break; 3133 case DMBIS: 3134 outb(com->modem_ctl_port, com->mcr_image |= mcr); 3135 break; 3136 case DMBIC: 3137 outb(com->modem_ctl_port, com->mcr_image &= ~mcr); 3138 break; 3139 } 3140 enable_intr(); 3141 return (0); 3142} 3143 3144static void 3145siosettimeout() 3146{ 3147 struct com_s *com; 3148 bool_t someopen; 3149 int unit; 3150 3151 /* 3152 * Set our timeout period to 1 second if no polled devices are open. 3153 * Otherwise set it to max(1/200, 1/hz). 3154 * Enable timeouts iff some device is open. 3155 */ 3156 untimeout(comwakeup, (void *)NULL, sio_timeout_handle); 3157 sio_timeout = hz; 3158 someopen = FALSE; 3159 for (unit = 0; unit < NSIOTOT; ++unit) { 3160 com = com_addr(unit); 3161 if (com != NULL && com->tp != NULL 3162 && com->tp->t_state & TS_ISOPEN && !com->gone) { 3163 someopen = TRUE; 3164 if (com->poll || com->poll_output) { 3165 sio_timeout = hz > 200 ? hz / 200 : 1; 3166 break; 3167 } 3168 } 3169 } 3170 if (someopen) { 3171 sio_timeouts_until_log = hz / sio_timeout; 3172 sio_timeout_handle = timeout(comwakeup, (void *)NULL, 3173 sio_timeout); 3174 } else { 3175 /* Flush error messages, if any. */ 3176 sio_timeouts_until_log = 1; 3177 comwakeup((void *)NULL); 3178 untimeout(comwakeup, (void *)NULL, sio_timeout_handle); 3179 } 3180} 3181 3182static void 3183comwakeup(chan) 3184 void *chan; 3185{ 3186 struct com_s *com; 3187 int unit; 3188 3189 sio_timeout_handle = timeout(comwakeup, (void *)NULL, sio_timeout); 3190 3191 /* 3192 * Recover from lost output interrupts. 3193 * Poll any lines that don't use interrupts. 3194 */ 3195 for (unit = 0; unit < NSIOTOT; ++unit) { 3196 com = com_addr(unit); 3197 if (com != NULL && !com->gone 3198 && (com->state >= (CS_BUSY | CS_TTGO) || com->poll)) { 3199 disable_intr(); 3200 siointr1(com); 3201 enable_intr(); 3202 } 3203 } 3204 3205 /* 3206 * Check for and log errors, but not too often. 3207 */ 3208 if (--sio_timeouts_until_log > 0) 3209 return; 3210 sio_timeouts_until_log = hz / sio_timeout; 3211 for (unit = 0; unit < NSIOTOT; ++unit) { 3212 int errnum; 3213 3214 com = com_addr(unit); 3215 if (com == NULL) 3216 continue; 3217 if (com->gone) 3218 continue; 3219 for (errnum = 0; errnum < CE_NTYPES; ++errnum) { 3220 u_int delta; 3221 u_long total; 3222 3223 disable_intr(); 3224 delta = com->delta_error_counts[errnum]; 3225 com->delta_error_counts[errnum] = 0; 3226 enable_intr(); 3227 if (delta == 0) 3228 continue; 3229 total = com->error_counts[errnum] += delta; 3230 log(LOG_ERR, "sio%d: %u more %s%s (total %lu)\n", 3231 unit, delta, error_desc[errnum], 3232 delta == 1 ? "" : "s", total); 3233 } 3234 } 3235} 3236 3237#ifdef PC98 3238/* commint is called when modem control line changes */ 3239static void 3240commint(dev_t dev) 3241{ 3242 register struct tty *tp; 3243 int stat,delta; 3244 struct com_s *com; 3245 int mynor,unit; 3246 3247 mynor = minor(dev); 3248 unit = MINOR_TO_UNIT(mynor); 3249 com = com_addr(unit); 3250 tp = com->tp; 3251 3252 stat = com_tiocm_get(com); 3253 delta = com_tiocm_get_delta(com); 3254 3255 if (com->state & CS_CTS_OFLOW) { 3256 if (stat & TIOCM_CTS) 3257 com->state |= CS_ODEVREADY; 3258 else 3259 com->state &= ~CS_ODEVREADY; 3260 } 3261 if ((delta & TIOCM_CAR) && (mynor & CALLOUT_MASK) == 0) { 3262 if (stat & TIOCM_CAR ) 3263 (void)(*linesw[tp->t_line].l_modem)(tp, 1); 3264 else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) { 3265 /* negate DTR, RTS */ 3266 com_tiocm_bic(com, (tp->t_cflag & HUPCL) ? 3267 TIOCM_DTR|TIOCM_RTS|TIOCM_LE : TIOCM_LE ); 3268 /* disable IENABLE */ 3269 com_int_TxRx_disable( com ); 3270 } 3271 } 3272} 3273#endif 3274 3275static void 3276disc_optim(tp, t, com) 3277 struct tty *tp; 3278 struct termios *t; 3279 struct com_s *com; 3280{ 3281 if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON)) 3282 && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK)) 3283 && (!(t->c_iflag & PARMRK) 3284 || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK)) 3285 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN)) 3286 && linesw[tp->t_line].l_rint == ttyinput) 3287 tp->t_state |= TS_CAN_BYPASS_L_RINT; 3288 else 3289 tp->t_state &= ~TS_CAN_BYPASS_L_RINT; 3290 com->hotchar = linesw[tp->t_line].l_hotchar; 3291} 3292 3293/* 3294 * Following are all routines needed for SIO to act as console 3295 */ 3296#include <machine/cons.h> 3297 3298struct siocnstate { 3299 u_char dlbl; 3300 u_char dlbh; 3301 u_char ier; 3302 u_char cfcr; 3303 u_char mcr; 3304}; 3305 3306static speed_t siocngetspeed __P((Port_t, struct speedtab *)); 3307static void siocnclose __P((struct siocnstate *sp)); 3308static void siocnopen __P((struct siocnstate *sp)); 3309static void siocntxwait __P((void)); 3310 3311static void 3312siocntxwait() 3313{ 3314 int timo; 3315 3316 /* 3317 * Wait for any pending transmission to finish. Required to avoid 3318 * the UART lockup bug when the speed is changed, and for normal 3319 * transmits. 3320 */ 3321 timo = 100000; 3322 while ((inb(siocniobase + com_lsr) & (LSR_TSRE | LSR_TXRDY)) 3323 != (LSR_TSRE | LSR_TXRDY) && --timo != 0) 3324 ; 3325} 3326 3327/* 3328 * Read the serial port specified and try to figure out what speed 3329 * it's currently running at. We're assuming the serial port has 3330 * been initialized and is basicly idle. This routine is only intended 3331 * to be run at system startup. 3332 * 3333 * If the value read from the serial port doesn't make sense, return 0. 3334 */ 3335 3336static speed_t 3337siocngetspeed(iobase, table) 3338 Port_t iobase; 3339 struct speedtab *table; 3340{ 3341 int code; 3342 u_char dlbh; 3343 u_char dlbl; 3344 u_char cfcr; 3345 3346 cfcr = inb(iobase + com_cfcr); 3347 outb(iobase + com_cfcr, CFCR_DLAB | cfcr); 3348 3349 dlbl = inb(iobase + com_dlbl); 3350 dlbh = inb(iobase + com_dlbh); 3351 3352 outb(iobase + com_cfcr, cfcr); 3353 3354 code = dlbh << 8 | dlbl; 3355 3356 for ( ; table->sp_speed != -1; table++) 3357 if (table->sp_code == code) 3358 return (table->sp_speed); 3359 3360 return 0; /* didn't match anything sane */ 3361} 3362 3363static void 3364siocnopen(sp) 3365 struct siocnstate *sp; 3366{ 3367 int divisor; 3368 u_char dlbh; 3369 u_char dlbl; 3370 Port_t iobase; 3371 3372 /* 3373 * Save all the device control registers except the fifo register 3374 * and set our default ones (cs8 -parenb speed=comdefaultrate). 3375 * We can't save the fifo register since it is read-only. 3376 */ 3377 iobase = siocniobase; 3378 sp->ier = inb(iobase + com_ier); 3379 outb(iobase + com_ier, 0); /* spltty() doesn't stop siointr() */ 3380 siocntxwait(); 3381 sp->cfcr = inb(iobase + com_cfcr); 3382 outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS); 3383 sp->dlbl = inb(iobase + com_dlbl); 3384 sp->dlbh = inb(iobase + com_dlbh); 3385 /* 3386 * Only set the divisor registers if they would change, since on 3387 * some 16550 incompatibles (Startech), setting them clears the 3388 * data input register. This also reduces the effects of the 3389 * UMC8669F bug. 3390 */ 3391 divisor = ttspeedtab(comdefaultrate, comspeedtab); 3392 dlbl = divisor & 0xFF; 3393 if (sp->dlbl != dlbl) 3394 outb(iobase + com_dlbl, dlbl); 3395 dlbh = (u_int) divisor >> 8; 3396 if (sp->dlbh != dlbh) 3397 outb(iobase + com_dlbh, dlbh); 3398 outb(iobase + com_cfcr, CFCR_8BITS); 3399 sp->mcr = inb(iobase + com_mcr); 3400 /* 3401 * We don't want interrupts, but must be careful not to "disable" 3402 * them by clearing the MCR_IENABLE bit, since that might cause 3403 * an interrupt by floating the IRQ line. 3404 */ 3405 outb(iobase + com_mcr, (sp->mcr & MCR_IENABLE) | MCR_DTR | MCR_RTS); 3406} 3407 3408static void 3409siocnclose(sp) 3410 struct siocnstate *sp; 3411{ 3412 Port_t iobase; 3413 3414 /* 3415 * Restore the device control registers. 3416 */ 3417 siocntxwait(); 3418 iobase = siocniobase; 3419 outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS); 3420 if (sp->dlbl != inb(iobase + com_dlbl)) 3421 outb(iobase + com_dlbl, sp->dlbl); 3422 if (sp->dlbh != inb(iobase + com_dlbh)) 3423 outb(iobase + com_dlbh, sp->dlbh); 3424 outb(iobase + com_cfcr, sp->cfcr); 3425 /* 3426 * XXX damp oscillations of MCR_DTR and MCR_RTS by not restoring them. 3427 */ 3428 outb(iobase + com_mcr, sp->mcr | MCR_DTR | MCR_RTS); 3429 outb(iobase + com_ier, sp->ier); 3430} 3431 3432void 3433siocnprobe(cp) 3434 struct consdev *cp; 3435{ 3436 speed_t boot_speed; 3437 u_char cfcr; 3438 struct isa_device *dvp; 3439 int s; 3440 struct siocnstate sp; 3441 3442 /* 3443 * Find our first enabled console, if any. If it is a high-level 3444 * console device, then initialize it and return successfully. 3445 * If it is a low-level console device, then initialize it and 3446 * return unsuccessfully. It must be initialized in both cases 3447 * for early use by console drivers and debuggers. Initializing 3448 * the hardware is not necessary in all cases, since the i/o 3449 * routines initialize it on the fly, but it is necessary if 3450 * input might arrive while the hardware is switched back to an 3451 * uninitialized state. We can't handle multiple console devices 3452 * yet because our low-level routines don't take a device arg. 3453 * We trust the user to set the console flags properly so that we 3454 * don't need to probe. 3455 */ 3456 cp->cn_pri = CN_DEAD; 3457 for (dvp = isa_devtab_tty; dvp->id_driver != NULL; dvp++) 3458 if (dvp->id_driver == &siodriver && dvp->id_enabled 3459 && COM_CONSOLE(dvp)) { 3460 siocniobase = dvp->id_iobase; 3461 s = spltty(); 3462 if (boothowto & RB_SERIAL) { 3463 boot_speed = siocngetspeed(siocniobase, 3464 comspeedtab); 3465 if (boot_speed) 3466 comdefaultrate = boot_speed; 3467 } 3468 3469 /* 3470 * Initialize the divisor latch. We can't rely on 3471 * siocnopen() to do this the first time, since it 3472 * avoids writing to the latch if the latch appears 3473 * to have the correct value. Also, if we didn't 3474 * just read the speed from the hardware, then we 3475 * need to set the speed in hardware so that 3476 * switching it later is null. 3477 */ 3478 cfcr = inb(siocniobase + com_cfcr); 3479 outb(siocniobase + com_cfcr, CFCR_DLAB | cfcr); 3480 outb(siocniobase + com_dlbl, 3481 COMBRD(comdefaultrate) & 0xff); 3482 outb(siocniobase + com_dlbh, 3483 (u_int) COMBRD(comdefaultrate) >> 8); 3484 outb(siocniobase + com_cfcr, cfcr); 3485 3486 siocnopen(&sp); 3487 splx(s); 3488 if (!COM_LLCONSOLE(dvp)) { 3489 cp->cn_dev = makedev(CDEV_MAJOR, dvp->id_unit); 3490 cp->cn_pri = COM_FORCECONSOLE(dvp) 3491 || boothowto & RB_SERIAL 3492 ? CN_REMOTE : CN_NORMAL; 3493 } 3494 break; 3495 } 3496} 3497 3498void 3499siocninit(cp) 3500 struct consdev *cp; 3501{ 3502 comconsole = DEV_TO_UNIT(cp->cn_dev); 3503} 3504 3505int 3506siocncheckc(dev) 3507 dev_t dev; 3508{ 3509 int c; 3510 Port_t iobase; 3511 int s; 3512 struct siocnstate sp; 3513 3514 iobase = siocniobase; 3515 s = spltty(); 3516 siocnopen(&sp); 3517 if (inb(iobase + com_lsr) & LSR_RXRDY) 3518 c = inb(iobase + com_data); 3519 else 3520 c = -1; 3521 siocnclose(&sp); 3522 splx(s); 3523 return (c); 3524} 3525 3526 3527int 3528siocngetc(dev) 3529 dev_t dev; 3530{ 3531 int c; 3532 Port_t iobase; 3533 int s; 3534 struct siocnstate sp; 3535 3536 iobase = siocniobase; 3537 s = spltty(); 3538 siocnopen(&sp); 3539 while (!(inb(iobase + com_lsr) & LSR_RXRDY)) 3540 ; 3541 c = inb(iobase + com_data); 3542 siocnclose(&sp); 3543 splx(s); 3544 return (c); 3545} 3546 3547void 3548siocnputc(dev, c) 3549 dev_t dev; 3550 int c; 3551{ 3552 int s; 3553 struct siocnstate sp; 3554 3555 s = spltty(); 3556 siocnopen(&sp); 3557 siocntxwait(); 3558 outb(siocniobase + com_data, c); 3559 siocnclose(&sp); 3560 splx(s); 3561} 3562 3563#ifdef DSI_SOFT_MODEM 3564/* 3565 * The magic code to download microcode to a "Connection 14.4+Fax" 3566 * modem from Digicom Systems Inc. Very magic. 3567 */ 3568 3569#define DSI_ERROR(str) { ptr = str; goto error; } 3570static int 3571LoadSoftModem(int unit, int base_io, u_long size, u_char *ptr) 3572{ 3573 int int_c,int_k; 3574 int data_0188, data_0187; 3575 3576 /* 3577 * First see if it is a DSI SoftModem 3578 */ 3579 if(!((inb(base_io+7) ^ inb(base_io+7)) & 0x80)) 3580 return ENODEV; 3581 3582 data_0188 = inb(base_io+4); 3583 data_0187 = inb(base_io+3); 3584 outb(base_io+3,0x80); 3585 outb(base_io+4,0x0C); 3586 outb(base_io+0,0x31); 3587 outb(base_io+1,0x8C); 3588 outb(base_io+7,0x10); 3589 outb(base_io+7,0x19); 3590 3591 if(0x18 != (inb(base_io+7) & 0x1A)) 3592 DSI_ERROR("dsp bus not granted"); 3593 3594 if(0x01 != (inb(base_io+7) & 0x01)) { 3595 outb(base_io+7,0x18); 3596 outb(base_io+7,0x19); 3597 if(0x01 != (inb(base_io+7) & 0x01)) 3598 DSI_ERROR("program mem not granted"); 3599 } 3600 3601 int_c = 0; 3602 3603 while(1) { 3604 if(int_c >= 7 || size <= 0x1800) 3605 break; 3606 3607 for(int_k = 0 ; int_k < 0x800; int_k++) { 3608 outb(base_io+0,*ptr++); 3609 outb(base_io+1,*ptr++); 3610 outb(base_io+2,*ptr++); 3611 } 3612 3613 size -= 0x1800; 3614 int_c++; 3615 } 3616 3617 if(size > 0x1800) { 3618 outb(base_io+7,0x18); 3619 outb(base_io+7,0x19); 3620 if(0x00 != (inb(base_io+7) & 0x01)) 3621 DSI_ERROR("program data not granted"); 3622 3623 for(int_k = 0 ; int_k < 0x800; int_k++) { 3624 outb(base_io+1,*ptr++); 3625 outb(base_io+2,0); 3626 outb(base_io+1,*ptr++); 3627 outb(base_io+2,*ptr++); 3628 } 3629 3630 size -= 0x1800; 3631 3632 while(size > 0x1800) { 3633 for(int_k = 0 ; int_k < 0xC00; int_k++) { 3634 outb(base_io+1,*ptr++); 3635 outb(base_io+2,*ptr++); 3636 } 3637 size -= 0x1800; 3638 } 3639 3640 if(size < 0x1800) { 3641 for(int_k=0;int_k<size/2;int_k++) { 3642 outb(base_io+1,*ptr++); 3643 outb(base_io+2,*ptr++); 3644 } 3645 } 3646 3647 } else if (size > 0) { 3648 if(int_c == 7) { 3649 outb(base_io+7,0x18); 3650 outb(base_io+7,0x19); 3651 if(0x00 != (inb(base_io+7) & 0x01)) 3652 DSI_ERROR("program data not granted"); 3653 for(int_k = 0 ; int_k < size/3; int_k++) { 3654 outb(base_io+1,*ptr++); 3655 outb(base_io+2,0); 3656 outb(base_io+1,*ptr++); 3657 outb(base_io+2,*ptr++); 3658 } 3659 } else { 3660 for(int_k = 0 ; int_k < size/3; int_k++) { 3661 outb(base_io+0,*ptr++); 3662 outb(base_io+1,*ptr++); 3663 outb(base_io+2,*ptr++); 3664 } 3665 } 3666 } 3667 outb(base_io+7,0x11); 3668 outb(base_io+7,3); 3669 3670 outb(base_io+4,data_0188 & 0xfb); 3671 3672 outb(base_io+3,data_0187); 3673 3674 return 0; 3675error: 3676 printf("sio%d: DSI SoftModem microcode load failed: <%s>\n",unit,ptr); 3677 outb(base_io+7,0x00); \ 3678 outb(base_io+3,data_0187); \ 3679 outb(base_io+4,data_0188); \ 3680 return EIO; 3681} 3682#endif /* DSI_SOFT_MODEM */ 3683 3684/* 3685 * support PnP cards if we are using 'em 3686 */ 3687 3688#if NPNP > 0 3689 3690static struct siopnp_ids { 3691 u_long vend_id; 3692 char *id_str; 3693} siopnp_ids[] = { 3694 { 0x5015f435, "MOT1550"}, 3695 { 0x8113b04e, "Supra1381"}, 3696 { 0x9012b04e, "Supra1290"}, 3697 { 0x11007256, "USR0011"}, 3698 { 0x30207256, "USR2030"}, 3699 { 0 } 3700}; 3701 3702static char *siopnp_probe(u_long csn, u_long vend_id); 3703static void siopnp_attach(u_long csn, u_long vend_id, char *name, 3704 struct isa_device *dev); 3705static u_long nsiopnp = NSIO; 3706 3707static struct pnp_device siopnp = { 3708 "siopnp", 3709 siopnp_probe, 3710 siopnp_attach, 3711 &nsiopnp, 3712 &tty_imask 3713}; 3714DATA_SET (pnpdevice_set, siopnp); 3715 3716static char * 3717siopnp_probe(u_long csn, u_long vend_id) 3718{ 3719 struct siopnp_ids *ids; 3720 char *s = NULL; 3721 3722 for(ids = siopnp_ids; ids->vend_id != 0; ids++) { 3723 if (vend_id == ids->vend_id) { 3724 s = ids->id_str; 3725 break; 3726 } 3727 } 3728 3729 if (s) { 3730 struct pnp_cinfo d; 3731 read_pnp_parms(&d, 0); 3732 if (d.enable == 0 || d.flags & 1) { 3733 printf("CSN %d is disabled.\n", csn); 3734 return (NULL); 3735 } 3736 3737 } 3738 3739 return (s); 3740} 3741 3742static void 3743siopnp_attach(u_long csn, u_long vend_id, char *name, struct isa_device *dev) 3744{ 3745 struct pnp_cinfo d; 3746 struct isa_device *dvp; 3747 3748 if (dev->id_unit >= NSIOTOT) 3749 return; 3750 3751 if (read_pnp_parms(&d, 0) == 0) { 3752 printf("failed to read pnp parms\n"); 3753 return; 3754 } 3755 3756 write_pnp_parms(&d, 0); 3757 3758 enable_pnp_card(); 3759 3760 dev->id_iobase = d.port[0]; 3761 dev->id_irq = (1 << d.irq[0]); 3762 dev->id_intr = siointr; 3763 dev->id_ri_flags = RI_FAST; 3764 dev->id_drq = -1; 3765 3766 if (dev->id_driver == NULL) { 3767 dev->id_driver = &siodriver; 3768 dvp = find_isadev(isa_devtab_tty, &siodriver, 0); 3769 if (dvp != NULL) 3770 dev->id_id = dvp->id_id; 3771 } 3772 3773 if ((dev->id_alive = sioprobe(dev)) != 0) 3774 sioattach(dev); 3775 else 3776 printf("sio%d: probe failed\n", dev->id_unit); 3777} 3778#endif 3779#ifdef PC98 3780/* 3781 * pc98 local function 3782 */ 3783 3784static void 3785com_tiocm_set(struct com_s *com, int msr) 3786{ 3787 int s; 3788 int tmp = 0; 3789 int mask = CMD8251_TxEN|CMD8251_RxEN|CMD8251_DTR|CMD8251_RTS; 3790 3791 s=spltty(); 3792 com->pc98_prev_modem_status = ( msr & (TIOCM_LE|TIOCM_DTR|TIOCM_RTS) ) 3793 | ( com->pc98_prev_modem_status & ~(TIOCM_LE|TIOCM_DTR|TIOCM_RTS) ); 3794 tmp |= (CMD8251_TxEN|CMD8251_RxEN); 3795 if ( msr & TIOCM_DTR ) tmp |= CMD8251_DTR; 3796 if ( msr & TIOCM_RTS ) tmp |= CMD8251_RTS; 3797 pc98_i8251_clear_or_cmd( com, mask, tmp ); 3798 splx(s); 3799} 3800 3801static void 3802com_tiocm_bis(struct com_s *com, int msr) 3803{ 3804 int s; 3805 int tmp = 0; 3806 3807 s=spltty(); 3808 com->pc98_prev_modem_status |= ( msr & (TIOCM_LE|TIOCM_DTR|TIOCM_RTS) ); 3809 tmp |= CMD8251_TxEN|CMD8251_RxEN; 3810 if ( msr & TIOCM_DTR ) tmp |= CMD8251_DTR; 3811 if ( msr & TIOCM_RTS ) tmp |= CMD8251_RTS; 3812 3813 pc98_i8251_or_cmd( com, tmp ); 3814 splx(s); 3815} 3816 3817static void 3818com_tiocm_bic(struct com_s *com, int msr) 3819{ 3820 int s; 3821 int tmp = msr; 3822 3823 s=spltty(); 3824 com->pc98_prev_modem_status &= ~( msr & (TIOCM_LE|TIOCM_DTR|TIOCM_RTS) ); 3825 if ( msr & TIOCM_DTR ) tmp |= CMD8251_DTR; 3826 if ( msr & TIOCM_RTS ) tmp |= CMD8251_RTS; 3827 3828 pc98_i8251_clear_cmd( com, tmp ); 3829 splx(s); 3830} 3831 3832static int 3833com_tiocm_get(struct com_s *com) 3834{ 3835 return( com->pc98_prev_modem_status ); 3836} 3837 3838static int 3839com_tiocm_get_delta(struct com_s *com) 3840{ 3841 int tmp; 3842 3843 tmp = com->pc98_modem_delta; 3844 com->pc98_modem_delta = 0; 3845 return( tmp ); 3846} 3847 3848/* convert to TIOCM_?? ( ioctl.h ) */ 3849static int 3850pc98_get_modem_status(struct com_s *com) 3851{ 3852 int stat, stat2; 3853 register int msr; 3854 3855 stat = inb(com->sts_port); 3856 stat2 = inb(com->in_modem_port); 3857 msr = com->pc98_prev_modem_status 3858 & ~(TIOCM_CAR|TIOCM_RI|TIOCM_DSR|TIOCM_CTS); 3859 if ( !(stat2 & CICSCD_CD) ) msr |= TIOCM_CAR; 3860 if ( !(stat2 & CICSCD_CI) ) msr |= TIOCM_RI; 3861 if ( stat & STS8251_DSR ) msr |= TIOCM_DSR; 3862 if ( !(stat2 & CICSCD_CS) ) msr |= TIOCM_CTS; 3863#if COM_CARRIER_DETECT_EMULATE 3864 if ( msr & (TIOCM_DSR|TIOCM_CTS) ) { 3865 msr |= TIOCM_CAR; 3866 } 3867#endif 3868 return(msr); 3869} 3870 3871static void 3872pc98_check_msr(void* chan) 3873{ 3874 int msr, delta; 3875 int s; 3876 register struct tty *tp; 3877 struct com_s *com; 3878 int mynor; 3879 int unit; 3880 dev_t dev; 3881 3882 dev=(dev_t)chan; 3883 mynor = minor(dev); 3884 unit = MINOR_TO_UNIT(mynor); 3885 com = com_addr(unit); 3886 tp = com->tp; 3887 3888 s = spltty(); 3889 msr = pc98_get_modem_status(com); 3890 /* make change flag */ 3891 delta = msr ^ com->pc98_prev_modem_status; 3892 if ( delta & TIOCM_CAR ) { 3893 if ( com->modem_car_chg_timer ) { 3894 if ( -- com->modem_car_chg_timer ) 3895 msr ^= TIOCM_CAR; 3896 } else { 3897 if ( com->modem_car_chg_timer = ( msr & TIOCM_CAR ) ? 3898 DCD_ON_RECOGNITION : DCD_OFF_TOLERANCE ) 3899 msr ^= TIOCM_CAR; 3900 } 3901 } else 3902 com->modem_car_chg_timer = 0; 3903 delta = ( msr ^ com->pc98_prev_modem_status ) & 3904 (TIOCM_CAR|TIOCM_RI|TIOCM_DSR|TIOCM_CTS); 3905 com->pc98_prev_modem_status = msr; 3906 delta = ( com->pc98_modem_delta |= delta ); 3907 splx(s); 3908 if ( com->modem_checking || (tp->t_state & (TS_ISOPEN)) ) { 3909 if ( delta ) { 3910 commint(dev); 3911 } 3912 timeout(pc98_check_msr, (caddr_t)dev, 3913 PC98_CHECK_MODEM_INTERVAL); 3914 } else { 3915 com->modem_checking = 0; 3916 } 3917} 3918 3919static void 3920pc98_msrint_start(dev_t dev) 3921{ 3922 struct com_s *com; 3923 int mynor; 3924 int unit; 3925 int s = spltty(); 3926 3927 mynor = minor(dev); 3928 unit = MINOR_TO_UNIT(mynor); 3929 com = com_addr(unit); 3930 /* modem control line check routine envoke interval is 1/10 sec */ 3931 if ( com->modem_checking == 0 ) { 3932 com->pc98_prev_modem_status = pc98_get_modem_status(com); 3933 com->pc98_modem_delta = 0; 3934 timeout(pc98_check_msr, (caddr_t)dev, 3935 PC98_CHECK_MODEM_INTERVAL); 3936 com->modem_checking = 1; 3937 } 3938 splx(s); 3939} 3940 3941static void 3942pc98_disable_i8251_interrupt(struct com_s *com, int mod) 3943{ 3944 /* disable interrupt */ 3945 register int tmp; 3946 3947 mod |= ~(IEN_Tx|IEN_TxEMP|IEN_Rx); 3948 COM_INT_DISABLE 3949 tmp = inb( com->intr_ctrl_port ) & ~(IEN_Tx|IEN_TxEMP|IEN_Rx); 3950 outb( com->intr_ctrl_port, (com->intr_enable&=~mod) | tmp ); 3951 COM_INT_ENABLE 3952} 3953 3954static void 3955pc98_enable_i8251_interrupt(struct com_s *com, int mod) 3956{ 3957 register int tmp; 3958 3959 COM_INT_DISABLE 3960 tmp = inb( com->intr_ctrl_port ) & ~(IEN_Tx|IEN_TxEMP|IEN_Rx); 3961 outb( com->intr_ctrl_port, (com->intr_enable|=mod) | tmp ); 3962 COM_INT_ENABLE 3963} 3964 3965static int 3966pc98_check_i8251_interrupt(struct com_s *com) 3967{ 3968 return ( com->intr_enable & 0x07 ); 3969} 3970 3971static void 3972pc98_i8251_clear_cmd(struct com_s *com, int x) 3973{ 3974 int tmp; 3975 3976 COM_INT_DISABLE 3977 tmp = com->pc98_prev_siocmd & ~(x); 3978 outb(com->cmd_port, tmp); 3979 com->pc98_prev_siocmd = tmp & ~(CMD8251_ER|CMD8251_RESET|CMD8251_EH); 3980 COM_INT_ENABLE 3981} 3982 3983static void 3984pc98_i8251_or_cmd(struct com_s *com, int x) 3985{ 3986 int tmp; 3987 3988 COM_INT_DISABLE 3989 tmp = com->pc98_prev_siocmd | (x); 3990 outb(com->cmd_port, tmp); 3991 com->pc98_prev_siocmd = tmp & ~(CMD8251_ER|CMD8251_RESET|CMD8251_EH); 3992 COM_INT_ENABLE 3993} 3994 3995static void 3996pc98_i8251_set_cmd(struct com_s *com, int x) 3997{ 3998 int tmp; 3999 4000 COM_INT_DISABLE 4001 tmp = (x); 4002 outb(com->cmd_port, tmp); 4003 com->pc98_prev_siocmd = tmp & ~(CMD8251_ER|CMD8251_RESET|CMD8251_EH); 4004 COM_INT_ENABLE 4005} 4006 4007static void 4008pc98_i8251_clear_or_cmd(struct com_s *com, int clr, int x) 4009{ 4010 int tmp; 4011 COM_INT_DISABLE 4012 tmp = com->pc98_prev_siocmd & ~(clr); 4013 tmp |= (x); 4014 outb(com->cmd_port, tmp); 4015 com->pc98_prev_siocmd = tmp & ~(CMD8251_ER|CMD8251_RESET|CMD8251_EH); 4016 COM_INT_ENABLE 4017} 4018 4019static int 4020pc98_i8251_get_cmd(struct com_s *com) 4021{ 4022 return com->pc98_prev_siocmd; 4023} 4024 4025static int 4026pc98_i8251_get_mod(struct com_s *com) 4027{ 4028 return com->pc98_prev_siomod; 4029} 4030 4031static void 4032pc98_i8251_reset(struct com_s *com, int mode, int command) 4033{ 4034 outb(com->cmd_port, 0); /* dummy */ 4035 DELAY(2); 4036 outb(com->cmd_port, 0); /* dummy */ 4037 DELAY(2); 4038 outb(com->cmd_port, 0); /* dummy */ 4039 DELAY(2); 4040 outb(com->cmd_port, CMD8251_RESET); /* internal reset */ 4041 DELAY(2); 4042 outb(com->cmd_port, mode ); /* mode register */ 4043 com->pc98_prev_siomod = mode; 4044 DELAY(2); 4045 pc98_i8251_set_cmd( com, (command|CMD8251_ER) ); 4046} 4047 4048static void 4049pc98_check_sysclock(void) 4050{ 4051 /* get system clock from port */ 4052 if ( pc98_machine_type & M_8M ) { 4053 /* 8 MHz system & H98 */ 4054 sysclock = 8; 4055 } else { 4056 /* 5 MHz system */ 4057 sysclock = 5; 4058 } 4059} 4060 4061static void 4062com_cflag_and_speed_set( struct com_s *com, int cflag, int speed) 4063{ 4064 int cfcr=0, count; 4065 int previnterrupt; 4066 4067 count = pc98_ttspeedtab( com, speed ); 4068 if ( count < 0 ) return; 4069 4070 previnterrupt = pc98_check_i8251_interrupt(com); 4071 pc98_disable_i8251_interrupt( com, IEN_Tx|IEN_TxEMP|IEN_Rx ); 4072 4073 switch ( cflag&CSIZE ) { 4074 case CS5: 4075 cfcr = MOD8251_5BITS; break; 4076 case CS6: 4077 cfcr = MOD8251_6BITS; break; 4078 case CS7: 4079 cfcr = MOD8251_7BITS; break; 4080 case CS8: 4081 cfcr = MOD8251_8BITS; break; 4082 } 4083 if ( cflag&PARENB ) { 4084 if ( cflag&PARODD ) 4085 cfcr |= MOD8251_PODD; 4086 else 4087 cfcr |= MOD8251_PEVEN; 4088 } else 4089 cfcr |= MOD8251_PDISAB; 4090 4091 if ( cflag&CSTOPB ) 4092 cfcr |= MOD8251_STOP2; 4093 else 4094 cfcr |= MOD8251_STOP1; 4095 4096 if ( count & 0x10000 ) 4097 cfcr |= MOD8251_CLKX1; 4098 else 4099 cfcr |= MOD8251_CLKX16; 4100 4101 if (epson_machine_id != 0x20) { /* XXX */ 4102 { 4103 int tmp; 4104 while (!((tmp = inb(com->sts_port)) & STS8251_TxEMP)) 4105 ; 4106 } 4107 } 4108 /* set baud rate from ospeed */ 4109 pc98_set_baud_rate( com, count ); 4110 4111 if ( cfcr != pc98_i8251_get_mod(com) ) 4112 pc98_i8251_reset(com, cfcr, pc98_i8251_get_cmd(com) ); 4113 4114 pc98_enable_i8251_interrupt( com, previnterrupt ); 4115} 4116 4117static int 4118pc98_ttspeedtab(struct com_s *com, int speed) 4119{ 4120 int effect_sp, count=-1, mod; 4121 4122 switch ( com->pc98_if_type ) { 4123 case COM_IF_INTERNAL: 4124 /* for *1CLK asynchronous! mode , TEFUTEFU */ 4125 effect_sp = ttspeedtab( speed, pc98speedtab ); 4126 if ( effect_sp < 0 ) 4127 effect_sp = ttspeedtab( (speed-1), pc98speedtab ); 4128 if ( effect_sp <= 0 ) 4129 return effect_sp; 4130 mod = (sysclock == 5 ? 2457600 : 1996800); 4131 if ( effect_sp == speed ) 4132 mod /= 16; 4133 count = mod / effect_sp; 4134 if ( count > 65535 ) 4135 return(-1); 4136 if ( effect_sp >= 2400 ) 4137 if ( !(sysclock != 5 && 4138 (effect_sp == 19200 || effect_sp == 38400)) ) 4139 if ( ( mod % effect_sp ) != 0 ) 4140 return(-1); 4141 if ( effect_sp != speed ) 4142 count |= 0x10000; 4143 break; 4144#ifdef COM_IF_PC9861K 4145 case COM_IF_PC9861K: 4146 effect_sp = speed; 4147 count = 1; 4148 break; 4149#endif 4150#ifdef COM_IF_PIO9032B 4151 case COM_IF_PIO9032B: 4152 if ( speed == 0 ) return 0; 4153 count = ttspeedtab( speed, comspeedtab_pio9032b ); 4154 if ( count < 0 ) return count; 4155 effect_sp = speed; 4156 break; 4157#endif 4158#ifdef COM_IF_B98_01 4159 case COM_IF_B98_01: 4160 effect_sp=speed; 4161 count = ttspeedtab( speed, comspeedtab_b98_01 ); 4162 if ( count <= 3 ) 4163 return -1; /* invalid speed/count */ 4164 if ( count <= 5 ) 4165 count |= 0x10000; /* x1 mode for 76800 and 153600 */ 4166 else 4167 count -= 4; /* x16 mode for slower */ 4168 break; 4169#endif 4170 } 4171 return count; 4172} 4173 4174static void 4175pc98_set_baud_rate( struct com_s *com, int count) 4176{ 4177 int s; 4178 4179 switch ( com->pc98_if_type ) { 4180 case COM_IF_INTERNAL: 4181 if ( count < 0 ) { 4182 printf( "[ Illegal count : %d ]", count ); 4183 return; 4184 } else if ( count == 0) 4185 return; 4186 /* set i8253 */ 4187 s = splclock(); 4188 outb( 0x77, 0xb6 ); 4189 outb( 0x5f, 0); 4190 outb( 0x75, count & 0xff ); 4191 outb( 0x5f, 0); 4192 outb( 0x75, (count >> 8) & 0xff ); 4193 splx(s); 4194 break; 4195#if 0 4196#ifdef COM_IF_PC9861K 4197 case COM_IF_PC9861K: 4198 break; 4199 /* ext. RS232C board: speed is determined by DIP switch */ 4200#endif 4201#endif /* 0 */ 4202#ifdef COM_IF_PIO9032B 4203 case COM_IF_PIO9032B: 4204 outb( com_addr[unit], count & 0x07 ); 4205 break; 4206#endif 4207#ifdef COM_IF_B98_01 4208 case COM_IF_B98_01: 4209 outb( com->iobase, count & 0x0f ); 4210#ifdef B98_01_OLD 4211 /* some old board should be controlled in different way, 4212 but this hasn't been tested yet.*/ 4213 outb( com->iobase+2, ( count & 0x10000 ) ? 0xf0 : 0xf2 ); 4214#endif 4215 break; 4216#endif 4217 } 4218} 4219static int 4220pc98_check_if_type( int iobase, struct siodev *iod) 4221{ 4222 int irr = 0, tmp = 0; 4223 int ret = 0; 4224 static short irq_tab[2][8] = { 4225 { 3, 5, 6, 9, 10, 12, 13, -1}, 4226 { 3, 10, 12, 13, 5, 6, 9, -1} 4227 }; 4228 iod->irq = 0; 4229 switch ( iobase & 0xff ) { 4230 case IO_COM1: 4231 iod->if_type = COM_IF_INTERNAL; 4232 ret = 0; iod->irq = 4; break; 4233#ifdef COM_IF_PC9861K 4234 case IO_COM2: 4235 iod->if_type = COM_IF_PC9861K; 4236 ret = 1; irr = 0; tmp = 3; break; 4237 case IO_COM3: 4238 iod->if_type = COM_IF_PC9861K; 4239 ret = 2; irr = 1; tmp = 3; break; 4240#endif 4241#ifdef COM_IF_PIO9032B 4242 case IO_COM_PIO9032B_2: 4243 iod->if_type = COM_IF_PIO9032B; 4244 ret = 1; irr = 0; tmp = 7; break; 4245 case IO_COM_PIO9032B_3: 4246 iod->if_type = COM_IF_PIO9032B; 4247 ret = 2; irr = 1; tmp = 7; break; 4248#endif 4249#ifdef COM_IF_B98_01 4250 case IO_COM_B98_01_2: 4251 iod->if_type = COM_IF_B98_01; 4252 ret = 1; irr = 0; tmp = 7; 4253 outb(iobase + 2, 0xf2); 4254 outb(iobase, 4); 4255 break; 4256 case IO_COM_B98_01_3: 4257 iod->if_type = COM_IF_B98_01; 4258 ret = 2; irr = 1; tmp = 7; 4259 outb(iobase + 2, 0xf2); 4260 outb(iobase , 4); 4261 break; 4262#endif 4263 default: 4264 if((iobase & 0x0f0) == 0xd0){ 4265 iod->if_type = MC16550; 4266 return 0; 4267 } 4268 return -1; 4269 } 4270 4271 iod->cmd = ( iobase & 0xff00 )|PC98SIO_cmd_port(ret); 4272 iod->sts = ( iobase & 0xff00 )|PC98SIO_sts_port(ret); 4273 iod->mod = ( iobase & 0xff00 )|PC98SIO_in_modem_port(ret); 4274 iod->ctrl = ( iobase & 0xff00 )|PC98SIO_intr_ctrl_port(ret); 4275 4276 if ( iod->irq == 0 ) { 4277 tmp &= inb( iod->mod ); 4278 iod->irq = irq_tab[irr][tmp]; 4279 if ( iod->irq == -1 ) return -1; 4280 } 4281 return 0; 4282} 4283static int 4284pc98_set_ioport( struct com_s *com, int io_base ) 4285{ 4286 int a, io, type; 4287 4288 switch ( io_base & 0xff ) { 4289 case IO_COM1: a = 0; io = 0; type = COM_IF_INTERNAL; 4290 pc98_check_sysclock(); break; 4291#ifdef COM_IF_PC9861K 4292 case IO_COM2: a = 1; io = 0; type = COM_IF_PC9861K; break; 4293 case IO_COM3: a = 2; io = 0; type = COM_IF_PC9861K; break; 4294#endif /* COM_IF_PC9861K */ 4295#ifdef COM_IF_PIO9032B 4296 /* PIO9032B : I/O address is changeable */ 4297 case IO_COM_PIO9032B_2: 4298 a = 1; io = io_base & 0xff00; 4299 type = COM_IF_PIO9032B; break; 4300 case IO_COM_PIO9032B_3: 4301 a = 2; io = io_base & 0xff00; 4302 type = COM_IF_PIO9032B; break; 4303#endif /* COM_IF_PIO9032B */ 4304#ifdef COM_IF_B98_01 4305 case IO_COM_B98_01_2: 4306 a = 1; io = 0; type = COM_IF_B98_01; break; 4307 case IO_COM_B98_01_3: 4308 a = 2; io = 0; type = COM_IF_B98_01; break; 4309#endif /* COM_IF_B98_01*/ 4310 default: /* i/o address not match */ 4311 return -1; 4312 } 4313 4314 com->pc98_if_type = type; 4315 com->data_port = io | PC98SIO_data_port(a); 4316 com->cmd_port = io | PC98SIO_cmd_port(a); 4317 com->sts_port = io | PC98SIO_sts_port(a); 4318 com->in_modem_port = io | PC98SIO_in_modem_port(a); 4319 com->intr_ctrl_port = io | PC98SIO_intr_ctrl_port(a); 4320 return 0; 4321} 4322#endif /* PC98 defined */ 4323