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