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