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