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