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