cy.c revision 32726
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.59 1997/12/28 06:23:03 bde Exp $ 31 */ 32 33#include "opt_compat.h" 34#include "opt_devfs.h" 35 36#include "cy.h" 37 38/* 39 * TODO: 40 * Implement BREAK. 41 * Fix overflows when closing line. 42 * Atomic COR change. 43 * Consoles. 44 */ 45 46/* 47 * Temporary compile-time configuration options. 48 */ 49#define RxFifoThreshold (CD1400_RX_FIFO_SIZE / 2) 50 /* Number of chars in the receiver FIFO before an 51 * an interrupt is generated. Should depend on 52 * line speed. Needs to be about 6 on a 486DX33 53 * for 4 active ports at 115200 bps. Why doesn't 54 * 10 work? 55 */ 56#define PollMode /* Use polling-based irq service routine, not the 57 * hardware svcack lines. Must be defined for 58 * Cyclom-16Y boards. Less efficient for Cyclom-8Ys, 59 * and stops 4 * 115200 bps from working. 60 */ 61#undef Smarts /* Enable slightly more CD1400 intelligence. Mainly 62 * the output CR/LF processing, plus we can avoid a 63 * few checks usually done in ttyinput(). 64 * 65 * XXX not fully implemented, and not particularly 66 * worthwhile. 67 */ 68#undef CyDebug /* Include debugging code (not very expensive). */ 69 70/* These will go away. */ 71#undef SOFT_CTS_OFLOW 72#define SOFT_HOTCHAR 73 74#include <sys/param.h> 75#include <sys/systm.h> 76#include <sys/tty.h> 77#include <sys/proc.h> 78#include <sys/conf.h> 79#include <sys/dkstat.h> 80#include <sys/fcntl.h> 81#include <sys/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 com->bytes_in += count; 1126 ioptr = com->iptr; 1127 ifree = com->ibufend - ioptr; 1128 if (count > ifree) { 1129 count -= ifree; 1130 com_events += ifree; 1131 if (ifree != 0) { 1132 if (com->do_timestamp) 1133 microtime(&com->timestamp); 1134 do { 1135 recv_data = cd_inb(iobase, 1136 CD1400_RDSR, 1137 cy_align); 1138#ifdef SOFT_HOTCHAR 1139 if (com->hotchar != 0 1140 && recv_data 1141 == com->hotchar) 1142 setsofttty(); 1143#endif 1144 ioptr[0] = recv_data; 1145 ioptr[CE_INPUT_OFFSET] = 0; 1146 ++ioptr; 1147 } while (--ifree != 0); 1148 } 1149 com->delta_error_counts 1150 [CE_INTERRUPT_BUF_OVERFLOW] += count; 1151 do { 1152 recv_data = cd_inb(iobase, CD1400_RDSR, 1153 cy_align); 1154#ifdef SOFT_HOTCHAR 1155 if (com->hotchar != 0 1156 && recv_data == com->hotchar) 1157 setsofttty(); 1158#endif 1159 } while (--count != 0); 1160 } else { 1161 if (com->do_timestamp) 1162 microtime(&com->timestamp); 1163 if (ioptr <= com->ihighwater 1164 && ioptr + count > com->ihighwater 1165 && com->state & CS_RTS_IFLOW) 1166#if 0 1167 outb(com->modem_ctl_port, 1168 com->mcr_image &= ~MCR_RTS); 1169#else 1170 cd_outb(iobase, CD1400_MSVR1, cy_align, 1171 com->mcr_image &= ~MCR_RTS); 1172#endif 1173 com_events += count; 1174 do { 1175 recv_data = cd_inb(iobase, CD1400_RDSR, 1176 cy_align); 1177#ifdef SOFT_HOTCHAR 1178 if (com->hotchar != 0 1179 && recv_data == com->hotchar) 1180 setsofttty(); 1181#endif 1182 ioptr[0] = recv_data; 1183 ioptr[CE_INPUT_OFFSET] = 0; 1184 ++ioptr; 1185 } while (--count != 0); 1186 } 1187 com->iptr = ioptr; 1188 } 1189cont: 1190 1191 /* terminate service context */ 1192#ifdef PollMode 1193 cd_outb(iobase, CD1400_RIR, cy_align, 1194 save_rir 1195 & ~(CD1400_RIR_RDIREQ | CD1400_RIR_RBUSY)); 1196 cd_outb(iobase, CD1400_CAR, cy_align, save_car); 1197#else 1198 cd_outb(iobase, CD1400_EOSRR, cy_align, 0); 1199#endif 1200 } 1201 if (status & CD1400_SVRR_MDMCH) { 1202 struct com_s *com; 1203 u_char modem_status; 1204#ifdef PollMode 1205 u_char save_car; 1206 u_char save_mir; 1207#else 1208 u_char vector; 1209#endif 1210 1211#ifdef PollMode 1212 save_mir = cd_inb(iobase, CD1400_MIR, cy_align); 1213 save_car = cd_inb(iobase, CD1400_CAR, cy_align); 1214 1215 /* enter modem service */ 1216 cd_outb(iobase, CD1400_CAR, cy_align, save_mir); 1217 1218 com = com_addr(baseu + cyu * CD1400_NO_OF_CHANNELS 1219 + (save_mir & CD1400_MIR_CHAN)); 1220#else 1221 /* ack modem service */ 1222 vector = cy_inb(iobase, CY8_SVCACKM); 1223 1224 com = com_addr(baseu 1225 + ((vector >> CD1400_xIVR_CHAN_SHIFT) 1226 & CD1400_xIVR_CHAN)); 1227#endif 1228 ++com->mdm; 1229 modem_status = cd_inb(iobase, CD1400_MSVR2, cy_align); 1230 if (modem_status != com->last_modem_status) { 1231 if (com->do_dcd_timestamp 1232 && !(com->last_modem_status & MSR_DCD) 1233 && modem_status & MSR_DCD) 1234 microtime(&com->dcd_timestamp); 1235 1236 /* 1237 * Schedule high level to handle DCD changes. Note 1238 * that we don't use the delta bits anywhere. Some 1239 * UARTs mess them up, and it's easy to remember the 1240 * previous bits and calculate the delta. 1241 */ 1242 com->last_modem_status = modem_status; 1243 if (!(com->state & CS_CHECKMSR)) { 1244 com_events += LOTS_OF_EVENTS; 1245 com->state |= CS_CHECKMSR; 1246 setsofttty(); 1247 } 1248 1249#ifdef SOFT_CTS_OFLOW 1250 /* handle CTS change immediately for crisp flow ctl */ 1251 if (com->state & CS_CTS_OFLOW) { 1252 if (modem_status & MSR_CTS) { 1253 com->state |= CS_ODEVREADY; 1254 if (com->state >= (CS_BUSY | CS_TTGO 1255 | CS_ODEVREADY) 1256 && !(com->intr_enable 1257 & CD1400_SRER_TXRDY)) 1258 cd_outb(iobase, CD1400_SRER, 1259 cy_align, 1260 com->intr_enable 1261 |= CD1400_SRER_TXRDY); 1262 } else { 1263 com->state &= ~CS_ODEVREADY; 1264 if (com->intr_enable 1265 & CD1400_SRER_TXRDY) 1266 cd_outb(iobase, CD1400_SRER, 1267 cy_align, 1268 com->intr_enable 1269 &= ~CD1400_SRER_TXRDY); 1270 } 1271 } 1272#endif 1273 } 1274 1275 /* terminate service context */ 1276#ifdef PollMode 1277 cd_outb(iobase, CD1400_MIR, cy_align, 1278 save_mir 1279 & ~(CD1400_MIR_RDIREQ | CD1400_MIR_RBUSY)); 1280 cd_outb(iobase, CD1400_CAR, cy_align, save_car); 1281#else 1282 cd_outb(iobase, CD1400_EOSRR, cy_align, 0); 1283#endif 1284 } 1285 if (status & CD1400_SVRR_TXRDY) { 1286 struct com_s *com; 1287#ifdef PollMode 1288 u_char save_car; 1289 u_char save_tir; 1290#else 1291 u_char vector; 1292#endif 1293 1294#ifdef PollMode 1295 save_tir = cd_inb(iobase, CD1400_TIR, cy_align); 1296 save_car = cd_inb(iobase, CD1400_CAR, cy_align); 1297 1298 /* enter tx service */ 1299 cd_outb(iobase, CD1400_CAR, cy_align, save_tir); 1300 com = com_addr(baseu 1301 + cyu * CD1400_NO_OF_CHANNELS 1302 + (save_tir & CD1400_TIR_CHAN)); 1303#else 1304 /* ack transmit service */ 1305 vector = cy_inb(iobase, CY8_SVCACKT); 1306 1307 com = com_addr(baseu 1308 + ((vector >> CD1400_xIVR_CHAN_SHIFT) 1309 & CD1400_xIVR_CHAN)); 1310#endif 1311 1312 if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) { 1313 u_char *ioptr; 1314 u_int ocount; 1315 1316 ioptr = com->obufq.l_head; 1317 ocount = com->obufq.l_tail - ioptr; 1318 if (ocount > CD1400_TX_FIFO_SIZE) 1319 ocount = CD1400_TX_FIFO_SIZE; 1320 com->bytes_out += ocount; 1321 do 1322 cd_outb(iobase, CD1400_TDR, cy_align, 1323 *ioptr++); 1324 while (--ocount != 0); 1325 com->obufq.l_head = ioptr; 1326 if (ioptr >= com->obufq.l_tail) { 1327 struct lbq *qp; 1328 1329 qp = com->obufq.l_next; 1330 qp->l_queued = FALSE; 1331 qp = qp->l_next; 1332 if (qp != NULL) { 1333 com->obufq.l_head = qp->l_head; 1334 com->obufq.l_tail = qp->l_tail; 1335 com->obufq.l_next = qp; 1336 } else { 1337 /* output just completed */ 1338 com->state &= ~CS_BUSY; 1339 cd_outb(iobase, CD1400_SRER, cy_align, 1340 com->intr_enable 1341 &= ~CD1400_SRER_TXRDY); 1342 } 1343 if (!(com->state & CS_ODONE)) { 1344 com_events += LOTS_OF_EVENTS; 1345 com->state |= CS_ODONE; 1346 1347 /* handle at high level ASAP */ 1348 setsofttty(); 1349 } 1350 } 1351 } 1352 1353 /* terminate service context */ 1354#ifdef PollMode 1355 cd_outb(iobase, CD1400_TIR, cy_align, 1356 save_tir 1357 & ~(CD1400_TIR_RDIREQ | CD1400_TIR_RBUSY)); 1358 cd_outb(iobase, CD1400_CAR, cy_align, save_car); 1359#else 1360 cd_outb(iobase, CD1400_EOSRR, cy_align, 0); 1361#endif 1362 } 1363 } 1364 1365 /* ensure an edge for the next interrupt */ 1366 cd_outb(cy_iobase, CY_CLEAR_INTR, cy_align, 0); 1367 1368 schedsofttty(); 1369 1370 COM_UNLOCK(); 1371} 1372 1373#if 0 1374static void 1375siointr1(com) 1376 struct com_s *com; 1377{ 1378} 1379#endif 1380 1381static int 1382sioioctl(dev, cmd, data, flag, p) 1383 dev_t dev; 1384 int cmd; 1385 caddr_t data; 1386 int flag; 1387 struct proc *p; 1388{ 1389 struct com_s *com; 1390 int error; 1391 cy_addr iobase; 1392 int mynor; 1393 int s; 1394 struct tty *tp; 1395#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 1396 int oldcmd; 1397 struct termios term; 1398#endif 1399 1400 mynor = minor(dev); 1401 com = com_addr(MINOR_TO_UNIT(mynor)); 1402 iobase = com->iobase; 1403 if (mynor & CONTROL_MASK) { 1404 struct termios *ct; 1405 1406 switch (mynor & CONTROL_MASK) { 1407 case CONTROL_INIT_STATE: 1408 ct = mynor & CALLOUT_MASK ? &com->it_out : &com->it_in; 1409 break; 1410 case CONTROL_LOCK_STATE: 1411 ct = mynor & CALLOUT_MASK ? &com->lt_out : &com->lt_in; 1412 break; 1413 default: 1414 return (ENODEV); /* /dev/nodev */ 1415 } 1416 switch (cmd) { 1417 case TIOCSETA: 1418 error = suser(p->p_ucred, &p->p_acflag); 1419 if (error != 0) 1420 return (error); 1421 *ct = *(struct termios *)data; 1422 return (0); 1423 case TIOCGETA: 1424 *(struct termios *)data = *ct; 1425 return (0); 1426 case TIOCGETD: 1427 *(int *)data = TTYDISC; 1428 return (0); 1429 case TIOCGWINSZ: 1430 bzero(data, sizeof(struct winsize)); 1431 return (0); 1432 default: 1433 return (ENOTTY); 1434 } 1435 } 1436 tp = com->tp; 1437#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 1438 term = tp->t_termios; 1439 oldcmd = cmd; 1440 error = ttsetcompat(tp, &cmd, data, &term); 1441 if (error != 0) 1442 return (error); 1443 if (cmd != oldcmd) 1444 data = (caddr_t)&term; 1445#endif 1446 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) { 1447 int cc; 1448 struct termios *dt = (struct termios *)data; 1449 struct termios *lt = mynor & CALLOUT_MASK 1450 ? &com->lt_out : &com->lt_in; 1451 1452 dt->c_iflag = (tp->t_iflag & lt->c_iflag) 1453 | (dt->c_iflag & ~lt->c_iflag); 1454 dt->c_oflag = (tp->t_oflag & lt->c_oflag) 1455 | (dt->c_oflag & ~lt->c_oflag); 1456 dt->c_cflag = (tp->t_cflag & lt->c_cflag) 1457 | (dt->c_cflag & ~lt->c_cflag); 1458 dt->c_lflag = (tp->t_lflag & lt->c_lflag) 1459 | (dt->c_lflag & ~lt->c_lflag); 1460 for (cc = 0; cc < NCCS; ++cc) 1461 if (lt->c_cc[cc] != 0) 1462 dt->c_cc[cc] = tp->t_cc[cc]; 1463 if (lt->c_ispeed != 0) 1464 dt->c_ispeed = tp->t_ispeed; 1465 if (lt->c_ospeed != 0) 1466 dt->c_ospeed = tp->t_ospeed; 1467 } 1468 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 1469 if (error != ENOIOCTL) 1470 return (error); 1471 s = spltty(); 1472 error = ttioctl(tp, cmd, data, flag); 1473 disc_optim(tp, &tp->t_termios, com); 1474 if (error != ENOIOCTL) { 1475 splx(s); 1476 return (error); 1477 } 1478 cd_outb(iobase, CD1400_CAR, com->cy_align, 1479 MINOR_TO_UNIT(mynor) & CD1400_CAR_CHAN); 1480 switch (cmd) { 1481#if 0 1482 case TIOCSBRK: 1483 outb(iobase + com_cfcr, com->cfcr_image |= CFCR_SBREAK); 1484 break; 1485 case TIOCCBRK: 1486 outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK); 1487 break; 1488#endif /* 0 */ 1489 case TIOCSDTR: 1490 (void)commctl(com, TIOCM_DTR, DMBIS); 1491 break; 1492 case TIOCCDTR: 1493 (void)commctl(com, TIOCM_DTR, DMBIC); 1494 break; 1495 /* 1496 * XXX should disallow changing MCR_RTS if CS_RTS_IFLOW is set. The 1497 * changes get undone on the next call to comparam(). 1498 */ 1499 case TIOCMSET: 1500 (void)commctl(com, *(int *)data, DMSET); 1501 break; 1502 case TIOCMBIS: 1503 (void)commctl(com, *(int *)data, DMBIS); 1504 break; 1505 case TIOCMBIC: 1506 (void)commctl(com, *(int *)data, DMBIC); 1507 break; 1508 case TIOCMGET: 1509 *(int *)data = commctl(com, 0, DMGET); 1510 break; 1511 case TIOCMSDTRWAIT: 1512 /* must be root since the wait applies to following logins */ 1513 error = suser(p->p_ucred, &p->p_acflag); 1514 if (error != 0) { 1515 splx(s); 1516 return (error); 1517 } 1518 com->dtr_wait = *(int *)data * hz / 100; 1519 break; 1520 case TIOCMGDTRWAIT: 1521 *(int *)data = com->dtr_wait * 100 / hz; 1522 break; 1523 case TIOCTIMESTAMP: 1524 com->do_timestamp = TRUE; 1525 *(struct timeval *)data = com->timestamp; 1526 break; 1527 case TIOCDCDTIMESTAMP: 1528 com->do_dcd_timestamp = TRUE; 1529 *(struct timeval *)data = com->dcd_timestamp; 1530 break; 1531 default: 1532 splx(s); 1533 return (ENOTTY); 1534 } 1535 splx(s); 1536 return (0); 1537} 1538 1539void 1540siopoll() 1541{ 1542 int unit; 1543 1544#ifdef CyDebug 1545 ++cy_timeouts; 1546#endif 1547 if (com_events == 0) 1548 return; 1549repeat: 1550 for (unit = 0; unit < NSIO; ++unit) { 1551 u_char *buf; 1552 struct com_s *com; 1553 u_char *ibuf; 1554 cy_addr iobase; 1555 int incc; 1556 struct tty *tp; 1557 1558 com = com_addr(unit); 1559 if (com == NULL) 1560 continue; 1561 tp = com->tp; 1562 if (tp == NULL) { 1563 /* 1564 * XXX forget any events related to closed devices 1565 * (actually never opened devices) so that we don't 1566 * loop. 1567 */ 1568 disable_intr(); 1569 incc = com->iptr - com->ibuf; 1570 com->iptr = com->ibuf; 1571 if (com->state & CS_CHECKMSR) { 1572 incc += LOTS_OF_EVENTS; 1573 com->state &= ~CS_CHECKMSR; 1574 } 1575 com_events -= incc; 1576 enable_intr(); 1577 if (incc != 0) 1578 log(LOG_DEBUG, 1579 "sio%d: %d events for device with no tp\n", 1580 unit, incc); 1581 continue; 1582 } 1583 1584 /* switch the role of the low-level input buffers */ 1585 if (com->iptr == (ibuf = com->ibuf)) { 1586 buf = NULL; /* not used, but compiler can't tell */ 1587 incc = 0; 1588 } else { 1589 buf = ibuf; 1590 disable_intr(); 1591 incc = com->iptr - buf; 1592 com_events -= incc; 1593 if (ibuf == com->ibuf1) 1594 ibuf = com->ibuf2; 1595 else 1596 ibuf = com->ibuf1; 1597 com->ibufend = ibuf + RS_IBUFSIZE; 1598 com->ihighwater = ibuf + RS_IHIGHWATER; 1599 com->iptr = ibuf; 1600 1601 /* 1602 * There is now room for another low-level buffer full 1603 * of input, so enable RTS if it is now disabled and 1604 * there is room in the high-level buffer. 1605 */ 1606 if ((com->state & CS_RTS_IFLOW) 1607 && !(com->mcr_image & MCR_RTS) 1608 && !(tp->t_state & TS_TBLOCK)) 1609#if 0 1610 outb(com->modem_ctl_port, 1611 com->mcr_image |= MCR_RTS); 1612#else 1613 iobase = com->iobase, 1614 cd_outb(iobase, CD1400_CAR, com->cy_align, 1615 unit & CD1400_CAR_CHAN), 1616 cd_outb(iobase, CD1400_MSVR1, com->cy_align, 1617 com->mcr_image |= MCR_RTS); 1618#endif 1619 enable_intr(); 1620 com->ibuf = ibuf; 1621 } 1622 1623 if (com->state & CS_CHECKMSR) { 1624 u_char delta_modem_status; 1625 1626 disable_intr(); 1627 delta_modem_status = com->last_modem_status 1628 ^ com->prev_modem_status; 1629 com->prev_modem_status = com->last_modem_status; 1630 com_events -= LOTS_OF_EVENTS; 1631 com->state &= ~CS_CHECKMSR; 1632 enable_intr(); 1633 if (delta_modem_status & MSR_DCD) 1634 (*linesw[tp->t_line].l_modem) 1635 (tp, com->prev_modem_status & MSR_DCD); 1636 } 1637 if (com->state & CS_ODONE) { 1638 disable_intr(); 1639 com_events -= LOTS_OF_EVENTS; 1640 com->state &= ~CS_ODONE; 1641 if (!(com->state & CS_BUSY)) 1642 com->tp->t_state &= ~TS_BUSY; 1643 enable_intr(); 1644 (*linesw[tp->t_line].l_start)(tp); 1645 } 1646 if (incc <= 0 || !(tp->t_state & TS_ISOPEN)) 1647 continue; 1648 /* 1649 * Avoid the grotesquely inefficient lineswitch routine 1650 * (ttyinput) in "raw" mode. It usually takes about 450 1651 * instructions (that's without canonical processing or echo!). 1652 * slinput is reasonably fast (usually 40 instructions plus 1653 * call overhead). 1654 */ 1655 if (tp->t_state & TS_CAN_BYPASS_L_RINT) { 1656 if (tp->t_rawq.c_cc + incc >= RB_I_HIGH_WATER 1657 && (com->state & CS_RTS_IFLOW 1658 || tp->t_iflag & IXOFF) 1659 && !(tp->t_state & TS_TBLOCK)) 1660 ttyblock(tp); 1661 tk_nin += incc; 1662 tk_rawcc += incc; 1663 tp->t_rawcc += incc; 1664 com->delta_error_counts[CE_TTY_BUF_OVERFLOW] 1665 += b_to_q((char *)buf, incc, &tp->t_rawq); 1666 ttwakeup(tp); 1667 if (tp->t_state & TS_TTSTOP 1668 && (tp->t_iflag & IXANY 1669 || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) { 1670 tp->t_state &= ~TS_TTSTOP; 1671 tp->t_lflag &= ~FLUSHO; 1672 comstart(tp); 1673 } 1674 } else { 1675 do { 1676 u_char line_status; 1677 int recv_data; 1678 1679 line_status = (u_char) buf[CE_INPUT_OFFSET]; 1680 recv_data = (u_char) *buf++; 1681 if (line_status 1682 & (LSR_BI | LSR_FE | LSR_OE | LSR_PE)) { 1683 if (line_status & LSR_BI) 1684 recv_data |= TTY_BI; 1685 if (line_status & LSR_FE) 1686 recv_data |= TTY_FE; 1687 if (line_status & LSR_OE) 1688 recv_data |= TTY_OE; 1689 if (line_status & LSR_PE) 1690 recv_data |= TTY_PE; 1691 } 1692 (*linesw[tp->t_line].l_rint)(recv_data, tp); 1693 } while (--incc > 0); 1694 } 1695 if (com_events == 0) 1696 break; 1697 } 1698 if (com_events >= LOTS_OF_EVENTS) 1699 goto repeat; 1700} 1701 1702static int 1703comparam(tp, t) 1704 struct tty *tp; 1705 struct termios *t; 1706{ 1707 int bits; 1708 int cflag; 1709 struct com_s *com; 1710 u_char cor_change; 1711 int idivisor; 1712 int iflag; 1713 cy_addr iobase; 1714 int iprescaler; 1715 int itimeout; 1716 int odivisor; 1717 int oprescaler; 1718 u_char opt; 1719 int s; 1720 int unit; 1721 1722 /* do historical conversions */ 1723 if (t->c_ispeed == 0) 1724 t->c_ispeed = t->c_ospeed; 1725 1726 /* check requested parameters */ 1727 idivisor = comspeed(t->c_ispeed, &iprescaler); 1728 if (idivisor < 0) 1729 return (EINVAL); 1730 odivisor = comspeed(t->c_ospeed, &oprescaler); 1731 if (odivisor < 0) 1732 return (EINVAL); 1733 1734 /* parameters are OK, convert them to the com struct and the device */ 1735 unit = DEV_TO_UNIT(tp->t_dev); 1736 com = com_addr(unit); 1737 iobase = com->iobase; 1738 s = spltty(); 1739 cd_outb(iobase, CD1400_CAR, com->cy_align, unit & CD1400_CAR_CHAN); 1740 if (odivisor == 0) 1741 (void)commctl(com, TIOCM_DTR, DMBIC); /* hang up line */ 1742 else 1743 (void)commctl(com, TIOCM_DTR, DMBIS); 1744 1745 if (idivisor != 0) { 1746 cd_outb(iobase, CD1400_RBPR, com->cy_align, idivisor); 1747 cd_outb(iobase, CD1400_RCOR, com->cy_align, iprescaler); 1748 } 1749 if (odivisor != 0) { 1750 cd_outb(iobase, CD1400_TBPR, com->cy_align, odivisor); 1751 cd_outb(iobase, CD1400_TCOR, com->cy_align, oprescaler); 1752 } 1753 1754 /* 1755 * channel control 1756 * receiver enable 1757 * transmitter enable (always set) 1758 */ 1759 cflag = t->c_cflag; 1760 opt = CD1400_CCR_CMDCHANCTL | CD1400_CCR_XMTEN 1761 | (cflag & CREAD ? CD1400_CCR_RCVEN : CD1400_CCR_RCVDIS); 1762 if (opt != com->channel_control) { 1763 com->channel_control = opt; 1764 cd1400_channel_cmd(iobase, opt, com->cy_align); 1765 } 1766 1767#ifdef Smarts 1768 /* set special chars */ 1769 /* XXX if one is _POSIX_VDISABLE, can't use some others */ 1770 if (t->c_cc[VSTOP] != _POSIX_VDISABLE) 1771 cd_outb(iobase, CD1400_SCHR1, com->cy_align, t->c_cc[VSTOP]); 1772 if (t->c_cc[VSTART] != _POSIX_VDISABLE) 1773 cd_outb(iobase, CD1400_SCHR2, com->cy_align, t->c_cc[VSTART]); 1774 if (t->c_cc[VINTR] != _POSIX_VDISABLE) 1775 cd_outb(iobase, CD1400_SCHR3, com->cy_align, t->c_cc[VINTR]); 1776 if (t->c_cc[VSUSP] != _POSIX_VDISABLE) 1777 cd_outb(iobase, CD1400_SCHR4, com->cy_align, t->c_cc[VSUSP]); 1778#endif 1779 1780 /* 1781 * set channel option register 1 - 1782 * parity mode 1783 * stop bits 1784 * char length 1785 */ 1786 opt = 0; 1787 /* parity */ 1788 if (cflag & PARENB) { 1789 if (cflag & PARODD) 1790 opt |= CD1400_COR1_PARODD; 1791 opt |= CD1400_COR1_PARNORMAL; 1792 } 1793 iflag = t->c_iflag; 1794 if (!(iflag & INPCK)) 1795 opt |= CD1400_COR1_NOINPCK; 1796 bits = 1 + 1; 1797 /* stop bits */ 1798 if (cflag & CSTOPB) { 1799 ++bits; 1800 opt |= CD1400_COR1_STOP2; 1801 } 1802 /* char length */ 1803 switch (cflag & CSIZE) { 1804 case CS5: 1805 bits += 5; 1806 opt |= CD1400_COR1_CS5; 1807 break; 1808 case CS6: 1809 bits += 6; 1810 opt |= CD1400_COR1_CS6; 1811 break; 1812 case CS7: 1813 bits += 7; 1814 opt |= CD1400_COR1_CS7; 1815 break; 1816 default: 1817 bits += 8; 1818 opt |= CD1400_COR1_CS8; 1819 break; 1820 } 1821 cor_change = 0; 1822 if (opt != com->cor[0]) { 1823 cor_change |= CD1400_CCR_COR1; 1824 cd_outb(iobase, CD1400_COR1, com->cy_align, com->cor[0] = opt); 1825 } 1826 1827 /* 1828 * Set receive time-out period, normally to max(one char time, 5 ms). 1829 */ 1830 if (t->c_ispeed == 0) 1831 itimeout = cd_inb(iobase, CD1400_RTPR, com->cy_align); 1832 else { 1833 itimeout = (1000 * bits + t->c_ispeed - 1) / t->c_ispeed; 1834#ifdef SOFT_HOTCHAR 1835#define MIN_RTP 1 1836#else 1837#define MIN_RTP 5 1838#endif 1839 if (itimeout < MIN_RTP) 1840 itimeout = MIN_RTP; 1841 } 1842 if (!(t->c_lflag & ICANON) && t->c_cc[VMIN] != 0 && t->c_cc[VTIME] != 0 1843 && t->c_cc[VTIME] * 10 > itimeout) 1844 itimeout = t->c_cc[VTIME] * 10; 1845 if (itimeout > 255) 1846 itimeout = 255; 1847 cd_outb(iobase, CD1400_RTPR, com->cy_align, itimeout); 1848 1849 /* 1850 * set channel option register 2 - 1851 * flow control 1852 */ 1853 opt = 0; 1854#ifdef Smarts 1855 if (iflag & IXANY) 1856 opt |= CD1400_COR2_IXANY; 1857 if (iflag & IXOFF) 1858 opt |= CD1400_COR2_IXOFF; 1859#endif 1860#ifndef SOFT_CTS_OFLOW 1861 if (cflag & CCTS_OFLOW) 1862 opt |= CD1400_COR2_CCTS_OFLOW; 1863#endif 1864 if (opt != com->cor[1]) { 1865 cor_change |= CD1400_CCR_COR2; 1866 cd_outb(iobase, CD1400_COR2, com->cy_align, com->cor[1] = opt); 1867 } 1868 1869 /* 1870 * set channel option register 3 - 1871 * receiver FIFO interrupt threshold 1872 * flow control 1873 */ 1874 opt = RxFifoThreshold; 1875#ifdef Smarts 1876 if (t->c_lflag & ICANON) 1877 opt |= CD1400_COR3_SCD34; /* detect INTR & SUSP chars */ 1878 if (iflag & IXOFF) 1879 /* detect and transparently handle START and STOP chars */ 1880 opt |= CD1400_COR3_FCT | CD1400_COR3_SCD12; 1881#endif 1882 if (opt != com->cor[2]) { 1883 cor_change |= CD1400_CCR_COR3; 1884 cd_outb(iobase, CD1400_COR3, com->cy_align, com->cor[2] = opt); 1885 } 1886 1887 /* notify the CD1400 if COR1-3 have changed */ 1888 if (cor_change) 1889 cd1400_channel_cmd(iobase, CD1400_CCR_CMDCORCHG | cor_change, 1890 com->cy_align); 1891 1892 /* 1893 * set channel option register 4 - 1894 * CR/NL processing 1895 * break processing 1896 * received exception processing 1897 */ 1898 opt = 0; 1899 if (iflag & IGNCR) 1900 opt |= CD1400_COR4_IGNCR; 1901#ifdef Smarts 1902 /* 1903 * we need a new ttyinput() for this, as we don't want to 1904 * have ICRNL && INLCR being done in both layers, or to have 1905 * synchronisation problems 1906 */ 1907 if (iflag & ICRNL) 1908 opt |= CD1400_COR4_ICRNL; 1909 if (iflag & INLCR) 1910 opt |= CD1400_COR4_INLCR; 1911#endif 1912 if (iflag & IGNBRK) 1913 opt |= CD1400_COR4_IGNBRK; 1914 if (!(iflag & BRKINT)) 1915 opt |= CD1400_COR4_NOBRKINT; 1916#if 0 1917 /* XXX using this "intelligence" breaks reporting of overruns. */ 1918 if (iflag & IGNPAR) 1919 opt |= CD1400_COR4_PFO_DISCARD; 1920 else { 1921 if (iflag & PARMRK) 1922 opt |= CD1400_COR4_PFO_ESC; 1923 else 1924 opt |= CD1400_COR4_PFO_NUL; 1925 } 1926#else 1927 opt |= CD1400_COR4_PFO_EXCEPTION; 1928#endif 1929 cd_outb(iobase, CD1400_COR4, com->cy_align, opt); 1930 1931 /* 1932 * set channel option register 5 - 1933 */ 1934 opt = 0; 1935 if (iflag & ISTRIP) 1936 opt |= CD1400_COR5_ISTRIP; 1937 if (t->c_iflag & IEXTEN) 1938 /* enable LNEXT (e.g. ctrl-v quoting) handling */ 1939 opt |= CD1400_COR5_LNEXT; 1940#ifdef Smarts 1941 if (t->c_oflag & ONLCR) 1942 opt |= CD1400_COR5_ONLCR; 1943 if (t->c_oflag & OCRNL) 1944 opt |= CD1400_COR5_OCRNL; 1945#endif 1946 cd_outb(iobase, CD1400_COR5, com->cy_align, opt); 1947 1948 /* 1949 * We always generate modem status change interrupts for CD changes. 1950 * Among other things, this is necessary to track TS_CARR_ON for 1951 * pstat to print even when the driver doesn't care. CD changes 1952 * should be rare so interrupts for them are not worth extra code to 1953 * avoid. We avoid interrupts for other modem status changes (except 1954 * for CTS changes when SOFT_CTS_OFLOW is configured) since this is 1955 * simplest and best. 1956 */ 1957 1958 /* 1959 * set modem change option register 1 1960 * generate modem interrupts on which 1 -> 0 input transitions 1961 * also controls auto-DTR output flow-control, which we don't use 1962 */ 1963 opt = CD1400_MCOR1_CDzd; 1964#ifdef SOFT_CTS_OFLOW 1965 if (cflag & CCTS_OFLOW) 1966 opt |= CD1400_MCOR1_CTSzd; 1967#endif 1968 cd_outb(iobase, CD1400_MCOR1, com->cy_align, opt); 1969 1970 /* 1971 * set modem change option register 2 1972 * generate modem interrupts on specific 0 -> 1 input transitions 1973 */ 1974 opt = CD1400_MCOR2_CDod; 1975#ifdef SOFT_CTS_OFLOW 1976 if (cflag & CCTS_OFLOW) 1977 opt |= CD1400_MCOR2_CTSod; 1978#endif 1979 cd_outb(iobase, CD1400_MCOR2, com->cy_align, opt); 1980 1981 /* 1982 * XXX should have done this long ago, but there is too much state 1983 * to change all atomically. 1984 */ 1985 disable_intr(); 1986 1987 com->state &= ~CS_TTGO; 1988 if (!(tp->t_state & TS_TTSTOP)) 1989 com->state |= CS_TTGO; 1990 if (cflag & CRTS_IFLOW) { 1991 com->state |= CS_RTS_IFLOW; 1992 /* 1993 * If CS_RTS_IFLOW just changed from off to on, the change 1994 * needs to be propagated to MCR_RTS. This isn't urgent, 1995 * so do it later by calling comstart() instead of repeating 1996 * a lot of code from comstart() here. 1997 */ 1998 } else if (com->state & CS_RTS_IFLOW) { 1999 com->state &= ~CS_RTS_IFLOW; 2000 /* 2001 * CS_RTS_IFLOW just changed from on to off. Force MCR_RTS 2002 * on here, since comstart() won't do it later. 2003 */ 2004#if 0 2005 outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS); 2006#else 2007 cd_outb(iobase, CD1400_MSVR1, com->cy_align, 2008 com->mcr_image |= MCR_RTS); 2009#endif 2010 } 2011 2012 /* 2013 * Set up state to handle output flow control. 2014 * XXX - worth handling MDMBUF (DCD) flow control at the lowest level? 2015 * Now has 10+ msec latency, while CTS flow has 50- usec latency. 2016 */ 2017 com->state |= CS_ODEVREADY; 2018#ifdef SOFT_CTS_OFLOW 2019 com->state &= ~CS_CTS_OFLOW; 2020 if (cflag & CCTS_OFLOW) { 2021 com->state |= CS_CTS_OFLOW; 2022 if (!(com->last_modem_status & MSR_CTS)) 2023 com->state &= ~CS_ODEVREADY; 2024 } 2025#endif 2026 /* XXX shouldn't call functions while intrs are disabled. */ 2027 disc_optim(tp, t, com); 2028#if 0 2029 /* 2030 * Recover from fiddling with CS_TTGO. We used to call siointr1() 2031 * unconditionally, but that defeated the careful discarding of 2032 * stale input in sioopen(). 2033 */ 2034 if (com->state >= (CS_BUSY | CS_TTGO)) 2035 siointr1(com); 2036#endif 2037 if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) { 2038 if (!(com->intr_enable & CD1400_SRER_TXRDY)) 2039 cd_outb(iobase, CD1400_SRER, com->cy_align, 2040 com->intr_enable |= CD1400_SRER_TXRDY); 2041 } else { 2042 if (com->intr_enable & CD1400_SRER_TXRDY) 2043 cd_outb(iobase, CD1400_SRER, com->cy_align, 2044 com->intr_enable &= ~CD1400_SRER_TXRDY); 2045 } 2046 2047 enable_intr(); 2048 splx(s); 2049 comstart(tp); 2050 return (0); 2051} 2052 2053static void 2054comstart(tp) 2055 struct tty *tp; 2056{ 2057 struct com_s *com; 2058 cy_addr iobase; 2059 int s; 2060#ifdef CyDebug 2061 bool_t started; 2062#endif 2063 int unit; 2064 2065 unit = DEV_TO_UNIT(tp->t_dev); 2066 com = com_addr(unit); 2067 iobase = com->iobase; 2068 s = spltty(); 2069 2070#ifdef CyDebug 2071 ++com->start_count; 2072 started = FALSE; 2073#endif 2074 2075 disable_intr(); 2076 cd_outb(iobase, CD1400_CAR, com->cy_align, unit & CD1400_CAR_CHAN); 2077 if (tp->t_state & TS_TTSTOP) { 2078 com->state &= ~CS_TTGO; 2079 if (com->intr_enable & CD1400_SRER_TXRDY) 2080 cd_outb(iobase, CD1400_SRER, com->cy_align, 2081 com->intr_enable &= ~CD1400_SRER_TXRDY); 2082 } else { 2083 com->state |= CS_TTGO; 2084 if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY) 2085 && !(com->intr_enable & CD1400_SRER_TXRDY)) 2086 cd_outb(iobase, CD1400_SRER, com->cy_align, 2087 com->intr_enable |= CD1400_SRER_TXRDY); 2088 } 2089 if (tp->t_state & TS_TBLOCK) { 2090 if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW) 2091#if 0 2092 outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS); 2093#else 2094 cd_outb(iobase, CD1400_MSVR1, com->cy_align, 2095 com->mcr_image &= ~MCR_RTS); 2096#endif 2097 } else { 2098 if (!(com->mcr_image & MCR_RTS) && com->iptr < com->ihighwater 2099 && com->state & CS_RTS_IFLOW) 2100#if 0 2101 outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS); 2102#else 2103 cd_outb(iobase, CD1400_MSVR1, com->cy_align, 2104 com->mcr_image |= MCR_RTS); 2105#endif 2106 } 2107 enable_intr(); 2108 if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) { 2109 ttwwakeup(tp); 2110 splx(s); 2111 return; 2112 } 2113 if (tp->t_outq.c_cc != 0) { 2114 struct lbq *qp; 2115 struct lbq *next; 2116 2117 if (!com->obufs[0].l_queued) { 2118#ifdef CyDebug 2119 started = TRUE; 2120#endif 2121 com->obufs[0].l_tail 2122 = com->obuf1 + q_to_b(&tp->t_outq, com->obuf1, 2123 sizeof com->obuf1); 2124 com->obufs[0].l_next = NULL; 2125 com->obufs[0].l_queued = TRUE; 2126 disable_intr(); 2127 if (com->state & CS_BUSY) { 2128 qp = com->obufq.l_next; 2129 while ((next = qp->l_next) != NULL) 2130 qp = next; 2131 qp->l_next = &com->obufs[0]; 2132 } else { 2133 com->obufq.l_head = com->obufs[0].l_head; 2134 com->obufq.l_tail = com->obufs[0].l_tail; 2135 com->obufq.l_next = &com->obufs[0]; 2136 com->state |= CS_BUSY; 2137 if (com->state >= (CS_BUSY | CS_TTGO 2138 | CS_ODEVREADY)) 2139 cd_outb(iobase, CD1400_SRER, 2140 com->cy_align, 2141 com->intr_enable 2142 |= CD1400_SRER_TXRDY); 2143 } 2144 enable_intr(); 2145 } 2146 if (tp->t_outq.c_cc != 0 && !com->obufs[1].l_queued) { 2147#ifdef CyDebug 2148 started = TRUE; 2149#endif 2150 com->obufs[1].l_tail 2151 = com->obuf2 + q_to_b(&tp->t_outq, com->obuf2, 2152 sizeof com->obuf2); 2153 com->obufs[1].l_next = NULL; 2154 com->obufs[1].l_queued = TRUE; 2155 disable_intr(); 2156 if (com->state & CS_BUSY) { 2157 qp = com->obufq.l_next; 2158 while ((next = qp->l_next) != NULL) 2159 qp = next; 2160 qp->l_next = &com->obufs[1]; 2161 } else { 2162 com->obufq.l_head = com->obufs[1].l_head; 2163 com->obufq.l_tail = com->obufs[1].l_tail; 2164 com->obufq.l_next = &com->obufs[1]; 2165 com->state |= CS_BUSY; 2166 if (com->state >= (CS_BUSY | CS_TTGO 2167 | CS_ODEVREADY)) 2168 cd_outb(iobase, CD1400_SRER, 2169 com->cy_align, 2170 com->intr_enable 2171 |= CD1400_SRER_TXRDY); 2172 } 2173 enable_intr(); 2174 } 2175 tp->t_state |= TS_BUSY; 2176 } 2177#ifdef CyDebug 2178 if (started) 2179 ++com->start_real; 2180#endif 2181#if 0 2182 disable_intr(); 2183 if (com->state >= (CS_BUSY | CS_TTGO)) 2184 siointr1(com); /* fake interrupt to start output */ 2185 enable_intr(); 2186#endif 2187 ttwwakeup(tp); 2188 splx(s); 2189} 2190 2191static void 2192siostop(tp, rw) 2193 struct tty *tp; 2194 int rw; 2195{ 2196 struct com_s *com; 2197 2198 com = com_addr(DEV_TO_UNIT(tp->t_dev)); 2199 disable_intr(); 2200 if (rw & FWRITE) { 2201 com->obufs[0].l_queued = FALSE; 2202 com->obufs[1].l_queued = FALSE; 2203 if (com->state & CS_ODONE) 2204 com_events -= LOTS_OF_EVENTS; 2205 com->state &= ~(CS_ODONE | CS_BUSY); 2206 com->tp->t_state &= ~TS_BUSY; 2207 } 2208 if (rw & FREAD) { 2209 com_events -= (com->iptr - com->ibuf); 2210 com->iptr = com->ibuf; 2211 } 2212 enable_intr(); 2213 comstart(tp); 2214 2215 /* XXX should clear h/w fifos too. */ 2216} 2217 2218static struct tty * 2219siodevtotty(dev) 2220 dev_t dev; 2221{ 2222 int mynor; 2223 int unit; 2224 2225 mynor = minor(dev); 2226 if (mynor & CONTROL_MASK) 2227 return (NULL); 2228 unit = MINOR_TO_UNIT(mynor); 2229 if ((u_int) unit >= NSIO) 2230 return (NULL); 2231 return (&sio_tty[unit]); 2232} 2233 2234static int 2235commctl(com, bits, how) 2236 struct com_s *com; 2237 int bits; 2238 int how; 2239{ 2240 cy_addr iobase; 2241 int mcr; 2242 int msr; 2243 2244 iobase = com->iobase; 2245 if (how == DMGET) { 2246 if (com->channel_control & CD1400_CCR_RCVEN) 2247 bits |= TIOCM_LE; 2248 mcr = com->mcr_image; 2249 if (mcr & MCR_DTR) 2250 bits |= TIOCM_DTR; 2251 if (mcr & MCR_RTS) 2252 /* XXX wired on for Cyclom-8Ys */ 2253 bits |= TIOCM_RTS; 2254 2255 /* 2256 * We must read the modem status from the hardware because 2257 * we don't generate modem status change interrupts for all 2258 * changes, so com->prev_modem_status is not guaranteed to 2259 * be up to date. This is safe, unlike for sio, because 2260 * reading the status register doesn't clear pending modem 2261 * status change interrupts. 2262 */ 2263 msr = cd_inb(iobase, CD1400_MSVR2, com->cy_align); 2264 2265 if (msr & MSR_CTS) 2266 bits |= TIOCM_CTS; 2267 if (msr & MSR_DCD) 2268 bits |= TIOCM_CD; 2269 if (msr & MSR_DSR) 2270 bits |= TIOCM_DSR; 2271 if (msr & MSR_RI) 2272 /* XXX not connected except for Cyclom-16Y? */ 2273 bits |= TIOCM_RI; 2274 return (bits); 2275 } 2276 mcr = 0; 2277 if (bits & TIOCM_DTR) 2278 mcr |= MCR_DTR; 2279 if (bits & TIOCM_RTS) 2280 mcr |= MCR_RTS; 2281 disable_intr(); 2282 switch (how) { 2283 case DMSET: 2284 com->mcr_image = mcr; 2285 cd_outb(iobase, CD1400_MSVR1, com->cy_align, mcr); 2286 cd_outb(iobase, CD1400_MSVR2, com->cy_align, mcr); 2287 break; 2288 case DMBIS: 2289 com->mcr_image = mcr = com->mcr_image | mcr; 2290 cd_outb(iobase, CD1400_MSVR1, com->cy_align, mcr); 2291 cd_outb(iobase, CD1400_MSVR2, com->cy_align, mcr); 2292 break; 2293 case DMBIC: 2294 com->mcr_image = mcr = com->mcr_image & ~mcr; 2295 cd_outb(iobase, CD1400_MSVR1, com->cy_align, mcr); 2296 cd_outb(iobase, CD1400_MSVR2, com->cy_align, mcr); 2297 break; 2298 } 2299 enable_intr(); 2300 return (0); 2301} 2302 2303static void 2304siosettimeout() 2305{ 2306 struct com_s *com; 2307 bool_t someopen; 2308 int unit; 2309 2310 /* 2311 * Set our timeout period to 1 second if no polled devices are open. 2312 * Otherwise set it to max(1/200, 1/hz). 2313 * Enable timeouts iff some device is open. 2314 */ 2315 untimeout(comwakeup, (void *)NULL, sio_timeout_handle); 2316 sio_timeout = hz; 2317 someopen = FALSE; 2318 for (unit = 0; unit < NSIO; ++unit) { 2319 com = com_addr(unit); 2320 if (com != NULL && com->tp != NULL 2321 && com->tp->t_state & TS_ISOPEN) { 2322 someopen = TRUE; 2323#if 0 2324 if (com->poll || com->poll_output) { 2325 sio_timeout = hz > 200 ? hz / 200 : 1; 2326 break; 2327 } 2328#endif 2329 } 2330 } 2331 if (someopen) { 2332 sio_timeouts_until_log = hz / sio_timeout; 2333 sio_timeout_handle = timeout(comwakeup, (void *)NULL, 2334 sio_timeout); 2335 } else { 2336 /* Flush error messages, if any. */ 2337 sio_timeouts_until_log = 1; 2338 comwakeup((void *)NULL); 2339 untimeout(comwakeup, (void *)NULL, sio_timeout_handle); 2340 } 2341} 2342 2343static void 2344comwakeup(chan) 2345 void *chan; 2346{ 2347 struct com_s *com; 2348 int unit; 2349 2350 sio_timeout_handle = timeout(comwakeup, (void *)NULL, sio_timeout); 2351 2352#if 0 2353 /* 2354 * Recover from lost output interrupts. 2355 * Poll any lines that don't use interrupts. 2356 */ 2357 for (unit = 0; unit < NSIO; ++unit) { 2358 com = com_addr(unit); 2359 if (com != NULL 2360 && (com->state >= (CS_BUSY | CS_TTGO) || com->poll)) { 2361 disable_intr(); 2362 siointr1(com); 2363 enable_intr(); 2364 } 2365 } 2366#endif 2367 2368 /* 2369 * Check for and log errors, but not too often. 2370 */ 2371 if (--sio_timeouts_until_log > 0) 2372 return; 2373 sio_timeouts_until_log = hz / sio_timeout; 2374 for (unit = 0; unit < NSIO; ++unit) { 2375 int errnum; 2376 2377 com = com_addr(unit); 2378 if (com == NULL) 2379 continue; 2380 for (errnum = 0; errnum < CE_NTYPES; ++errnum) { 2381 u_int delta; 2382 u_long total; 2383 2384 disable_intr(); 2385 delta = com->delta_error_counts[errnum]; 2386 com->delta_error_counts[errnum] = 0; 2387 enable_intr(); 2388 if (delta == 0) 2389 continue; 2390 total = com->error_counts[errnum] += delta; 2391 log(LOG_ERR, "cy%d: %u more %s%s (total %lu)\n", 2392 unit, delta, error_desc[errnum], 2393 delta == 1 ? "" : "s", total); 2394 } 2395 } 2396} 2397 2398static void 2399disc_optim(tp, t, com) 2400 struct tty *tp; 2401 struct termios *t; 2402 struct com_s *com; 2403{ 2404#ifndef SOFT_HOTCHAR 2405 cy_addr iobase; 2406 u_char opt; 2407#endif 2408 2409 /* 2410 * XXX can skip a lot more cases if Smarts. Maybe 2411 * (IGNCR | ISTRIP | IXON) in c_iflag. But perhaps we 2412 * shouldn't skip if (TS_CNTTB | TS_LNCH) is set in t_state. 2413 */ 2414 if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON)) 2415 && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK)) 2416 && (!(t->c_iflag & PARMRK) 2417 || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK)) 2418 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN)) 2419 && linesw[tp->t_line].l_rint == ttyinput) 2420 tp->t_state |= TS_CAN_BYPASS_L_RINT; 2421 else 2422 tp->t_state &= ~TS_CAN_BYPASS_L_RINT; 2423 /* 2424 * Prepare to reduce input latency for packet 2425 * discplines with a end of packet character. 2426 */ 2427 if (tp->t_line == SLIPDISC) 2428 com->hotchar = 0xc0; 2429 else if (tp->t_line == PPPDISC) 2430 com->hotchar = 0x7e; 2431 else 2432 com->hotchar = 0; 2433#ifndef SOFT_HOTCHAR 2434 iobase = com->iobase; 2435 cd_outb(iobase, CD1400_CAR, com->cy_align, com->unit & CD1400_CAR_CHAN); 2436 opt = com->cor[2] & ~CD1400_COR3_SCD34; 2437 if (com->hotchar != 0) { 2438 cd_outb(iobase, CD1400_SCHR3, com->cy_align, com->hotchar); 2439 cd_outb(iobase, CD1400_SCHR4, com->cy_align, com->hotchar); 2440 opt |= CD1400_COR3_SCD34; 2441 } 2442 if (opt != com->cor[2]) { 2443 cd_outb(iobase, CD1400_COR3, com->cy_align, com->cor[2] = opt); 2444 cd1400_channel_cmd(com->iobase, 2445 CD1400_CCR_CMDCORCHG | CD1400_CCR_COR3, 2446 com->cy_align); 2447 } 2448#endif 2449} 2450 2451#ifdef Smarts 2452/* standard line discipline input routine */ 2453int 2454cyinput(c, tp) 2455 int c; 2456 struct tty *tp; 2457{ 2458 /* XXX duplicate ttyinput(), but without the IXOFF/IXON/ISTRIP/IPARMRK 2459 * bits, as they are done by the CD1400. Hardly worth the effort, 2460 * given that high-throughput sessions are raw anyhow. 2461 */ 2462} 2463#endif /* Smarts */ 2464 2465static int 2466comspeed(speed, prescaler_io) 2467 speed_t speed; 2468 int *prescaler_io; 2469{ 2470 int actual; 2471 int error; 2472 int divider; 2473 int prescaler; 2474 int prescaler_unit; 2475 2476 if (speed == 0) 2477 return (0); 2478 if (speed < 0 || speed > 150000) 2479 return (-1); 2480 2481 /* determine which prescaler to use */ 2482 for (prescaler_unit = 4, prescaler = 2048; prescaler_unit; 2483 prescaler_unit--, prescaler >>= 2) { 2484 if (CY_CLOCK / prescaler / speed > 63) 2485 break; 2486 } 2487 2488 divider = (CY_CLOCK / prescaler * 2 / speed + 1) / 2; /* round off */ 2489 if (divider > 255) 2490 divider = 255; 2491 actual = CY_CLOCK/prescaler/divider; 2492 error = ((actual - speed) * 2000 / speed + 1) / 2; /* percentage */ 2493 2494 /* 3.0% max error tolerance */ 2495 if (error < -30 || error > 30) 2496 return (-1); 2497 2498#if 0 2499 printf("prescaler = %d (%d)\n", prescaler, prescaler_unit); 2500 printf("divider = %d (%x)\n", divider, divider); 2501 printf("actual = %d\n", actual); 2502 printf("error = %d\n", error); 2503#endif 2504 2505 *prescaler_io = prescaler_unit; 2506 return (divider); 2507} 2508 2509static void 2510cd1400_channel_cmd(iobase, cmd, cy_align) 2511 cy_addr iobase; 2512 int cmd; 2513 int cy_align; 2514{ 2515 /* XXX hsu@clinet.fi: This is always more dependent on ISA bus speed, 2516 as the card is probed every round? Replaced delaycount with 8k. 2517 Either delaycount has to be implemented in FreeBSD or more sensible 2518 way of doing these should be implemented. DELAY isn't enough here. 2519 */ 2520 u_int maxwait = 5 * 8 * 1024; /* approx. 5 ms */ 2521 2522 /* wait for processing of previous command to complete */ 2523 while (cd_inb(iobase, CD1400_CCR, cy_align) && maxwait--) 2524 ; 2525 2526 if (!maxwait) 2527 log(LOG_ERR, "cy: channel command timeout (%d loops) - arrgh\n", 2528 5 * 8 * 1024); 2529 2530 cd_outb(iobase, CD1400_CCR, cy_align, cmd); 2531} 2532 2533#ifdef CyDebug 2534/* useful in ddb */ 2535void 2536cystatus(unit) 2537 int unit; 2538{ 2539 struct com_s *com; 2540 cy_addr iobase; 2541 u_int ocount; 2542 struct tty *tp; 2543 2544 com = com_addr(unit); 2545 printf("info for channel %d\n", unit); 2546 printf("------------------\n"); 2547 printf("total cyclom service probes:\t%d\n", cy_svrr_probes); 2548 printf("calls to upper layer:\t\t%d\n", cy_timeouts); 2549 if (com == NULL) 2550 return; 2551 iobase = com->iobase; 2552 printf("\n"); 2553 printf("cd1400 base address:\\tt%p\n", iobase); 2554 cd_outb(iobase, CD1400_CAR, com->cy_align, unit & CD1400_CAR_CHAN); 2555 printf("saved channel_control:\t\t0x%02x\n", com->channel_control); 2556 printf("saved cor1-3:\t\t\t0x%02x 0x%02x 0x%02x\n", 2557 com->cor[0], com->cor[1], com->cor[2]); 2558 printf("service request enable reg:\t0x%02x (0x%02x cached)\n", 2559 cd_inb(iobase, CD1400_SRER, com->cy_align), com->intr_enable); 2560 printf("service request register:\t0x%02x\n", 2561 cd_inb(iobase, CD1400_SVRR, com->cy_align)); 2562 printf("modem status:\t\t\t0x%02x (0x%02x cached)\n", 2563 cd_inb(iobase, CD1400_MSVR2, com->cy_align), 2564 com->prev_modem_status); 2565 printf("rx/tx/mdm interrupt registers:\t0x%02x 0x%02x 0x%02x\n", 2566 cd_inb(iobase, CD1400_RIR, com->cy_align), 2567 cd_inb(iobase, CD1400_TIR, com->cy_align), 2568 cd_inb(iobase, CD1400_MIR, com->cy_align)); 2569 printf("\n"); 2570 printf("com state:\t\t\t0x%02x\n", com->state); 2571 printf("calls to comstart():\t\t%d (%d useful)\n", 2572 com->start_count, com->start_real); 2573 printf("rx buffer chars free:\t\t%d\n", com->iptr - com->ibuf); 2574 ocount = 0; 2575 if (com->obufs[0].l_queued) 2576 ocount += com->obufs[0].l_tail - com->obufs[0].l_head; 2577 if (com->obufs[1].l_queued) 2578 ocount += com->obufs[1].l_tail - com->obufs[1].l_head; 2579 printf("tx buffer chars:\t\t%u\n", ocount); 2580 printf("received chars:\t\t\t%d\n", com->bytes_in); 2581 printf("received exceptions:\t\t%d\n", com->recv_exception); 2582 printf("modem signal deltas:\t\t%d\n", com->mdm); 2583 printf("transmitted chars:\t\t%d\n", com->bytes_out); 2584 printf("\n"); 2585 tp = com->tp; 2586 if (tp != NULL) { 2587 printf("tty state:\t\t\t0x%08x\n", tp->t_state); 2588 printf( 2589 "upper layer queue lengths:\t%d raw, %d canon, %d output\n", 2590 tp->t_rawq.c_cc, tp->t_canq.c_cc, tp->t_outq.c_cc); 2591 } else 2592 printf("tty state:\t\t\tclosed\n"); 2593} 2594#endif /* CyDebug */ 2595