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