cy_isa.c revision 6454
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.1 1995/02/09 09:47:27 jkh Exp $ 31 */ 32 33/* 34 * Device minor number encoding: 35 * 36 * c c x x u u u u - bits in the minor device number 37 * 38 * bits meaning 39 * ---- ------- 40 * uuuu physical serial line (i.e. unit) to use 41 * 0-7 on a cyclom-8Y, 0-15 on a cyclom-16Y 42 * xx unused 43 * cc carrier control mode 44 * 00 complete hardware carrier control of the tty. 45 * DCD must be high for the open(2) to complete. 46 * 01 dialin pseudo-device (not yet implemented) 47 * 10 carrier ignored until a high->low transition 48 * 11 carrier completed ignored 49 */ 50 51/* 52 * Known deficiencies: 53 * 54 * * no BREAK handling - breaks are ignored, and can't be sent either 55 * * no support for bad-char reporting, except via PARMRK 56 * * no support for dialin + dialout devices 57 */ 58 59#include "cy.h" 60#if NCY > 0 61 62/* This disgusing hack because we actually have 16 units on one controller */ 63#if NCY < 2 64#undef NCY 65#define NCY (16) 66#endif 67 68#include <sys/param.h> 69#include <sys/systm.h> 70#include <sys/kernel.h> 71#include <sys/malloc.h> 72#include <sys/ioctl.h> 73#include <sys/tty.h> 74#include <sys/proc.h> 75#include <sys/user.h> 76#include <sys/conf.h> 77#include <sys/file.h> 78#include <sys/uio.h> 79#include <sys/kernel.h> 80#include <sys/syslog.h> 81 82#include <machine/cpu.h> 83#ifdef NetBSD 84#include <machine/pio.h> 85#endif 86#include <machine/cpufunc.h> 87 88#include <i386/isa/isa_device.h> 89#include <i386/isa/ic/cd1400.h> 90 91#define RxFifoThreshold 3 /* 3 characters (out of 12) in the receive 92 * FIFO before an interrupt is generated 93 */ 94#define FastRawInput /* bypass the regular char-by-char canonical input 95 * processing whenever possible 96 */ 97#define PollMode /* use polling-based irq service routine, not the 98 * hardware svcack lines. Must be defined for 99 * cyclom-16y boards. 100 * 101 * XXX cyclom-8y doesn't work without this defined 102 * either (!) 103 */ 104#define LogOverruns /* log receive fifo overruns */ 105#undef TxBuffer /* buffer driver output, to be slightly more 106 * efficient 107 * 108 * XXX presently buggy 109 */ 110#undef Smarts /* enable slightly more CD1400 intelligence. Mainly 111 * the output CR/LF processing, plus we can avoid a 112 * few checks usually done in ttyinput(). 113 * 114 * XXX not yet implemented, and not particularly 115 * worthwhile either. 116 */ 117#define CyDebug /* include debugging code (minimal effect on 118 * performance) 119 */ 120 121#define CY_RX_BUFS 2 /* two receive buffers per port */ 122#define CY_RX_BUF_SIZE 256 /* bytes per receive buffer */ 123#define CY_TX_BUF_SIZE 512 /* bytes per transmit buffer */ 124 125/* #define CD1400s_PER_CYCLOM 1 */ /* cyclom-4y */ 126/* #define CD1400s_PER_CYCLOM 2 */ /* cyclom-8y */ 127#define CD1400s_PER_CYCLOM 4 /* cyclom-16y */ 128 129/* FreeBSD's getty doesn't know option for setting RTS/CTS handshake. Its 130 getty, like a lot of other old cruft, should be replaced with something 131 which used POSIX tty interfaces which at least allow enabling it. In the 132 meantime, use the force. */ 133#define ALWAYS_RTS_CTS 1 134 135#if CD1400s_PER_CYCLOM < 4 136#define CD1400_MEMSIZE 0x400 /* 4*256 bytes per chip: cyclom-[48]y */ 137#else 138#define CD1400_MEMSIZE 0x100 /* 256 bytes per chip: cyclom-16y */ 139 /* XXX or is it 0x400 like the rest? */ 140#define CYCLOM_16 1 /* This is a cyclom-16Y */ 141#endif 142 143#define PORTS_PER_CYCLOM (CD1400_NO_OF_CHANNELS * CD1400s_PER_CYCLOM) 144#define CYCLOM_RESET_16 0x1400 /* cyclom-16y reset */ 145#define CYCLOM_CLEAR_INTR 0x1800 /* intr ack address */ 146#define CYCLOM_CLOCK 25000000 /* baud rate clock */ 147 148#define CY_UNITMASK 0x0f 149#define CY_CARRIERMASK 0xC0 150#define CY_CARRIERSHIFT 6 151 152#define UNIT(x) (minor(x) & CY_UNITMASK) 153#define CARRIER_MODE(x) ((minor(x) & CY_CARRIERMASK) >> CY_CARRIERSHIFT) 154 155typedef u_char * volatile cy_addr; 156 157int cyprobe(struct isa_device *dev); 158int cyattach(struct isa_device *isdp); 159void cystart(struct tty *tp); 160int cyparam(struct tty *tp, struct termios *t); 161int cyspeed(int speed, int *prescaler_io); 162static void cy_channel_init(dev_t dev, int reset); 163static void cd1400_channel_cmd(cy_addr base, u_char cmd); 164 165/* hsu@clinet.fi: sigh */ 166#ifdef __NetBSD__ 167#define DELAY(foo) delay(foo) 168void delay(int delay); 169#endif 170 171/* Better get rid of this until the core people agree on kernel interfaces. 172 At least it will then compile on both WhichBSDs. 173 */ 174#if 0 175extern unsigned int delaycount; /* calibrated 1 ms cpu-spin delay */ 176#endif 177 178struct isa_driver cydriver = { 179 cyprobe, cyattach, "cy" 180}; 181 182/* low-level ping-pong buffer structure */ 183 184struct cy_buf { 185 u_char *next_char; /* location of next char to write */ 186 u_int free; /* free chars remaining in buffer */ 187 struct cy_buf *next_buf; /* circular, you know */ 188 u_char buf[CY_RX_BUF_SIZE]; /* start of the buffer */ 189}; 190 191/* low-level ring buffer */ 192 193#ifdef TxBuffer 194struct cy_ring { 195 u_char buf[CY_TX_BUF_SIZE]; 196 u_char *head; 197 u_char *tail; /* next pos. to insert char */ 198 u_char *endish; /* physical end of buf */ 199 u_int used; /* no. of chars in queue */ 200}; 201#endif 202 203 204/* 205 * define a structure to keep track of each serial line 206 */ 207 208struct cy { 209 cy_addr base_addr; /* base address of this port's cd1400 */ 210 struct tty *tty; 211 u_int dtrwait; /* time (in ticks) to hold dtr low after close */ 212 u_int recv_exception; /* exception chars received */ 213 u_int recv_normal; /* normal chars received */ 214 u_int xmit; /* chars transmitted */ 215 u_int mdm; /* modem signal changes */ 216#ifdef CyDebug 217 u_int start_count; /* no. of calls to cystart() */ 218 u_int start_real; /* no. of calls that did something */ 219#endif 220 u_char carrier_mode; /* hardware carrier handling mode */ 221 /* 222 * 0 = always use 223 * 1 = always use (dialin port) 224 * 2 = ignore during open, then use it 225 * 3 = ignore completely 226 */ 227 u_char carrier_delta; /* true if carrier has changed state */ 228 u_char fifo_overrun; /* true if cd1400 receive fifo has... */ 229 u_char rx_buf_overrun; /* true if low-level buf overflow */ 230 u_char intr_enable; /* CD1400 SRER shadow */ 231 u_char modem_sig; /* CD1400 modem signal shadow */ 232 u_char channel_control;/* CD1400 CCR control command shadow */ 233 u_char cor[3]; /* CD1400 COR1-3 shadows */ 234#ifdef Smarts 235 u_char spec_char[4]; /* CD1400 SCHR1-4 shadows */ 236#endif 237 struct cy_buf *rx_buf; /* current receive buffer */ 238 struct cy_buf rx_buf_pool[CY_RX_BUFS];/* receive ping-pong buffers */ 239#ifdef TxBuffer 240 struct cy_ring tx_buf; /* transmit buffer */ 241#endif 242}; 243 244int cydefaultrate = TTYDEF_SPEED; 245cy_addr cyclom_base; /* base address of the card */ 246static struct cy *info[NCY*PORTS_PER_CYCLOM]; 247#ifdef __FreeBSD__ /* XXX actually only temporarily for 2.1-Development */ 248struct tty cy_tty[NCY*PORTS_PER_CYCLOM]; 249#else 250struct tty *cy_tty[NCY*PORTS_PER_CYCLOM]; 251#endif 252static volatile u_char timeout_scheduled = 0; /* true if a timeout has been scheduled */ 253 254#ifdef CyDebug 255u_int cy_svrr_probes = 0; /* debugging */ 256u_int cy_timeouts = 0; 257u_int cy_timeout_req = 0; 258#endif 259 260/**********************************************************************/ 261 262int 263cyprobe(struct isa_device *dev) 264{ 265 int i, j; 266 u_char version = 0; /* firmware version */ 267 268 /* Cyclom-16Y hardware reset (Cyclom-8Ys don't care) */ 269 i = *(cy_addr)(dev->id_maddr + CYCLOM_RESET_16); 270 271 DELAY(500); /* wait for the board to get its act together (500 us) */ 272 273 for (i = 0; i < CD1400s_PER_CYCLOM; i++) { 274 cy_addr base = dev->id_maddr + i * CD1400_MEMSIZE; 275 276 /* wait for chip to become ready for new command */ 277 for (j = 0; j < 100; j += 50) { 278 DELAY(50); /* wait 50 us */ 279 280 if (!*(base + CD1400_CCR)) 281 break; 282 } 283 284 /* clear the GFRCR register */ 285 *(base + CD1400_GFRCR) = 0; 286 287 /* issue a reset command */ 288 *(base + CD1400_CCR) = CD1400_CMD_RESET; 289 290 /* wait for the CD1400 to initialise itself */ 291 for (j = 0; j < 1000; j += 50) { 292 DELAY(50); /* wait 50 us */ 293 294 /* retrieve firmware version */ 295 version = *(base + CD1400_GFRCR); 296 if (version) 297 break; 298 } 299 300 /* anything in the 40-4f range is fine */ 301 if ((version & 0xf0) != 0x40) { 302 return 0; 303 } 304 } 305 306 return 1; /* found */ 307} 308 309 310int 311cyattach(struct isa_device *isdp) 312{ 313/* u_char unit = UNIT(isdp->id_unit); */ 314 int i, j, k; 315 316 /* global variable used various routines */ 317 cyclom_base = (cy_addr)isdp->id_maddr; 318 319 for (i = 0, k = 0; i < CD1400s_PER_CYCLOM; i++) { 320 cy_addr base = cyclom_base + i * CD1400_MEMSIZE; 321 322 /* setup a 1ms clock tick */ 323 *(base + CD1400_PPR) = CD1400_CLOCK_25_1MS; 324 325 for (j = 0; j < CD1400_NO_OF_CHANNELS; j++, k++) { 326 struct cy *ip; 327 328 /* 329 * grab some space. it'd be more polite to do this in cyopen(), 330 * but hey. 331 */ 332 info[k] = ip = malloc(sizeof(struct cy), M_DEVBUF, M_WAITOK); 333 334 /* clear all sorts of junk */ 335 bzero(ip, sizeof(struct cy)); 336 337 ip->base_addr = base; 338 339 /* initialise the channel, without resetting it first */ 340 cy_channel_init(k, 0); 341 } 342 } 343 344 /* clear interrupts */ 345 *(cyclom_base + CYCLOM_CLEAR_INTR) = (u_char)0; 346 347 return 1; 348} 349 350 351int 352cyopen(dev_t dev, int flag, int mode, struct proc *p) 353{ 354 u_int unit = UNIT(dev); 355 struct cy *infop; 356 cy_addr base; 357 struct tty *tp; 358 int error = 0; 359 u_char carrier; 360 361 if (unit >= /* NCY * ? */ PORTS_PER_CYCLOM) 362 return (ENXIO); 363 364 infop = info[unit]; 365 base = infop->base_addr; 366#ifdef __FreeBSD__ 367 infop->tty = &cy_tty[unit]; 368#else 369 if (!cy_tty[unit]) 370 infop->tty = cy_tty[unit] = ttymalloc(); 371#endif 372 tp = infop->tty; 373 374 tp->t_oproc = cystart; 375 tp->t_param = cyparam; 376 tp->t_dev = dev; 377 if (!(tp->t_state & TS_ISOPEN)) { 378 tp->t_state |= TS_WOPEN; 379 ttychars(tp); 380 if (tp->t_ispeed == 0) { 381 tp->t_iflag = TTYDEF_IFLAG; 382 tp->t_oflag = TTYDEF_OFLAG; 383 tp->t_cflag = TTYDEF_CFLAG; 384 tp->t_lflag = TTYDEF_LFLAG; 385 tp->t_ispeed = tp->t_ospeed = cydefaultrate; 386 } 387 388 (void) spltty(); 389 cy_channel_init(unit, 1); /* reset the hardware */ 390 391 /* 392 * raise dtr and generally set things up correctly. this 393 * has the side-effect of selecting the appropriate cd1400 394 * channel, to help us with subsequent channel control stuff 395 */ 396 cyparam(tp, &tp->t_termios); 397 398 /* check carrier, and set t_state's TS_CARR_ON flag accordingly */ 399 infop->modem_sig = *(base + CD1400_MSVR); 400 carrier = infop->modem_sig & CD1400_MSVR_CD; 401 402 if (carrier || (infop->carrier_mode >= 2)) 403 tp->t_state |= TS_CARR_ON; 404 else 405 tp->t_state &=~ TS_CARR_ON; 406 407 /* 408 * enable modem & rx interrupts - relies on cyparam() 409 * having selected the appropriate cd1400 channel 410 */ 411 infop->intr_enable = (1 << 7) | (1 << 4); 412 *(base + CD1400_SRER) = infop->intr_enable; 413 414 ttsetwater(tp); 415 } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) 416 return (EBUSY); 417 418 if (!(flag & O_NONBLOCK)) 419 while (!(tp->t_cflag & CLOCAL) && 420 !(tp->t_state & TS_CARR_ON) && !error) 421 error = ttysleep(tp, (caddr_t)&tp->t_rawq, 422 TTIPRI|PCATCH, ttopen, 0); 423 (void) spl0(); 424 425 if (!error) 426 error = (*linesw[(u_char)tp->t_line].l_open)(dev, tp); 427 return (error); 428} /* end of cyopen() */ 429 430 431void 432cyclose_wakeup(void *arg) 433{ 434 wakeup(arg); 435} /* end of cyclose_wakeup() */ 436 437 438int 439cyclose(dev_t dev, int flag, int mode, struct proc *p) 440{ 441 u_int unit = UNIT(dev); 442 struct cy *infop = info[unit]; 443 struct tty *tp = infop->tty; 444 cy_addr base = infop->base_addr; 445 int s; 446 447 (*linesw[(u_char)tp->t_line].l_close)(tp, flag); 448 449 s = spltty(); 450 /* select the appropriate channel on the CD1400 */ 451 *(base + CD1400_CAR) = (u_char)(unit & 0x03); 452 453 /* disable this channel and lower DTR */ 454 infop->intr_enable = 0; 455 *(base + CD1400_SRER) = (u_char)0; /* no intrs */ 456 *(base + CD1400_DTR) = (u_char)CD1400_DTR_CLEAR; /* no DTR */ 457 infop->modem_sig &= ~CD1400_MSVR_DTR; 458 459 /* disable receiver (leave transmitter enabled) */ 460 infop->channel_control = (1 << 4) | (1 << 3) | 1; 461 cd1400_channel_cmd(base, infop->channel_control); 462 splx(s); 463 464 ttyclose(tp); 465#ifdef broken /* session holds a ref to the tty; can't deallocate */ 466 ttyfree(tp); 467 infop->tty = cy_tty[unit] = (struct tty *)NULL; 468#endif 469 470 if (infop->dtrwait) { 471 int error; 472 473 timeout(cyclose_wakeup, (caddr_t)&infop->dtrwait, infop->dtrwait); 474 do { 475 error = tsleep((caddr_t)&infop->dtrwait, 476 TTIPRI|PCATCH, "cyclose", 0); 477 } while (error == ERESTART); 478 } 479 480 return 0; 481} /* end of cyclose() */ 482 483 484int 485cyread(dev_t dev, struct uio *uio, int flag) 486{ 487 u_int unit = UNIT(dev); 488 struct tty *tp = info[unit]->tty; 489 490 return (*linesw[(u_char)tp->t_line].l_read)(tp, uio, flag); 491} /* end of cyread() */ 492 493 494int 495cywrite(dev_t dev, struct uio *uio, int flag) 496{ 497 u_int unit = UNIT(dev); 498 struct tty *tp = info[unit]->tty; 499 500#ifdef Smarts 501 /* XXX duplicate ttwrite(), but without so much output processing on 502 * CR & LF chars. Hardly worth the effort, given that high-throughput 503 * sessions are raw anyhow. 504 */ 505#else 506 return (*linesw[(u_char)tp->t_line].l_write)(tp, uio, flag); 507#endif 508} /* end of cywrite() */ 509 510 511#ifdef Smarts 512/* standard line discipline input routine */ 513int 514cyinput(int c, struct tty *tp) 515{ 516 /* XXX duplicate ttyinput(), but without the IXOFF/IXON/ISTRIP/IPARMRK 517 * bits, as they are done by the CD1400. Hardly worth the effort, 518 * given that high-throughput sessions are raw anyhow. 519 */ 520} /* end of cyinput() */ 521#endif /* Smarts */ 522 523 524inline static void 525service_upper_rx(int unit) 526{ 527 struct cy *ip = info[unit]; 528 struct tty *tp = ip->tty; 529 struct cy_buf *buf; 530 int i; 531 u_char *ch; 532 533 buf = ip->rx_buf; 534 535 /* give service_rx() a new one */ 536 disable_intr(); /* faster than spltty() */ 537 ip->rx_buf = buf->next_buf; 538 enable_intr(); 539 540 if (tp->t_state & TS_ISOPEN) { 541 ch = buf->buf; 542 i = buf->next_char - buf->buf; 543 544#ifdef FastRawInput 545 /* try to avoid calling the line discipline stuff if we can */ 546 if ((tp->t_line == 0) && 547 !(tp->t_iflag & (ICRNL | IMAXBEL | INLCR)) && 548 !(tp->t_lflag & (ECHO | ECHONL | ICANON | IEXTEN | 549 ISIG | PENDIN)) && 550 !(tp->t_state & (TS_CNTTB | TS_LNCH))) { 551 552 i = b_to_q(ch, i, &tp->t_rawq); 553 if (i) { 554 /* 555 * we have no RTS flow control support on cy-8 556 * boards, so this is really just tough luck 557 */ 558 559 log(LOG_WARNING, "cy%d: tty input queue overflow\n", 560 unit); 561 } 562 563 ttwakeup(tp); /* notify any readers */ 564 } 565 else 566#endif /* FastRawInput */ 567 { 568 while (i--) 569 (*linesw[(u_char)tp->t_line].l_rint)((int)*ch++, tp); 570 } 571 } 572 573 /* clear the buffer we've just processed */ 574 buf->next_char = buf->buf; 575 buf->free = CY_RX_BUF_SIZE; 576} /* end of service_upper_rx() */ 577 578 579#ifdef TxBuffer 580static void 581service_upper_tx(int unit) 582{ 583 struct cy *ip = info[unit]; 584 struct tty *tp = ip->tty; 585 586 tp->t_state &=~ (TS_BUSY|TS_FLUSH); 587 588 if (tp->t_outq.c_cc <= tp->t_lowat) { 589 if (tp->t_state&TS_ASLEEP) { 590 tp->t_state &= ~TS_ASLEEP; 591 wakeup((caddr_t)&tp->t_outq); 592 } 593 selwakeup(&tp->t_wsel); 594 } 595 596 if (tp->t_outq.c_cc > 0) { 597 struct cy_ring *txq = &ip->tx_buf; 598 int free_count = CY_TX_BUF_SIZE - ip->tx_buf.used; 599 u_char *cp = txq->tail; 600 int count; 601 int chars_done; 602 603 tp->t_state |= TS_BUSY; 604 605 /* find the largest contig. copy we can do */ 606 count = ((txq->endish - cp) > free_count) ? 607 free_count : txq->endish - cp; 608 609 count = ((cp + free_count) > txq->endish) ? 610 txq->endish - cp : free_count; 611 612 /* copy the first slab */ 613 chars_done = q_to_b(&tp->t_outq, cp, count); 614 615 /* check for wrap-around time */ 616 cp += chars_done; 617 if (cp == txq->endish) 618 cp = txq->buf; /* back to the start */ 619 620 /* copy anything else, after we've wrapped around */ 621 if ((chars_done == count) && (count != free_count)) { 622 /* copy the second slab */ 623 count = q_to_b(&tp->t_outq, cp, free_count - count); 624 cp += count; 625 chars_done += count; 626 } 627 628 /* 629 * update queue, protecting ourselves from any rampant 630 * lower-layers 631 */ 632 disable_intr(); 633 txq->tail = cp; 634 txq->used += chars_done; 635 enable_intr(); 636 } 637 638 if (!tp->t_outq.c_cc) 639 tp->t_state &=~ TS_BUSY; 640} /* end of service_upper_tx() */ 641#endif /* TxBuffer */ 642 643 644inline static void 645service_upper_mdm(int unit) 646{ 647 struct cy *ip = info[unit]; 648 649 if (ip->carrier_delta) { 650 int carrier = ip->modem_sig & CD1400_MSVR_CD; 651 struct tty *tp = ip->tty; 652 653 if (!(*linesw[(u_char)tp->t_line].l_modem)(tp, carrier)) { 654 cy_addr base = ip->base_addr; 655 656 /* clear DTR */ 657 disable_intr(); 658 *(base + CD1400_CAR) = (u_char)(unit & 0x03); 659 *(base + CD1400_DTR) = (u_char)CD1400_DTR_CLEAR; 660 ip->modem_sig &= ~CD1400_MSVR_DTR; 661 ip->carrier_delta = 0; 662 enable_intr(); 663 } 664 else { 665 disable_intr(); 666 ip->carrier_delta = 0; 667 enable_intr(); 668 } 669 } 670} /* end of service_upper_mdm() */ 671 672 673/* upper level character processing routine */ 674void 675cytimeout(void *ptr) 676{ 677 int unit; 678 679 timeout_scheduled = 0; 680 681#ifdef CyDebug 682 cy_timeouts++; 683#endif 684 685 /* check each port in turn */ 686 for (unit = 0; unit < NCY*PORTS_PER_CYCLOM; unit++) { 687 struct cy *ip = info[unit]; 688#ifndef TxBuffer 689 struct tty *tp = ip->tty; 690#endif 691 692 /* ignore anything that is not open */ 693 if (!ip->tty) 694 continue; 695 696 /* 697 * any received chars to handle? (doesn't matter if intr routine 698 * kicks in while we're testing this) 699 */ 700 if (ip->rx_buf->free != CY_RX_BUF_SIZE) 701 service_upper_rx(unit); 702 703#ifdef TxBuffer 704 /* anything to add to the transmit buffer (low-water mark)? */ 705 if (ip->tx_buf.used < CY_TX_BUF_SIZE/2) 706 service_upper_tx(unit); 707#else 708 if (tp->t_outq.c_cc <= tp->t_lowat) { 709 if (tp->t_state&TS_ASLEEP) { 710 tp->t_state &= ~TS_ASLEEP; 711 wakeup((caddr_t)&tp->t_outq); 712 } 713 selwakeup(&tp->t_wsel); 714 } 715#endif 716 717 /* anything modem signals altered? */ 718 service_upper_mdm(unit); 719 720 /* any overruns to log? */ 721#ifdef LogOverruns 722 if (ip->fifo_overrun) { 723 /* 724 * turn off the alarm - not important enough to bother 725 * with interrupt protection. 726 */ 727 ip->fifo_overrun = 0; 728 729 log(LOG_WARNING, "cy%d: receive fifo overrun\n", unit); 730 } 731#endif 732 if (ip->rx_buf_overrun) { 733 /* 734 * turn off the alarm - not important enough to bother 735 * with interrupt protection. 736 */ 737 ip->rx_buf_overrun = 0; 738 739 log(LOG_WARNING, "cy%d: receive buffer full\n", unit); 740 } 741 } 742} /* cytimeout() */ 743 744 745inline static void 746schedule_upper_service(void) 747{ 748#ifdef CyDebug 749 cy_timeout_req++; 750#endif 751 752 if (!timeout_scheduled) { 753 timeout(cytimeout, (caddr_t)0, 1); /* call next tick */ 754 timeout_scheduled = 1; 755 } 756} /* end of schedule_upper_service() */ 757 758 759/* initialise a channel on the cyclom board */ 760 761static void 762cy_channel_init(dev_t dev, int reset) 763{ 764 u_int unit = UNIT(dev); 765 int carrier_mode = CARRIER_MODE(dev); 766 struct cy *ip = info[unit]; 767 cy_addr base = ip->base_addr; 768 struct tty *tp = ip->tty; 769 struct cy_buf *buf, *next_buf; 770 int i; 771#ifndef PollMode 772 u_char cd1400_unit; 773#endif 774 775 /* clear the structure and refill it */ 776 bzero(ip, sizeof(struct cy)); 777 ip->base_addr = base; 778 ip->tty = tp; 779 ip->carrier_mode = carrier_mode; 780 781 /* select channel of the CD1400 */ 782 *(base + CD1400_CAR) = (u_char)(unit & 0x03); 783 784 if (reset) 785 cd1400_channel_cmd(base, 0x80); /* reset the channel */ 786 787 /* set LIVR to 0 - intr routines depend on this */ 788 *(base + CD1400_LIVR) = 0; 789 790#ifndef PollMode 791 /* set top four bits of {R,T,M}ICR to the cd1400 792 * number, cd1400_unit 793 */ 794 cd1400_unit = unit / CD1400_NO_OF_CHANNELS; 795 *(base + CD1400_RICR) = (u_char)(cd1400_unit << 4); 796 *(base + CD1400_TICR) = (u_char)(cd1400_unit << 4); 797 *(base + CD1400_MICR) = (u_char)(cd1400_unit << 4); 798#endif 799 800 ip->dtrwait = hz/4; /* quarter of a second */ 801 802 /* setup low-level buffers */ 803 i = CY_RX_BUFS; 804 ip->rx_buf = next_buf = &ip->rx_buf_pool[0]; 805 while (i--) { 806 buf = &ip->rx_buf_pool[i]; 807 808 buf->next_char = buf->buf; /* first char to use */ 809 buf->free = CY_RX_BUF_SIZE; /* i.e. empty */ 810 buf->next_buf = next_buf; /* where to go next */ 811 next_buf = buf; 812 } 813 814#ifdef TxBuffer 815 ip->tx_buf.endish = ip->tx_buf.buf + CY_TX_BUF_SIZE; 816 817 /* clear the low-level tx buffer */ 818 ip->tx_buf.head = ip->tx_buf.tail = ip->tx_buf.buf; 819 ip->tx_buf.used = 0; 820#endif 821 822 /* clear the low-level rx buffer */ 823 ip->rx_buf->next_char = ip->rx_buf->buf; /* first char to use */ 824 ip->rx_buf->free = CY_RX_BUF_SIZE; /* completely empty */ 825} /* end of cy_channel_init() */ 826 827 828/* service a receive interrupt */ 829inline static void 830service_rx(int cd, caddr_t base) 831{ 832 struct cy *infop; 833 unsigned count; 834 int ch; 835 u_char serv_type, channel; 836#ifdef PollMode 837 u_char save_rir, save_car; 838#endif 839 840 /* setup */ 841#ifdef PollMode 842 save_rir = *(base + CD1400_RIR); 843 channel = cd * CD1400_NO_OF_CHANNELS + (save_rir & 0x3); 844 save_car = *(base + CD1400_CAR); 845 *(base + CD1400_CAR) = save_rir; /* enter modem service */ 846 serv_type = *(base + CD1400_RIVR); 847#else 848 serv_type = *(base + CD1400_SVCACKR); /* ack receive service */ 849 channel = ((u_char)*(base + CD1400_RICR)) >> 2; /* get cyclom channel # */ 850 851#ifdef CyDebug 852 if (channel >= PORTS_PER_CYCLOM) { 853 printf("cy: service_rx - channel %02x\n", channel); 854 panic("cy: service_rx - bad channel"); 855 } 856#endif 857#endif 858 859 infop = info[channel]; 860 861 /* read those chars */ 862 if (serv_type & CD1400_RIVR_EXCEPTION) { 863 /* read the exception status */ 864 u_char status = *(base + CD1400_RDSR); 865 866 /* XXX is it a break? Do something if it is! */ 867 868 /* XXX is IGNPAR not set? Store a null in the buffer. */ 869 870#ifdef LogOverruns 871 if (status & CD1400_RDSR_OVERRUN) { 872#if 0 873 ch |= TTY_PE; /* for SLIP */ 874#endif 875 infop->fifo_overrun++; 876 } 877#endif 878 infop->recv_exception++; 879 } 880 else { 881 struct cy_buf *buf = infop->rx_buf; 882 883 count = (u_char)*(base + CD1400_RDCR); /* how many to read? */ 884 infop->recv_normal += count; 885 if (buf->free < count) { 886 infop->rx_buf_overrun += count; 887 888 /* read & discard everything */ 889 while (count--) 890 ch = (u_char)*(base + CD1400_RDSR); 891 } 892 else { 893 /* slurp it into our low-level buffer */ 894 buf->free -= count; 895 while (count--) { 896 ch = (u_char)*(base + CD1400_RDSR); /* read the char */ 897 *(buf->next_char++) = ch; 898 } 899 } 900 } 901 902#ifdef PollMode 903 *(base + CD1400_RIR) = (u_char)(save_rir & 0x3f); /* terminate service context */ 904#else 905 *(base + CD1400_EOSRR) = (u_char)0; /* terminate service context */ 906#endif 907} /* end of service_rx */ 908 909 910/* service a transmit interrupt */ 911inline static void 912service_tx(int cd, caddr_t base) 913{ 914 struct cy *ip; 915#ifdef TxBuffer 916 struct cy_ring *txq; 917#else 918 struct tty *tp; 919#endif 920 u_char channel; 921#ifdef PollMode 922 u_char save_tir, save_car; 923#else 924 u_char vector; 925#endif 926 927 /* setup */ 928#ifdef PollMode 929 save_tir = *(base + CD1400_TIR); 930 channel = cd * CD1400_NO_OF_CHANNELS + (save_tir & 0x3); 931 save_car = *(base + CD1400_CAR); 932 *(base + CD1400_CAR) = save_tir; /* enter tx service */ 933#else 934 vector = *(base + CD1400_SVCACKT); /* ack transmit service */ 935 channel = ((u_char)*(base + CD1400_TICR)) >> 2; /* get cyclom channel # */ 936 937#ifdef CyDebug 938 if (channel >= PORTS_PER_CYCLOM) { 939 printf("cy: service_tx - channel %02x\n", channel); 940 panic("cy: service_tx - bad channel"); 941 } 942#endif 943#endif 944 945 ip = info[channel]; 946#ifdef TxBuffer 947 txq = &ip->tx_buf; 948 949 if (txq->used > 0) { 950 cy_addr base = ip->base_addr; 951 int count = min(CD1400_FIFOSIZE, txq->used); 952 int chars_done = count; 953 u_char *cp = txq->head; 954 u_char *buf_end = txq->endish; 955 956 /* ip->state |= CY_BUSY; */ 957 while (count--) { 958 *(base + CD1400_TDR) = *cp++; 959 if (cp >= buf_end) 960 cp = txq->buf; 961 }; 962 txq->head = cp; 963 txq->used -= chars_done; /* important that this is atomic */ 964 ip->xmit += chars_done; 965 } 966 967 /* 968 * disable tx intrs if no more chars to send. we re-enable 969 * them in cystart() 970 */ 971 if (!txq->used) { 972 ip->intr_enable &=~ (1 << 2); 973 *(base + CD1400_SRER) = ip->intr_enable; 974 /* ip->state &= ~CY_BUSY; */ 975 } 976#else 977 tp = ip->tty; 978 979 if (!(tp->t_state & TS_TTSTOP) && (tp->t_outq.c_cc > 0)) { 980 cy_addr base = ip->base_addr; 981 int count = min(CD1400_FIFOSIZE, tp->t_outq.c_cc); 982 983 ip->xmit += count; 984 tp->t_state |= TS_BUSY; 985 while (count--) 986 *(base + CD1400_TDR) = getc(&tp->t_outq); 987 } 988 989 /* 990 * disable tx intrs if no more chars to send. we re-enable them 991 * in cystart() 992 */ 993 if (!tp->t_outq.c_cc) { 994 ip->intr_enable &=~ (1 << 2); 995 *(base + CD1400_SRER) = ip->intr_enable; 996 tp->t_state &= ~TS_BUSY; 997 } 998#endif 999 1000#ifdef PollMode 1001 *(base + CD1400_TIR) = (u_char)(save_tir & 0x3f); /* terminate service context */ 1002#else 1003 *(base + CD1400_EOSRR) = (u_char)0; /* terminate service context */ 1004#endif 1005} /* end of service_tx */ 1006 1007 1008/* service a modem status interrupt */ 1009inline static void 1010service_mdm(int cd, caddr_t base) 1011{ 1012 struct cy *infop; 1013 u_char channel, deltas; 1014#ifdef PollMode 1015 u_char save_mir, save_car; 1016#else 1017 u_char vector; 1018#endif 1019 1020 /* setup */ 1021#ifdef PollMode 1022 save_mir = *(base + CD1400_MIR); 1023 channel = cd * CD1400_NO_OF_CHANNELS + (save_mir & 0x3); 1024 save_car = *(base + CD1400_CAR); 1025 *(base + CD1400_CAR) = save_mir; /* enter modem service */ 1026#else 1027 vector = *(base + CD1400_SVCACKM); /* ack modem service */ 1028 channel = ((u_char)*(base + CD1400_MICR)) >> 2; /* get cyclom channel # */ 1029 1030#ifdef CyDebug 1031 if (channel >= PORTS_PER_CYCLOM) { 1032 printf("cy: service_mdm - channel %02x\n", channel); 1033 panic("cy: service_mdm - bad channel"); 1034 } 1035#endif 1036#endif 1037 1038 infop = info[channel]; 1039 1040 /* read the siggies and see what's changed */ 1041 infop->modem_sig = (u_char)*(base + CD1400_MSVR); 1042 deltas = (u_char)*(base + CD1400_MISR); 1043 1044 if ((infop->carrier_mode <= 2) && (deltas & CD1400_MISR_CDd)) 1045 /* something for the upper layer to deal with */ 1046 infop->carrier_delta = 1; 1047 1048 infop->mdm++; 1049 1050 /* terminate service context */ 1051#ifdef PollMode 1052 *(base + CD1400_MIR) = (u_char)(save_mir & 0x3f); 1053#else 1054 *(base + CD1400_EOSRR) = (u_char)0; 1055#endif 1056} /* end of service_mdm */ 1057 1058 1059int 1060cyintr(int unit) 1061{ 1062 int cd; 1063 u_char status; 1064 1065 /* check each CD1400 in turn */ 1066 for (cd = 0; cd < CD1400s_PER_CYCLOM; cd++) { 1067 cy_addr base = cyclom_base + cd*CD1400_MEMSIZE; 1068 1069 /* poll to see if it has any work */ 1070 while (status = (u_char)*(base + CD1400_SVRR)) { 1071#ifdef CyDebug 1072 cy_svrr_probes++; 1073#endif 1074 /* service requests as appropriate, giving priority to RX */ 1075 if (status & CD1400_SVRR_RX) 1076 service_rx(cd, base); 1077 if (status & CD1400_SVRR_TX) 1078 service_tx(cd, base); 1079 if (status & CD1400_SVRR_MDM) 1080 service_mdm(cd, base); 1081 } 1082 } 1083 1084 /* request upper level service to deal with whatever happened */ 1085 schedule_upper_service(); 1086 1087 /* re-enable interrupts on the cyclom */ 1088 *(cyclom_base + CYCLOM_CLEAR_INTR) = (u_char)0; 1089 1090 return 1; 1091} 1092 1093 1094int 1095cyioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) 1096{ 1097 int unit = UNIT(dev); 1098 struct cy *infop = info[unit]; 1099 struct tty *tp = infop->tty; 1100 int error; 1101 1102 error = (*linesw[(u_char)tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 1103 if (error >= 0) 1104 return (error); 1105 error = ttioctl(tp, cmd, data, flag 1106#ifdef NetBSD 1107 , p 1108#endif 1109 ); 1110 if (error >= 0) 1111 return (error); 1112 1113 switch (cmd) { 1114#ifdef notyet /* sigh - more junk to do XXX */ 1115 case TIOCSBRK: 1116 break; 1117 case TIOCCBRK: 1118 break; 1119 case TIOCSDTR: 1120 break; 1121 case TIOCCDTR: 1122 break; 1123 1124 case TIOCMSET: 1125 break; 1126 case TIOCMBIS: 1127 break; 1128 case TIOCMBIC: 1129 break; 1130#endif /* notyet */ 1131 1132 case TIOCMGET: { 1133 int bits = 0; 1134 u_char status = infop->modem_sig; 1135 1136 if (status & CD1400_MSVR_DTR) bits |= TIOCM_DTR | TIOCM_RTS; 1137 if (status & CD1400_MSVR_CD) bits |= TIOCM_CD; 1138 if (status & CD1400_MSVR_CTS) bits |= TIOCM_CTS; 1139 if (status & CD1400_MSVR_DSR) bits |= TIOCM_DSR; 1140#ifdef CYCLOM_16 1141 if (status & CD1400_MSVR_RI) bits |= TIOCM_RI; 1142#endif 1143 if (infop->channel_control & 0x02) bits |= TIOCM_LE; 1144 *(int *)data = bits; 1145 break; 1146 } 1147 1148#ifdef TIOCMSBIDIR 1149 case TIOCMSBIDIR: 1150 return (ENOTTY); 1151#endif /* TIOCMSBIDIR */ 1152 1153#ifdef TIOCMGBIDIR 1154 case TIOCMGBIDIR: 1155 return (ENOTTY); 1156#endif /* TIOCMGBIDIR */ 1157 1158#ifdef TIOCMSDTRWAIT 1159 case TIOCMSDTRWAIT: 1160 /* must be root to set dtr delay */ 1161 if (p->p_ucred->cr_uid != 0) 1162 return(EPERM); 1163 1164 infop->dtrwait = *(u_int *)data; 1165 break; 1166#endif /* TIOCMSDTRWAIT */ 1167 1168#ifdef TIOCMGDTRWAIT 1169 case TIOCMGDTRWAIT: 1170 *(u_int *)data = infop->dtrwait; 1171 break; 1172#endif /* TIOCMGDTRWAIT */ 1173 1174 default: 1175 return (ENOTTY); 1176 } 1177 1178 return 0; 1179} /* end of cyioctl() */ 1180 1181 1182int 1183cyparam(struct tty *tp, struct termios *t) 1184{ 1185 u_char unit = UNIT(tp->t_dev); 1186 struct cy *infop = info[unit]; 1187 cy_addr base = infop->base_addr; 1188 int cflag = t->c_cflag; 1189 int iflag = t->c_iflag; 1190 int ispeed, ospeed; 1191 int itimeout; 1192 int iprescaler, oprescaler; 1193 int s; 1194 u_char cor_change = 0; 1195 u_char opt; 1196 1197 if (!t->c_ispeed) 1198 t->c_ispeed = t->c_ospeed; 1199 1200 s = spltty(); 1201 1202 /* select the appropriate channel on the CD1400 */ 1203 *(base + CD1400_CAR) = unit & 0x03; 1204 1205 /* handle DTR drop on speed == 0 trick */ 1206 if (t->c_ospeed == 0) { 1207 *(base + CD1400_DTR) = CD1400_DTR_CLEAR; 1208 infop->modem_sig &= ~CD1400_MSVR_DTR; 1209 } 1210 else { 1211 *(base + CD1400_DTR) = CD1400_DTR_SET; 1212 infop->modem_sig |= CD1400_MSVR_DTR; 1213 } 1214 1215 /* set baud rates if they've changed from last time */ 1216 1217 if ((ospeed = cyspeed(t->c_ospeed, &oprescaler)) < 0) 1218 return EINVAL; 1219 *(base + CD1400_TBPR) = (u_char)ospeed; 1220 *(base + CD1400_TCOR) = (u_char)oprescaler; 1221 1222 if ((ispeed = cyspeed(t->c_ispeed, &iprescaler)) < 0) 1223 return EINVAL; 1224 *(base + CD1400_RBPR) = (u_char)ispeed; 1225 *(base + CD1400_RCOR) = (u_char)iprescaler; 1226 1227 /* 1228 * set receive time-out period 1229 * generate a rx interrupt if no new chars are received in 1230 * this many ticks 1231 * don't bother comparing old & new VMIN, VTIME and ispeed - it 1232 * can't be much worse just to calculate and set it each time! 1233 * certainly less hassle. :-) 1234 */ 1235 1236 /* 1237 * calculate minimum timeout period: 1238 * 5 ms or the time it takes to receive 1 char, rounded up to the 1239 * next ms, whichever is greater 1240 */ 1241 if (t->c_ispeed > 0) { 1242 itimeout = (t->c_ispeed > 2200) ? 5 : (10000/t->c_ispeed + 1); 1243 1244 /* if we're using VTIME as an inter-char timeout, and it is set to 1245 * be longer than the minimum calculated above, go for it 1246 */ 1247 if (t->c_cc[VMIN] && t->c_cc[VTIME] && t->c_cc[VTIME]*10 > itimeout) 1248 itimeout = t->c_cc[VTIME]*10; 1249 1250 /* store it, taking care not to overflow the byte-sized register */ 1251 *(base + CD1400_RTPR) = (u_char)((itimeout <= 255) ? itimeout : 255); 1252 } 1253 1254 1255 /* 1256 * channel control 1257 * receiver enable 1258 * transmitter enable (always set) 1259 */ 1260 opt = (1 << 4) | (1 << 3) | ((cflag & CREAD) ? (1 << 1) : 1); 1261 if (opt != infop->channel_control) { 1262 infop->channel_control = opt; 1263 cd1400_channel_cmd(base, opt); 1264 } 1265 1266#ifdef Smarts 1267 /* set special chars */ 1268 if (t->c_cc[VSTOP] != _POSIX_VDISABLE && 1269 (t->c_cc[VSTOP] != infop->spec_char[0])) { 1270 *(base + CD1400_SCHR1) = infop->spec_char[0] = t->c_cc[VSTOP]; 1271 } 1272 if (t->c_cc[VSTART] != _POSIX_VDISABLE && 1273 (t->c_cc[VSTART] != infop->spec_char[1])) { 1274 *(base + CD1400_SCHR2) = infop->spec_char[0] = t->c_cc[VSTART]; 1275 } 1276 if (t->c_cc[VINTR] != _POSIX_VDISABLE && 1277 (t->c_cc[VINTR] != infop->spec_char[2])) { 1278 *(base + CD1400_SCHR3) = infop->spec_char[0] = t->c_cc[VINTR]; 1279 } 1280 if (t->c_cc[VSUSP] != _POSIX_VDISABLE && 1281 (t->c_cc[VSUSP] != infop->spec_char[3])) { 1282 *(base + CD1400_SCHR4) = infop->spec_char[0] = t->c_cc[VSUSP]; 1283 } 1284#endif 1285 1286 /* 1287 * set channel option register 1 - 1288 * parity mode 1289 * stop bits 1290 * char length 1291 */ 1292 opt = 0; 1293 /* parity */ 1294 if (cflag & PARENB) { 1295 if (cflag & PARODD) 1296 opt |= 1 << 7; 1297 opt |= 2 << 5; /* normal parity mode */ 1298 } 1299 if (!(iflag & INPCK)) 1300 opt |= 1 << 4; /* ignore parity */ 1301 /* stop bits */ 1302 if (cflag & CSTOPB) 1303 opt |= 2 << 2; 1304 /* char length */ 1305 opt |= (cflag & CSIZE) >> 8; /* nasty, but fast */ 1306 if (opt != infop->cor[0]) { 1307 cor_change |= 1 << 1; 1308 *(base + CD1400_COR1) = opt; 1309 } 1310 1311 /* 1312 * set channel option register 2 - 1313 * flow control 1314 */ 1315 opt = 0; 1316#ifdef Smarts 1317 if (iflag & IXANY) 1318 opt |= 1 << 7; /* auto output restart on any char after XOFF */ 1319 if (iflag & IXOFF) 1320 opt |= 1 << 6; /* auto XOFF output flow-control */ 1321#endif 1322#ifndef ALWAYS_RTS_CTS 1323 if (cflag & CCTS_OFLOW) 1324#endif 1325 opt |= 1 << 1; /* auto CTS flow-control */ 1326 1327 if (opt != infop->cor[1]) { 1328 cor_change |= 1 << 2; 1329 *(base + CD1400_COR2) = opt; 1330 } 1331 1332 /* 1333 * set channel option register 3 - 1334 * receiver FIFO interrupt threshold 1335 * flow control 1336 */ 1337 opt = RxFifoThreshold; /* rx fifo threshold */ 1338#ifdef Smarts 1339 if (t->c_lflag & ICANON) 1340 opt |= 1 << 6; /* detect INTR & SUSP chars */ 1341 if (iflag & IXOFF) 1342 opt |= (1 << 5) | (1 << 4); /* transparent in-band flow control */ 1343#endif 1344 if (opt != infop->cor[2]) { 1345 cor_change |= 1 << 3; 1346 *(base + CD1400_COR3) = opt; 1347 } 1348 1349 1350 /* notify the CD1400 if COR1-3 have changed */ 1351 if (cor_change) { 1352 cor_change |= 1 << 6; /* COR change flag */ 1353 cd1400_channel_cmd(base, cor_change); 1354 } 1355 1356 /* 1357 * set channel option register 4 - 1358 * CR/NL processing 1359 * break processing 1360 * received exception processing 1361 */ 1362 opt = 0; 1363 if (iflag & IGNCR) 1364 opt |= 1 << 7; 1365#ifdef Smarts 1366 /* 1367 * we need a new ttyinput() for this, as we don't want to 1368 * have ICRNL && INLCR being done in both layers, or to have 1369 * synchronisation problems 1370 */ 1371 if (iflag & ICRNL) 1372 opt |= 1 << 6; 1373 if (iflag & INLCR) 1374 opt |= 1 << 5; 1375#endif 1376 if (iflag & IGNBRK) 1377 opt |= 1 << 4; 1378 if (!(iflag & BRKINT)) 1379 opt |= 1 << 3; 1380 if (iflag & IGNPAR) 1381#ifdef LogOverruns 1382 opt |= 0; /* broken chars cause receive exceptions */ 1383#else 1384 opt |= 2; /* discard broken chars */ 1385#endif 1386 else { 1387 if (iflag & PARMRK) 1388 opt |= 4; /* precede broken chars with 0xff 0x0 */ 1389 else 1390#ifdef LogOverruns 1391 opt |= 0; /* broken chars cause receive exceptions */ 1392#else 1393 opt |= 3; /* convert framing/parity errs to nulls */ 1394#endif 1395 } 1396 *(base + CD1400_COR4) = opt; 1397 1398 /* 1399 * set channel option register 5 - 1400 */ 1401 opt = 0; 1402 if (iflag & ISTRIP) 1403 opt |= 1 << 7; 1404 if (t->c_iflag & IEXTEN) { 1405 opt |= 1 << 6; /* enable LNEXT (e.g. ctrl-v quoting) handling */ 1406 } 1407#ifdef Smarts 1408 if (t->c_oflag & ONLCR) 1409 opt |= 1 << 1; 1410 if (t->c_oflag & OCRNL) 1411 opt |= 1; 1412#endif 1413 *(base + CD1400_COR5) = opt; 1414 1415 /* 1416 * set modem change option register 1 1417 * generate modem interrupts on which 1 -> 0 input transitions 1418 * also controls auto-DTR output flow-control, which we don't use 1419 */ 1420 opt = (cflag & CLOCAL) ? 0 : 1 << 4; /* CD */ 1421 *(base + CD1400_MCOR1) = opt; 1422 1423 /* 1424 * set modem change option register 2 1425 * generate modem interrupts on specific 0 -> 1 input transitions 1426 */ 1427 opt = (cflag & CLOCAL) ? 0 : 1 << 4; /* CD */ 1428 *(base + CD1400_MCOR2) = opt; 1429 1430 splx(s); 1431 1432 return 0; 1433} /* end of cyparam */ 1434 1435 1436void 1437cystart(struct tty *tp) 1438{ 1439 u_char unit = UNIT(tp->t_dev); 1440 struct cy *infop = info[unit]; 1441 cy_addr base = infop->base_addr; 1442 int s; 1443 1444#ifdef CyDebug 1445 infop->start_count++; 1446#endif 1447 1448 /* check the flow-control situation */ 1449 if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) 1450 return; 1451 1452 if (tp->t_outq.c_cc <= tp->t_lowat) { 1453 if (tp->t_state&TS_ASLEEP) { 1454 tp->t_state &= ~TS_ASLEEP; 1455 wakeup((caddr_t)&tp->t_outq); 1456 } 1457 selwakeup(&tp->t_wsel); 1458 } 1459 1460#ifdef TxBuffer 1461 service_upper_tx(unit); /* feed the monster */ 1462#endif 1463 1464 s = spltty(); 1465 1466 if (!(infop->intr_enable & (1 << 2))) { 1467 /* select the channel */ 1468 *(base + CD1400_CAR) = unit & (u_char)3; 1469 1470 /* (re)enable interrupts to set things in motion */ 1471 infop->intr_enable |= (1 << 2); 1472 *(base + CD1400_SRER) = infop->intr_enable; 1473 1474 infop->start_real++; 1475 } 1476 1477 splx(s); 1478} /* end of cystart() */ 1479 1480 1481int 1482cystop(struct tty *tp, int flag) 1483{ 1484 u_char unit = UNIT(tp->t_dev); 1485 struct cy *ip = info[unit]; 1486 cy_addr base = ip->base_addr; 1487 int s; 1488 1489 s = spltty(); 1490 1491 /* select the channel */ 1492 *(base + CD1400_CAR) = unit & 3; 1493 1494 /* halt output by disabling transmit interrupts */ 1495 ip->intr_enable &=~ (1 << 2); 1496 *(base + CD1400_SRER) = ip->intr_enable; 1497 1498 splx(s); 1499 1500 return 0; 1501} 1502 1503 1504int 1505cyselect(dev_t dev, int rw, struct proc *p) 1506{ 1507 return (ttselect(UNIT(dev), rw, p)); 1508} /* end of cyselect() */ 1509 1510 1511int 1512cyspeed(int speed, int *prescaler_io) 1513{ 1514 int actual; 1515 int error; 1516 int divider; 1517 int prescaler; 1518 int prescaler_unit; 1519 1520 if (speed == 0) 1521 return 0; 1522 1523 if (speed < 0 || speed > 150000) 1524 return -1; 1525 1526 /* determine which prescaler to use */ 1527 for (prescaler_unit = 4, prescaler = 2048; prescaler_unit; 1528 prescaler_unit--, prescaler >>= 2) { 1529 if (CYCLOM_CLOCK/prescaler/speed > 63) 1530 break; 1531 } 1532 1533 divider = (CYCLOM_CLOCK/prescaler*2/speed + 1)/2; /* round off */ 1534 if (divider > 255) 1535 divider = 255; 1536 actual = CYCLOM_CLOCK/prescaler/divider; 1537 error = ((actual-speed)*2000/speed +1)/2; /* percentage */ 1538 1539 /* 3.0% max error tolerance */ 1540 if (error < -30 || error > 30) 1541 return -1; 1542 1543#if 0 1544 printf("prescaler = %d (%d)\n", prescaler, prescaler_unit); 1545 printf("divider = %d (%x)\n", divider, divider); 1546 printf("actual = %d\n", actual); 1547 printf("error = %d\n", error); 1548#endif 1549 1550 *prescaler_io = prescaler_unit; 1551 return divider; 1552} /* end of cyspeed() */ 1553 1554 1555static void 1556cd1400_channel_cmd(cy_addr base, u_char cmd) 1557{ 1558 /* XXX hsu@clinet.fi: This is always more dependent on ISA bus speed, 1559 as the card is probed every round? Replaced delaycount with 8k. 1560 Either delaycount has to be implemented in FreeBSD or more sensible 1561 way of doing these should be implemented. DELAY isn't enough here. 1562 */ 1563 unsigned maxwait = 5 * 8 * 1024; /* approx. 5 ms */ 1564 1565 /* wait for processing of previous command to complete */ 1566 while (*(base + CD1400_CCR) && maxwait--) 1567 ; 1568 1569 if (!maxwait) 1570 log(LOG_ERR, "cy: channel command timeout (%d loops) - arrgh\n", 1571 5 * 8 * 1024); 1572 1573 *(base + CD1400_CCR) = cmd; 1574} /* end of cd1400_channel_cmd() */ 1575 1576 1577#ifdef CyDebug 1578/* useful in ddb */ 1579void 1580cyclear(void) 1581{ 1582 /* clear the timeout request */ 1583 disable_intr(); 1584 timeout_scheduled = 0; 1585 enable_intr(); 1586} 1587 1588void 1589cyclearintr(void) 1590{ 1591 /* clear interrupts */ 1592 *(cyclom_base + CYCLOM_CLEAR_INTR) = (u_char)0; 1593} 1594 1595int 1596cyparam_dummy(struct tty *tp, struct termios *t) 1597{ 1598 return 0; 1599} 1600 1601void 1602cyset(int unit, int active) 1603{ 1604 if (unit < 0 || unit >= /* NCY *? */ PORTS_PER_CYCLOM) { 1605 printf("bad unit number %d\n", unit); 1606 return; 1607 } 1608#ifdef __FreeBSD__ 1609 cy_tty[unit].t_param = active ? cyparam : cyparam_dummy; 1610#else 1611 cy_tty[unit]->t_param = active ? cyparam : cyparam_dummy; 1612#endif 1613} 1614 1615 1616/* useful in ddb */ 1617void 1618cystatus(int unit) 1619{ 1620 struct cy *infop = info[unit]; 1621 struct tty *tp = infop->tty; 1622 cy_addr base = infop->base_addr; 1623 1624 printf("info for channel %d\n", unit); 1625 printf("------------------\n"); 1626 1627 printf("cd1400 base address:\t0x%x\n", (int)infop->base_addr); 1628 1629 /* select the port */ 1630 *(base + CD1400_CAR) = (u_char)unit; 1631 1632 printf("saved channel_control:\t%02x\n", infop->channel_control); 1633 printf("saved cor1:\t\t%02x\n", infop->cor[0]); 1634 printf("service request enable reg:\t%02x (%02x cached)\n", 1635 (u_char)*(base + CD1400_SRER), infop->intr_enable); 1636 printf("service request register:\t%02x\n", 1637 (u_char)*(base + CD1400_SVRR)); 1638 printf("\n"); 1639 printf("modem status:\t\t\t%02x (%02x cached)\n", 1640 (u_char)*(base + CD1400_MSVR), infop->modem_sig); 1641 printf("rx/tx/mdm interrupt registers:\t%02x %02x %02x\n", 1642 (u_char)*(base + CD1400_RIR), (u_char)*(base + CD1400_TIR), 1643 (u_char)*(base + CD1400_MIR)); 1644 printf("\n"); 1645 if (tp) { 1646 printf("tty state:\t\t\t%04x\n", tp->t_state); 1647 printf("upper layer queue lengths:\t%d raw, %d canon, %d output\n", 1648 tp->t_rawq.c_cc, tp->t_canq.c_cc, tp->t_outq.c_cc); 1649 } 1650 else 1651 printf("tty state:\t\t\tclosed\n"); 1652 printf("\n"); 1653 1654 printf("calls to cystart():\t\t%d (%d useful)\n", 1655 infop->start_count, infop->start_real); 1656 printf("\n"); 1657 printf("total cyclom service probes:\t%d\n", cy_svrr_probes); 1658 printf("calls to upper layer:\t\t%d\n", cy_timeouts); 1659 printf("rx buffer chars free:\t\t%d\n", infop->rx_buf->free); 1660#ifdef TxBuffer 1661 printf("tx buffer chars used:\t\t%d\n", infop->tx_buf.used); 1662#endif 1663 printf("received chars:\t\t\t%d good, %d exception\n", 1664 infop->recv_normal, infop->recv_exception); 1665 printf("transmitted chars:\t\t%d\n", infop->xmit); 1666 printf("modem signal deltas:\t\t%d\n", infop->mdm); 1667 printf("\n"); 1668} /* end of cystatus() */ 1669#endif 1670#endif /* NCY > 0 */ 1671