cy.c revision 41388
1/*- 2 * cyclades cyclom-y serial driver 3 * Andrew Herbert <andrew@werple.apana.org.au>, 17 August 1993 4 * 5 * Copyright (c) 1993 Andrew Herbert. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. The name Andrew Herbert may not be used to endorse or promote products 17 * derived from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED 20 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 22 * NO EVENT SHALL I BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 * 30 * $Id: cy.c,v 1.75 1998/11/28 13:18:16 bde Exp $ 31 */ 32 33#include "opt_compat.h" 34#include "opt_devfs.h" 35 36#include "cy.h" 37 38/* 39 * TODO: 40 * Implement BREAK. 41 * Fix overflows when closing line. 42 * Atomic COR change. 43 * Consoles. 44 */ 45 46/* 47 * Temporary compile-time configuration options. 48 */ 49#define RxFifoThreshold (CD1400_RX_FIFO_SIZE / 2) 50 /* Number of chars in the receiver FIFO before an 51 * an interrupt is generated. Should depend on 52 * line speed. Needs to be about 6 on a 486DX33 53 * for 4 active ports at 115200 bps. Why doesn't 54 * 10 work? 55 */ 56#define PollMode /* Use polling-based irq service routine, not the 57 * hardware svcack lines. Must be defined for 58 * Cyclom-16Y boards. Less efficient for Cyclom-8Ys, 59 * and stops 4 * 115200 bps from working. 60 */ 61#undef Smarts /* Enable slightly more CD1400 intelligence. Mainly 62 * the output CR/LF processing, plus we can avoid a 63 * few checks usually done in ttyinput(). 64 * 65 * XXX not fully implemented, and not particularly 66 * worthwhile. 67 */ 68#undef CyDebug /* Include debugging code (not very expensive). */ 69 70/* These will go away. */ 71#undef SOFT_CTS_OFLOW 72#define SOFT_HOTCHAR 73 74#include <sys/param.h> 75#include <sys/systm.h> 76#include <sys/tty.h> 77#include <sys/proc.h> 78#include <sys/conf.h> 79#include <sys/dkstat.h> 80#include <sys/fcntl.h> 81#include <sys/interrupt.h> 82#include <sys/kernel.h> 83#include <sys/malloc.h> 84#include <sys/syslog.h> 85#ifdef DEVFS 86#include <sys/devfsext.h> 87#endif 88 89#include <machine/clock.h> 90#include <machine/ipl.h> 91 92#include <i386/isa/isa_device.h> 93#include <i386/isa/cyreg.h> 94#include <i386/isa/ic/cd1400.h> 95 96#ifdef SMP 97#define disable_intr() COM_DISABLE_INTR() 98#define enable_intr() COM_ENABLE_INTR() 99#endif /* SMP */ 100 101/* 102 * Dictionary so that I can name everything *sio* or *com* to compare with 103 * sio.c. There is also lots of ugly formatting and unnecessary ifdefs to 104 * simplify the comparision. These will go away. 105 */ 106#define LSR_BI CD1400_RDSR_BREAK 107#define LSR_FE CD1400_RDSR_FE 108#define LSR_OE CD1400_RDSR_OE 109#define LSR_PE CD1400_RDSR_PE 110#define MCR_DTR CD1400_MSVR2_DTR 111#define MCR_RTS CD1400_MSVR1_RTS 112#define MSR_CTS CD1400_MSVR2_CTS 113#define MSR_DCD CD1400_MSVR2_CD 114#define MSR_DSR CD1400_MSVR2_DSR 115#define MSR_RI CD1400_MSVR2_RI 116#define NSIO (NCY * CY_MAX_PORTS) 117#define comconsole cyconsole 118#define comdefaultrate cydefaultrate 119#define com_events cy_events 120#define comhardclose cyhardclose 121#define commctl cymctl 122#define comparam cyparam 123#define comspeed cyspeed 124#define comstart cystart 125#define comwakeup cywakeup 126#define nsio_tty ncy_tty 127#define p_com_addr p_cy_addr 128#define sioattach cyattach 129#define sioclose cyclose 130#define siodevtotty cydevtotty 131#define siodriver cydriver 132#define siodtrwakeup cydtrwakeup 133#define siointr cyintr 134#define siointr1 cyintr1 135#define sioioctl cyioctl 136#define sioopen cyopen 137#define siopoll cypoll 138#define sioprobe cyprobe 139#define sioread cyread 140#define siosettimeout cysettimeout 141#define siostop cystop 142#define siowrite cywrite 143#define sio_registered cy_registered 144#define sio_timeout cy_timeout 145#define sio_timeout_handle cy_timeout_handle 146#define sio_timeouts_until_log cy_timeouts_until_log 147#define sio_tty cy_tty 148 149#define CY_MAX_PORTS (CD1400_NO_OF_CHANNELS * CY_MAX_CD1400s) 150 151/* We encode the cyclom unit number (cyu) in spare bits in the IVR's. */ 152#define CD1400_xIVR_CHAN_SHIFT 3 153#define CD1400_xIVR_CHAN 0x1F 154 155#define LOTS_OF_EVENTS 64 /* helps separate urgent events from input */ 156#define RS_IBUFSIZE 256 157 158#define CALLOUT_MASK 0x80 159#define CONTROL_MASK 0x60 160#define CONTROL_INIT_STATE 0x20 161#define CONTROL_LOCK_STATE 0x40 162#define DEV_TO_UNIT(dev) (MINOR_TO_UNIT(minor(dev))) 163#define MINOR_MAGIC_MASK (CALLOUT_MASK | CONTROL_MASK) 164#define MINOR_TO_UNIT(mynor) (((mynor) >> 16) * CY_MAX_PORTS \ 165 | (((mynor) & 0xff) & ~MINOR_MAGIC_MASK)) 166 167/* 168 * Input buffer watermarks. 169 * The external device is asked to stop sending when the buffer exactly reaches 170 * high water, or when the high level requests it. 171 * The high level is notified immediately (rather than at a later clock tick) 172 * when this watermark is reached. 173 * The buffer size is chosen so the watermark should almost never be reached. 174 * The low watermark is invisibly 0 since the buffer is always emptied all at 175 * once. 176 */ 177#define RS_IHIGHWATER (3 * RS_IBUFSIZE / 4) 178 179/* 180 * com state bits. 181 * (CS_BUSY | CS_TTGO) and (CS_BUSY | CS_TTGO | CS_ODEVREADY) must be higher 182 * than the other bits so that they can be tested as a group without masking 183 * off the low bits. 184 * 185 * The following com and tty flags correspond closely: 186 * CS_BUSY = TS_BUSY (maintained by comstart(), siopoll() and 187 * siostop()) 188 * CS_TTGO = ~TS_TTSTOP (maintained by comparam() and comstart()) 189 * CS_CTS_OFLOW = CCTS_OFLOW (maintained by comparam()) 190 * CS_RTS_IFLOW = CRTS_IFLOW (maintained by comparam()) 191 * TS_FLUSH is not used. 192 * XXX I think TIOCSETA doesn't clear TS_TTSTOP when it clears IXON. 193 * XXX CS_*FLOW should be CF_*FLOW in com->flags (control flags not state). 194 */ 195#define CS_BUSY 0x80 /* output in progress */ 196#define CS_TTGO 0x40 /* output not stopped by XOFF */ 197#define CS_ODEVREADY 0x20 /* external device h/w ready (CTS) */ 198#define CS_CHECKMSR 1 /* check of MSR scheduled */ 199#define CS_CTS_OFLOW 2 /* use CTS output flow control */ 200#define CS_DTR_OFF 0x10 /* DTR held off */ 201#define CS_ODONE 4 /* output completed */ 202#define CS_RTS_IFLOW 8 /* use RTS input flow control */ 203#define CSE_ODONE 1 /* output transmitted */ 204 205static char const * const error_desc[] = { 206#define CE_OVERRUN 0 207 "silo overflow", 208#define CE_INTERRUPT_BUF_OVERFLOW 1 209 "interrupt-level buffer overflow", 210#define CE_TTY_BUF_OVERFLOW 2 211 "tty-level buffer overflow", 212}; 213 214#define CE_NTYPES 3 215#define CE_RECORD(com, errnum) (++(com)->delta_error_counts[errnum]) 216 217/* types. XXX - should be elsewhere */ 218typedef u_char bool_t; /* boolean */ 219typedef u_char volatile *cy_addr; 220 221/* queue of linear buffers */ 222struct lbq { 223 u_char *l_head; /* next char to process */ 224 u_char *l_tail; /* one past the last char to process */ 225 struct lbq *l_next; /* next in queue */ 226 bool_t l_queued; /* nonzero if queued */ 227}; 228 229/* com device structure */ 230struct com_s { 231 u_char state; /* miscellaneous flag bits */ 232 bool_t active_out; /* nonzero if the callout device is open */ 233#if 0 234 u_char cfcr_image; /* copy of value written to CFCR */ 235#endif 236 u_char extra_state; /* more flag bits, separate for order trick */ 237#if 0 238 u_char fifo_image; /* copy of value written to FIFO */ 239#endif 240 u_char gfrcr_image; /* copy of value read from GFRCR */ 241#if 0 242 bool_t hasfifo; /* nonzero for 16550 UARTs */ 243 bool_t loses_outints; /* nonzero if device loses output interrupts */ 244#endif 245 u_char mcr_dtr; /* MCR bit that is wired to DTR */ 246 u_char mcr_image; /* copy of value written to MCR */ 247 u_char mcr_rts; /* MCR bit that is wired to RTS */ 248#if 0 249#ifdef COM_MULTIPORT 250 bool_t multiport; /* is this unit part of a multiport device? */ 251#endif /* COM_MULTIPORT */ 252 bool_t no_irq; /* nonzero if irq is not attached */ 253 bool_t poll; /* nonzero if polling is required */ 254 bool_t poll_output; /* nonzero if polling for output is required */ 255#endif 256 int unit; /* unit number */ 257 int dtr_wait; /* time to hold DTR down on close (* 1/hz) */ 258#if 0 259 u_int tx_fifo_size; 260#endif 261 u_int wopeners; /* # processes waiting for DCD in open() */ 262 263 /* 264 * The high level of the driver never reads status registers directly 265 * because there would be too many side effects to handle conveniently. 266 * Instead, it reads copies of the registers stored here by the 267 * interrupt handler. 268 */ 269 u_char last_modem_status; /* last MSR read by intr handler */ 270 u_char prev_modem_status; /* last MSR handled by high level */ 271 272 u_char hotchar; /* ldisc-specific char to be handled ASAP */ 273 u_char *ibuf; /* start of input buffer */ 274 u_char *ibufend; /* end of input buffer */ 275 u_char *ihighwater; /* threshold in input buffer */ 276 u_char *iptr; /* next free spot in input buffer */ 277 278 struct lbq obufq; /* head of queue of output buffers */ 279 struct lbq obufs[2]; /* output buffers */ 280 281 int cy_align; /* index for register alignment */ 282 cy_addr cy_iobase; /* base address of this port's cyclom */ 283 cy_addr iobase; /* base address of this port's cd1400 */ 284 int mcr_rts_reg; /* cd1400 reg number of reg holding mcr_rts */ 285 286 struct tty *tp; /* cross reference */ 287 288 /* Initial state. */ 289 struct termios it_in; /* should be in struct tty */ 290 struct termios it_out; 291 292 /* Lock state. */ 293 struct termios lt_in; /* should be in struct tty */ 294 struct termios lt_out; 295 296 bool_t do_timestamp; 297 bool_t do_dcd_timestamp; 298 struct timeval timestamp; 299 struct timeval dcd_timestamp; 300 301 u_long bytes_in; /* statistics */ 302 u_long bytes_out; 303 u_int delta_error_counts[CE_NTYPES]; 304 u_long error_counts[CE_NTYPES]; 305 306 u_int recv_exception; /* exception chars received */ 307 u_int mdm; /* modem signal changes */ 308#ifdef CyDebug 309 u_int start_count; /* no. of calls to comstart() */ 310 u_int start_real; /* no. of calls that did something */ 311#endif 312 u_char car; /* CD1400 CAR shadow (if first unit in cd) */ 313 u_char channel_control;/* CD1400 CCR control command shadow */ 314 u_char cor[3]; /* CD1400 COR1-3 shadows */ 315 u_char intr_enable; /* CD1400 SRER shadow */ 316 317 /* 318 * Ping-pong input buffers. The extra factor of 2 in the sizes is 319 * to allow for an error byte for each input byte. 320 */ 321#define CE_INPUT_OFFSET RS_IBUFSIZE 322 u_char ibuf1[2 * RS_IBUFSIZE]; 323 u_char ibuf2[2 * RS_IBUFSIZE]; 324 325 /* 326 * Data area for output buffers. Someday we should build the output 327 * buffer queue without copying data. 328 */ 329 u_char obuf1[256]; 330 u_char obuf2[256]; 331#ifdef DEVFS 332 void *devfs_token_ttyd; 333 void *devfs_token_ttyl; 334 void *devfs_token_ttyi; 335 void *devfs_token_cuaa; 336 void *devfs_token_cual; 337 void *devfs_token_cuai; 338#endif 339}; 340 341/* PCI driver entry point. */ 342int cyattach_common __P((cy_addr cy_iobase, int cy_align)); 343ointhand2_t siointr; 344 345static int cy_units __P((cy_addr cy_iobase, int cy_align)); 346static int sioattach __P((struct isa_device *dev)); 347static void cd1400_channel_cmd __P((struct com_s *com, int cmd)); 348static int cd_getreg __P((struct com_s *com, int reg)); 349static void cd_setreg __P((struct com_s *com, int reg, int val)); 350static timeout_t siodtrwakeup; 351static void comhardclose __P((struct com_s *com)); 352#if 0 353static void siointr1 __P((struct com_s *com)); 354#endif 355static int commctl __P((struct com_s *com, int bits, int how)); 356static int comparam __P((struct tty *tp, struct termios *t)); 357static swihand_t siopoll; 358static int sioprobe __P((struct isa_device *dev)); 359static void siosettimeout __P((void)); 360static int comspeed __P((speed_t speed, u_long cy_clock, 361 int *prescaler_io)); 362static void comstart __P((struct tty *tp)); 363static timeout_t comwakeup; 364static void disc_optim __P((struct tty *tp, struct termios *t, 365 struct com_s *com)); 366 367#ifdef CyDebug 368void cystatus __P((int unit)); 369#endif 370 371static char driver_name[] = "cy"; 372 373/* table and macro for fast conversion from a unit number to its com struct */ 374static struct com_s *p_com_addr[NSIO]; 375#define com_addr(unit) (p_com_addr[unit]) 376 377struct isa_driver siodriver = { 378 sioprobe, sioattach, driver_name 379}; 380 381static d_open_t sioopen; 382static d_close_t sioclose; 383static d_read_t sioread; 384static d_write_t siowrite; 385static d_ioctl_t sioioctl; 386static d_stop_t siostop; 387static d_devtotty_t siodevtotty; 388 389#define CDEV_MAJOR 48 390static struct cdevsw sio_cdevsw = { 391 sioopen, sioclose, sioread, siowrite, 392 sioioctl, siostop, noreset, siodevtotty, 393 ttpoll, nommap, NULL, driver_name, 394 NULL, -1, nodump, nopsize, 395 D_TTY, 396}; 397 398static int comconsole = -1; 399static speed_t comdefaultrate = TTYDEF_SPEED; 400static u_int com_events; /* input chars + weighted output completions */ 401static bool_t sio_registered; 402static int sio_timeout; 403static int sio_timeouts_until_log; 404static struct callout_handle sio_timeout_handle 405 = CALLOUT_HANDLE_INITIALIZER(&sio_timeout_handle); 406#if 0 /* XXX */ 407static struct tty *sio_tty[NSIO]; 408#else 409static struct tty sio_tty[NSIO]; 410#endif 411static const int nsio_tty = NSIO; 412 413#ifdef CyDebug 414static u_int cd_inbs; 415static u_int cy_inbs; 416static u_int cd_outbs; 417static u_int cy_outbs; 418static u_int cy_svrr_probes; 419static u_int cy_timeouts; 420#endif 421 422static int cy_chip_offset[] = { 423 0x0000, 0x0400, 0x0800, 0x0c00, 0x0200, 0x0600, 0x0a00, 0x0e00, 424}; 425static int cy_nr_cd1400s[NCY]; 426static int cy_total_devices; 427#undef RxFifoThreshold 428static int volatile RxFifoThreshold = (CD1400_RX_FIFO_SIZE / 2); 429 430static int 431sioprobe(dev) 432 struct isa_device *dev; 433{ 434 cy_addr iobase; 435 436 iobase = (cy_addr)dev->id_maddr; 437 438 /* Cyclom-16Y hardware reset (Cyclom-8Ys don't care) */ 439 cy_inb(iobase, CY16_RESET, 0); /* XXX? */ 440 DELAY(500); /* wait for the board to get its act together */ 441 442 /* this is needed to get the board out of reset */ 443 cy_outb(iobase, CY_CLEAR_INTR, 0, 0); 444 DELAY(500); 445 446 return (cy_units(iobase, 0) == 0 ? 0 : -1); 447} 448 449static int 450cy_units(cy_iobase, cy_align) 451 cy_addr cy_iobase; 452 int cy_align; 453{ 454 int cyu; 455 u_char firmware_version; 456 int i; 457 cy_addr iobase; 458 459 for (cyu = 0; cyu < CY_MAX_CD1400s; ++cyu) { 460 iobase = cy_iobase + (cy_chip_offset[cyu] << cy_align); 461 462 /* wait for chip to become ready for new command */ 463 for (i = 0; i < 10; i++) { 464 DELAY(50); 465 if (!cd_inb(iobase, CD1400_CCR, cy_align)) 466 break; 467 } 468 469 /* clear the GFRCR register */ 470 cd_outb(iobase, CD1400_GFRCR, cy_align, 0); 471 472 /* issue a reset command */ 473 cd_outb(iobase, CD1400_CCR, cy_align, 474 CD1400_CCR_CMDRESET | CD1400_CCR_FULLRESET); 475 476 /* wait for the CD1400 to initialize itself */ 477 for (i = 0; i < 200; i++) { 478 DELAY(50); 479 480 /* retrieve firmware version */ 481 firmware_version = cd_inb(iobase, CD1400_GFRCR, 482 cy_align); 483 if ((firmware_version & 0xf0) == 0x40) 484 break; 485 } 486 487 /* 488 * Anything in the 0x40-0x4F range is fine. 489 * If one CD1400 is bad then we don't support higher 490 * numbered good ones on this board. 491 */ 492 if ((firmware_version & 0xf0) != 0x40) 493 break; 494 } 495 return (cyu); 496} 497 498static int 499sioattach(isdp) 500 struct isa_device *isdp; 501{ 502 int adapter; 503 504 adapter = cyattach_common((cy_addr) isdp->id_maddr, 0); 505 if (adapter < 0) 506 return (0); 507 508 /* 509 * XXX 510 * This kludge is to allow ISA/PCI device specifications in the 511 * kernel config file to be in any order. 512 */ 513 if (isdp->id_unit != adapter) { 514 printf("cy%d: attached as cy%d\n", isdp->id_unit, adapter); 515 isdp->id_unit = adapter; /* XXX */ 516 } 517 isdp->id_ointr = siointr; 518 isdp->id_ri_flags |= RI_FAST; 519 return (1); 520} 521 522int 523cyattach_common(cy_iobase, cy_align) 524 cy_addr cy_iobase; 525 int cy_align; 526{ 527 int adapter; 528 int cyu; 529 dev_t dev; 530 u_char firmware_version; 531 cy_addr iobase; 532 int ncyu; 533 int unit; 534 535 adapter = cy_total_devices; 536 if ((u_int)adapter >= NCY) { 537 printf( 538 "cy%d: can't attach adapter: insufficient cy devices configured\n", 539 adapter); 540 return (-1); 541 } 542 ncyu = cy_units(cy_iobase, cy_align); 543 if (ncyu == 0) 544 return (-1); 545 cy_nr_cd1400s[adapter] = ncyu; 546 cy_total_devices++; 547 548 unit = adapter * CY_MAX_PORTS; 549 for (cyu = 0; cyu < ncyu; ++cyu) { 550 int cdu; 551 552 iobase = (cy_addr) (cy_iobase 553 + (cy_chip_offset[cyu] << cy_align)); 554 firmware_version = cd_inb(iobase, CD1400_GFRCR, cy_align); 555 556 /* Set up a receive timeout period of than 1+ ms. */ 557 cd_outb(iobase, CD1400_PPR, cy_align, 558 howmany(CY_CLOCK(firmware_version) 559 / CD1400_PPR_PRESCALER, 1000)); 560 561 for (cdu = 0; cdu < CD1400_NO_OF_CHANNELS; ++cdu, ++unit) { 562 struct com_s *com; 563 int s; 564 565 com = malloc(sizeof *com, M_DEVBUF, M_NOWAIT); 566 if (com == NULL) 567 break; 568 bzero(com, sizeof *com); 569 com->unit = unit; 570 com->gfrcr_image = firmware_version; 571 if (CY_RTS_DTR_SWAPPED(firmware_version)) { 572 com->mcr_dtr = MCR_RTS; 573 com->mcr_rts = MCR_DTR; 574 com->mcr_rts_reg = CD1400_MSVR2; 575 } else { 576 com->mcr_dtr = MCR_DTR; 577 com->mcr_rts = MCR_RTS; 578 com->mcr_rts_reg = CD1400_MSVR1; 579 } 580 com->dtr_wait = 3 * hz; 581 com->iptr = com->ibuf = com->ibuf1; 582 com->ibufend = com->ibuf1 + RS_IBUFSIZE; 583 com->ihighwater = com->ibuf1 + RS_IHIGHWATER; 584 com->obufs[0].l_head = com->obuf1; 585 com->obufs[1].l_head = com->obuf2; 586 587 com->cy_align = cy_align; 588 com->cy_iobase = cy_iobase; 589 com->iobase = iobase; 590 com->car = ~CD1400_CAR_CHAN; 591 592 /* 593 * We don't use all the flags from <sys/ttydefaults.h> since they 594 * are only relevant for logins. It's important to have echo off 595 * initially so that the line doesn't start blathering before the 596 * echo flag can be turned off. 597 */ 598 com->it_in.c_iflag = 0; 599 com->it_in.c_oflag = 0; 600 com->it_in.c_cflag = TTYDEF_CFLAG; 601 com->it_in.c_lflag = 0; 602 if (unit == comconsole) { 603 com->it_in.c_iflag = TTYDEF_IFLAG; 604 com->it_in.c_oflag = TTYDEF_OFLAG; 605 com->it_in.c_cflag = TTYDEF_CFLAG | CLOCAL; 606 com->it_in.c_lflag = TTYDEF_LFLAG; 607 com->lt_out.c_cflag = com->lt_in.c_cflag = CLOCAL; 608 } 609 termioschars(&com->it_in); 610 com->it_in.c_ispeed = com->it_in.c_ospeed = comdefaultrate; 611 com->it_out = com->it_in; 612 613 s = spltty(); 614 com_addr(unit) = com; 615 splx(s); 616 617 if (!sio_registered) { 618 dev = makedev(CDEV_MAJOR, 0); 619 cdevsw_add(&dev, &sio_cdevsw, NULL); 620 register_swi(SWI_TTY, siopoll); 621 sio_registered = TRUE; 622 } 623#ifdef DEVFS 624 com->devfs_token_ttyd = devfs_add_devswf(&sio_cdevsw, 625 unit, DV_CHR, 626 UID_ROOT, GID_WHEEL, 0600, "ttyc%r%r", adapter, 627 unit % CY_MAX_PORTS); 628 com->devfs_token_ttyi = devfs_add_devswf(&sio_cdevsw, 629 unit | CONTROL_INIT_STATE, DV_CHR, 630 UID_ROOT, GID_WHEEL, 0600, "ttyic%r%r", adapter, 631 unit % CY_MAX_PORTS); 632 com->devfs_token_ttyl = devfs_add_devswf(&sio_cdevsw, 633 unit | CONTROL_LOCK_STATE, DV_CHR, 634 UID_ROOT, GID_WHEEL, 0600, "ttylc%r%r", adapter, 635 unit % CY_MAX_PORTS); 636 com->devfs_token_cuaa = devfs_add_devswf(&sio_cdevsw, 637 unit | CALLOUT_MASK, DV_CHR, 638 UID_UUCP, GID_DIALER, 0660, "cuac%r%r", adapter, 639 unit % CY_MAX_PORTS); 640 com->devfs_token_cuai = devfs_add_devswf(&sio_cdevsw, 641 unit | CALLOUT_MASK | CONTROL_INIT_STATE, DV_CHR, 642 UID_UUCP, GID_DIALER, 0660, "cuaic%r%r", adapter, 643 unit % CY_MAX_PORTS); 644 com->devfs_token_cual = devfs_add_devswf(&sio_cdevsw, 645 unit | CALLOUT_MASK | CONTROL_LOCK_STATE, DV_CHR, 646 UID_UUCP, GID_DIALER, 0660, "cualc%r%r", adapter, 647 unit % CY_MAX_PORTS); 648#endif 649 } 650 } 651 652 /* ensure an edge for the next interrupt */ 653 cy_outb(cy_iobase, CY_CLEAR_INTR, cy_align, 0); 654 655 return (adapter); 656} 657 658static int 659sioopen(dev, flag, mode, p) 660 dev_t dev; 661 int flag; 662 int mode; 663 struct proc *p; 664{ 665 struct com_s *com; 666 int error; 667 int mynor; 668 int s; 669 struct tty *tp; 670 int unit; 671 672 mynor = minor(dev); 673 unit = MINOR_TO_UNIT(mynor); 674 if ((u_int) unit >= NSIO || (com = com_addr(unit)) == NULL) 675 return (ENXIO); 676 if (mynor & CONTROL_MASK) 677 return (0); 678#if 0 /* XXX */ 679 tp = com->tp = sio_tty[unit] = ttymalloc(sio_tty[unit]); 680#else 681 tp = com->tp = &sio_tty[unit]; 682#endif 683 s = spltty(); 684 /* 685 * We jump to this label after all non-interrupted sleeps to pick 686 * up any changes of the device state. 687 */ 688open_top: 689 while (com->state & CS_DTR_OFF) { 690 error = tsleep(&com->dtr_wait, TTIPRI | PCATCH, "cydtr", 0); 691 if (error != 0) 692 goto out; 693 } 694 if (tp->t_state & TS_ISOPEN) { 695 /* 696 * The device is open, so everything has been initialized. 697 * Handle conflicts. 698 */ 699 if (mynor & CALLOUT_MASK) { 700 if (!com->active_out) { 701 error = EBUSY; 702 goto out; 703 } 704 } else { 705 if (com->active_out) { 706 if (flag & O_NONBLOCK) { 707 error = EBUSY; 708 goto out; 709 } 710 error = tsleep(&com->active_out, 711 TTIPRI | PCATCH, "cybi", 0); 712 if (error != 0) 713 goto out; 714 goto open_top; 715 } 716 } 717 if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) { 718 error = EBUSY; 719 goto out; 720 } 721 } else { 722 /* 723 * The device isn't open, so there are no conflicts. 724 * Initialize it. Initialization is done twice in many 725 * cases: to preempt sleeping callin opens if we are 726 * callout, and to complete a callin open after DCD rises. 727 */ 728 tp->t_oproc = comstart; 729 tp->t_param = comparam; 730 tp->t_dev = dev; 731 tp->t_termios = mynor & CALLOUT_MASK 732 ? com->it_out : com->it_in; 733 tp->t_ififosize = 2 * RS_IBUFSIZE; 734 tp->t_ispeedwat = (speed_t)-1; 735 tp->t_ospeedwat = (speed_t)-1; 736#if 0 737 (void)commctl(com, TIOCM_DTR | TIOCM_RTS, DMSET); 738 com->poll = com->no_irq; 739 com->poll_output = com->loses_outints; 740#endif 741 ++com->wopeners; 742 743 /* reset this channel */ 744 cd1400_channel_cmd(com, CD1400_CCR_CMDRESET); 745 746 /* 747 * Resetting disables the transmitter and receiver as well as 748 * flushing the fifos so some of our cached state becomes 749 * invalid. The documentation suggests that all registers 750 * for the current channel are reset to defaults, but 751 * apparently none are. We wouldn't want DTR cleared. 752 */ 753 com->channel_control = 0; 754 755 /* Encode per-board unit in LIVR for access in intr routines. */ 756 cd_setreg(com, CD1400_LIVR, 757 (unit & CD1400_xIVR_CHAN) << CD1400_xIVR_CHAN_SHIFT); 758 759 /* 760 * raise dtr and generally set things up correctly. this 761 * has the side-effect of selecting the appropriate cd1400 762 * channel, to help us with subsequent channel control stuff 763 */ 764 error = comparam(tp, &tp->t_termios); 765 --com->wopeners; 766 if (error != 0) 767 goto out; 768 /* 769 * XXX we should goto open_top if comparam() slept. 770 */ 771#if 0 772 if (com->hasfifo) { 773 /* 774 * (Re)enable and drain fifos. 775 * 776 * Certain SMC chips cause problems if the fifos 777 * are enabled while input is ready. Turn off the 778 * fifo if necessary to clear the input. We test 779 * the input ready bit after enabling the fifos 780 * since we've already enabled them in comparam() 781 * and to handle races between enabling and fresh 782 * input. 783 */ 784 while (TRUE) { 785 outb(iobase + com_fifo, 786 FIFO_RCV_RST | FIFO_XMT_RST 787 | com->fifo_image); 788 DELAY(100); 789 if (!(inb(com->line_status_port) & LSR_RXRDY)) 790 break; 791 outb(iobase + com_fifo, 0); 792 DELAY(100); 793 (void) inb(com->data_port); 794 } 795 } 796 797 disable_intr(); 798 (void) inb(com->line_status_port); 799 (void) inb(com->data_port); 800 com->prev_modem_status = com->last_modem_status 801 = inb(com->modem_status_port); 802 outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS 803 | IER_EMSC); 804 enable_intr(); 805#else /* !0 */ 806 /* XXX raise RTS too */ 807 (void)commctl(com, TIOCM_DTR | TIOCM_RTS, DMSET); 808 disable_intr(); 809 com->prev_modem_status = com->last_modem_status 810 = cd_getreg(com, CD1400_MSVR2); 811 cd_setreg(com, CD1400_SRER, 812 com->intr_enable 813 = CD1400_SRER_MDMCH | CD1400_SRER_RXDATA); 814 enable_intr(); 815#endif /* 0 */ 816 /* 817 * Handle initial DCD. Callout devices get a fake initial 818 * DCD (trapdoor DCD). If we are callout, then any sleeping 819 * callin opens get woken up and resume sleeping on "cybi" 820 * instead of "cydcd". 821 */ 822 /* 823 * XXX `mynor & CALLOUT_MASK' should be 824 * `tp->t_cflag & (SOFT_CARRIER | TRAPDOOR_CARRIER) where 825 * TRAPDOOR_CARRIER is the default initial state for callout 826 * devices and SOFT_CARRIER is like CLOCAL except it hides 827 * the true carrier. 828 */ 829 if (com->prev_modem_status & MSR_DCD || mynor & CALLOUT_MASK) 830 (*linesw[tp->t_line].l_modem)(tp, 1); 831 } 832 /* 833 * Wait for DCD if necessary. 834 */ 835 if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK) 836 && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) { 837 ++com->wopeners; 838 error = tsleep(TSA_CARR_ON(tp), TTIPRI | PCATCH, "cydcd", 0); 839 --com->wopeners; 840 if (error != 0) 841 goto out; 842 goto open_top; 843 } 844 error = (*linesw[tp->t_line].l_open)(dev, tp); 845 disc_optim(tp, &tp->t_termios, com); 846 if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK) 847 com->active_out = TRUE; 848 siosettimeout(); 849out: 850 splx(s); 851 if (!(tp->t_state & TS_ISOPEN) && com->wopeners == 0) 852 comhardclose(com); 853 return (error); 854} 855 856static int 857sioclose(dev, flag, mode, p) 858 dev_t dev; 859 int flag; 860 int mode; 861 struct proc *p; 862{ 863 struct com_s *com; 864 int mynor; 865 int s; 866 struct tty *tp; 867 868 mynor = minor(dev); 869 if (mynor & CONTROL_MASK) 870 return (0); 871 com = com_addr(MINOR_TO_UNIT(mynor)); 872 tp = com->tp; 873 s = spltty(); 874 (*linesw[tp->t_line].l_close)(tp, flag); 875 disc_optim(tp, &tp->t_termios, com); 876 siostop(tp, FREAD | FWRITE); 877 comhardclose(com); 878 ttyclose(tp); 879 siosettimeout(); 880 splx(s); 881#ifdef broken /* session holds a ref to the tty; can't deallocate */ 882 ttyfree(tp); 883 com->tp = sio_tty[unit] = NULL; 884#endif 885 return (0); 886} 887 888static void 889comhardclose(com) 890 struct com_s *com; 891{ 892 cy_addr iobase; 893 int s; 894 struct tty *tp; 895 int unit; 896 897 unit = com->unit; 898 iobase = com->iobase; 899 s = spltty(); 900#if 0 901 com->poll = FALSE; 902 com->poll_output = FALSE; 903#endif 904 com->do_timestamp = 0; 905#if 0 906 outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK); 907#endif 908 909 { 910#if 0 911 outb(iobase + com_ier, 0); 912#else 913 disable_intr(); 914 cd_setreg(com, CD1400_SRER, com->intr_enable = 0); 915 enable_intr(); 916#endif 917 tp = com->tp; 918 if (tp->t_cflag & HUPCL 919 /* 920 * XXX we will miss any carrier drop between here and the 921 * next open. Perhaps we should watch DCD even when the 922 * port is closed; it is not sufficient to check it at 923 * the next open because it might go up and down while 924 * we're not watching. 925 */ 926 || !com->active_out 927 && !(com->prev_modem_status & MSR_DCD) 928 && !(com->it_in.c_cflag & CLOCAL) 929 || !(tp->t_state & TS_ISOPEN)) { 930 (void)commctl(com, TIOCM_DTR, DMBIC); 931 932 /* Disable receiver (leave transmitter enabled). */ 933 com->channel_control = CD1400_CCR_CMDCHANCTL 934 | CD1400_CCR_XMTEN 935 | CD1400_CCR_RCVDIS; 936 cd1400_channel_cmd(com, com->channel_control); 937 938 if (com->dtr_wait != 0 && !(com->state & CS_DTR_OFF)) { 939 timeout(siodtrwakeup, com, com->dtr_wait); 940 com->state |= CS_DTR_OFF; 941 } 942 } 943 } 944#if 0 945 if (com->hasfifo) { 946 /* 947 * Disable fifos so that they are off after controlled 948 * reboots. Some BIOSes fail to detect 16550s when the 949 * fifos are enabled. 950 */ 951 outb(iobase + com_fifo, 0); 952 } 953#endif 954 com->active_out = FALSE; 955 wakeup(&com->active_out); 956 wakeup(TSA_CARR_ON(tp)); /* restart any wopeners */ 957 splx(s); 958} 959 960static int 961sioread(dev, uio, flag) 962 dev_t dev; 963 struct uio *uio; 964 int flag; 965{ 966 int mynor; 967 struct tty *tp; 968 969 mynor = minor(dev); 970 if (mynor & CONTROL_MASK) 971 return (ENODEV); 972 tp = com_addr(MINOR_TO_UNIT(mynor))->tp; 973 return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 974} 975 976static int 977siowrite(dev, uio, flag) 978 dev_t dev; 979 struct uio *uio; 980 int flag; 981{ 982 int mynor; 983 struct tty *tp; 984 int unit; 985 986 mynor = minor(dev); 987 if (mynor & CONTROL_MASK) 988 return (ENODEV); 989 990 unit = MINOR_TO_UNIT(mynor); 991 tp = com_addr(unit)->tp; 992 /* 993 * (XXX) We disallow virtual consoles if the physical console is 994 * a serial port. This is in case there is a display attached that 995 * is not the console. In that situation we don't need/want the X 996 * server taking over the console. 997 */ 998 if (constty != NULL && unit == comconsole) 999 constty = NULL; 1000#ifdef Smarts 1001 /* XXX duplicate ttwrite(), but without so much output processing on 1002 * CR & LF chars. Hardly worth the effort, given that high-throughput 1003 * sessions are raw anyhow. 1004 */ 1005#else 1006 return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 1007#endif 1008} 1009 1010static void 1011siodtrwakeup(chan) 1012 void *chan; 1013{ 1014 struct com_s *com; 1015 1016 com = (struct com_s *)chan; 1017 com->state &= ~CS_DTR_OFF; 1018 wakeup(&com->dtr_wait); 1019} 1020 1021void 1022siointr(unit) 1023 int unit; 1024{ 1025 int baseu; 1026 int cy_align; 1027 cy_addr cy_iobase; 1028 int cyu; 1029 cy_addr iobase; 1030 u_char status; 1031 1032 COM_LOCK(); /* XXX could this be placed down lower in the loop? */ 1033 1034 baseu = unit * CY_MAX_PORTS; 1035 cy_align = com_addr(baseu)->cy_align; 1036 cy_iobase = com_addr(baseu)->cy_iobase; 1037 1038 /* check each CD1400 in turn */ 1039 for (cyu = 0; cyu < cy_nr_cd1400s[unit]; ++cyu) { 1040 iobase = (cy_addr) (cy_iobase 1041 + (cy_chip_offset[cyu] << cy_align)); 1042 /* poll to see if it has any work */ 1043 status = cd_inb(iobase, CD1400_SVRR, cy_align); 1044 if (status == 0) 1045 continue; 1046#ifdef CyDebug 1047 ++cy_svrr_probes; 1048#endif 1049 /* service requests as appropriate, giving priority to RX */ 1050 if (status & CD1400_SVRR_RXRDY) { 1051 struct com_s *com; 1052 u_int count; 1053 u_char *ioptr; 1054 u_char line_status; 1055 u_char recv_data; 1056 u_char serv_type; 1057#ifdef PollMode 1058 u_char save_rir; 1059#endif 1060 1061#ifdef PollMode 1062 save_rir = cd_inb(iobase, CD1400_RIR, cy_align); 1063 1064 /* enter rx service */ 1065 cd_outb(iobase, CD1400_CAR, cy_align, save_rir); 1066 com_addr(baseu + cyu * CD1400_NO_OF_CHANNELS)->car 1067 = save_rir & CD1400_CAR_CHAN; 1068 1069 serv_type = cd_inb(iobase, CD1400_RIVR, cy_align); 1070 com = com_addr(baseu 1071 + ((serv_type >> CD1400_xIVR_CHAN_SHIFT) 1072 & CD1400_xIVR_CHAN)); 1073#else 1074 /* ack receive service */ 1075 serv_type = cy_inb(iobase, CY8_SVCACKR, cy_align); 1076 1077 com = com_addr(baseu + 1078 + ((serv_type >> CD1400_xIVR_CHAN_SHIFT) 1079 & CD1400_xIVR_CHAN)); 1080#endif 1081 1082 if (serv_type & CD1400_RIVR_EXCEPTION) { 1083 ++com->recv_exception; 1084 line_status = cd_inb(iobase, CD1400_RDSR, cy_align); 1085 /* break/unnattached error bits or real input? */ 1086 recv_data = cd_inb(iobase, CD1400_RDSR, cy_align); 1087#ifndef SOFT_HOTCHAR 1088 if (line_status & CD1400_RDSR_SPECIAL 1089 && com->hotchar != 0) 1090 setsofttty(); 1091#endif 1092#if 1 /* XXX "intelligent" PFO error handling would break O error handling */ 1093 if (line_status & (LSR_PE|LSR_FE|LSR_BI)) { 1094 /* 1095 Don't store PE if IGNPAR and BI if IGNBRK, 1096 this hack allows "raw" tty optimization 1097 works even if IGN* is set. 1098 */ 1099 if ( com->tp == NULL 1100 || !(com->tp->t_state & TS_ISOPEN) 1101 || (line_status & (LSR_PE|LSR_FE)) 1102 && (com->tp->t_iflag & IGNPAR) 1103 || (line_status & LSR_BI) 1104 && (com->tp->t_iflag & IGNBRK)) 1105 goto cont; 1106 if ( (line_status & (LSR_PE|LSR_FE)) 1107 && (com->tp->t_state & TS_CAN_BYPASS_L_RINT) 1108 && ((line_status & LSR_FE) 1109 || (line_status & LSR_PE) 1110 && (com->tp->t_iflag & INPCK))) 1111 recv_data = 0; 1112 } 1113#endif /* 1 */ 1114 ++com->bytes_in; 1115#ifdef SOFT_HOTCHAR 1116 if (com->hotchar != 0 && recv_data == com->hotchar) 1117 setsofttty(); 1118#endif 1119 ioptr = com->iptr; 1120 if (ioptr >= com->ibufend) 1121 CE_RECORD(com, CE_INTERRUPT_BUF_OVERFLOW); 1122 else { 1123 if (com->do_timestamp) 1124 microtime(&com->timestamp); 1125 ++com_events; 1126 ioptr[0] = recv_data; 1127 ioptr[CE_INPUT_OFFSET] = line_status; 1128 com->iptr = ++ioptr; 1129 if (ioptr == com->ihighwater 1130 && com->state & CS_RTS_IFLOW) 1131#if 0 1132 outb(com->modem_ctl_port, 1133 com->mcr_image &= ~MCR_RTS); 1134#else 1135 cd_outb(iobase, com->mcr_rts_reg, 1136 cy_align, 1137 com->mcr_image &= 1138 ~com->mcr_rts); 1139#endif 1140 if (line_status & LSR_OE) 1141 CE_RECORD(com, CE_OVERRUN); 1142 } 1143 goto cont; 1144 } else { 1145 int ifree; 1146 1147 count = cd_inb(iobase, CD1400_RDCR, cy_align); 1148 if (!count) 1149 goto cont; 1150 com->bytes_in += count; 1151 ioptr = com->iptr; 1152 ifree = com->ibufend - ioptr; 1153 if (count > ifree) { 1154 count -= ifree; 1155 com_events += ifree; 1156 if (ifree != 0) { 1157 if (com->do_timestamp) 1158 microtime(&com->timestamp); 1159 do { 1160 recv_data = cd_inb(iobase, 1161 CD1400_RDSR, 1162 cy_align); 1163#ifdef SOFT_HOTCHAR 1164 if (com->hotchar != 0 1165 && recv_data 1166 == com->hotchar) 1167 setsofttty(); 1168#endif 1169 ioptr[0] = recv_data; 1170 ioptr[CE_INPUT_OFFSET] = 0; 1171 ++ioptr; 1172 } while (--ifree != 0); 1173 } 1174 com->delta_error_counts 1175 [CE_INTERRUPT_BUF_OVERFLOW] += count; 1176 do { 1177 recv_data = cd_inb(iobase, CD1400_RDSR, 1178 cy_align); 1179#ifdef SOFT_HOTCHAR 1180 if (com->hotchar != 0 1181 && recv_data == com->hotchar) 1182 setsofttty(); 1183#endif 1184 } while (--count != 0); 1185 } else { 1186 if (com->do_timestamp) 1187 microtime(&com->timestamp); 1188 if (ioptr <= com->ihighwater 1189 && ioptr + count > com->ihighwater 1190 && com->state & CS_RTS_IFLOW) 1191#if 0 1192 outb(com->modem_ctl_port, 1193 com->mcr_image &= ~MCR_RTS); 1194#else 1195 cd_outb(iobase, com->mcr_rts_reg, 1196 cy_align, 1197 com->mcr_image 1198 &= ~com->mcr_rts); 1199#endif 1200 com_events += count; 1201 do { 1202 recv_data = cd_inb(iobase, CD1400_RDSR, 1203 cy_align); 1204#ifdef SOFT_HOTCHAR 1205 if (com->hotchar != 0 1206 && recv_data == com->hotchar) 1207 setsofttty(); 1208#endif 1209 ioptr[0] = recv_data; 1210 ioptr[CE_INPUT_OFFSET] = 0; 1211 ++ioptr; 1212 } while (--count != 0); 1213 } 1214 com->iptr = ioptr; 1215 } 1216cont: 1217 1218 /* terminate service context */ 1219#ifdef PollMode 1220 cd_outb(iobase, CD1400_RIR, cy_align, 1221 save_rir 1222 & ~(CD1400_RIR_RDIREQ | CD1400_RIR_RBUSY)); 1223#else 1224 cd_outb(iobase, CD1400_EOSRR, cy_align, 0); 1225#endif 1226 } 1227 if (status & CD1400_SVRR_MDMCH) { 1228 struct com_s *com; 1229 u_char modem_status; 1230#ifdef PollMode 1231 u_char save_mir; 1232#else 1233 u_char vector; 1234#endif 1235 1236#ifdef PollMode 1237 save_mir = cd_inb(iobase, CD1400_MIR, cy_align); 1238 1239 /* enter modem service */ 1240 cd_outb(iobase, CD1400_CAR, cy_align, save_mir); 1241 com_addr(baseu + cyu * CD1400_NO_OF_CHANNELS)->car 1242 = save_mir & CD1400_CAR_CHAN; 1243 1244 com = com_addr(baseu + cyu * CD1400_NO_OF_CHANNELS 1245 + (save_mir & CD1400_MIR_CHAN)); 1246#else 1247 /* ack modem service */ 1248 vector = cy_inb(iobase, CY8_SVCACKM, cy_align); 1249 1250 com = com_addr(baseu 1251 + ((vector >> CD1400_xIVR_CHAN_SHIFT) 1252 & CD1400_xIVR_CHAN)); 1253#endif 1254 ++com->mdm; 1255 modem_status = cd_inb(iobase, CD1400_MSVR2, cy_align); 1256 if (modem_status != com->last_modem_status) { 1257 if (com->do_dcd_timestamp 1258 && !(com->last_modem_status & MSR_DCD) 1259 && modem_status & MSR_DCD) 1260 microtime(&com->dcd_timestamp); 1261 1262 /* 1263 * Schedule high level to handle DCD changes. Note 1264 * that we don't use the delta bits anywhere. Some 1265 * UARTs mess them up, and it's easy to remember the 1266 * previous bits and calculate the delta. 1267 */ 1268 com->last_modem_status = modem_status; 1269 if (!(com->state & CS_CHECKMSR)) { 1270 com_events += LOTS_OF_EVENTS; 1271 com->state |= CS_CHECKMSR; 1272 setsofttty(); 1273 } 1274 1275#ifdef SOFT_CTS_OFLOW 1276 /* handle CTS change immediately for crisp flow ctl */ 1277 if (com->state & CS_CTS_OFLOW) { 1278 if (modem_status & MSR_CTS) { 1279 com->state |= CS_ODEVREADY; 1280 if (com->state >= (CS_BUSY | CS_TTGO 1281 | CS_ODEVREADY) 1282 && !(com->intr_enable 1283 & CD1400_SRER_TXRDY)) 1284 cd_outb(iobase, CD1400_SRER, 1285 cy_align, 1286 com->intr_enable 1287 = com->intr_enable 1288 & ~CD1400_SRER_TXMPTY 1289 | CD1400_SRER_TXRDY); 1290 } else { 1291 com->state &= ~CS_ODEVREADY; 1292 if (com->intr_enable 1293 & CD1400_SRER_TXRDY) 1294 cd_outb(iobase, CD1400_SRER, 1295 cy_align, 1296 com->intr_enable 1297 = com->intr_enable 1298 & ~CD1400_SRER_TXRDY 1299 | CD1400_SRER_TXMPTY); 1300 } 1301 } 1302#endif 1303 } 1304 1305 /* terminate service context */ 1306#ifdef PollMode 1307 cd_outb(iobase, CD1400_MIR, cy_align, 1308 save_mir 1309 & ~(CD1400_MIR_RDIREQ | CD1400_MIR_RBUSY)); 1310#else 1311 cd_outb(iobase, CD1400_EOSRR, cy_align, 0); 1312#endif 1313 } 1314 if (status & CD1400_SVRR_TXRDY) { 1315 struct com_s *com; 1316#ifdef PollMode 1317 u_char save_tir; 1318#else 1319 u_char vector; 1320#endif 1321 1322#ifdef PollMode 1323 save_tir = cd_inb(iobase, CD1400_TIR, cy_align); 1324 1325 /* enter tx service */ 1326 cd_outb(iobase, CD1400_CAR, cy_align, save_tir); 1327 com_addr(baseu + cyu * CD1400_NO_OF_CHANNELS)->car 1328 = save_tir & CD1400_CAR_CHAN; 1329 1330 com = com_addr(baseu 1331 + cyu * CD1400_NO_OF_CHANNELS 1332 + (save_tir & CD1400_TIR_CHAN)); 1333#else 1334 /* ack transmit service */ 1335 vector = cy_inb(iobase, CY8_SVCACKT, cy_align); 1336 1337 com = com_addr(baseu 1338 + ((vector >> CD1400_xIVR_CHAN_SHIFT) 1339 & CD1400_xIVR_CHAN)); 1340#endif 1341 1342 if (com->intr_enable & CD1400_SRER_TXMPTY) { 1343 if (!(com->extra_state & CSE_ODONE)) { 1344 com_events += LOTS_OF_EVENTS; 1345 com->extra_state |= CSE_ODONE; 1346 setsofttty(); 1347 } 1348 cd_outb(iobase, CD1400_SRER, cy_align, 1349 com->intr_enable 1350 &= ~CD1400_SRER_TXMPTY); 1351 goto terminate_tx_service; 1352 } 1353 if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) { 1354 u_char *ioptr; 1355 u_int ocount; 1356 1357 ioptr = com->obufq.l_head; 1358 ocount = com->obufq.l_tail - ioptr; 1359 if (ocount > CD1400_TX_FIFO_SIZE) 1360 ocount = CD1400_TX_FIFO_SIZE; 1361 com->bytes_out += ocount; 1362 do 1363 cd_outb(iobase, CD1400_TDR, cy_align, 1364 *ioptr++); 1365 while (--ocount != 0); 1366 com->obufq.l_head = ioptr; 1367 if (ioptr >= com->obufq.l_tail) { 1368 struct lbq *qp; 1369 1370 qp = com->obufq.l_next; 1371 qp->l_queued = FALSE; 1372 qp = qp->l_next; 1373 if (qp != NULL) { 1374 com->obufq.l_head = qp->l_head; 1375 com->obufq.l_tail = qp->l_tail; 1376 com->obufq.l_next = qp; 1377 } else { 1378 /* output just completed */ 1379 com->state &= ~CS_BUSY; 1380 1381 /* 1382 * The setting of CSE_ODONE may be 1383 * stale here. We currently only 1384 * use it when CS_BUSY is set, and 1385 * fixing it when we clear CS_BUSY 1386 * is easiest. 1387 */ 1388 if (com->extra_state & CSE_ODONE) { 1389 com_events -= LOTS_OF_EVENTS; 1390 com->extra_state &= ~CSE_ODONE; 1391 } 1392 1393 cd_outb(iobase, CD1400_SRER, cy_align, 1394 com->intr_enable 1395 = com->intr_enable 1396 & ~CD1400_SRER_TXRDY 1397 | CD1400_SRER_TXMPTY); 1398 } 1399 if (!(com->state & CS_ODONE)) { 1400 com_events += LOTS_OF_EVENTS; 1401 com->state |= CS_ODONE; 1402 1403 /* handle at high level ASAP */ 1404 setsofttty(); 1405 } 1406 } 1407 } 1408 1409 /* terminate service context */ 1410terminate_tx_service: 1411#ifdef PollMode 1412 cd_outb(iobase, CD1400_TIR, cy_align, 1413 save_tir 1414 & ~(CD1400_TIR_RDIREQ | CD1400_TIR_RBUSY)); 1415#else 1416 cd_outb(iobase, CD1400_EOSRR, cy_align, 0); 1417#endif 1418 } 1419 } 1420 1421 /* ensure an edge for the next interrupt */ 1422 cy_outb(cy_iobase, CY_CLEAR_INTR, cy_align, 0); 1423 1424 schedsofttty(); 1425 1426 COM_UNLOCK(); 1427} 1428 1429#if 0 1430static void 1431siointr1(com) 1432 struct com_s *com; 1433{ 1434} 1435#endif 1436 1437static int 1438sioioctl(dev, cmd, data, flag, p) 1439 dev_t dev; 1440 u_long cmd; 1441 caddr_t data; 1442 int flag; 1443 struct proc *p; 1444{ 1445 struct com_s *com; 1446 int error; 1447 int mynor; 1448 int s; 1449 struct tty *tp; 1450#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 1451 int oldcmd; 1452 struct termios term; 1453#endif 1454 1455 mynor = minor(dev); 1456 com = com_addr(MINOR_TO_UNIT(mynor)); 1457 if (mynor & CONTROL_MASK) { 1458 struct termios *ct; 1459 1460 switch (mynor & CONTROL_MASK) { 1461 case CONTROL_INIT_STATE: 1462 ct = mynor & CALLOUT_MASK ? &com->it_out : &com->it_in; 1463 break; 1464 case CONTROL_LOCK_STATE: 1465 ct = mynor & CALLOUT_MASK ? &com->lt_out : &com->lt_in; 1466 break; 1467 default: 1468 return (ENODEV); /* /dev/nodev */ 1469 } 1470 switch (cmd) { 1471 case TIOCSETA: 1472 error = suser(p->p_ucred, &p->p_acflag); 1473 if (error != 0) 1474 return (error); 1475 *ct = *(struct termios *)data; 1476 return (0); 1477 case TIOCGETA: 1478 *(struct termios *)data = *ct; 1479 return (0); 1480 case TIOCGETD: 1481 *(int *)data = TTYDISC; 1482 return (0); 1483 case TIOCGWINSZ: 1484 bzero(data, sizeof(struct winsize)); 1485 return (0); 1486 default: 1487 return (ENOTTY); 1488 } 1489 } 1490 tp = com->tp; 1491#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 1492 term = tp->t_termios; 1493 oldcmd = cmd; 1494 error = ttsetcompat(tp, &cmd, data, &term); 1495 if (error != 0) 1496 return (error); 1497 if (cmd != oldcmd) 1498 data = (caddr_t)&term; 1499#endif 1500 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) { 1501 int cc; 1502 struct termios *dt = (struct termios *)data; 1503 struct termios *lt = mynor & CALLOUT_MASK 1504 ? &com->lt_out : &com->lt_in; 1505 1506 dt->c_iflag = (tp->t_iflag & lt->c_iflag) 1507 | (dt->c_iflag & ~lt->c_iflag); 1508 dt->c_oflag = (tp->t_oflag & lt->c_oflag) 1509 | (dt->c_oflag & ~lt->c_oflag); 1510 dt->c_cflag = (tp->t_cflag & lt->c_cflag) 1511 | (dt->c_cflag & ~lt->c_cflag); 1512 dt->c_lflag = (tp->t_lflag & lt->c_lflag) 1513 | (dt->c_lflag & ~lt->c_lflag); 1514 for (cc = 0; cc < NCCS; ++cc) 1515 if (lt->c_cc[cc] != 0) 1516 dt->c_cc[cc] = tp->t_cc[cc]; 1517 if (lt->c_ispeed != 0) 1518 dt->c_ispeed = tp->t_ispeed; 1519 if (lt->c_ospeed != 0) 1520 dt->c_ospeed = tp->t_ospeed; 1521 } 1522 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 1523 if (error != ENOIOCTL) 1524 return (error); 1525 s = spltty(); 1526 error = ttioctl(tp, cmd, data, flag); 1527 disc_optim(tp, &tp->t_termios, com); 1528 if (error != ENOIOCTL) { 1529 splx(s); 1530 return (error); 1531 } 1532 switch (cmd) { 1533#if 0 1534 case TIOCSBRK: 1535 outb(iobase + com_cfcr, com->cfcr_image |= CFCR_SBREAK); 1536 break; 1537 case TIOCCBRK: 1538 outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK); 1539 break; 1540#endif /* 0 */ 1541 case TIOCSDTR: 1542 (void)commctl(com, TIOCM_DTR, DMBIS); 1543 break; 1544 case TIOCCDTR: 1545 (void)commctl(com, TIOCM_DTR, DMBIC); 1546 break; 1547 /* 1548 * XXX should disallow changing MCR_RTS if CS_RTS_IFLOW is set. The 1549 * changes get undone on the next call to comparam(). 1550 */ 1551 case TIOCMSET: 1552 (void)commctl(com, *(int *)data, DMSET); 1553 break; 1554 case TIOCMBIS: 1555 (void)commctl(com, *(int *)data, DMBIS); 1556 break; 1557 case TIOCMBIC: 1558 (void)commctl(com, *(int *)data, DMBIC); 1559 break; 1560 case TIOCMGET: 1561 *(int *)data = commctl(com, 0, DMGET); 1562 break; 1563 case TIOCMSDTRWAIT: 1564 /* must be root since the wait applies to following logins */ 1565 error = suser(p->p_ucred, &p->p_acflag); 1566 if (error != 0) { 1567 splx(s); 1568 return (error); 1569 } 1570 com->dtr_wait = *(int *)data * hz / 100; 1571 break; 1572 case TIOCMGDTRWAIT: 1573 *(int *)data = com->dtr_wait * 100 / hz; 1574 break; 1575 case TIOCTIMESTAMP: 1576 com->do_timestamp = TRUE; 1577 *(struct timeval *)data = com->timestamp; 1578 break; 1579 case TIOCDCDTIMESTAMP: 1580 com->do_dcd_timestamp = TRUE; 1581 *(struct timeval *)data = com->dcd_timestamp; 1582 break; 1583 default: 1584 splx(s); 1585 return (ENOTTY); 1586 } 1587 splx(s); 1588 return (0); 1589} 1590 1591static void 1592siopoll() 1593{ 1594 int unit; 1595 1596#ifdef CyDebug 1597 ++cy_timeouts; 1598#endif 1599 if (com_events == 0) 1600 return; 1601repeat: 1602 for (unit = 0; unit < NSIO; ++unit) { 1603 u_char *buf; 1604 struct com_s *com; 1605 u_char *ibuf; 1606 int incc; 1607 struct tty *tp; 1608 1609 com = com_addr(unit); 1610 if (com == NULL) 1611 continue; 1612 tp = com->tp; 1613 if (tp == NULL) { 1614 /* 1615 * XXX forget any events related to closed devices 1616 * (actually never opened devices) so that we don't 1617 * loop. 1618 */ 1619 disable_intr(); 1620 incc = com->iptr - com->ibuf; 1621 com->iptr = com->ibuf; 1622 if (com->state & CS_CHECKMSR) { 1623 incc += LOTS_OF_EVENTS; 1624 com->state &= ~CS_CHECKMSR; 1625 } 1626 com_events -= incc; 1627 enable_intr(); 1628 if (incc != 0) 1629 log(LOG_DEBUG, 1630 "sio%d: %d events for device with no tp\n", 1631 unit, incc); 1632 continue; 1633 } 1634 1635 /* switch the role of the low-level input buffers */ 1636 if (com->iptr == (ibuf = com->ibuf)) { 1637 buf = NULL; /* not used, but compiler can't tell */ 1638 incc = 0; 1639 } else { 1640 buf = ibuf; 1641 disable_intr(); 1642 incc = com->iptr - buf; 1643 com_events -= incc; 1644 if (ibuf == com->ibuf1) 1645 ibuf = com->ibuf2; 1646 else 1647 ibuf = com->ibuf1; 1648 com->ibufend = ibuf + RS_IBUFSIZE; 1649 com->ihighwater = ibuf + RS_IHIGHWATER; 1650 com->iptr = ibuf; 1651 1652 /* 1653 * There is now room for another low-level buffer full 1654 * of input, so enable RTS if it is now disabled and 1655 * there is room in the high-level buffer. 1656 */ 1657 if ((com->state & CS_RTS_IFLOW) 1658 && !(com->mcr_image & com->mcr_rts) 1659 && !(tp->t_state & TS_TBLOCK)) 1660#if 0 1661 outb(com->modem_ctl_port, 1662 com->mcr_image |= MCR_RTS); 1663#else 1664 cd_setreg(com, com->mcr_rts_reg, 1665 com->mcr_image |= com->mcr_rts); 1666#endif 1667 enable_intr(); 1668 com->ibuf = ibuf; 1669 } 1670 1671 if (com->state & CS_CHECKMSR) { 1672 u_char delta_modem_status; 1673 1674 disable_intr(); 1675 delta_modem_status = com->last_modem_status 1676 ^ com->prev_modem_status; 1677 com->prev_modem_status = com->last_modem_status; 1678 com_events -= LOTS_OF_EVENTS; 1679 com->state &= ~CS_CHECKMSR; 1680 enable_intr(); 1681 if (delta_modem_status & MSR_DCD) 1682 (*linesw[tp->t_line].l_modem) 1683 (tp, com->prev_modem_status & MSR_DCD); 1684 } 1685 if (com->state & CS_ODONE) { 1686 disable_intr(); 1687 com_events -= LOTS_OF_EVENTS; 1688 com->state &= ~CS_ODONE; 1689 enable_intr(); 1690 (*linesw[tp->t_line].l_start)(tp); 1691 } 1692 if (com->extra_state & CSE_ODONE) { 1693 disable_intr(); 1694 com_events -= LOTS_OF_EVENTS; 1695 com->extra_state &= ~CSE_ODONE; 1696 enable_intr(); 1697 if (!(com->state & CS_BUSY)) { 1698 tp->t_state &= ~TS_BUSY; 1699 ttwwakeup(com->tp); 1700 } 1701 } 1702 if (incc <= 0 || !(tp->t_state & TS_ISOPEN)) 1703 continue; 1704 /* 1705 * Avoid the grotesquely inefficient lineswitch routine 1706 * (ttyinput) in "raw" mode. It usually takes about 450 1707 * instructions (that's without canonical processing or echo!). 1708 * slinput is reasonably fast (usually 40 instructions plus 1709 * call overhead). 1710 */ 1711 if (tp->t_state & TS_CAN_BYPASS_L_RINT) { 1712 if (tp->t_rawq.c_cc + incc > tp->t_ihiwat 1713 && (com->state & CS_RTS_IFLOW 1714 || tp->t_iflag & IXOFF) 1715 && !(tp->t_state & TS_TBLOCK)) 1716 ttyblock(tp); 1717 tk_nin += incc; 1718 tk_rawcc += incc; 1719 tp->t_rawcc += incc; 1720 com->delta_error_counts[CE_TTY_BUF_OVERFLOW] 1721 += b_to_q((char *)buf, incc, &tp->t_rawq); 1722 ttwakeup(tp); 1723 if (tp->t_state & TS_TTSTOP 1724 && (tp->t_iflag & IXANY 1725 || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) { 1726 tp->t_state &= ~TS_TTSTOP; 1727 tp->t_lflag &= ~FLUSHO; 1728 comstart(tp); 1729 } 1730 } else { 1731 do { 1732 u_char line_status; 1733 int recv_data; 1734 1735 line_status = (u_char) buf[CE_INPUT_OFFSET]; 1736 recv_data = (u_char) *buf++; 1737 if (line_status 1738 & (LSR_BI | LSR_FE | LSR_OE | LSR_PE)) { 1739 if (line_status & LSR_BI) 1740 recv_data |= TTY_BI; 1741 if (line_status & LSR_FE) 1742 recv_data |= TTY_FE; 1743 if (line_status & LSR_OE) 1744 recv_data |= TTY_OE; 1745 if (line_status & LSR_PE) 1746 recv_data |= TTY_PE; 1747 } 1748 (*linesw[tp->t_line].l_rint)(recv_data, tp); 1749 } while (--incc > 0); 1750 } 1751 if (com_events == 0) 1752 break; 1753 } 1754 if (com_events >= LOTS_OF_EVENTS) 1755 goto repeat; 1756} 1757 1758static int 1759comparam(tp, t) 1760 struct tty *tp; 1761 struct termios *t; 1762{ 1763 int bits; 1764 int cflag; 1765 struct com_s *com; 1766 u_char cor_change; 1767 u_long cy_clock; 1768 int idivisor; 1769 int iflag; 1770 int iprescaler; 1771 int itimeout; 1772 int odivisor; 1773 int oprescaler; 1774 u_char opt; 1775 int s; 1776 int unit; 1777 1778 /* do historical conversions */ 1779 if (t->c_ispeed == 0) 1780 t->c_ispeed = t->c_ospeed; 1781 1782 unit = DEV_TO_UNIT(tp->t_dev); 1783 com = com_addr(unit); 1784 1785 /* check requested parameters */ 1786 cy_clock = CY_CLOCK(com->gfrcr_image); 1787 idivisor = comspeed(t->c_ispeed, cy_clock, &iprescaler); 1788 if (idivisor < 0) 1789 return (EINVAL); 1790 odivisor = comspeed(t->c_ospeed, cy_clock, &oprescaler); 1791 if (odivisor < 0) 1792 return (EINVAL); 1793 1794 /* parameters are OK, convert them to the com struct and the device */ 1795 s = spltty(); 1796 if (odivisor == 0) 1797 (void)commctl(com, TIOCM_DTR, DMBIC); /* hang up line */ 1798 else 1799 (void)commctl(com, TIOCM_DTR, DMBIS); 1800 1801 if (idivisor != 0) { 1802 cd_setreg(com, CD1400_RBPR, idivisor); 1803 cd_setreg(com, CD1400_RCOR, iprescaler); 1804 } 1805 if (odivisor != 0) { 1806 cd_setreg(com, CD1400_TBPR, odivisor); 1807 cd_setreg(com, CD1400_TCOR, oprescaler); 1808 } 1809 1810 /* 1811 * channel control 1812 * receiver enable 1813 * transmitter enable (always set) 1814 */ 1815 cflag = t->c_cflag; 1816 opt = CD1400_CCR_CMDCHANCTL | CD1400_CCR_XMTEN 1817 | (cflag & CREAD ? CD1400_CCR_RCVEN : CD1400_CCR_RCVDIS); 1818 if (opt != com->channel_control) { 1819 com->channel_control = opt; 1820 cd1400_channel_cmd(com, opt); 1821 } 1822 1823#ifdef Smarts 1824 /* set special chars */ 1825 /* XXX if one is _POSIX_VDISABLE, can't use some others */ 1826 if (t->c_cc[VSTOP] != _POSIX_VDISABLE) 1827 cd_setreg(com, CD1400_SCHR1, t->c_cc[VSTOP]); 1828 if (t->c_cc[VSTART] != _POSIX_VDISABLE) 1829 cd_setreg(com, CD1400_SCHR2, t->c_cc[VSTART]); 1830 if (t->c_cc[VINTR] != _POSIX_VDISABLE) 1831 cd_setreg(com, CD1400_SCHR3, t->c_cc[VINTR]); 1832 if (t->c_cc[VSUSP] != _POSIX_VDISABLE) 1833 cd_setreg(com, CD1400_SCHR4, t->c_cc[VSUSP]); 1834#endif 1835 1836 /* 1837 * set channel option register 1 - 1838 * parity mode 1839 * stop bits 1840 * char length 1841 */ 1842 opt = 0; 1843 /* parity */ 1844 if (cflag & PARENB) { 1845 if (cflag & PARODD) 1846 opt |= CD1400_COR1_PARODD; 1847 opt |= CD1400_COR1_PARNORMAL; 1848 } 1849 iflag = t->c_iflag; 1850 if (!(iflag & INPCK)) 1851 opt |= CD1400_COR1_NOINPCK; 1852 bits = 1 + 1; 1853 /* stop bits */ 1854 if (cflag & CSTOPB) { 1855 ++bits; 1856 opt |= CD1400_COR1_STOP2; 1857 } 1858 /* char length */ 1859 switch (cflag & CSIZE) { 1860 case CS5: 1861 bits += 5; 1862 opt |= CD1400_COR1_CS5; 1863 break; 1864 case CS6: 1865 bits += 6; 1866 opt |= CD1400_COR1_CS6; 1867 break; 1868 case CS7: 1869 bits += 7; 1870 opt |= CD1400_COR1_CS7; 1871 break; 1872 default: 1873 bits += 8; 1874 opt |= CD1400_COR1_CS8; 1875 break; 1876 } 1877 cor_change = 0; 1878 if (opt != com->cor[0]) { 1879 cor_change |= CD1400_CCR_COR1; 1880 cd_setreg(com, CD1400_COR1, com->cor[0] = opt); 1881 } 1882 1883 /* 1884 * Set receive time-out period, normally to max(one char time, 5 ms). 1885 */ 1886 if (t->c_ispeed == 0) 1887 itimeout = cd_getreg(com, CD1400_RTPR); 1888 else { 1889 itimeout = (1000 * bits + t->c_ispeed - 1) / t->c_ispeed; 1890#ifdef SOFT_HOTCHAR 1891#define MIN_RTP 1 1892#else 1893#define MIN_RTP 5 1894#endif 1895 if (itimeout < MIN_RTP) 1896 itimeout = MIN_RTP; 1897 } 1898 if (!(t->c_lflag & ICANON) && t->c_cc[VMIN] != 0 && t->c_cc[VTIME] != 0 1899 && t->c_cc[VTIME] * 10 > itimeout) 1900 itimeout = t->c_cc[VTIME] * 10; 1901 if (itimeout > 255) 1902 itimeout = 255; 1903 cd_setreg(com, CD1400_RTPR, itimeout); 1904 1905 /* 1906 * set channel option register 2 - 1907 * flow control 1908 */ 1909 opt = 0; 1910#ifdef Smarts 1911 if (iflag & IXANY) 1912 opt |= CD1400_COR2_IXANY; 1913 if (iflag & IXOFF) 1914 opt |= CD1400_COR2_IXOFF; 1915#endif 1916#ifndef SOFT_CTS_OFLOW 1917 if (cflag & CCTS_OFLOW) 1918 opt |= CD1400_COR2_CCTS_OFLOW; 1919#endif 1920 if (opt != com->cor[1]) { 1921 cor_change |= CD1400_CCR_COR2; 1922 cd_setreg(com, CD1400_COR2, com->cor[1] = opt); 1923 } 1924 1925 /* 1926 * set channel option register 3 - 1927 * receiver FIFO interrupt threshold 1928 * flow control 1929 */ 1930 opt = RxFifoThreshold; 1931#ifdef Smarts 1932 if (t->c_lflag & ICANON) 1933 opt |= CD1400_COR3_SCD34; /* detect INTR & SUSP chars */ 1934 if (iflag & IXOFF) 1935 /* detect and transparently handle START and STOP chars */ 1936 opt |= CD1400_COR3_FCT | CD1400_COR3_SCD12; 1937#endif 1938 if (opt != com->cor[2]) { 1939 cor_change |= CD1400_CCR_COR3; 1940 cd_setreg(com, CD1400_COR3, com->cor[2] = opt); 1941 } 1942 1943 /* notify the CD1400 if COR1-3 have changed */ 1944 if (cor_change) 1945 cd1400_channel_cmd(com, CD1400_CCR_CMDCORCHG | cor_change); 1946 1947 /* 1948 * set channel option register 4 - 1949 * CR/NL processing 1950 * break processing 1951 * received exception processing 1952 */ 1953 opt = 0; 1954 if (iflag & IGNCR) 1955 opt |= CD1400_COR4_IGNCR; 1956#ifdef Smarts 1957 /* 1958 * we need a new ttyinput() for this, as we don't want to 1959 * have ICRNL && INLCR being done in both layers, or to have 1960 * synchronisation problems 1961 */ 1962 if (iflag & ICRNL) 1963 opt |= CD1400_COR4_ICRNL; 1964 if (iflag & INLCR) 1965 opt |= CD1400_COR4_INLCR; 1966#endif 1967 if (iflag & IGNBRK) 1968 opt |= CD1400_COR4_IGNBRK; 1969 if (!(iflag & BRKINT)) 1970 opt |= CD1400_COR4_NOBRKINT; 1971#if 0 1972 /* XXX using this "intelligence" breaks reporting of overruns. */ 1973 if (iflag & IGNPAR) 1974 opt |= CD1400_COR4_PFO_DISCARD; 1975 else { 1976 if (iflag & PARMRK) 1977 opt |= CD1400_COR4_PFO_ESC; 1978 else 1979 opt |= CD1400_COR4_PFO_NUL; 1980 } 1981#else 1982 opt |= CD1400_COR4_PFO_EXCEPTION; 1983#endif 1984 cd_setreg(com, CD1400_COR4, opt); 1985 1986 /* 1987 * set channel option register 5 - 1988 */ 1989 opt = 0; 1990 if (iflag & ISTRIP) 1991 opt |= CD1400_COR5_ISTRIP; 1992 if (t->c_iflag & IEXTEN) 1993 /* enable LNEXT (e.g. ctrl-v quoting) handling */ 1994 opt |= CD1400_COR5_LNEXT; 1995#ifdef Smarts 1996 if (t->c_oflag & ONLCR) 1997 opt |= CD1400_COR5_ONLCR; 1998 if (t->c_oflag & OCRNL) 1999 opt |= CD1400_COR5_OCRNL; 2000#endif 2001 cd_setreg(com, CD1400_COR5, opt); 2002 2003 /* 2004 * We always generate modem status change interrupts for CD changes. 2005 * Among other things, this is necessary to track TS_CARR_ON for 2006 * pstat to print even when the driver doesn't care. CD changes 2007 * should be rare so interrupts for them are not worth extra code to 2008 * avoid. We avoid interrupts for other modem status changes (except 2009 * for CTS changes when SOFT_CTS_OFLOW is configured) since this is 2010 * simplest and best. 2011 */ 2012 2013 /* 2014 * set modem change option register 1 2015 * generate modem interrupts on which 1 -> 0 input transitions 2016 * also controls auto-DTR output flow-control, which we don't use 2017 */ 2018 opt = CD1400_MCOR1_CDzd; 2019#ifdef SOFT_CTS_OFLOW 2020 if (cflag & CCTS_OFLOW) 2021 opt |= CD1400_MCOR1_CTSzd; 2022#endif 2023 cd_setreg(com, CD1400_MCOR1, opt); 2024 2025 /* 2026 * set modem change option register 2 2027 * generate modem interrupts on specific 0 -> 1 input transitions 2028 */ 2029 opt = CD1400_MCOR2_CDod; 2030#ifdef SOFT_CTS_OFLOW 2031 if (cflag & CCTS_OFLOW) 2032 opt |= CD1400_MCOR2_CTSod; 2033#endif 2034 cd_setreg(com, CD1400_MCOR2, opt); 2035 2036 /* 2037 * XXX should have done this long ago, but there is too much state 2038 * to change all atomically. 2039 */ 2040 disable_intr(); 2041 2042 com->state &= ~CS_TTGO; 2043 if (!(tp->t_state & TS_TTSTOP)) 2044 com->state |= CS_TTGO; 2045 if (cflag & CRTS_IFLOW) { 2046 com->state |= CS_RTS_IFLOW; 2047 /* 2048 * If CS_RTS_IFLOW just changed from off to on, the change 2049 * needs to be propagated to MCR_RTS. This isn't urgent, 2050 * so do it later by calling comstart() instead of repeating 2051 * a lot of code from comstart() here. 2052 */ 2053 } else if (com->state & CS_RTS_IFLOW) { 2054 com->state &= ~CS_RTS_IFLOW; 2055 /* 2056 * CS_RTS_IFLOW just changed from on to off. Force MCR_RTS 2057 * on here, since comstart() won't do it later. 2058 */ 2059#if 0 2060 outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS); 2061#else 2062 cd_setreg(com, com->mcr_rts_reg, 2063 com->mcr_image |= com->mcr_rts); 2064#endif 2065 } 2066 2067 /* 2068 * Set up state to handle output flow control. 2069 * XXX - worth handling MDMBUF (DCD) flow control at the lowest level? 2070 * Now has 10+ msec latency, while CTS flow has 50- usec latency. 2071 */ 2072 com->state |= CS_ODEVREADY; 2073#ifdef SOFT_CTS_OFLOW 2074 com->state &= ~CS_CTS_OFLOW; 2075 if (cflag & CCTS_OFLOW) { 2076 com->state |= CS_CTS_OFLOW; 2077 if (!(com->last_modem_status & MSR_CTS)) 2078 com->state &= ~CS_ODEVREADY; 2079 } 2080#endif 2081 /* XXX shouldn't call functions while intrs are disabled. */ 2082 disc_optim(tp, t, com); 2083#if 0 2084 /* 2085 * Recover from fiddling with CS_TTGO. We used to call siointr1() 2086 * unconditionally, but that defeated the careful discarding of 2087 * stale input in sioopen(). 2088 */ 2089 if (com->state >= (CS_BUSY | CS_TTGO)) 2090 siointr1(com); 2091#endif 2092 if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) { 2093 if (!(com->intr_enable & CD1400_SRER_TXRDY)) 2094 cd_setreg(com, CD1400_SRER, 2095 com->intr_enable 2096 = com->intr_enable & ~CD1400_SRER_TXMPTY 2097 | CD1400_SRER_TXRDY); 2098 } else { 2099 if (com->intr_enable & CD1400_SRER_TXRDY) 2100 cd_setreg(com, CD1400_SRER, 2101 com->intr_enable 2102 = com->intr_enable & ~CD1400_SRER_TXRDY 2103 | CD1400_SRER_TXMPTY); 2104 } 2105 2106 enable_intr(); 2107 splx(s); 2108 comstart(tp); 2109 return (0); 2110} 2111 2112static void 2113comstart(tp) 2114 struct tty *tp; 2115{ 2116 struct com_s *com; 2117 int s; 2118#ifdef CyDebug 2119 bool_t started; 2120#endif 2121 int unit; 2122 2123 unit = DEV_TO_UNIT(tp->t_dev); 2124 com = com_addr(unit); 2125 s = spltty(); 2126 2127#ifdef CyDebug 2128 ++com->start_count; 2129 started = FALSE; 2130#endif 2131 2132 disable_intr(); 2133 if (tp->t_state & TS_TTSTOP) { 2134 com->state &= ~CS_TTGO; 2135 if (com->intr_enable & CD1400_SRER_TXRDY) 2136 cd_setreg(com, CD1400_SRER, 2137 com->intr_enable 2138 = com->intr_enable & ~CD1400_SRER_TXRDY 2139 | CD1400_SRER_TXMPTY); 2140 } else { 2141 com->state |= CS_TTGO; 2142 if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY) 2143 && !(com->intr_enable & CD1400_SRER_TXRDY)) 2144 cd_setreg(com, CD1400_SRER, 2145 com->intr_enable 2146 = com->intr_enable & ~CD1400_SRER_TXMPTY 2147 | CD1400_SRER_TXRDY); 2148 } 2149 if (tp->t_state & TS_TBLOCK) { 2150 if (com->mcr_image & com->mcr_rts && com->state & CS_RTS_IFLOW) 2151#if 0 2152 outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS); 2153#else 2154 cd_setreg(com, com->mcr_rts_reg, 2155 com->mcr_image &= ~com->mcr_rts); 2156#endif 2157 } else { 2158 if (!(com->mcr_image & com->mcr_rts) 2159 && com->iptr < com->ihighwater 2160 && com->state & CS_RTS_IFLOW) 2161#if 0 2162 outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS); 2163#else 2164 cd_setreg(com, com->mcr_rts_reg, 2165 com->mcr_image |= com->mcr_rts); 2166#endif 2167 } 2168 enable_intr(); 2169 if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) { 2170 ttwwakeup(tp); 2171 splx(s); 2172 return; 2173 } 2174 if (tp->t_outq.c_cc != 0) { 2175 struct lbq *qp; 2176 struct lbq *next; 2177 2178 if (!com->obufs[0].l_queued) { 2179#ifdef CyDebug 2180 started = TRUE; 2181#endif 2182 com->obufs[0].l_tail 2183 = com->obuf1 + q_to_b(&tp->t_outq, com->obuf1, 2184 sizeof com->obuf1); 2185 com->obufs[0].l_next = NULL; 2186 com->obufs[0].l_queued = TRUE; 2187 disable_intr(); 2188 if (com->state & CS_BUSY) { 2189 qp = com->obufq.l_next; 2190 while ((next = qp->l_next) != NULL) 2191 qp = next; 2192 qp->l_next = &com->obufs[0]; 2193 } else { 2194 com->obufq.l_head = com->obufs[0].l_head; 2195 com->obufq.l_tail = com->obufs[0].l_tail; 2196 com->obufq.l_next = &com->obufs[0]; 2197 com->state |= CS_BUSY; 2198 if (com->state >= (CS_BUSY | CS_TTGO 2199 | CS_ODEVREADY)) 2200 cd_setreg(com, CD1400_SRER, 2201 com->intr_enable 2202 = com->intr_enable 2203 & ~CD1400_SRER_TXMPTY 2204 | CD1400_SRER_TXRDY); 2205 } 2206 enable_intr(); 2207 } 2208 if (tp->t_outq.c_cc != 0 && !com->obufs[1].l_queued) { 2209#ifdef CyDebug 2210 started = TRUE; 2211#endif 2212 com->obufs[1].l_tail 2213 = com->obuf2 + q_to_b(&tp->t_outq, com->obuf2, 2214 sizeof com->obuf2); 2215 com->obufs[1].l_next = NULL; 2216 com->obufs[1].l_queued = TRUE; 2217 disable_intr(); 2218 if (com->state & CS_BUSY) { 2219 qp = com->obufq.l_next; 2220 while ((next = qp->l_next) != NULL) 2221 qp = next; 2222 qp->l_next = &com->obufs[1]; 2223 } else { 2224 com->obufq.l_head = com->obufs[1].l_head; 2225 com->obufq.l_tail = com->obufs[1].l_tail; 2226 com->obufq.l_next = &com->obufs[1]; 2227 com->state |= CS_BUSY; 2228 if (com->state >= (CS_BUSY | CS_TTGO 2229 | CS_ODEVREADY)) 2230 cd_setreg(com, CD1400_SRER, 2231 com->intr_enable 2232 = com->intr_enable 2233 & ~CD1400_SRER_TXMPTY 2234 | CD1400_SRER_TXRDY); 2235 } 2236 enable_intr(); 2237 } 2238 tp->t_state |= TS_BUSY; 2239 } 2240#ifdef CyDebug 2241 if (started) 2242 ++com->start_real; 2243#endif 2244#if 0 2245 disable_intr(); 2246 if (com->state >= (CS_BUSY | CS_TTGO)) 2247 siointr1(com); /* fake interrupt to start output */ 2248 enable_intr(); 2249#endif 2250 ttwwakeup(tp); 2251 splx(s); 2252} 2253 2254static void 2255siostop(tp, rw) 2256 struct tty *tp; 2257 int rw; 2258{ 2259 struct com_s *com; 2260 2261 com = com_addr(DEV_TO_UNIT(tp->t_dev)); 2262 disable_intr(); 2263 if (rw & FWRITE) { 2264 com->obufs[0].l_queued = FALSE; 2265 com->obufs[1].l_queued = FALSE; 2266 if (com->state & CS_ODONE) 2267 com_events -= LOTS_OF_EVENTS; 2268 com->state &= ~(CS_ODONE | CS_BUSY); 2269 if (com->extra_state & CSE_ODONE) { 2270 com_events -= LOTS_OF_EVENTS; 2271 com->extra_state &= ~CSE_ODONE; 2272 } 2273 com->tp->t_state &= ~TS_BUSY; 2274 } 2275 if (rw & FREAD) { 2276 com_events -= (com->iptr - com->ibuf); 2277 com->iptr = com->ibuf; 2278 } 2279 enable_intr(); 2280 comstart(tp); 2281 2282 /* XXX should clear h/w fifos too. */ 2283} 2284 2285static struct tty * 2286siodevtotty(dev) 2287 dev_t dev; 2288{ 2289 int mynor; 2290 int unit; 2291 2292 mynor = minor(dev); 2293 if (mynor & CONTROL_MASK) 2294 return (NULL); 2295 unit = MINOR_TO_UNIT(mynor); 2296 if ((u_int) unit >= NSIO) 2297 return (NULL); 2298 return (&sio_tty[unit]); 2299} 2300 2301static int 2302commctl(com, bits, how) 2303 struct com_s *com; 2304 int bits; 2305 int how; 2306{ 2307 int mcr; 2308 int msr; 2309 2310 if (how == DMGET) { 2311 if (com->channel_control & CD1400_CCR_RCVEN) 2312 bits |= TIOCM_LE; 2313 mcr = com->mcr_image; 2314 if (mcr & com->mcr_dtr) 2315 bits |= TIOCM_DTR; 2316 if (mcr & com->mcr_rts) 2317 /* XXX wired on for Cyclom-8Ys */ 2318 bits |= TIOCM_RTS; 2319 2320 /* 2321 * We must read the modem status from the hardware because 2322 * we don't generate modem status change interrupts for all 2323 * changes, so com->prev_modem_status is not guaranteed to 2324 * be up to date. This is safe, unlike for sio, because 2325 * reading the status register doesn't clear pending modem 2326 * status change interrupts. 2327 */ 2328 msr = cd_getreg(com, CD1400_MSVR2); 2329 2330 if (msr & MSR_CTS) 2331 bits |= TIOCM_CTS; 2332 if (msr & MSR_DCD) 2333 bits |= TIOCM_CD; 2334 if (msr & MSR_DSR) 2335 bits |= TIOCM_DSR; 2336 if (msr & MSR_RI) 2337 /* XXX not connected except for Cyclom-16Y? */ 2338 bits |= TIOCM_RI; 2339 return (bits); 2340 } 2341 mcr = 0; 2342 if (bits & TIOCM_DTR) 2343 mcr |= com->mcr_dtr; 2344 if (bits & TIOCM_RTS) 2345 mcr |= com->mcr_rts; 2346 disable_intr(); 2347 switch (how) { 2348 case DMSET: 2349 com->mcr_image = mcr; 2350 cd_setreg(com, CD1400_MSVR1, mcr); 2351 cd_setreg(com, CD1400_MSVR2, mcr); 2352 break; 2353 case DMBIS: 2354 com->mcr_image = mcr = com->mcr_image | mcr; 2355 cd_setreg(com, CD1400_MSVR1, mcr); 2356 cd_setreg(com, CD1400_MSVR2, mcr); 2357 break; 2358 case DMBIC: 2359 com->mcr_image = mcr = com->mcr_image & ~mcr; 2360 cd_setreg(com, CD1400_MSVR1, mcr); 2361 cd_setreg(com, CD1400_MSVR2, mcr); 2362 break; 2363 } 2364 enable_intr(); 2365 return (0); 2366} 2367 2368static void 2369siosettimeout() 2370{ 2371 struct com_s *com; 2372 bool_t someopen; 2373 int unit; 2374 2375 /* 2376 * Set our timeout period to 1 second if no polled devices are open. 2377 * Otherwise set it to max(1/200, 1/hz). 2378 * Enable timeouts iff some device is open. 2379 */ 2380 untimeout(comwakeup, (void *)NULL, sio_timeout_handle); 2381 sio_timeout = hz; 2382 someopen = FALSE; 2383 for (unit = 0; unit < NSIO; ++unit) { 2384 com = com_addr(unit); 2385 if (com != NULL && com->tp != NULL 2386 && com->tp->t_state & TS_ISOPEN) { 2387 someopen = TRUE; 2388#if 0 2389 if (com->poll || com->poll_output) { 2390 sio_timeout = hz > 200 ? hz / 200 : 1; 2391 break; 2392 } 2393#endif 2394 } 2395 } 2396 if (someopen) { 2397 sio_timeouts_until_log = hz / sio_timeout; 2398 sio_timeout_handle = timeout(comwakeup, (void *)NULL, 2399 sio_timeout); 2400 } else { 2401 /* Flush error messages, if any. */ 2402 sio_timeouts_until_log = 1; 2403 comwakeup((void *)NULL); 2404 untimeout(comwakeup, (void *)NULL, sio_timeout_handle); 2405 } 2406} 2407 2408static void 2409comwakeup(chan) 2410 void *chan; 2411{ 2412 struct com_s *com; 2413 int unit; 2414 2415 sio_timeout_handle = timeout(comwakeup, (void *)NULL, sio_timeout); 2416 2417#if 0 2418 /* 2419 * Recover from lost output interrupts. 2420 * Poll any lines that don't use interrupts. 2421 */ 2422 for (unit = 0; unit < NSIO; ++unit) { 2423 com = com_addr(unit); 2424 if (com != NULL 2425 && (com->state >= (CS_BUSY | CS_TTGO) || com->poll)) { 2426 disable_intr(); 2427 siointr1(com); 2428 enable_intr(); 2429 } 2430 } 2431#endif 2432 2433 /* 2434 * Check for and log errors, but not too often. 2435 */ 2436 if (--sio_timeouts_until_log > 0) 2437 return; 2438 sio_timeouts_until_log = hz / sio_timeout; 2439 for (unit = 0; unit < NSIO; ++unit) { 2440 int errnum; 2441 2442 com = com_addr(unit); 2443 if (com == NULL) 2444 continue; 2445 for (errnum = 0; errnum < CE_NTYPES; ++errnum) { 2446 u_int delta; 2447 u_long total; 2448 2449 disable_intr(); 2450 delta = com->delta_error_counts[errnum]; 2451 com->delta_error_counts[errnum] = 0; 2452 enable_intr(); 2453 if (delta == 0) 2454 continue; 2455 total = com->error_counts[errnum] += delta; 2456 log(LOG_ERR, "cy%d: %u more %s%s (total %lu)\n", 2457 unit, delta, error_desc[errnum], 2458 delta == 1 ? "" : "s", total); 2459 } 2460 } 2461} 2462 2463static void 2464disc_optim(tp, t, com) 2465 struct tty *tp; 2466 struct termios *t; 2467 struct com_s *com; 2468{ 2469#ifndef SOFT_HOTCHAR 2470 u_char opt; 2471#endif 2472 2473 /* 2474 * XXX can skip a lot more cases if Smarts. Maybe 2475 * (IGNCR | ISTRIP | IXON) in c_iflag. But perhaps we 2476 * shouldn't skip if (TS_CNTTB | TS_LNCH) is set in t_state. 2477 */ 2478 if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON)) 2479 && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK)) 2480 && (!(t->c_iflag & PARMRK) 2481 || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK)) 2482 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN)) 2483 && linesw[tp->t_line].l_rint == ttyinput) 2484 tp->t_state |= TS_CAN_BYPASS_L_RINT; 2485 else 2486 tp->t_state &= ~TS_CAN_BYPASS_L_RINT; 2487 com->hotchar = linesw[tp->t_line].l_hotchar; 2488#ifndef SOFT_HOTCHAR 2489 opt = com->cor[2] & ~CD1400_COR3_SCD34; 2490 if (com->hotchar != 0) { 2491 cd_setreg(com, CD1400_SCHR3, com->hotchar); 2492 cd_setreg(com, CD1400_SCHR4, com->hotchar); 2493 opt |= CD1400_COR3_SCD34; 2494 } 2495 if (opt != com->cor[2]) { 2496 cd_setreg(com, CD1400_COR3, com->cor[2] = opt); 2497 cd1400_channel_cmd(com, CD1400_CCR_CMDCORCHG | CD1400_CCR_COR3); 2498 } 2499#endif 2500} 2501 2502#ifdef Smarts 2503/* standard line discipline input routine */ 2504int 2505cyinput(c, tp) 2506 int c; 2507 struct tty *tp; 2508{ 2509 /* XXX duplicate ttyinput(), but without the IXOFF/IXON/ISTRIP/IPARMRK 2510 * bits, as they are done by the CD1400. Hardly worth the effort, 2511 * given that high-throughput sessions are raw anyhow. 2512 */ 2513} 2514#endif /* Smarts */ 2515 2516static int 2517comspeed(speed, cy_clock, prescaler_io) 2518 speed_t speed; 2519 u_long cy_clock; 2520 int *prescaler_io; 2521{ 2522 int actual; 2523 int error; 2524 int divider; 2525 int prescaler; 2526 int prescaler_unit; 2527 2528 if (speed == 0) 2529 return (0); 2530 if (speed < 0 || speed > 150000) 2531 return (-1); 2532 2533 /* determine which prescaler to use */ 2534 for (prescaler_unit = 4, prescaler = 2048; prescaler_unit; 2535 prescaler_unit--, prescaler >>= 2) { 2536 if (cy_clock / prescaler / speed > 63) 2537 break; 2538 } 2539 2540 divider = (cy_clock / prescaler * 2 / speed + 1) / 2; /* round off */ 2541 if (divider > 255) 2542 divider = 255; 2543 actual = cy_clock/prescaler/divider; 2544 2545 /* 10 times error in percent: */ 2546 error = ((actual - (long)speed) * 2000 / (long)speed + 1) / 2; 2547 2548 /* 3.0% max error tolerance */ 2549 if (error < -30 || error > 30) 2550 return (-1); 2551 2552#if 0 2553 printf("prescaler = %d (%d)\n", prescaler, prescaler_unit); 2554 printf("divider = %d (%x)\n", divider, divider); 2555 printf("actual = %d\n", actual); 2556 printf("error = %d\n", error); 2557#endif 2558 2559 *prescaler_io = prescaler_unit; 2560 return (divider); 2561} 2562 2563static void 2564cd1400_channel_cmd(com, cmd) 2565 struct com_s *com; 2566 int cmd; 2567{ 2568 /* XXX hsu@clinet.fi: This is always more dependent on ISA bus speed, 2569 as the card is probed every round? Replaced delaycount with 8k. 2570 Either delaycount has to be implemented in FreeBSD or more sensible 2571 way of doing these should be implemented. DELAY isn't enough here. 2572 */ 2573 u_int maxwait = 5 * 8 * 1024; /* approx. 5 ms */ 2574 2575 /* wait for processing of previous command to complete */ 2576 while (cd_getreg(com, CD1400_CCR) && maxwait--) 2577 ; 2578 2579 if (!maxwait) 2580 log(LOG_ERR, "cy: channel command timeout (%d loops) - arrgh\n", 2581 5 * 8 * 1024); 2582 2583 cd_setreg(com, CD1400_CCR, cmd); 2584} 2585 2586static int 2587cd_getreg(com, reg) 2588 struct com_s *com; 2589 int reg; 2590{ 2591 struct com_s *basecom; 2592 u_char car; 2593 int cy_align; 2594 u_long ef; 2595 cy_addr iobase; 2596 int val; 2597 2598 basecom = com_addr(com->unit & ~(CD1400_NO_OF_CHANNELS - 1)); 2599 car = com->unit & CD1400_CAR_CHAN; 2600 cy_align = com->cy_align; 2601 iobase = com->iobase; 2602 ef = read_eflags(); 2603 disable_intr(); 2604 if (basecom->car != car) 2605 cd_outb(iobase, CD1400_CAR, cy_align, basecom->car = car); 2606 val = cd_inb(iobase, reg, cy_align); 2607 write_eflags(ef); 2608 return (val); 2609} 2610 2611static void 2612cd_setreg(com, reg, val) 2613 struct com_s *com; 2614 int reg; 2615 int val; 2616{ 2617 struct com_s *basecom; 2618 u_char car; 2619 int cy_align; 2620 u_long ef; 2621 cy_addr iobase; 2622 2623 basecom = com_addr(com->unit & ~(CD1400_NO_OF_CHANNELS - 1)); 2624 car = com->unit & CD1400_CAR_CHAN; 2625 cy_align = com->cy_align; 2626 iobase = com->iobase; 2627 ef = read_eflags(); 2628 disable_intr(); 2629 if (basecom->car != car) 2630 cd_outb(iobase, CD1400_CAR, cy_align, basecom->car = car); 2631 cd_outb(iobase, reg, cy_align, val); 2632 write_eflags(ef); 2633} 2634 2635#ifdef CyDebug 2636/* useful in ddb */ 2637void 2638cystatus(unit) 2639 int unit; 2640{ 2641 struct com_s *com; 2642 cy_addr iobase; 2643 u_int ocount; 2644 struct tty *tp; 2645 2646 com = com_addr(unit); 2647 printf("info for channel %d\n", unit); 2648 printf("------------------\n"); 2649 printf("total cyclom service probes:\t%d\n", cy_svrr_probes); 2650 printf("calls to upper layer:\t\t%d\n", cy_timeouts); 2651 if (com == NULL) 2652 return; 2653 iobase = com->iobase; 2654 printf("\n"); 2655 printf("cd1400 base address:\\tt%p\n", iobase); 2656 printf("saved channel_control:\t\t0x%02x\n", com->channel_control); 2657 printf("saved cor1-3:\t\t\t0x%02x 0x%02x 0x%02x\n", 2658 com->cor[0], com->cor[1], com->cor[2]); 2659 printf("service request enable reg:\t0x%02x (0x%02x cached)\n", 2660 cd_getreg(com, CD1400_SRER), com->intr_enable); 2661 printf("service request register:\t0x%02x\n", 2662 cd_inb(iobase, CD1400_SVRR, com->cy_align)); 2663 printf("modem status:\t\t\t0x%02x (0x%02x cached)\n", 2664 cd_getreg(com, CD1400_MSVR2), com->prev_modem_status); 2665 printf("rx/tx/mdm interrupt registers:\t0x%02x 0x%02x 0x%02x\n", 2666 cd_inb(iobase, CD1400_RIR, com->cy_align), 2667 cd_inb(iobase, CD1400_TIR, com->cy_align), 2668 cd_inb(iobase, CD1400_MIR, com->cy_align)); 2669 printf("\n"); 2670 printf("com state:\t\t\t0x%02x\n", com->state); 2671 printf("calls to comstart():\t\t%d (%d useful)\n", 2672 com->start_count, com->start_real); 2673 printf("rx buffer chars free:\t\t%d\n", com->iptr - com->ibuf); 2674 ocount = 0; 2675 if (com->obufs[0].l_queued) 2676 ocount += com->obufs[0].l_tail - com->obufs[0].l_head; 2677 if (com->obufs[1].l_queued) 2678 ocount += com->obufs[1].l_tail - com->obufs[1].l_head; 2679 printf("tx buffer chars:\t\t%u\n", ocount); 2680 printf("received chars:\t\t\t%d\n", com->bytes_in); 2681 printf("received exceptions:\t\t%d\n", com->recv_exception); 2682 printf("modem signal deltas:\t\t%d\n", com->mdm); 2683 printf("transmitted chars:\t\t%d\n", com->bytes_out); 2684 printf("\n"); 2685 tp = com->tp; 2686 if (tp != NULL) { 2687 printf("tty state:\t\t\t0x%08x\n", tp->t_state); 2688 printf( 2689 "upper layer queue lengths:\t%d raw, %d canon, %d output\n", 2690 tp->t_rawq.c_cc, tp->t_canq.c_cc, tp->t_outq.c_cc); 2691 } else 2692 printf("tty state:\t\t\tclosed\n"); 2693} 2694#endif /* CyDebug */ 2695