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