1/* 2 * Rocketport device driver for Linux 3 * 4 * Written by Theodore Ts'o, 1995, 1996, 1997. 5 * 6 * Copyright (C) 1995, 1996, 1997 by Comtrol, Inc. 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License as 10 * published by the Free Software Foundation; either version 2 of the 11 * License, or (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, but 14 * WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 */ 22 23/* 24 * Minor number schema: 25 * 26 * +-------------------------------+ 27 * | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 28 * +---+-------+-------+-----------+ 29 * | C | Board | AIOP | Port # | 30 * +---+-------+-------+-----------+ 31 * 32 * C=0 implements normal POSIX tty. 33 * C=1 is reserved for the callout device. 34 * 35 * Normally, the user won't have to worry about the AIOP; as far as 36 * the user is concerned, the lower 5 bits of the minor number address 37 * the ports on a particular board (from 0 up to 32). 38 */ 39 40/* Kernel includes */ 41 42#include <linux/config.h> 43#include <linux/version.h> 44 45#ifdef CONFIG_PCI 46#define ENABLE_PCI 47#endif 48 49#include <linux/module.h> 50#include <linux/errno.h> 51#include <linux/major.h> 52#include <linux/kernel.h> 53#include <linux/signal.h> 54#include <linux/slab.h> 55#include <linux/mm.h> 56 57#include <linux/sched.h> 58#include <linux/timer.h> 59#include <linux/interrupt.h> 60#include <linux/tty.h> 61#include <linux/tty_flip.h> 62#include <linux/string.h> 63#include <linux/fcntl.h> 64#include <linux/ptrace.h> 65#include <linux/ioport.h> 66#ifdef ENABLE_PCI 67#include <linux/pci.h> 68#if (LINUX_VERSION_CODE < 0x020163) /* 2.1.99 */ 69#include <linux/bios32.h> 70#endif 71#endif 72#if (LINUX_VERSION_CODE >= 131343) /* 2.1.15 -- XX get correct version */ 73#include <linux/init.h> 74#endif 75 76#include "rocket_int.h" 77#ifdef LOCAL_ROCKET_H 78#include "rocket.h" 79#include "version.h" 80#else 81#include <linux/rocket.h> 82#define ROCKET_VERSION "1.14c" 83#define ROCKET_DATE "24-Aug-98" 84#endif /* LOCAL_ROCKET_H */ 85 86#define ROCKET_PARANOIA_CHECK 87#define ROCKET_SOFT_FLOW 88 89#undef ROCKET_DEBUG_OPEN 90#undef ROCKET_DEBUG_INTR 91#undef ROCKET_DEBUG_WRITE 92#undef ROCKET_DEBUG_FLOW 93#undef ROCKET_DEBUG_THROTTLE 94#undef ROCKET_DEBUG_WAIT_UNTIL_SENT 95#undef ROCKET_DEBUG_RECEIVE 96#undef ROCKET_DEBUG_HANGUP 97 98 99/* CAUTION!!!!! The TIME_STAT Function relies on the Pentium 64 bit 100 * register. For various reasons related to 1.2.13, the test for this 101 * register is omitted from this driver. If you are going to enable 102 * this option, make sure you are running a Pentium CPU and that a 103 * cat of /proc/cpuinfo shows ability TS Counters as Yes. Warning part 104 * done, don't cry to me if you enable this options and things won't 105 * work. If it gives you any problems, then disable the option. The code 106 * in this function is pretty straight forward, if it breaks on your 107 * CPU, there is probably something funny about your CPU. 108 */ 109 110#undef TIME_STAT /* For performing timing statistics on driver. */ 111 /* Produces printks, one every TIME_COUNTER loops, eats */ 112 /* some of your CPU time. Good for testing or */ 113 /* other checking, otherwise, leave it undefed */ 114 /* Doug Ledford */ 115#define TIME_STAT_CPU 100 /* This needs to be set to your processor speed */ 116 /* For example, 100Mhz CPU, set this to 100 */ 117#define TIME_COUNTER 180000 /* This is how many iterations to run before */ 118 /* performing the printk statements. */ 119 /* 6000 = 1 minute, 360000 = 1 hour, etc. */ 120 /* Since time_stat is long long, this */ 121 /* Can be really high if you want :) */ 122#undef TIME_STAT_VERBOSE /* Undef this if you want a terse log message. */ 123 124#define _INLINE_ inline 125 126static struct r_port *rp_table[MAX_RP_PORTS]; 127static struct tty_struct *rocket_table[MAX_RP_PORTS]; 128static unsigned int xmit_flags[NUM_BOARDS]; 129static struct termios *rocket_termios[MAX_RP_PORTS]; 130static struct termios *rocket_termios_locked[MAX_RP_PORTS]; 131static void rp_wait_until_sent(struct tty_struct *tty, int timeout); 132static void rp_flush_buffer(struct tty_struct *tty); 133 134static struct tty_driver rocket_driver, callout_driver; 135static int rocket_refcount; 136 137static int rp_num_ports_open; 138 139static struct timer_list rocket_timer; 140 141unsigned long board1; 142unsigned long board2; 143unsigned long board3; 144unsigned long board4; 145unsigned long controller; 146unsigned long support_low_speed; 147int rp_baud_base = 460800; 148static unsigned long rcktpt_io_addr[NUM_BOARDS]; 149static int max_board; 150#ifdef TIME_STAT 151static unsigned long long time_stat; 152static unsigned long time_stat_short; 153static unsigned long time_stat_long; 154static unsigned long time_counter; 155#endif 156 157#if ((LINUX_VERSION_CODE > 0x020111) && defined(MODULE)) 158MODULE_AUTHOR("Theodore Ts'o"); 159MODULE_DESCRIPTION("Comtrol Rocketport driver"); 160MODULE_LICENSE("GPL"); 161MODULE_PARM(board1, "i"); 162MODULE_PARM_DESC(board1, "I/O port for (ISA) board #1"); 163MODULE_PARM(board2, "i"); 164MODULE_PARM_DESC(board2, "I/O port for (ISA) board #2"); 165MODULE_PARM(board3, "i"); 166MODULE_PARM_DESC(board3, "I/O port for (ISA) board #3"); 167MODULE_PARM(board4, "i"); 168MODULE_PARM_DESC(board4, "I/O port for (ISA) board #4"); 169MODULE_PARM(controller, "i"); 170MODULE_PARM_DESC(controller, "I/O port for (ISA) rocketport controller"); 171MODULE_PARM(support_low_speed, "i"); 172MODULE_PARM_DESC(support_low_speed, "0 means support 50 baud, 1 means support 460400 baud"); 173#endif 174 175#if (LINUX_VERSION_CODE < 131336) 176int copy_from_user(void *to, const void *from_user, unsigned long len) 177{ 178 int error; 179 180 error = verify_area(VERIFY_READ, from_user, len); 181 if (error) 182 return len; 183 memcpy_fromfs(to, from_user, len); 184 return 0; 185} 186 187int copy_to_user(void *to_user, const void *from, unsigned long len) 188{ 189 int error; 190 191 error = verify_area(VERIFY_WRITE, to_user, len); 192 if (error) 193 return len; 194 memcpy_tofs(to_user, from, len); 195 return 0; 196} 197 198static inline int signal_pending(struct task_struct *p) 199{ 200 return (p->signal & ~p->blocked) != 0; 201} 202 203#else 204#include <asm/uaccess.h> 205#endif 206 207/* 208 * tmp_buf is used as a temporary buffer by rp_write. We need to 209 * lock it in case the memcpy_fromfs blocks while swapping in a page, 210 * and some other program tries to do a serial write at the same time. 211 * Since the lock will only come under contention when the system is 212 * swapping and available memory is low, it makes sense to share one 213 * buffer across all the serial ports, since it significantly saves 214 * memory if large numbers of serial ports are open. 215 */ 216static unsigned char *tmp_buf = 0; 217static DECLARE_MUTEX(tmp_buf_sem); 218 219static void rp_start(struct tty_struct *tty); 220 221static inline int rocket_paranoia_check(struct r_port *info, 222 kdev_t device, const char *routine) 223{ 224#ifdef ROCKET_PARANOIA_CHECK 225 static const char *badmagic = 226 "Warning: bad magic number for rocketport struct (%d, %d) in %s\n"; 227 if (!info) 228 return 1; 229 if (info->magic != RPORT_MAGIC) { 230 printk(badmagic, MAJOR(device), MINOR(device), routine); 231 return 1; 232 } 233#endif 234 return 0; 235} 236 237/* 238 * Here begins the interrupt/polling routine for the Rocketport! 239 */ 240static _INLINE_ void rp_do_receive(struct r_port *info, struct tty_struct *tty, 241 CHANNEL_t *cp, unsigned int ChanStatus) 242{ 243 unsigned int CharNStat; 244 int ToRecv, wRecv, space, count; 245 unsigned char *cbuf; 246 char *fbuf; 247 248 ToRecv= sGetRxCnt(cp); 249 space = 2*TTY_FLIPBUF_SIZE; 250 cbuf = tty->flip.char_buf; 251 fbuf = tty->flip.flag_buf; 252 count = 0; 253#ifdef ROCKET_DEBUG_INTR 254 printk("rp_do_receive(%d, %d)...", ToRecv, space); 255#endif 256 if (ToRecv == 0 || (space <= 0)) 257 return; 258 259 /* 260 * determine how many we can actually read in. If we can't 261 * read any in then we have a software overrun condition. 262 */ 263 if (ToRecv > space) 264 ToRecv = space; 265 266 /* 267 * if status indicates there are errored characters in the 268 * FIFO, then enter status mode (a word in FIFO holds 269 * character and status). 270 */ 271 if (ChanStatus & (RXFOVERFL | RXBREAK | RXFRAME | RXPARITY)) { 272 if (!(ChanStatus & STATMODE)) { 273#ifdef ROCKET_DEBUG_RECEIVE 274 printk("Entering STATMODE..."); 275#endif 276 ChanStatus |= STATMODE; 277 sEnRxStatusMode(cp); 278 } 279 } 280 281 /* 282 * if we previously entered status mode, then read down the 283 * FIFO one word at a time, pulling apart the character and 284 * the status. Update error counters depending on status 285 */ 286 if (ChanStatus & STATMODE) { 287#ifdef ROCKET_DEBUG_RECEIVE 288 printk("Ignore %x, read %x...", info->ignore_status_mask, 289 info->read_status_mask); 290#endif 291 while (ToRecv) { 292 CharNStat= sInW(sGetTxRxDataIO(cp)); 293 294#ifdef ROCKET_DEBUG_RECEIVE 295 printk("%x...", CharNStat); 296#endif 297 298 if (CharNStat & STMBREAKH) 299 CharNStat &= ~(STMFRAMEH | STMPARITYH); 300 if (CharNStat & info->ignore_status_mask) { 301 ToRecv--; 302 continue; 303 } 304 CharNStat &= info->read_status_mask; 305 if (CharNStat & STMBREAKH) { 306 *fbuf++ = TTY_BREAK; 307 } else if (CharNStat & STMPARITYH) 308 *fbuf++ = TTY_PARITY; 309 else if (CharNStat & STMFRAMEH) 310 *fbuf++ = TTY_FRAME; 311 else if (CharNStat & STMRCVROVRH) 312 *fbuf++ =TTY_OVERRUN; 313 else 314 *fbuf++ = 0; 315 *cbuf++ = CharNStat & 0xff; 316 count++; 317 ToRecv--; 318 } 319 320 /* 321 * after we've emptied the FIFO in status mode, turn 322 * status mode back off 323 */ 324 if (sGetRxCnt(cp) == 0) { 325#ifdef ROCKET_DEBUG_RECEIVE 326 printk("Status mode off.\n"); 327#endif 328 sDisRxStatusMode(cp); 329 } 330 } else { 331 /* 332 * we aren't in status mode, so read down the FIFO two 333 * characters at time by doing repeated word IO 334 * transfer. 335 */ 336 wRecv= ToRecv >> 1; 337 if (wRecv) 338 sInStrW(sGetTxRxDataIO(cp), cbuf, 339 wRecv); 340 if (ToRecv & 1) 341 cbuf[ToRecv-1] = sInB(sGetTxRxDataIO(cp)); 342 memset(fbuf, 0, ToRecv); 343 cbuf += ToRecv; 344 fbuf += ToRecv; 345 count += ToRecv; 346 } 347 tty->ldisc.receive_buf(tty, tty->flip.char_buf, 348 tty->flip.flag_buf, count); 349} 350 351/* 352 * This routine is called when a transmit interrupt is found. It's 353 * responsible for pushing data found in the transmit buffer out to 354 * the serial card. 355 */ 356static _INLINE_ void rp_do_transmit(struct r_port *info) 357{ 358 int c; 359 CHANNEL_t *cp = &info->channel; 360 struct tty_struct *tty; 361 362#ifdef ROCKET_DEBUG_INTR 363 printk("rp_do_transmit "); 364#endif 365 if (!info) 366 return; 367 if (!info->tty) { 368 printk("rp: WARNING rp_do_transmit called with info->tty==NULL\n"); 369 xmit_flags[info->line >> 5] &= ~(1 << (info->line & 0x1f)); 370 return; 371 } 372 tty = info->tty; 373 info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp); 374 while (1) { 375 if (tty->stopped || tty->hw_stopped) 376 break; 377 c = MIN(info->xmit_fifo_room, 378 MIN(info->xmit_cnt, 379 XMIT_BUF_SIZE - info->xmit_tail)); 380 if (c <= 0 || info->xmit_fifo_room <= 0) 381 break; 382 sOutStrW(sGetTxRxDataIO(cp), 383 info->xmit_buf + info->xmit_tail, c/2); 384 if (c & 1) 385 sOutB(sGetTxRxDataIO(cp), 386 info->xmit_buf[info->xmit_tail + c - 387 1]); 388 info->xmit_tail += c; 389 info->xmit_tail &= XMIT_BUF_SIZE-1; 390 info->xmit_cnt -= c; 391 info->xmit_fifo_room -= c; 392#ifdef ROCKET_DEBUG_INTR 393 printk("tx %d chars...", c); 394#endif 395 } 396 if (info->xmit_cnt == 0) 397 xmit_flags[info->line >> 5] &= ~(1 << (info->line & 0x1f)); 398 if (info->xmit_cnt < WAKEUP_CHARS) { 399 if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && 400 tty->ldisc.write_wakeup) 401 (tty->ldisc.write_wakeup)(tty); 402 wake_up_interruptible(&tty->write_wait); 403 } 404#ifdef ROCKET_DEBUG_INTR 405 printk("(%d,%d,%d,%d)...", info->xmit_cnt, info->xmit_head, 406 info->xmit_tail, info->xmit_fifo_room); 407#endif 408} 409 410/* 411 * This function is called for each port which has signalled an 412 * interrupt. It checks what interrupts are pending and services 413 * them. 414 */ 415static _INLINE_ void rp_handle_port(struct r_port *info) 416{ 417 CHANNEL_t *cp; 418 struct tty_struct *tty; 419 unsigned int IntMask, ChanStatus; 420 421 if (!info) 422 return; 423 if ( (info->flags & ROCKET_INITIALIZED) == 0 ) { 424 printk("rp: WARNING: rp_handle_port called with info->flags & NOT_INIT\n"); 425 return; 426 } 427 if (!info->tty) { 428 printk("rp: WARNING: rp_handle_port called with info->tty==NULL\n"); 429 return; 430 } 431 cp = &info->channel; 432 tty = info->tty; 433 434 IntMask = sGetChanIntID(cp) & info->intmask; 435#ifdef ROCKET_DEBUG_INTR 436 printk("rp_interrupt %02x...", IntMask); 437#endif 438 ChanStatus= sGetChanStatus(cp); 439 if (IntMask & RXF_TRIG) { /* Rx FIFO trigger level */ 440 rp_do_receive(info, tty, cp, ChanStatus); 441 } 442 if (IntMask & DELTA_CD) { /* CD change */ 443#if (defined(ROCKET_DEBUG_OPEN) || defined(ROCKET_DEBUG_INTR) || \ 444 defined(ROCKET_DEBUG_HANGUP)) 445 printk("ttyR%d CD now %s...", info->line, 446 (ChanStatus & CD_ACT) ? "on" : "off"); 447#endif 448 if (!(ChanStatus & CD_ACT) && 449 info->cd_status && 450 !((info->flags & ROCKET_CALLOUT_ACTIVE) && 451 (info->flags & ROCKET_CALLOUT_NOHUP))) { 452#ifdef ROCKET_DEBUG_HANGUP 453 printk("CD drop, calling hangup.\n"); 454#endif 455 tty_hangup(tty); 456 } 457 info->cd_status = (ChanStatus & CD_ACT) ? 1 : 0; 458 wake_up_interruptible(&info->open_wait); 459 } 460#ifdef ROCKET_DEBUG_INTR 461 if (IntMask & DELTA_CTS) { /* CTS change */ 462 printk("CTS change...\n"); 463 } 464 if (IntMask & DELTA_DSR) { /* DSR change */ 465 printk("DSR change...\n"); 466 } 467#endif 468} 469 470/* 471 * The top level polling routine. 472 */ 473static void rp_do_poll(unsigned long dummy) 474{ 475 CONTROLLER_t *ctlp; 476 int ctrl, aiop, ch, line; 477 unsigned int xmitmask; 478 unsigned char CtlMask, AiopMask; 479 480#ifdef TIME_STAT 481 unsigned long loop_time; 482 unsigned long long time_stat_tmp=0, time_stat_tmp2=0; 483 484 rdtscll(time_stat_tmp); 485#endif /* TIME_STAT */ 486 487 for (ctrl=0; ctrl < max_board; ctrl++) { 488 if (rcktpt_io_addr[ctrl] <= 0) 489 continue; 490 ctlp= sCtlNumToCtlPtr(ctrl); 491 492#ifdef ENABLE_PCI 493 if(ctlp->BusType == isPCI) 494 CtlMask= sPCIGetControllerIntStatus(ctlp); 495 else 496#endif 497 CtlMask= sGetControllerIntStatus(ctlp); 498 for (aiop=0; CtlMask; CtlMask >>= 1, aiop++) { 499 if (CtlMask & 1) { 500 AiopMask= sGetAiopIntStatus(ctlp, aiop); 501 for (ch=0; AiopMask; AiopMask >>= 1, ch++) { 502 if (AiopMask & 1) { 503 line = (ctrl << 5) | 504 (aiop << 3) | ch; 505 rp_handle_port(rp_table[line]); 506 } 507 } 508 } 509 } 510 xmitmask = xmit_flags[ctrl]; 511 for (line = ctrl << 5; xmitmask; xmitmask >>= 1, line++) { 512 if (xmitmask & 1) 513 rp_do_transmit(rp_table[line]); 514 } 515 } 516 517 /* 518 * Reset the timer so we get called at the next clock tick. 519 */ 520 if (rp_num_ports_open) { 521 mod_timer(&rocket_timer, jiffies + 1); 522 } 523#ifdef TIME_STAT 524 rdtscll(time_stat_tmp2); 525 time_stat_tmp2 -= time_stat_tmp; 526 time_stat += time_stat_tmp2; 527 if (time_counter == 0) 528 time_stat_short = time_stat_long = time_stat_tmp2; 529 else { 530 if ( time_stat_tmp2 < time_stat_short ) 531 time_stat_short = time_stat_tmp2; 532 else if ( time_stat_tmp2 > time_stat_long ) 533 time_stat_long = time_stat_tmp2; 534 } 535 if ( ++time_counter == TIME_COUNTER ) { 536 loop_time = (unsigned long) ( ((unsigned long)(time_stat >> 32) * ( (unsigned long)(0xffffffff)/(TIME_STAT_CPU * TIME_COUNTER) ) ) + ((unsigned long)time_stat/(TIME_STAT_CPU*TIME_COUNTER))); 537#ifdef TIME_STAT_VERBOSE 538 printk("rp_do_poll: Interrupt Timings\n"); 539 printk(" %5ld iterations; %ld us min,\n", 540 (long)TIME_COUNTER, (time_stat_short/TIME_STAT_CPU)); 541 printk(" %5ld us max, %ld us average per iteration.\n", 542 (time_stat_long/TIME_STAT_CPU), loop_time); 543 printk("We want to use < 5,000 us for an iteration.\n"); 544#else /* TIME_STAT_VERBOSE */ 545 printk("rp: %ld loops: %ld min, %ld max, %ld us/loop.\n", 546 (long)TIME_COUNTER, (time_stat_short/TIME_STAT_CPU), 547 (time_stat_long/TIME_STAT_CPU), loop_time); 548#endif /* TIME_STAT_VERBOSE */ 549 time_counter = time_stat = 0; 550 time_stat_short = time_stat_long = 0; 551 } 552#endif /* TIME_STAT */ 553} 554/* 555 * Here ends the interrupt/polling routine. 556 */ 557 558 559/* 560 * This function initializes the r_port structure, as well as enabling 561 * the port on the RocketPort board. 562 */ 563static void init_r_port(int board, int aiop, int chan) 564{ 565 struct r_port *info; 566 int line; 567 CONTROLLER_T *ctlp; 568 CHANNEL_t *cp; 569 570 line = (board << 5) | (aiop << 3) | chan; 571 572 ctlp= sCtlNumToCtlPtr(board); 573 574 info = kmalloc(sizeof(struct r_port), GFP_KERNEL); 575 if (!info) { 576 printk("Couldn't allocate info struct for line #%d\n", line); 577 return; 578 } 579 memset(info, 0, sizeof(struct r_port)); 580 581 info->magic = RPORT_MAGIC; 582 info->line = line; 583 info->ctlp = ctlp; 584 info->board = board; 585 info->aiop = aiop; 586 info->chan = chan; 587 info->closing_wait = 3000; 588 info->close_delay = 50; 589 info->callout_termios =callout_driver.init_termios; 590 info->normal_termios = rocket_driver.init_termios; 591 init_waitqueue_head(&info->open_wait); 592 init_waitqueue_head(&info->close_wait); 593 594 info->intmask = RXF_TRIG | TXFIFO_MT | SRC_INT | DELTA_CD | 595 DELTA_CTS | DELTA_DSR; 596 if (sInitChan(ctlp, &info->channel, aiop, chan) == 0) { 597 printk("Rocketport sInitChan(%d, %d, %d) failed!\n", 598 board, aiop, chan); 599 kfree(info); 600 return; 601 } 602 cp = &info->channel; 603 rp_table[line] = info; 604} 605 606#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ 607static int baud_table[] = { 608 0, 50, 75, 110, 134, 150, 200, 300, 609 600, 1200, 1800, 2400, 4800, 9600, 19200, 610 38400, 57600, 115200, 230400, 460800, 0 }; 611#endif 612 613/* 614 * This routine configures a rocketport port so according to its 615 * termio settings. 616 */ 617static void configure_r_port(struct r_port *info) 618{ 619 unsigned cflag; 620 unsigned long flags; 621 int bits, baud; 622#if (LINUX_VERSION_CODE < 131393) /* Linux 2.1.65 */ 623 int i; 624#endif 625 CHANNEL_t *cp; 626 627 if (!info->tty || !info->tty->termios) 628 return; 629 cp = &info->channel; 630 cflag = info->tty->termios->c_cflag; 631 632 /* Byte size and parity */ 633 if ((cflag & CSIZE) == CS8) { 634 sSetData8(cp); 635 bits = 10; 636 } else { 637 sSetData7(cp); 638 bits = 9; 639 } 640 if (cflag & CSTOPB) { 641 sSetStop2(cp); 642 bits++; 643 } else { 644 sSetStop1(cp); 645 } 646 647 if (cflag & PARENB) { 648 sEnParity(cp); 649 bits++; 650 if (cflag & PARODD) { 651 sSetOddParity(cp); 652 } else { 653 sSetEvenParity(cp); 654 } 655 } else { 656 sDisParity(cp); 657 } 658 659 /* baud rate */ 660#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ 661 i = cflag & CBAUD; 662 if (i & CBAUDEX) { 663 i &= ~CBAUDEX; 664 if (i < 1 || i > 4) 665 info->tty->termios->c_cflag &= ~CBAUDEX; 666 else 667 i += 15; 668 } 669 if (i == 15) { 670 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI) 671 i += 1; 672 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI) 673 i += 2; 674 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI) 675 i += 3; 676 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP) 677 i += 4; 678 } 679 baud = baud_table[i] ? baud_table[i] : 9600; 680#else 681 baud = tty_get_baud_rate(info->tty); 682 if (!baud) 683 baud = 9600; 684#endif 685 info->cps = baud / bits; 686 sSetBaud(cp, (rp_baud_base/baud) - 1); 687 688 if (cflag & CRTSCTS) { 689 info->intmask |= DELTA_CTS; 690 sEnCTSFlowCtl(cp); 691 } else { 692 info->intmask &= ~DELTA_CTS; 693 sDisCTSFlowCtl(cp); 694 } 695 sSetRTS(&info->channel); 696 if (cflag & CLOCAL) 697 info->intmask &= ~DELTA_CD; 698 else { 699 save_flags(flags); cli(); 700 if (sGetChanStatus(cp) & CD_ACT) 701 info->cd_status = 1; 702 else 703 info->cd_status = 0; 704 info->intmask |= DELTA_CD; 705 restore_flags(flags); 706 } 707 708 /* 709 * Handle software flow control in the board 710 */ 711#ifdef ROCKET_SOFT_FLOW 712 if (I_IXON(info->tty)) { 713 sEnTxSoftFlowCtl(cp); 714 if (I_IXANY(info->tty)) { 715 sEnIXANY(cp); 716 } else { 717 sDisIXANY(cp); 718 } 719 sSetTxXONChar(cp, START_CHAR(info->tty)); 720 sSetTxXOFFChar(cp, STOP_CHAR(info->tty)); 721 } else { 722 sDisTxSoftFlowCtl(cp); 723 sDisIXANY(cp); 724 sClrTxXOFF(cp); 725 } 726#endif 727 728 /* 729 * Set up ignore/read mask words 730 */ 731 info->read_status_mask = STMRCVROVRH | 0xFF; 732 if (I_INPCK(info->tty)) 733 info->read_status_mask |= STMFRAMEH | STMPARITYH; 734 if (I_BRKINT(info->tty) || I_PARMRK(info->tty)) 735 info->read_status_mask |= STMBREAKH; 736 737 /* 738 * Characters to ignore 739 */ 740 info->ignore_status_mask = 0; 741 if (I_IGNPAR(info->tty)) 742 info->ignore_status_mask |= STMFRAMEH | STMPARITYH; 743 if (I_IGNBRK(info->tty)) { 744 info->ignore_status_mask |= STMBREAKH; 745 /* 746 * If we're ignoring parity and break indicators, 747 * ignore overruns too. (For real raw support). 748 */ 749 if (I_IGNPAR(info->tty)) 750 info->ignore_status_mask |= STMRCVROVRH; 751 } 752} 753 754static int block_til_ready(struct tty_struct *tty, struct file * filp, 755 struct r_port *info) 756{ 757 DECLARE_WAITQUEUE(wait, current); 758 int retval; 759 int do_clocal = 0, extra_count = 0; 760 unsigned long flags; 761 762 /* 763 * If the device is in the middle of being closed, then block 764 * until it's done, and then try again. 765 */ 766 if (tty_hung_up_p(filp)) 767 return ((info->flags & ROCKET_HUP_NOTIFY) ? 768 -EAGAIN : -ERESTARTSYS); 769 if (info->flags & ROCKET_CLOSING) { 770 interruptible_sleep_on(&info->close_wait); 771 return ((info->flags & ROCKET_HUP_NOTIFY) ? 772 -EAGAIN : -ERESTARTSYS); 773 } 774 775 /* 776 * If this is a callout device, then just make sure the normal 777 * device isn't being used. 778 */ 779 if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) { 780 if (info->flags & ROCKET_NORMAL_ACTIVE) 781 return -EBUSY; 782 if ((info->flags & ROCKET_CALLOUT_ACTIVE) && 783 (info->flags & ROCKET_SESSION_LOCKOUT) && 784 (info->session != current->session)) 785 return -EBUSY; 786 if ((info->flags & ROCKET_CALLOUT_ACTIVE) && 787 (info->flags & ROCKET_PGRP_LOCKOUT) && 788 (info->pgrp != current->pgrp)) 789 return -EBUSY; 790 info->flags |= ROCKET_CALLOUT_ACTIVE; 791 return 0; 792 } 793 794 /* 795 * If non-blocking mode is set, or the port is not enabled, 796 * then make the check up front and then exit. 797 */ 798 if ((filp->f_flags & O_NONBLOCK) || 799 (tty->flags & (1 << TTY_IO_ERROR))) { 800 if (info->flags & ROCKET_CALLOUT_ACTIVE) 801 return -EBUSY; 802 info->flags |= ROCKET_NORMAL_ACTIVE; 803 return 0; 804 } 805 806 if (info->flags & ROCKET_CALLOUT_ACTIVE) { 807 if (info->normal_termios.c_cflag & CLOCAL) 808 do_clocal = 1; 809 } else { 810 if (tty->termios->c_cflag & CLOCAL) 811 do_clocal = 1; 812 } 813 814 /* 815 * Block waiting for the carrier detect and the line to become 816 * free (i.e., not in use by the callout). While we are in 817 * this loop, info->count is dropped by one, so that 818 * rp_close() knows when to free things. We restore it upon 819 * exit, either normal or abnormal. 820 */ 821 retval = 0; 822 add_wait_queue(&info->open_wait, &wait); 823#ifdef ROCKET_DEBUG_OPEN 824 printk("block_til_ready before block: ttyR%d, count = %d\n", 825 info->line, info->count); 826#endif 827 save_flags(flags); cli(); 828 if (!tty_hung_up_p(filp)) { 829 extra_count = 1; 830 info->count--; 831 } 832 restore_flags(flags); 833 info->blocked_open++; 834 while (1) { 835 if (!(info->flags & ROCKET_CALLOUT_ACTIVE) && 836 (tty->termios->c_cflag & CBAUD)) { 837 sSetDTR(&info->channel); 838 sSetRTS(&info->channel); 839 } 840 set_current_state(TASK_INTERRUPTIBLE); 841 if (tty_hung_up_p(filp) || 842 !(info->flags & ROCKET_INITIALIZED)) { 843 if (info->flags & ROCKET_HUP_NOTIFY) 844 retval = -EAGAIN; 845 else 846 retval = -ERESTARTSYS; 847 break; 848 } 849 if (!(info->flags & ROCKET_CALLOUT_ACTIVE) && 850 !(info->flags & ROCKET_CLOSING) && 851 (do_clocal || (sGetChanStatusLo(&info->channel) & 852 CD_ACT))) 853 break; 854 if (signal_pending(current)) { 855 retval = -ERESTARTSYS; 856 break; 857 } 858#ifdef ROCKET_DEBUG_OPEN 859 printk("block_til_ready blocking: ttyR%d, count = %d, flags=0x%0x\n", 860 info->line, info->count, info->flags); 861#endif 862 schedule(); 863 } 864 current->state = TASK_RUNNING; 865 remove_wait_queue(&info->open_wait, &wait); 866 cli(); 867 if (extra_count) 868 info->count++; 869 restore_flags(flags); 870 info->blocked_open--; 871#ifdef ROCKET_DEBUG_OPEN 872 printk("block_til_ready after blocking: ttyR%d, count = %d\n", 873 info->line, info->count); 874#endif 875 if (retval) 876 return retval; 877 info->flags |= ROCKET_NORMAL_ACTIVE; 878 return 0; 879} 880 881/* 882 * This routine is called whenever a rocketport board is opened. 883 */ 884static int rp_open(struct tty_struct *tty, struct file * filp) 885{ 886 struct r_port *info; 887 int line, retval; 888 CHANNEL_t *cp; 889 unsigned long page; 890 891 line = MINOR(tty->device) - tty->driver.minor_start; 892 if ((line < 0) || (line >= MAX_RP_PORTS)) 893 return -ENODEV; 894 if (!tmp_buf) { 895 page = get_free_page(GFP_KERNEL); 896 if (!page) 897 return -ENOMEM; 898 if (tmp_buf) 899 free_page(page); 900 else 901 tmp_buf = (unsigned char *) page; 902 } 903 page = get_free_page(GFP_KERNEL); 904 if (!page) 905 return -ENOMEM; 906 907 tty->driver_data = info = rp_table[line]; 908 909 if (info->flags & ROCKET_CLOSING) { 910 interruptible_sleep_on(&info->close_wait); 911 free_page(page); 912 return ((info->flags & ROCKET_HUP_NOTIFY) ? 913 -EAGAIN : -ERESTARTSYS); 914 } 915 916 /* 917 * We must not sleep from here until the port is marked fully 918 * in use. 919 */ 920 if (rp_table[line] == NULL) { 921 tty->flags = (1 << TTY_IO_ERROR); 922 free_page(page); 923 return 0; 924 } 925 if (!info) { 926 printk("rp_open: rp_table[%d] is NULL!\n", line); 927 free_page(page); 928 return -EIO; 929 } 930 if (info->xmit_buf) 931 free_page(page); 932 else 933 info->xmit_buf = (unsigned char *) page; 934 info->tty = tty; 935 936 if (info->flags & ROCKET_CLOSING) { 937 interruptible_sleep_on(&info->close_wait); 938 return ((info->flags & ROCKET_HUP_NOTIFY) ? 939 -EAGAIN : -ERESTARTSYS); 940 } 941 942 if (info->count++ == 0) { 943#ifdef MODULE 944 MOD_INC_USE_COUNT; 945#endif 946 rp_num_ports_open++; 947#ifdef ROCKET_DEBUG_OPEN 948 printk("rocket mod++ = %d...", rp_num_ports_open); 949#endif 950 } 951#ifdef ROCKET_DEBUG_OPEN 952 printk("rp_open ttyR%d, count=%d\n", info->line, info->count); 953#endif 954 /* 955 * Info->count is now 1; so it's safe to sleep now. 956 */ 957 info->session = current->session; 958 info->pgrp = current->pgrp; 959 960 cp = &info->channel; 961 sSetRxTrigger(cp, TRIG_1); 962 if (sGetChanStatus(cp) & CD_ACT) 963 info->cd_status = 1; 964 else 965 info->cd_status = 0; 966 sDisRxStatusMode(cp); 967 sFlushRxFIFO(cp); 968 sFlushTxFIFO(cp); 969 970 sEnInterrupts(cp, (TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN)); 971 sSetRxTrigger(cp, TRIG_1); 972 973 sGetChanStatus(cp); 974 sDisRxStatusMode(cp); 975 sClrTxXOFF(cp); 976 977 sDisCTSFlowCtl(cp); 978 sDisTxSoftFlowCtl(cp); 979 980 sEnRxFIFO(cp); 981 sEnTransmit(cp); 982 983 info->flags |= ROCKET_INITIALIZED; 984 985#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */ 986 /* 987 * Set up the tty->alt_speed kludge 988 */ 989 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI) 990 info->tty->alt_speed = 57600; 991 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI) 992 info->tty->alt_speed = 115200; 993 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI) 994 info->tty->alt_speed = 230400; 995 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP) 996 info->tty->alt_speed = 460800; 997#endif 998 999 configure_r_port(info); 1000 if (tty->termios->c_cflag & CBAUD) { 1001 sSetDTR(cp); 1002 sSetRTS(cp); 1003 } 1004 1005 mod_timer(&rocket_timer, jiffies + 1); 1006 1007 retval = block_til_ready(tty, filp, info); 1008 if (retval) { 1009#ifdef ROCKET_DEBUG_OPEN 1010 printk("rp_open returning after block_til_ready with %d\n", 1011 retval); 1012#endif 1013 return retval; 1014 } 1015 1016 if ((info->count == 1) && (info->flags & ROCKET_SPLIT_TERMIOS)) { 1017 if (tty->driver.subtype == SERIAL_TYPE_NORMAL) 1018 *tty->termios = info->normal_termios; 1019 else 1020 *tty->termios = info->callout_termios; 1021 configure_r_port(info); 1022 } 1023 1024 return 0; 1025} 1026 1027static void rp_close(struct tty_struct *tty, struct file * filp) 1028{ 1029 struct r_port * info = (struct r_port *)tty->driver_data; 1030 unsigned long flags; 1031 int timeout; 1032 CHANNEL_t *cp; 1033 1034 if (rocket_paranoia_check(info, tty->device, "rp_close")) 1035 return; 1036 1037#ifdef ROCKET_DEBUG_OPEN 1038 printk("rp_close ttyR%d, count = %d\n", info->line, info->count); 1039#endif 1040 1041 save_flags(flags); cli(); 1042 1043 if (tty_hung_up_p(filp)) { 1044 restore_flags(flags); 1045 return; 1046 } 1047 if ((tty->count == 1) && (info->count != 1)) { 1048 /* 1049 * Uh, oh. tty->count is 1, which means that the tty 1050 * structure will be freed. Info->count should always 1051 * be one in these conditions. If it's greater than 1052 * one, we've got real problems, since it means the 1053 * serial port won't be shutdown. 1054 */ 1055 printk("rp_close: bad serial port count; tty->count is 1, " 1056 "info->count is %d\n", info->count); 1057 info->count = 1; 1058 } 1059 if (--info->count < 0) { 1060 printk("rp_close: bad serial port count for ttyR%d: %d\n", 1061 info->line, info->count); 1062 info->count = 0; 1063 } 1064 if (info->count) { 1065 restore_flags(flags); 1066 return; 1067 } 1068 info->flags |= ROCKET_CLOSING; 1069 /* 1070 * Save the termios structure, since this port may have 1071 * separate termios for callout and dialin. 1072 */ 1073 if (info->flags & ROCKET_NORMAL_ACTIVE) 1074 info->normal_termios = *tty->termios; 1075 if (info->flags & ROCKET_CALLOUT_ACTIVE) 1076 info->callout_termios = *tty->termios; 1077 1078 cp = &info->channel; 1079 1080 /* 1081 * Notify the line discpline to only process XON/XOFF characters 1082 */ 1083 tty->closing = 1; 1084 1085 /* 1086 * If transmission was throttled by the application request, 1087 * just flush the xmit buffer. 1088 */ 1089#if (LINUX_VERSION_CODE >= 131343) 1090 if (tty->flow_stopped) 1091 rp_flush_buffer(tty); 1092#endif 1093 1094 /* 1095 * Wait for the transmit buffer to clear 1096 */ 1097 if (info->closing_wait != ROCKET_CLOSING_WAIT_NONE) 1098 tty_wait_until_sent(tty, info->closing_wait); 1099 /* 1100 * Before we drop DTR, make sure the UART transmitter 1101 * has completely drained; this is especially 1102 * important if there is a transmit FIFO! 1103 */ 1104 timeout = (sGetTxCnt(cp)+1) * HZ / info->cps; 1105 if (timeout == 0) 1106 timeout = 1; 1107 rp_wait_until_sent(tty, timeout); 1108 1109 xmit_flags[info->line >> 5] &= ~(1 << (info->line & 0x1f)); 1110 sDisTransmit(cp); 1111 sDisInterrupts(cp, (TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN)); 1112 sDisCTSFlowCtl(cp); 1113 sDisTxSoftFlowCtl(cp); 1114 sClrTxXOFF(cp); 1115 sFlushRxFIFO(cp); 1116 sFlushTxFIFO(cp); 1117 sClrRTS(cp); 1118 if (C_HUPCL(tty)) { 1119 sClrDTR(cp); 1120 } 1121 if (tty->driver.flush_buffer) 1122 tty->driver.flush_buffer(tty); 1123 if (tty->ldisc.flush_buffer) 1124 tty->ldisc.flush_buffer(tty); 1125 1126 xmit_flags[info->line >> 5] &= ~(1 << (info->line & 0x1f)); 1127 if (info->blocked_open) { 1128 if (info->close_delay) { 1129 current->state = TASK_INTERRUPTIBLE; 1130 schedule_timeout(info->close_delay); 1131 } 1132 wake_up_interruptible(&info->open_wait); 1133 } else { 1134 if (info->xmit_buf) { 1135 free_page((unsigned long) info->xmit_buf); 1136 info->xmit_buf = 0; 1137 } 1138 } 1139 info->flags &= ~(ROCKET_INITIALIZED | ROCKET_CLOSING | 1140 ROCKET_CALLOUT_ACTIVE | ROCKET_NORMAL_ACTIVE); 1141 tty->closing = 0; 1142 wake_up_interruptible(&info->close_wait); 1143 1144#ifdef MODULE 1145 MOD_DEC_USE_COUNT; 1146#endif 1147 rp_num_ports_open--; 1148#ifdef ROCKET_DEBUG_OPEN 1149 printk("rocket mod-- = %d...", rp_num_ports_open); 1150#endif 1151 restore_flags(flags); 1152 1153#ifdef ROCKET_DEBUG_OPEN 1154 printk("rp_close ttyR%d complete shutdown\n", info->line); 1155#endif 1156 1157} 1158 1159static void rp_set_termios(struct tty_struct *tty, struct termios *old_termios) 1160{ 1161 struct r_port * info = (struct r_port *)tty->driver_data; 1162 CHANNEL_t *cp; 1163 unsigned cflag; 1164 1165 1166 if (rocket_paranoia_check(info, tty->device, "rp_set_termios")) 1167 return; 1168 1169 cflag = tty->termios->c_cflag; 1170 1171 if (cflag == old_termios->c_cflag) 1172 return; 1173 1174 /* 1175 * This driver doesn't support CS5 or CS6 1176 */ 1177 if (((cflag & CSIZE) == CS5) || 1178 ((cflag & CSIZE) == CS6)) 1179 tty->termios->c_cflag = ((cflag & ~CSIZE) | 1180 (old_termios->c_cflag & CSIZE)); 1181 1182 configure_r_port(info); 1183 1184 cp = &info->channel; 1185 1186 /* Handle transition to B0 status */ 1187 if ((old_termios->c_cflag & CBAUD) && 1188 !(tty->termios->c_cflag & CBAUD)) { 1189 sClrDTR(cp); 1190 sClrRTS(cp); 1191 } 1192 1193 /* Handle transition away from B0 status */ 1194 if (!(old_termios->c_cflag & CBAUD) && 1195 (tty->termios->c_cflag & CBAUD)) { 1196 if (!tty->hw_stopped || 1197 !(tty->termios->c_cflag & CRTSCTS)) { 1198 sSetRTS(cp); 1199 } 1200 sSetDTR(cp); 1201 } 1202 1203 if ((old_termios->c_cflag & CRTSCTS) && 1204 !(tty->termios->c_cflag & CRTSCTS)) { 1205 tty->hw_stopped = 0; 1206 rp_start(tty); 1207 } 1208} 1209 1210/* 1211 * Here are the routines used by rp_ioctl 1212 */ 1213#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ 1214static void send_break( struct r_port * info, int duration) 1215{ 1216 current->state = TASK_INTERRUPTIBLE; 1217 cli(); 1218 sSendBreak(&info->channel); 1219 schedule_timeout(duration); 1220 sClrBreak(&info->channel); 1221 sti(); 1222} 1223#else 1224static void rp_break(struct tty_struct *tty, int break_state) 1225{ 1226 struct r_port * info = (struct r_port *)tty->driver_data; 1227 unsigned long flags; 1228 1229 if (rocket_paranoia_check(info, tty->device, "rp_break")) 1230 return; 1231 1232 save_flags(flags); cli(); 1233 if (break_state == -1) { 1234 sSendBreak(&info->channel); 1235 } else { 1236 sClrBreak(&info->channel); 1237 } 1238 restore_flags(flags); 1239} 1240#endif 1241 1242static int get_modem_info(struct r_port * info, unsigned int *value) 1243{ 1244 unsigned int control, result, ChanStatus; 1245 1246 ChanStatus = sGetChanStatusLo(&info->channel); 1247 1248 control = info->channel.TxControl[3]; 1249 result = ((control & SET_RTS) ? TIOCM_RTS : 0) 1250 | ((control & SET_DTR) ? TIOCM_DTR : 0) 1251 | ((ChanStatus & CD_ACT) ? TIOCM_CAR : 0) 1252 /* TIOCM_RNG not supported */ 1253 | ((ChanStatus & DSR_ACT) ? TIOCM_DSR : 0) 1254 | ((ChanStatus & CTS_ACT) ? TIOCM_CTS : 0); 1255 1256 if (copy_to_user(value, &result, sizeof(int))) 1257 return -EFAULT; 1258 return 0; 1259} 1260 1261static int set_modem_info(struct r_port * info, unsigned int cmd, 1262 unsigned int *value) 1263{ 1264 unsigned int arg; 1265 1266 if (copy_from_user(&arg, value, sizeof(int))) 1267 return -EFAULT; 1268 1269 switch (cmd) { 1270 case TIOCMBIS: 1271 if (arg & TIOCM_RTS) 1272 info->channel.TxControl[3] |= SET_RTS; 1273 if (arg & TIOCM_DTR) 1274 info->channel.TxControl[3] |= SET_DTR; 1275 break; 1276 case TIOCMBIC: 1277 if (arg & TIOCM_RTS) 1278 info->channel.TxControl[3] &= ~SET_RTS; 1279 if (arg & TIOCM_DTR) 1280 info->channel.TxControl[3] &= ~SET_DTR; 1281 break; 1282 case TIOCMSET: 1283 info->channel.TxControl[3] = 1284 ((info->channel.TxControl[3] & ~(SET_RTS | SET_DTR)) 1285 | ((arg & TIOCM_RTS) ? SET_RTS : 0) 1286 | ((arg & TIOCM_DTR) ? SET_DTR : 0)); 1287 break; 1288 default: 1289 return -EINVAL; 1290 } 1291 1292 sOutDW(info->channel.IndexAddr, 1293 *(DWord_t *) &(info->channel.TxControl[0])); 1294 1295 return 0; 1296} 1297 1298static int get_config(struct r_port * info, struct rocket_config * retinfo) 1299{ 1300 struct rocket_config tmp; 1301 1302 if (!retinfo) 1303 return -EFAULT; 1304 memset(&tmp, 0, sizeof(tmp)); 1305 tmp.line = info->line; 1306 tmp.flags = info->flags; 1307 tmp.close_delay = info->close_delay; 1308 tmp.closing_wait = info->closing_wait; 1309 tmp.port = rcktpt_io_addr[(info->line >> 5) & 3]; 1310 1311 if (copy_to_user(retinfo,&tmp,sizeof(*retinfo))) 1312 return -EFAULT; 1313 return 0; 1314} 1315 1316static int set_config(struct r_port * info, struct rocket_config * new_info) 1317{ 1318 struct rocket_config new_serial; 1319 1320 if (copy_from_user(&new_serial, new_info, sizeof(new_serial))) 1321 return -EFAULT; 1322 1323#ifdef CAP_SYS_ADMIN 1324 if (!capable(CAP_SYS_ADMIN)) 1325#else 1326 if (!suser()) 1327#endif 1328 { 1329 if ((new_serial.flags & ~ROCKET_USR_MASK) != 1330 (info->flags & ~ROCKET_USR_MASK)) 1331 return -EPERM; 1332 info->flags = ((info->flags & ~ROCKET_USR_MASK) | 1333 (new_serial.flags & ROCKET_USR_MASK)); 1334 configure_r_port(info); 1335 return 0; 1336 } 1337 1338 info->flags = ((info->flags & ~ROCKET_FLAGS) | 1339 (new_serial.flags & ROCKET_FLAGS)); 1340 info->close_delay = new_serial.close_delay; 1341 info->closing_wait = new_serial.closing_wait; 1342 1343#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */ 1344 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI) 1345 info->tty->alt_speed = 57600; 1346 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI) 1347 info->tty->alt_speed = 115200; 1348 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI) 1349 info->tty->alt_speed = 230400; 1350 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP) 1351 info->tty->alt_speed = 460800; 1352#endif 1353 1354 configure_r_port(info); 1355 return 0; 1356} 1357 1358static int get_ports(struct r_port * info, struct rocket_ports * retports) 1359{ 1360 struct rocket_ports tmp; 1361 int board, port, index; 1362 1363 if (!retports) 1364 return -EFAULT; 1365 memset(&tmp, 0, sizeof(tmp)); 1366 tmp.tty_major = rocket_driver.major; 1367 tmp.callout_major = callout_driver.major; 1368 for (board = 0; board < 4; board++) { 1369 index = board << 5; 1370 for (port = 0; port < 32; port++, index++) { 1371 if (rp_table[index]) 1372 tmp.port_bitmap[board] |= 1 << port; 1373 } 1374 } 1375 if (copy_to_user(retports,&tmp,sizeof(*retports))) 1376 return -EFAULT; 1377 return 0; 1378} 1379 1380static int rp_ioctl(struct tty_struct *tty, struct file * file, 1381 unsigned int cmd, unsigned long arg) 1382{ 1383 struct r_port * info = (struct r_port *)tty->driver_data; 1384#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ 1385 int retval, tmp; 1386#endif 1387 1388 if (cmd != RCKP_GET_PORTS && 1389 rocket_paranoia_check(info, tty->device, "rp_ioctl")) 1390 return -ENODEV; 1391 1392 switch (cmd) { 1393#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ 1394 case TCSBRK: /* SVID version: non-zero arg --> no break */ 1395 retval = tty_check_change(tty); 1396 if (retval) 1397 return retval; 1398 tty_wait_until_sent(tty, 0); 1399 if (signal_pending(current)) 1400 return -EINTR; 1401 if (!arg) { 1402 send_break(info, HZ/4); /* 1/4 second */ 1403 if (signal_pending(current)) 1404 return -EINTR; 1405 } 1406 return 0; 1407 case TCSBRKP: /* support for POSIX tcsendbreak() */ 1408 retval = tty_check_change(tty); 1409 if (retval) 1410 return retval; 1411 tty_wait_until_sent(tty, 0); 1412 if (signal_pending(current)) 1413 return -EINTR; 1414 send_break(info, arg ? arg*(HZ/10) : HZ/4); 1415 if (signal_pending(current)) 1416 return -EINTR; 1417 return 0; 1418 case TIOCGSOFTCAR: 1419 tmp = C_CLOCAL(tty) ? 1 : 0; 1420 if (copy_to_user((void *)arg, &tmp, sizeof(int))) 1421 return -EFAULT; 1422 return 0; 1423 case TIOCSSOFTCAR: 1424 if (copy_from_user(&tmp, (void *)arg, sizeof(int))) 1425 return -EFAULT; 1426 1427 tty->termios->c_cflag = 1428 ((tty->termios->c_cflag & ~CLOCAL) | 1429 (tmp ? CLOCAL : 0)); 1430 return 0; 1431#endif 1432 case TIOCMGET: 1433 return get_modem_info(info, (unsigned int *) arg); 1434 case TIOCMBIS: 1435 case TIOCMBIC: 1436 case TIOCMSET: 1437 return set_modem_info(info, cmd, (unsigned int *) arg); 1438 case RCKP_GET_STRUCT: 1439 if (copy_to_user((void *) arg, info, 1440 sizeof(struct r_port))) 1441 return -EFAULT; 1442 return 0; 1443 1444 case RCKP_GET_CONFIG: 1445 return get_config(info, (struct rocket_config *) arg); 1446 case RCKP_SET_CONFIG: 1447 return set_config(info, (struct rocket_config *) arg); 1448 1449 case RCKP_GET_PORTS: 1450 return get_ports(info, (struct rocket_ports *) arg); 1451 default: 1452 return -ENOIOCTLCMD; 1453 } 1454 return 0; 1455} 1456 1457#if (defined(ROCKET_DEBUG_FLOW) || defined(ROCKET_DEBUG_THROTTLE)) 1458static char *rp_tty_name(struct tty_struct *tty, char *buf) 1459{ 1460 if (tty) 1461 sprintf(buf, "%s%d", tty->driver.name, 1462 MINOR(tty->device) - tty->driver.minor_start + 1463 tty->driver.name_base); 1464 else 1465 strcpy(buf, "NULL tty"); 1466 return buf; 1467} 1468#endif 1469 1470static void rp_send_xchar(struct tty_struct *tty, char ch) 1471{ 1472 struct r_port *info = (struct r_port *)tty->driver_data; 1473 CHANNEL_t *cp; 1474 1475 if (rocket_paranoia_check(info, tty->device, "rp_send_xchar")) 1476 return; 1477 1478 cp = &info->channel; 1479 if (sGetTxCnt(cp)) 1480 sWriteTxPrioByte(cp, ch); 1481 else 1482 sWriteTxByte(sGetTxRxDataIO(cp), ch); 1483} 1484 1485static void rp_throttle(struct tty_struct * tty) 1486{ 1487 struct r_port *info = (struct r_port *)tty->driver_data; 1488 CHANNEL_t *cp; 1489#ifdef ROCKET_DEBUG_THROTTLE 1490 char buf[64]; 1491 1492 printk("throttle %s: %d....\n", rp_tty_name(tty, buf), 1493 tty->ldisc.chars_in_buffer(tty)); 1494#endif 1495 1496 if (rocket_paranoia_check(info, tty->device, "rp_throttle")) 1497 return; 1498 1499 cp = &info->channel; 1500 if (I_IXOFF(tty)) 1501 rp_send_xchar(tty, STOP_CHAR(tty)); 1502 1503 sClrRTS(&info->channel); 1504} 1505 1506static void rp_unthrottle(struct tty_struct * tty) 1507{ 1508 struct r_port *info = (struct r_port *)tty->driver_data; 1509 CHANNEL_t *cp; 1510#ifdef ROCKET_DEBUG_THROTTLE 1511 char buf[64]; 1512 1513 printk("unthrottle %s: %d....\n", rp_tty_name(tty, buf), 1514 tty->ldisc.chars_in_buffer(tty)); 1515#endif 1516 1517 if (rocket_paranoia_check(info, tty->device, "rp_throttle")) 1518 return; 1519 1520 cp = &info->channel; 1521 if (I_IXOFF(tty)) 1522 rp_send_xchar(tty, START_CHAR(tty)); 1523 1524 sSetRTS(&info->channel); 1525} 1526 1527/* 1528 * ------------------------------------------------------------ 1529 * rp_stop() and rp_start() 1530 * 1531 * This routines are called before setting or resetting tty->stopped. 1532 * They enable or disable transmitter interrupts, as necessary. 1533 * ------------------------------------------------------------ 1534 */ 1535static void rp_stop(struct tty_struct *tty) 1536{ 1537 struct r_port * info = (struct r_port *)tty->driver_data; 1538#ifdef ROCKET_DEBUG_FLOW 1539 char buf[64]; 1540 1541 printk("stop %s: %d %d....\n", rp_tty_name(tty, buf), 1542 info->xmit_cnt, info->xmit_fifo_room); 1543#endif 1544 1545 if (rocket_paranoia_check(info, tty->device, "rp_stop")) 1546 return; 1547 1548 if (sGetTxCnt(&info->channel)) 1549 sDisTransmit(&info->channel); 1550} 1551 1552static void rp_start(struct tty_struct *tty) 1553{ 1554 struct r_port * info = (struct r_port *)tty->driver_data; 1555#ifdef ROCKET_DEBUG_FLOW 1556 char buf[64]; 1557 1558 printk("start %s: %d %d....\n", rp_tty_name(tty, buf), 1559 info->xmit_cnt, info->xmit_fifo_room); 1560#endif 1561 1562 if (rocket_paranoia_check(info, tty->device, "rp_stop")) 1563 return; 1564 1565 sEnTransmit(&info->channel); 1566 xmit_flags[info->line >> 5] |= (1 << (info->line & 0x1f)); 1567} 1568 1569/* 1570 * rp_wait_until_sent() --- wait until the transmitter is empty 1571 */ 1572static void rp_wait_until_sent(struct tty_struct *tty, int timeout) 1573{ 1574 struct r_port *info = (struct r_port *)tty->driver_data; 1575 CHANNEL_t *cp; 1576 unsigned long orig_jiffies; 1577 int check_time, exit_time; 1578 int txcnt; 1579 1580 if (rocket_paranoia_check(info, tty->device, "rp_wait_until_sent")) 1581 return; 1582 1583 cp = &info->channel; 1584 1585 orig_jiffies = jiffies; 1586#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT 1587 printk("In RP_wait_until_sent(%d) (jiff=%lu)...", timeout, jiffies); 1588 printk("cps=%d...", info->cps); 1589#endif 1590 while (1) { 1591 txcnt = sGetTxCnt(cp); 1592 if (!txcnt) { 1593 if (sGetChanStatusLo(cp) & TXSHRMT) 1594 break; 1595 check_time = (HZ / info->cps) / 5; 1596 } else 1597 check_time = HZ * txcnt / info->cps; 1598 if (timeout) { 1599 exit_time = orig_jiffies + timeout - jiffies; 1600 if (exit_time <= 0) 1601 break; 1602 if (exit_time < check_time) 1603 check_time = exit_time; 1604 } 1605 if (check_time == 0) 1606 check_time = 1; 1607#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT 1608 printk("txcnt = %d (jiff=%lu,check=%d)...", txcnt, 1609 jiffies, check_time); 1610#endif 1611 current->state = TASK_INTERRUPTIBLE; 1612 schedule_timeout(check_time); 1613 if (signal_pending(current)) 1614 break; 1615 } 1616 current->state = TASK_RUNNING; 1617#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT 1618 printk("txcnt = %d (jiff=%lu)...done\n", txcnt, jiffies); 1619#endif 1620} 1621 1622/* 1623 * rp_hangup() --- called by tty_hangup() when a hangup is signaled. 1624 */ 1625static void rp_hangup(struct tty_struct *tty) 1626{ 1627 CHANNEL_t *cp; 1628 struct r_port * info = (struct r_port *)tty->driver_data; 1629 1630 if (rocket_paranoia_check(info, tty->device, "rp_hangup")) 1631 return; 1632 1633#if (defined(ROCKET_DEBUG_OPEN) || defined(ROCKET_DEBUG_HANGUP)) 1634 printk("rp_hangup of ttyR%d...", info->line); 1635#endif 1636 /* 1637 * If the port is in the process of being closed, just force 1638 * the transmit buffer to be empty, and let rp_close handle 1639 * the clean up. 1640 */ 1641 if (info->flags & ROCKET_CLOSING) { 1642 cli(); 1643 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; 1644 sti(); 1645 wake_up_interruptible(&tty->write_wait); 1646 return; 1647 } 1648 if (info->count) { 1649#ifdef MODULE 1650 MOD_DEC_USE_COUNT; 1651#endif 1652 rp_num_ports_open--; 1653 } 1654 1655 xmit_flags[info->line >> 5] &= ~(1 << (info->line & 0x1f)); 1656 info->count = 0; 1657 info->flags &= ~(ROCKET_NORMAL_ACTIVE|ROCKET_CALLOUT_ACTIVE); 1658 info->tty = 0; 1659 1660 cp = &info->channel; 1661 sDisRxFIFO(cp); 1662 sDisTransmit(cp); 1663 sDisInterrupts(cp, (TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN)); 1664 sDisCTSFlowCtl(cp); 1665 sDisTxSoftFlowCtl(cp); 1666 sClrTxXOFF(cp); 1667 info->flags &= ~ROCKET_INITIALIZED; 1668 1669 wake_up_interruptible(&info->open_wait); 1670} 1671 1672/* 1673 * The Rocketport write routines. The Rocketport driver uses a 1674 * double-buffering strategy, with the twist that if the in-memory CPU 1675 * buffer is empty, and there's space in the transmit FIFO, the 1676 * writing routines will write directly to transmit FIFO. 1677 * 1678 * This gets a little tricky, but I'm pretty sure I got it all right. 1679 */ 1680static void rp_put_char(struct tty_struct *tty, unsigned char ch) 1681{ 1682 struct r_port * info = (struct r_port *)tty->driver_data; 1683 CHANNEL_t *cp; 1684 1685 if (rocket_paranoia_check(info, tty->device, "rp_put_char")) 1686 return; 1687 1688#ifdef ROCKET_DEBUG_WRITE 1689 printk("rp_put_char %c...", ch); 1690#endif 1691 1692 cp = &info->channel; 1693 1694 if (!tty->stopped && !tty->hw_stopped && info->xmit_fifo_room == 0) 1695 info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp); 1696 1697 if (tty->stopped || tty->hw_stopped || 1698 info->xmit_fifo_room == 0 || info->xmit_cnt != 0) { 1699 info->xmit_buf[info->xmit_head++] = ch; 1700 info->xmit_head &= XMIT_BUF_SIZE-1; 1701 info->xmit_cnt++; 1702 xmit_flags[info->line >> 5] |= (1 << (info->line & 0x1f)); 1703 } else { 1704 sOutB(sGetTxRxDataIO(cp), ch); 1705 info->xmit_fifo_room--; 1706 } 1707} 1708 1709static int rp_write(struct tty_struct * tty, int from_user, 1710 const unsigned char *buf, int count) 1711{ 1712 struct r_port * info = (struct r_port *)tty->driver_data; 1713 CHANNEL_t *cp; 1714 const unsigned char *b; 1715 int c, retval = 0; 1716 unsigned long flags; 1717 1718 if (count <= 0 || rocket_paranoia_check(info, tty->device, "rp_write")) 1719 return 0; 1720 1721#ifdef ROCKET_DEBUG_WRITE 1722 printk("rp_write %d chars...", count); 1723#endif 1724 cp = &info->channel; 1725 1726 if (!tty->stopped && !tty->hw_stopped && info->xmit_fifo_room == 0) 1727 info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp); 1728 1729 if (!tty->stopped && !tty->hw_stopped && info->xmit_cnt == 0 1730 && info->xmit_fifo_room >= 0) { 1731 c = MIN(count, info->xmit_fifo_room); 1732 b = buf; 1733 if (from_user) { 1734 down(&tmp_buf_sem); 1735 c -= copy_from_user(tmp_buf, buf, c); 1736 b = tmp_buf; 1737 up(&tmp_buf_sem); 1738 /* In case we got pre-empted */ 1739 if (!c) { 1740 retval = -EFAULT; 1741 goto end; 1742 } 1743 if (info->tty == 0) 1744 goto end; 1745 c = MIN(c, info->xmit_fifo_room); 1746 } 1747 sOutStrW(sGetTxRxDataIO(cp), b, c/2); 1748 if (c & 1) 1749 sOutB(sGetTxRxDataIO(cp), b[c-1]); 1750 retval += c; 1751 buf += c; 1752 count -= c; 1753 info->xmit_fifo_room -= c; 1754 } 1755 if (!count) 1756 goto end; 1757 1758 save_flags(flags); 1759 while (1) { 1760 if (info->tty == 0) { 1761 restore_flags(flags); 1762 goto end; 1763 } 1764 c = MIN(count, MIN(XMIT_BUF_SIZE - info->xmit_cnt - 1, 1765 XMIT_BUF_SIZE - info->xmit_head)); 1766 if (c <= 0) 1767 break; 1768 1769 b = buf; 1770 if (from_user) { 1771 down(&tmp_buf_sem); 1772 c -= copy_from_user(tmp_buf, buf, c); 1773 b = tmp_buf; 1774 up(&tmp_buf_sem); 1775 if (!c) { 1776 if (retval == 0) 1777 retval = -EFAULT; 1778 goto end_intr; 1779 } 1780 /* In case we got pre-empted */ 1781 if (info->tty == 0) 1782 goto end_intr; 1783 } 1784 cli(); 1785 c = MIN(c, MIN(XMIT_BUF_SIZE - info->xmit_cnt - 1, 1786 XMIT_BUF_SIZE - info->xmit_head)); 1787 memcpy(info->xmit_buf + info->xmit_head, b, c); 1788 info->xmit_head = (info->xmit_head + c) & (XMIT_BUF_SIZE-1); 1789 info->xmit_cnt += c; 1790 restore_flags(flags); 1791 buf += c; 1792 count -= c; 1793 retval += c; 1794 } 1795end_intr: 1796 if ((retval > 0) && !tty->stopped && !tty->hw_stopped) 1797 xmit_flags[info->line >> 5] |= (1 << (info->line & 0x1f)); 1798 restore_flags(flags); 1799end: 1800 if (info->xmit_cnt < WAKEUP_CHARS) { 1801 if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && 1802 tty->ldisc.write_wakeup) 1803 (tty->ldisc.write_wakeup)(tty); 1804 wake_up_interruptible(&tty->write_wait); 1805 } 1806 return retval; 1807} 1808 1809/* 1810 * Return the number of characters that can be sent. We estimate 1811 * only using the in-memory transmit buffer only, and ignore the 1812 * potential space in the transmit FIFO. 1813 */ 1814static int rp_write_room(struct tty_struct *tty) 1815{ 1816 struct r_port * info = (struct r_port *)tty->driver_data; 1817 int ret; 1818 1819 if (rocket_paranoia_check(info, tty->device, "rp_write_room")) 1820 return 0; 1821 1822 ret = XMIT_BUF_SIZE - info->xmit_cnt - 1; 1823 if (ret < 0) 1824 ret = 0; 1825#ifdef ROCKET_DEBUG_WRITE 1826 printk("rp_write_room returns %d...", ret); 1827#endif 1828 return ret; 1829} 1830 1831/* 1832 * Return the number of characters in the buffer. Again, this only 1833 * counts those characters in the in-memory transmit buffer. 1834 */ 1835static int rp_chars_in_buffer(struct tty_struct *tty) 1836{ 1837 struct r_port * info = (struct r_port *)tty->driver_data; 1838 CHANNEL_t *cp; 1839 1840 if (rocket_paranoia_check(info, tty->device, "rp_chars_in_buffer")) 1841 return 0; 1842 1843 cp = &info->channel; 1844 1845#ifdef ROCKET_DEBUG_WRITE 1846 printk("rp_chars_in_buffer returns %d...", info->xmit_cnt); 1847#endif 1848 return info->xmit_cnt; 1849} 1850 1851static void rp_flush_buffer(struct tty_struct *tty) 1852{ 1853 struct r_port * info = (struct r_port *)tty->driver_data; 1854 CHANNEL_t *cp; 1855 1856 if (rocket_paranoia_check(info, tty->device, "rp_flush_buffer")) 1857 return; 1858 1859 cli(); 1860 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; 1861 sti(); 1862 wake_up_interruptible(&tty->write_wait); 1863 if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && 1864 tty->ldisc.write_wakeup) 1865 (tty->ldisc.write_wakeup)(tty); 1866 1867 cp = &info->channel; 1868 1869 sFlushTxFIFO(cp); 1870} 1871 1872#ifdef ENABLE_PCI 1873#if (LINUX_VERSION_CODE < 0x020163) /* 2.1.99 */ 1874/* For compatibility */ 1875static struct pci_dev *pci_find_slot(unsigned char bus, 1876 unsigned char device_fn) 1877{ 1878 unsigned short vendor_id, device_id; 1879 int ret, error; 1880 static struct pci_dev ret_struct; 1881 1882 error = pcibios_read_config_word(bus, device_fn, PCI_VENDOR_ID, 1883 &vendor_id); 1884 ret = pcibios_read_config_word(bus, device_fn, PCI_DEVICE_ID, 1885 &device_id); 1886 if (error == 0) 1887 error = ret; 1888 1889 if (error) { 1890 printk("PCI RocketPort error: %s not initializing due to error" 1891 "reading configuration space\n", 1892 pcibios_strerror(error)); 1893 return(0); 1894 } 1895 1896 memset(&ret_struct, 0, sizeof(ret_struct)); 1897 ret_struct.device = device_id; 1898 1899 return &ret_struct; 1900} 1901#endif 1902 1903int __init register_PCI(int i, unsigned int bus, unsigned int device_fn) 1904{ 1905 int num_aiops, aiop, max_num_aiops, num_chan, chan; 1906 unsigned int aiopio[MAX_AIOPS_PER_BOARD]; 1907 char *str; 1908 CONTROLLER_t *ctlp; 1909 struct pci_dev *dev = pci_find_slot(bus, device_fn); 1910#if (LINUX_VERSION_CODE < 0x020163) /* 2.1.99 */ 1911 int ret; 1912 unsigned int port; 1913#endif 1914 1915 if (!dev) 1916 return 0; 1917 1918 if (pci_enable_device(dev)) 1919 return 0; 1920 1921 rcktpt_io_addr[i] = pci_resource_start (dev, 0); 1922 switch(dev->device) { 1923 case PCI_DEVICE_ID_RP4QUAD: 1924 str = "Quadcable"; 1925 max_num_aiops = 1; 1926 break; 1927 case PCI_DEVICE_ID_RP8OCTA: 1928 str = "Octacable"; 1929 max_num_aiops = 1; 1930 break; 1931 case PCI_DEVICE_ID_RP8INTF: 1932 str = "8"; 1933 max_num_aiops = 1; 1934 break; 1935 case PCI_DEVICE_ID_RP8J: 1936 str = "8J"; 1937 max_num_aiops = 1; 1938 break; 1939 case PCI_DEVICE_ID_RP16INTF: 1940 str = "16"; 1941 max_num_aiops = 2; 1942 break; 1943 case PCI_DEVICE_ID_RP32INTF: 1944 str = "32"; 1945 max_num_aiops = 4; 1946 break; 1947 case PCI_DEVICE_ID_RPP4: 1948 str = "Plus Quadcable"; 1949 max_num_aiops = 1; 1950 break; 1951 case PCI_DEVICE_ID_RPP8: 1952 str = "Plus Octacable"; 1953 max_num_aiops = 1; 1954 break; 1955 case PCI_DEVICE_ID_RP8M: 1956 str = "8-port Modem"; 1957 max_num_aiops = 1; 1958 break; 1959 default: 1960 str = "(unknown/unsupported)"; 1961 max_num_aiops = 0; 1962 break; 1963 } 1964 for(aiop=0;aiop < max_num_aiops;aiop++) 1965 aiopio[aiop] = rcktpt_io_addr[i] + (aiop * 0x40); 1966 ctlp = sCtlNumToCtlPtr(i); 1967 num_aiops = sPCIInitController(ctlp, i, 1968 aiopio, max_num_aiops, 0, 1969 FREQ_DIS, 0); 1970 printk("Rocketport controller #%d found at %02x:%02x, " 1971 "%d AIOP(s) (PCI Rocketport %s)\n", i, bus, device_fn, 1972 num_aiops, str); 1973 if(num_aiops <= 0) { 1974 rcktpt_io_addr[i] = 0; 1975 return(0); 1976 } 1977 for(aiop = 0;aiop < num_aiops; aiop++) { 1978 sResetAiopByNum(ctlp, aiop); 1979 sEnAiop(ctlp, aiop); 1980 num_chan = sGetAiopNumChan(ctlp, aiop); 1981 for(chan=0;chan < num_chan; chan++) 1982 init_r_port(i, aiop, chan); 1983 } 1984 return(1); 1985} 1986 1987static int __init init_PCI(int boards_found) 1988{ 1989 unsigned char bus, device_fn; 1990 int i, count = 0; 1991 1992 for(i=0; i < (NUM_BOARDS - boards_found); i++) { 1993 if (!pcibios_find_device(PCI_VENDOR_ID_RP, 1994 PCI_DEVICE_ID_RP4QUAD, i, &bus, &device_fn)) 1995 if (register_PCI(count+boards_found, bus, device_fn)) 1996 count++; 1997 if (!pcibios_find_device(PCI_VENDOR_ID_RP, 1998 PCI_DEVICE_ID_RP8J, i, &bus, &device_fn)) 1999 if (register_PCI(count+boards_found, bus, device_fn)) 2000 count++; 2001 if(!pcibios_find_device(PCI_VENDOR_ID_RP, 2002 PCI_DEVICE_ID_RP8OCTA, i, &bus, &device_fn)) 2003 if(register_PCI(count+boards_found, bus, device_fn)) 2004 count++; 2005 if(!pcibios_find_device(PCI_VENDOR_ID_RP, 2006 PCI_DEVICE_ID_RP8INTF, i, &bus, &device_fn)) 2007 if(register_PCI(count+boards_found, bus, device_fn)) 2008 count++; 2009 if(!pcibios_find_device(PCI_VENDOR_ID_RP, 2010 PCI_DEVICE_ID_RP16INTF, i, &bus, &device_fn)) 2011 if(register_PCI(count+boards_found, bus, device_fn)) 2012 count++; 2013 if(!pcibios_find_device(PCI_VENDOR_ID_RP, 2014 PCI_DEVICE_ID_RP32INTF, i, &bus, &device_fn)) 2015 if(register_PCI(count+boards_found, bus, device_fn)) 2016 count++; 2017 if(!pcibios_find_device(PCI_VENDOR_ID_RP, 2018 PCI_DEVICE_ID_RP4QUAD, i, &bus, &device_fn)) 2019 if(register_PCI(count+boards_found, bus, device_fn)) 2020 count++; 2021 if(!pcibios_find_device(PCI_VENDOR_ID_RP, 2022 PCI_DEVICE_ID_RP8J, i, &bus, &device_fn)) 2023 if(register_PCI(count+boards_found, bus, device_fn)) 2024 count++; 2025 if(!pcibios_find_device(PCI_VENDOR_ID_RP, 2026 PCI_DEVICE_ID_RPP4, i, &bus, &device_fn)) 2027 if(register_PCI(count+boards_found, bus, device_fn)) 2028 count++; 2029 if(!pcibios_find_device(PCI_VENDOR_ID_RP, 2030 PCI_DEVICE_ID_RPP8, i, &bus, &device_fn)) 2031 if(register_PCI(count+boards_found, bus, device_fn)) 2032 count++; 2033 if(!pcibios_find_device(PCI_VENDOR_ID_RP, 2034 PCI_DEVICE_ID_RP8M, i, &bus, &device_fn)) 2035 if(register_PCI(count+boards_found, bus, device_fn)) 2036 count++; 2037 } 2038 return(count); 2039} 2040#endif 2041 2042static int __init init_ISA(int i, int *reserved_controller) 2043{ 2044 int num_aiops, num_chan; 2045 int aiop, chan; 2046 unsigned int aiopio[MAX_AIOPS_PER_BOARD]; 2047 CONTROLLER_t *ctlp; 2048 2049 if (rcktpt_io_addr[i] == 0) 2050 return(0); 2051 2052 if (check_region(rcktpt_io_addr[i],64)) { 2053 printk("RocketPort board address 0x%lx in use...\n", 2054 rcktpt_io_addr[i]); 2055 rcktpt_io_addr[i] = 0; 2056 return(0); 2057 } 2058 2059 for (aiop=0; aiop<MAX_AIOPS_PER_BOARD; aiop++) 2060 aiopio[aiop]= rcktpt_io_addr[i] + (aiop * 0x400); 2061 ctlp= sCtlNumToCtlPtr(i); 2062 num_aiops = sInitController(ctlp, i, controller + (i*0x400), 2063 aiopio, MAX_AIOPS_PER_BOARD, 0, 2064 FREQ_DIS, 0); 2065 if (num_aiops <= 0) { 2066 rcktpt_io_addr[i] = 0; 2067 return(0); 2068 } 2069 for (aiop = 0; aiop < num_aiops; aiop++) { 2070 sResetAiopByNum(ctlp, aiop); 2071 sEnAiop(ctlp, aiop); 2072 num_chan = sGetAiopNumChan(ctlp,aiop); 2073 for (chan=0; chan < num_chan; chan++) 2074 init_r_port(i, aiop, chan); 2075 } 2076 printk("Rocketport controller #%d found at 0x%lx, " 2077 "%d AIOPs\n", i, rcktpt_io_addr[i], 2078 num_aiops); 2079 if (rcktpt_io_addr[i] + 0x40 == controller) { 2080 *reserved_controller = 1; 2081 request_region(rcktpt_io_addr[i], 68, 2082 "Comtrol Rocketport"); 2083 } else { 2084 request_region(rcktpt_io_addr[i], 64, 2085 "Comtrol Rocketport"); 2086 } 2087 return(1); 2088} 2089 2090 2091/* 2092 * The module "startup" routine; it's run when the module is loaded. 2093 */ 2094int __init rp_init(void) 2095{ 2096 int i, retval, pci_boards_found, isa_boards_found; 2097 int reserved_controller = 0; 2098 2099 printk("Rocketport device driver module, version %s, %s\n", 2100 ROCKET_VERSION, ROCKET_DATE); 2101 2102 /* 2103 * Set up the timer channel. If it is already in use by 2104 * some other driver, give up. 2105 */ 2106 if (rocket_timer.function) { 2107 printk("rocket.o: Timer already in use!\n"); 2108 return -EBUSY; 2109 } 2110 init_timer(&rocket_timer); 2111 rocket_timer.function = rp_do_poll; 2112 2113 /* 2114 * Initialize the array of pointers to our own internal state 2115 * structures. 2116 */ 2117 memset(rp_table, 0, sizeof(rp_table)); 2118 memset(xmit_flags, 0, sizeof(xmit_flags)); 2119 2120 if (board1 == 0) 2121 board1 = 0x180; 2122 if (controller == 0) 2123 controller = board1 + 0x40; 2124 2125 if (check_region(controller, 4)) { 2126 printk("Controller IO addresses in use, unloading driver.\n"); 2127 return -EBUSY; 2128 } 2129 2130 rcktpt_io_addr[0] = board1; 2131 rcktpt_io_addr[1] = board2; 2132 rcktpt_io_addr[2] = board3; 2133 rcktpt_io_addr[3] = board4; 2134 2135 /* 2136 * If support_low_speed is set, use the slow clock prescale, 2137 * which supports 50 bps 2138 */ 2139 if (support_low_speed) { 2140 sClockPrescale = 0x19; /* mod 9 (divide by 10) prescale */ 2141 rp_baud_base = 230400; 2142 } else { 2143 sClockPrescale = 0x14; /* mod 4 (devide by 5) prescale */ 2144 rp_baud_base = 460800; 2145 } 2146 2147 /* 2148 * OK, let's probe each of the controllers looking for boards. 2149 */ 2150 isa_boards_found = 0; 2151 pci_boards_found = 0; 2152 for (i=0; i < NUM_BOARDS; i++) { 2153 if(init_ISA(i, &reserved_controller)) 2154 isa_boards_found++; 2155 } 2156#ifdef ENABLE_PCI 2157 if (pcibios_present()) { 2158 if(isa_boards_found < NUM_BOARDS) 2159 pci_boards_found = init_PCI(isa_boards_found); 2160 } else { 2161 printk("No PCI BIOS found\n"); 2162 } 2163#endif 2164 max_board = pci_boards_found + isa_boards_found; 2165 2166 if (max_board == 0) { 2167 printk("No rocketport ports found; unloading driver.\n"); 2168 rocket_timer.function = 0; 2169 return -ENODEV; 2170 } 2171 2172 if (reserved_controller == 0) 2173 request_region(controller, 4, "Comtrol Rocketport"); 2174 2175 /* 2176 * Set up the tty driver structure and then register this 2177 * driver with the tty layer. 2178 */ 2179 memset(&rocket_driver, 0, sizeof(struct tty_driver)); 2180 rocket_driver.magic = TTY_DRIVER_MAGIC; 2181#ifdef CONFIG_DEVFS_FS 2182 rocket_driver.name = "tts/R%d"; 2183#else 2184 rocket_driver.name = "ttyR"; 2185#endif 2186 rocket_driver.major = TTY_ROCKET_MAJOR; 2187 rocket_driver.minor_start = 0; 2188 rocket_driver.num = MAX_RP_PORTS; 2189 rocket_driver.type = TTY_DRIVER_TYPE_SERIAL; 2190 rocket_driver.subtype = SERIAL_TYPE_NORMAL; 2191 rocket_driver.init_termios = tty_std_termios; 2192 rocket_driver.init_termios.c_cflag = 2193 B9600 | CS8 | CREAD | HUPCL | CLOCAL; 2194 rocket_driver.flags = TTY_DRIVER_REAL_RAW; 2195 rocket_driver.refcount = &rocket_refcount; 2196 rocket_driver.table = rocket_table; 2197 rocket_driver.termios = rocket_termios; 2198 rocket_driver.termios_locked = rocket_termios_locked; 2199 2200 rocket_driver.open = rp_open; 2201 rocket_driver.close = rp_close; 2202 rocket_driver.write = rp_write; 2203 rocket_driver.put_char = rp_put_char; 2204 rocket_driver.write_room = rp_write_room; 2205 rocket_driver.chars_in_buffer = rp_chars_in_buffer; 2206 rocket_driver.flush_buffer = rp_flush_buffer; 2207 rocket_driver.ioctl = rp_ioctl; 2208 rocket_driver.throttle = rp_throttle; 2209 rocket_driver.unthrottle = rp_unthrottle; 2210 rocket_driver.set_termios = rp_set_termios; 2211 rocket_driver.stop = rp_stop; 2212 rocket_driver.start = rp_start; 2213 rocket_driver.hangup = rp_hangup; 2214#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */ 2215 rocket_driver.break_ctl = rp_break; 2216#endif 2217#if (LINUX_VERSION_CODE >= 131343) 2218 rocket_driver.send_xchar = rp_send_xchar; 2219 rocket_driver.wait_until_sent = rp_wait_until_sent; 2220#endif 2221 2222 /* 2223 * The callout device is just like normal device except for 2224 * the minor number and the subtype code. 2225 */ 2226 callout_driver = rocket_driver; 2227#ifdef CONFIG_DEVFS_FS 2228 callout_driver.name = "cua/R%d"; 2229#else 2230 callout_driver.name = "cur"; 2231#endif 2232 callout_driver.major = CUA_ROCKET_MAJOR; 2233 callout_driver.minor_start = 0; 2234 callout_driver.subtype = SERIAL_TYPE_CALLOUT; 2235 2236 retval = tty_register_driver(&callout_driver); 2237 if (retval < 0) { 2238 printk("Couldn't install Rocketport callout driver " 2239 "(error %d)\n", -retval); 2240 return -1; 2241 } 2242 2243 retval = tty_register_driver(&rocket_driver); 2244 if (retval < 0) { 2245 printk("Couldn't install tty Rocketport driver " 2246 "(error %d)\n", -retval); 2247 return -1; 2248 } 2249#ifdef ROCKET_DEBUG_OPEN 2250 printk("Rocketport driver is major %d, callout is %d\n", 2251 rocket_driver.major, callout_driver.major); 2252#endif 2253 2254 return 0; 2255} 2256 2257#ifdef MODULE 2258int init_module(void) 2259{ 2260 return rp_init(); 2261} 2262 2263void 2264cleanup_module( void) { 2265 int retval; 2266 int i; 2267 int released_controller = 0; 2268 2269 del_timer_sync(&rocket_timer); 2270 2271 retval = tty_unregister_driver(&callout_driver); 2272 if (retval) { 2273 printk("Error %d while trying to unregister " 2274 "rocketport callout driver\n", -retval); 2275 } 2276 retval = tty_unregister_driver(&rocket_driver); 2277 if (retval) { 2278 printk("Error %d while trying to unregister " 2279 "rocketport driver\n", -retval); 2280 } 2281 for (i = 0; i < MAX_RP_PORTS; i++) { 2282 if (rp_table[i]) 2283 kfree(rp_table[i]); 2284 } 2285 for (i=0; i < NUM_BOARDS; i++) { 2286 if (rcktpt_io_addr[i] <= 0) 2287 continue; 2288 if (rcktpt_io_addr[i] + 0x40 == controller) { 2289 released_controller++; 2290 release_region(rcktpt_io_addr[i], 68); 2291 } else 2292 release_region(rcktpt_io_addr[i], 64); 2293 if (released_controller == 0) 2294 release_region(controller, 4); 2295 } 2296 if (tmp_buf) 2297 free_page((unsigned long) tmp_buf); 2298 rocket_timer.function = 0; 2299} 2300#endif 2301 2302/*********************************************************************** 2303 Copyright 1994 Comtrol Corporation. 2304 All Rights Reserved. 2305 2306The following source code is subject to Comtrol Corporation's 2307Developer's License Agreement. 2308 2309This source code is protected by United States copyright law and 2310international copyright treaties. 2311 2312This source code may only be used to develop software products that 2313will operate with Comtrol brand hardware. 2314 2315You may not reproduce nor distribute this source code in its original 2316form but must produce a derivative work which includes portions of 2317this source code only. 2318 2319The portions of this source code which you use in your derivative 2320work must bear Comtrol's copyright notice: 2321 2322 Copyright 1994 Comtrol Corporation. 2323 2324***********************************************************************/ 2325 2326#ifndef TRUE 2327#define TRUE 1 2328#endif 2329 2330#ifndef FALSE 2331#define FALSE 0 2332#endif 2333 2334static Byte_t RData[RDATASIZE] = 2335{ 2336 0x00, 0x09, 0xf6, 0x82, 2337 0x02, 0x09, 0x86, 0xfb, 2338 0x04, 0x09, 0x00, 0x0a, 2339 0x06, 0x09, 0x01, 0x0a, 2340 0x08, 0x09, 0x8a, 0x13, 2341 0x0a, 0x09, 0xc5, 0x11, 2342 0x0c, 0x09, 0x86, 0x85, 2343 0x0e, 0x09, 0x20, 0x0a, 2344 0x10, 0x09, 0x21, 0x0a, 2345 0x12, 0x09, 0x41, 0xff, 2346 0x14, 0x09, 0x82, 0x00, 2347 0x16, 0x09, 0x82, 0x7b, 2348 0x18, 0x09, 0x8a, 0x7d, 2349 0x1a, 0x09, 0x88, 0x81, 2350 0x1c, 0x09, 0x86, 0x7a, 2351 0x1e, 0x09, 0x84, 0x81, 2352 0x20, 0x09, 0x82, 0x7c, 2353 0x22, 0x09, 0x0a, 0x0a 2354}; 2355 2356static Byte_t RRegData[RREGDATASIZE]= 2357{ 2358 0x00, 0x09, 0xf6, 0x82, /* 00: Stop Rx processor */ 2359 0x08, 0x09, 0x8a, 0x13, /* 04: Tx software flow control */ 2360 0x0a, 0x09, 0xc5, 0x11, /* 08: XON char */ 2361 0x0c, 0x09, 0x86, 0x85, /* 0c: XANY */ 2362 0x12, 0x09, 0x41, 0xff, /* 10: Rx mask char */ 2363 0x14, 0x09, 0x82, 0x00, /* 14: Compare/Ignore #0 */ 2364 0x16, 0x09, 0x82, 0x7b, /* 18: Compare #1 */ 2365 0x18, 0x09, 0x8a, 0x7d, /* 1c: Compare #2 */ 2366 0x1a, 0x09, 0x88, 0x81, /* 20: Interrupt #1 */ 2367 0x1c, 0x09, 0x86, 0x7a, /* 24: Ignore/Replace #1 */ 2368 0x1e, 0x09, 0x84, 0x81, /* 28: Interrupt #2 */ 2369 0x20, 0x09, 0x82, 0x7c, /* 2c: Ignore/Replace #2 */ 2370 0x22, 0x09, 0x0a, 0x0a /* 30: Rx FIFO Enable */ 2371}; 2372 2373CONTROLLER_T sController[CTL_SIZE] = 2374{ 2375 {-1,-1,0,0,0,0,0,0,0,0,0,{0,0,0,0},{0,0,0,0},{-1,-1,-1,-1},{0,0,0,0}}, 2376 {-1,-1,0,0,0,0,0,0,0,0,0,{0,0,0,0},{0,0,0,0},{-1,-1,-1,-1},{0,0,0,0}}, 2377 {-1,-1,0,0,0,0,0,0,0,0,0,{0,0,0,0},{0,0,0,0},{-1,-1,-1,-1},{0,0,0,0}}, 2378 {-1,-1,0,0,0,0,0,0,0,0,0,{0,0,0,0},{0,0,0,0},{-1,-1,-1,-1},{0,0,0,0}} 2379}; 2380 2381 2382Byte_t sBitMapClrTbl[8] = 2383{ 2384 0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f 2385}; 2386 2387Byte_t sBitMapSetTbl[8] = 2388{ 2389 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80 2390}; 2391 2392int sClockPrescale = 0x14; 2393 2394/*************************************************************************** 2395Function: sInitController 2396Purpose: Initialization of controller global registers and controller 2397 structure. 2398Call: sInitController(CtlP,CtlNum,MudbacIO,AiopIOList,AiopIOListSize, 2399 IRQNum,Frequency,PeriodicOnly) 2400 CONTROLLER_T *CtlP; Ptr to controller structure 2401 int CtlNum; Controller number 2402 ByteIO_t MudbacIO; Mudbac base I/O address. 2403 ByteIO_t *AiopIOList; List of I/O addresses for each AIOP. 2404 This list must be in the order the AIOPs will be found on the 2405 controller. Once an AIOP in the list is not found, it is 2406 assumed that there are no more AIOPs on the controller. 2407 int AiopIOListSize; Number of addresses in AiopIOList 2408 int IRQNum; Interrupt Request number. Can be any of the following: 2409 0: Disable global interrupts 2410 3: IRQ 3 2411 4: IRQ 4 2412 5: IRQ 5 2413 9: IRQ 9 2414 10: IRQ 10 2415 11: IRQ 11 2416 12: IRQ 12 2417 15: IRQ 15 2418 Byte_t Frequency: A flag identifying the frequency 2419 of the periodic interrupt, can be any one of the following: 2420 FREQ_DIS - periodic interrupt disabled 2421 FREQ_137HZ - 137 Hertz 2422 FREQ_69HZ - 69 Hertz 2423 FREQ_34HZ - 34 Hertz 2424 FREQ_17HZ - 17 Hertz 2425 FREQ_9HZ - 9 Hertz 2426 FREQ_4HZ - 4 Hertz 2427 If IRQNum is set to 0 the Frequency parameter is 2428 overidden, it is forced to a value of FREQ_DIS. 2429 int PeriodicOnly: TRUE if all interrupts except the periodic 2430 interrupt are to be blocked. 2431 FALSE is both the periodic interrupt and 2432 other channel interrupts are allowed. 2433 If IRQNum is set to 0 the PeriodicOnly parameter is 2434 overidden, it is forced to a value of FALSE. 2435Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller 2436 initialization failed. 2437 2438Comments: 2439 If periodic interrupts are to be disabled but AIOP interrupts 2440 are allowed, set Frequency to FREQ_DIS and PeriodicOnly to FALSE. 2441 2442 If interrupts are to be completely disabled set IRQNum to 0. 2443 2444 Setting Frequency to FREQ_DIS and PeriodicOnly to TRUE is an 2445 invalid combination. 2446 2447 This function performs initialization of global interrupt modes, 2448 but it does not actually enable global interrupts. To enable 2449 and disable global interrupts use functions sEnGlobalInt() and 2450 sDisGlobalInt(). Enabling of global interrupts is normally not 2451 done until all other initializations are complete. 2452 2453 Even if interrupts are globally enabled, they must also be 2454 individually enabled for each channel that is to generate 2455 interrupts. 2456 2457Warnings: No range checking on any of the parameters is done. 2458 2459 No context switches are allowed while executing this function. 2460 2461 After this function all AIOPs on the controller are disabled, 2462 they can be enabled with sEnAiop(). 2463*/ 2464int sInitController( CONTROLLER_T *CtlP, 2465 int CtlNum, 2466 ByteIO_t MudbacIO, 2467 ByteIO_t *AiopIOList, 2468 int AiopIOListSize, 2469 int IRQNum, 2470 Byte_t Frequency, 2471 int PeriodicOnly) 2472{ 2473 int i; 2474 ByteIO_t io; 2475 2476 CtlP->CtlNum = CtlNum; 2477 CtlP->CtlID = CTLID_0001; /* controller release 1 */ 2478 CtlP->BusType = isISA; 2479 CtlP->MBaseIO = MudbacIO; 2480 CtlP->MReg1IO = MudbacIO + 1; 2481 CtlP->MReg2IO = MudbacIO + 2; 2482 CtlP->MReg3IO = MudbacIO + 3; 2483 CtlP->MReg2 = 0; /* interrupt disable */ 2484 CtlP->MReg3 = 0; /* no periodic interrupts */ 2485 sOutB(CtlP->MReg2IO,CtlP->MReg2); 2486 sOutB(CtlP->MReg3IO,CtlP->MReg3); 2487 sControllerEOI(CtlP); /* clear EOI if warm init */ 2488 /* Init AIOPs */ 2489 CtlP->NumAiop = 0; 2490 for(i=0; i < AiopIOListSize; i++) 2491 { 2492 io = AiopIOList[i]; 2493 CtlP->AiopIO[i] = (WordIO_t)io; 2494 CtlP->AiopIntChanIO[i] = io + _INT_CHAN; 2495 sOutB(CtlP->MReg2IO,CtlP->MReg2 | (i & 0x03)); /* AIOP index */ 2496 sOutB(MudbacIO,(Byte_t)(io >> 6)); /* set up AIOP I/O in MUDBAC */ 2497 sEnAiop(CtlP,i); /* enable the AIOP */ 2498 2499 CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */ 2500 if(CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */ 2501 { 2502 sDisAiop(CtlP,i); /* disable AIOP */ 2503 break; /* done looking for AIOPs */ 2504 } 2505 2506 CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t)io); /* num channels in AIOP */ 2507 sOutW((WordIO_t)io + _INDX_ADDR,_CLK_PRE); /* clock prescaler */ 2508 sOutB(io + _INDX_DATA,sClockPrescale); 2509 CtlP->NumAiop++; /* bump count of AIOPs */ 2510 sDisAiop(CtlP,i); /* disable AIOP */ 2511 } 2512 2513 if(CtlP->NumAiop == 0) 2514 return(-1); 2515 else 2516 return(CtlP->NumAiop); 2517} 2518 2519/*************************************************************************** 2520Function: sPCIInitController 2521Purpose: Initialization of controller global registers and controller 2522 structure. 2523Call: sPCIInitController(CtlP,CtlNum,AiopIOList,AiopIOListSize, 2524 IRQNum,Frequency,PeriodicOnly) 2525 CONTROLLER_T *CtlP; Ptr to controller structure 2526 int CtlNum; Controller number 2527 ByteIO_t *AiopIOList; List of I/O addresses for each AIOP. 2528 This list must be in the order the AIOPs will be found on the 2529 controller. Once an AIOP in the list is not found, it is 2530 assumed that there are no more AIOPs on the controller. 2531 int AiopIOListSize; Number of addresses in AiopIOList 2532 int IRQNum; Interrupt Request number. Can be any of the following: 2533 0: Disable global interrupts 2534 3: IRQ 3 2535 4: IRQ 4 2536 5: IRQ 5 2537 9: IRQ 9 2538 10: IRQ 10 2539 11: IRQ 11 2540 12: IRQ 12 2541 15: IRQ 15 2542 Byte_t Frequency: A flag identifying the frequency 2543 of the periodic interrupt, can be any one of the following: 2544 FREQ_DIS - periodic interrupt disabled 2545 FREQ_137HZ - 137 Hertz 2546 FREQ_69HZ - 69 Hertz 2547 FREQ_34HZ - 34 Hertz 2548 FREQ_17HZ - 17 Hertz 2549 FREQ_9HZ - 9 Hertz 2550 FREQ_4HZ - 4 Hertz 2551 If IRQNum is set to 0 the Frequency parameter is 2552 overidden, it is forced to a value of FREQ_DIS. 2553 int PeriodicOnly: TRUE if all interrupts except the periodic 2554 interrupt are to be blocked. 2555 FALSE is both the periodic interrupt and 2556 other channel interrupts are allowed. 2557 If IRQNum is set to 0 the PeriodicOnly parameter is 2558 overidden, it is forced to a value of FALSE. 2559Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller 2560 initialization failed. 2561 2562Comments: 2563 If periodic interrupts are to be disabled but AIOP interrupts 2564 are allowed, set Frequency to FREQ_DIS and PeriodicOnly to FALSE. 2565 2566 If interrupts are to be completely disabled set IRQNum to 0. 2567 2568 Setting Frequency to FREQ_DIS and PeriodicOnly to TRUE is an 2569 invalid combination. 2570 2571 This function performs initialization of global interrupt modes, 2572 but it does not actually enable global interrupts. To enable 2573 and disable global interrupts use functions sEnGlobalInt() and 2574 sDisGlobalInt(). Enabling of global interrupts is normally not 2575 done until all other initializations are complete. 2576 2577 Even if interrupts are globally enabled, they must also be 2578 individually enabled for each channel that is to generate 2579 interrupts. 2580 2581Warnings: No range checking on any of the parameters is done. 2582 2583 No context switches are allowed while executing this function. 2584 2585 After this function all AIOPs on the controller are disabled, 2586 they can be enabled with sEnAiop(). 2587*/ 2588int sPCIInitController( CONTROLLER_T *CtlP, 2589 int CtlNum, 2590 ByteIO_t *AiopIOList, 2591 int AiopIOListSize, 2592 int IRQNum, 2593 Byte_t Frequency, 2594 int PeriodicOnly) 2595{ 2596 int i; 2597 ByteIO_t io; 2598 2599 CtlP->CtlNum = CtlNum; 2600 CtlP->CtlID = CTLID_0001; /* controller release 1 */ 2601 CtlP->BusType = isPCI; /* controller release 1 */ 2602 2603 CtlP->PCIIO = (WordIO_t)((ByteIO_t)AiopIOList[0] + _PCI_INT_FUNC); 2604 2605 sPCIControllerEOI(CtlP); /* clear EOI if warm init */ 2606 /* Init AIOPs */ 2607 CtlP->NumAiop = 0; 2608 for(i=0; i < AiopIOListSize; i++) 2609 { 2610 io = AiopIOList[i]; 2611 CtlP->AiopIO[i] = (WordIO_t)io; 2612 CtlP->AiopIntChanIO[i] = io + _INT_CHAN; 2613 2614 CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */ 2615 if(CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */ 2616 break; /* done looking for AIOPs */ 2617 2618 CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t)io); /* num channels in AIOP */ 2619 sOutW((WordIO_t)io + _INDX_ADDR,_CLK_PRE); /* clock prescaler */ 2620 sOutB(io + _INDX_DATA,sClockPrescale); 2621 CtlP->NumAiop++; /* bump count of AIOPs */ 2622 } 2623 2624 if(CtlP->NumAiop == 0) 2625 return(-1); 2626 else 2627 return(CtlP->NumAiop); 2628} 2629 2630/*************************************************************************** 2631Function: sReadAiopID 2632Purpose: Read the AIOP idenfication number directly from an AIOP. 2633Call: sReadAiopID(io) 2634 ByteIO_t io: AIOP base I/O address 2635Return: int: Flag AIOPID_XXXX if a valid AIOP is found, where X 2636 is replace by an identifying number. 2637 Flag AIOPID_NULL if no valid AIOP is found 2638Warnings: No context switches are allowed while executing this function. 2639 2640*/ 2641int sReadAiopID(ByteIO_t io) 2642{ 2643 Byte_t AiopID; /* ID byte from AIOP */ 2644 2645 sOutB(io + _CMD_REG,RESET_ALL); /* reset AIOP */ 2646 sOutB(io + _CMD_REG,0x0); 2647 AiopID = sInB(io + _CHN_STAT0) & 0x07; 2648 if(AiopID == 0x06) 2649 return(1); 2650 else /* AIOP does not exist */ 2651 return(-1); 2652} 2653 2654/*************************************************************************** 2655Function: sReadAiopNumChan 2656Purpose: Read the number of channels available in an AIOP directly from 2657 an AIOP. 2658Call: sReadAiopNumChan(io) 2659 WordIO_t io: AIOP base I/O address 2660Return: int: The number of channels available 2661Comments: The number of channels is determined by write/reads from identical 2662 offsets within the SRAM address spaces for channels 0 and 4. 2663 If the channel 4 space is mirrored to channel 0 it is a 4 channel 2664 AIOP, otherwise it is an 8 channel. 2665Warnings: No context switches are allowed while executing this function. 2666*/ 2667int sReadAiopNumChan(WordIO_t io) 2668{ 2669 Word_t x; 2670 2671 sOutDW((DWordIO_t)io + _INDX_ADDR,0x12340000L); /* write to chan 0 SRAM */ 2672 sOutW(io + _INDX_ADDR,0); /* read from SRAM, chan 0 */ 2673 x = sInW(io + _INDX_DATA); 2674 sOutW(io + _INDX_ADDR,0x4000); /* read from SRAM, chan 4 */ 2675 if(x != sInW(io + _INDX_DATA)) /* if different must be 8 chan */ 2676 return(8); 2677 else 2678 return(4); 2679} 2680 2681/*************************************************************************** 2682Function: sInitChan 2683Purpose: Initialization of a channel and channel structure 2684Call: sInitChan(CtlP,ChP,AiopNum,ChanNum) 2685 CONTROLLER_T *CtlP; Ptr to controller structure 2686 CHANNEL_T *ChP; Ptr to channel structure 2687 int AiopNum; AIOP number within controller 2688 int ChanNum; Channel number within AIOP 2689Return: int: TRUE if initialization succeeded, FALSE if it fails because channel 2690 number exceeds number of channels available in AIOP. 2691Comments: This function must be called before a channel can be used. 2692Warnings: No range checking on any of the parameters is done. 2693 2694 No context switches are allowed while executing this function. 2695*/ 2696int sInitChan( CONTROLLER_T *CtlP, 2697 CHANNEL_T *ChP, 2698 int AiopNum, 2699 int ChanNum) 2700{ 2701 int i; 2702 WordIO_t AiopIO; 2703 WordIO_t ChIOOff; 2704 Byte_t *ChR; 2705 Word_t ChOff; 2706 static Byte_t R[4]; 2707 int brd9600; 2708 2709 if(ChanNum >= CtlP->AiopNumChan[AiopNum]) 2710 return(FALSE); /* exceeds num chans in AIOP */ 2711 2712 /* Channel, AIOP, and controller identifiers */ 2713 ChP->CtlP = CtlP; 2714 ChP->ChanID = CtlP->AiopID[AiopNum]; 2715 ChP->AiopNum = AiopNum; 2716 ChP->ChanNum = ChanNum; 2717 2718 /* Global direct addresses */ 2719 AiopIO = CtlP->AiopIO[AiopNum]; 2720 ChP->Cmd = (ByteIO_t)AiopIO + _CMD_REG; 2721 ChP->IntChan = (ByteIO_t)AiopIO + _INT_CHAN; 2722 ChP->IntMask = (ByteIO_t)AiopIO + _INT_MASK; 2723 ChP->IndexAddr = (DWordIO_t)AiopIO + _INDX_ADDR; 2724 ChP->IndexData = AiopIO + _INDX_DATA; 2725 2726 /* Channel direct addresses */ 2727 ChIOOff = AiopIO + ChP->ChanNum * 2; 2728 ChP->TxRxData = ChIOOff + _TD0; 2729 ChP->ChanStat = ChIOOff + _CHN_STAT0; 2730 ChP->TxRxCount = ChIOOff + _FIFO_CNT0; 2731 ChP->IntID = (ByteIO_t)AiopIO + ChP->ChanNum + _INT_ID0; 2732 2733 /* Initialize the channel from the RData array */ 2734 for(i=0; i < RDATASIZE; i+=4) 2735 { 2736 R[0] = RData[i]; 2737 R[1] = RData[i+1] + 0x10 * ChanNum; 2738 R[2] = RData[i+2]; 2739 R[3] = RData[i+3]; 2740 sOutDW(ChP->IndexAddr,*((DWord_t *)&R[0])); 2741 } 2742 2743 ChR = ChP->R; 2744 for(i=0; i < RREGDATASIZE; i+=4) 2745 { 2746 ChR[i] = RRegData[i]; 2747 ChR[i+1] = RRegData[i+1] + 0x10 * ChanNum; 2748 ChR[i+2] = RRegData[i+2]; 2749 ChR[i+3] = RRegData[i+3]; 2750 } 2751 2752 /* Indexed registers */ 2753 ChOff = (Word_t)ChanNum * 0x1000; 2754 2755 if (sClockPrescale == 0x14) 2756 brd9600 = 47; 2757 else 2758 brd9600 = 23; 2759 2760 ChP->BaudDiv[0] = (Byte_t)(ChOff + _BAUD); 2761 ChP->BaudDiv[1] = (Byte_t)((ChOff + _BAUD) >> 8); 2762 ChP->BaudDiv[2] = (Byte_t)brd9600; 2763 ChP->BaudDiv[3] = (Byte_t)(brd9600 >> 8); 2764 sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->BaudDiv[0]); 2765 2766 ChP->TxControl[0] = (Byte_t)(ChOff + _TX_CTRL); 2767 ChP->TxControl[1] = (Byte_t)((ChOff + _TX_CTRL) >> 8); 2768 ChP->TxControl[2] = 0; 2769 ChP->TxControl[3] = 0; 2770 sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->TxControl[0]); 2771 2772 ChP->RxControl[0] = (Byte_t)(ChOff + _RX_CTRL); 2773 ChP->RxControl[1] = (Byte_t)((ChOff + _RX_CTRL) >> 8); 2774 ChP->RxControl[2] = 0; 2775 ChP->RxControl[3] = 0; 2776 sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->RxControl[0]); 2777 2778 ChP->TxEnables[0] = (Byte_t)(ChOff + _TX_ENBLS); 2779 ChP->TxEnables[1] = (Byte_t)((ChOff + _TX_ENBLS) >> 8); 2780 ChP->TxEnables[2] = 0; 2781 ChP->TxEnables[3] = 0; 2782 sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->TxEnables[0]); 2783 2784 ChP->TxCompare[0] = (Byte_t)(ChOff + _TXCMP1); 2785 ChP->TxCompare[1] = (Byte_t)((ChOff + _TXCMP1) >> 8); 2786 ChP->TxCompare[2] = 0; 2787 ChP->TxCompare[3] = 0; 2788 sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->TxCompare[0]); 2789 2790 ChP->TxReplace1[0] = (Byte_t)(ChOff + _TXREP1B1); 2791 ChP->TxReplace1[1] = (Byte_t)((ChOff + _TXREP1B1) >> 8); 2792 ChP->TxReplace1[2] = 0; 2793 ChP->TxReplace1[3] = 0; 2794 sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->TxReplace1[0]); 2795 2796 ChP->TxReplace2[0] = (Byte_t)(ChOff + _TXREP2); 2797 ChP->TxReplace2[1] = (Byte_t)((ChOff + _TXREP2) >> 8); 2798 ChP->TxReplace2[2] = 0; 2799 ChP->TxReplace2[3] = 0; 2800 sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->TxReplace2[0]); 2801 2802 ChP->TxFIFOPtrs = ChOff + _TXF_OUTP; 2803 ChP->TxFIFO = ChOff + _TX_FIFO; 2804 2805 sOutB(ChP->Cmd,(Byte_t)ChanNum | RESTXFCNT); /* apply reset Tx FIFO count */ 2806 sOutB(ChP->Cmd,(Byte_t)ChanNum); /* remove reset Tx FIFO count */ 2807 sOutW((WordIO_t)ChP->IndexAddr,ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */ 2808 sOutW(ChP->IndexData,0); 2809 ChP->RxFIFOPtrs = ChOff + _RXF_OUTP; 2810 ChP->RxFIFO = ChOff + _RX_FIFO; 2811 2812 sOutB(ChP->Cmd,(Byte_t)ChanNum | RESRXFCNT); /* apply reset Rx FIFO count */ 2813 sOutB(ChP->Cmd,(Byte_t)ChanNum); /* remove reset Rx FIFO count */ 2814 sOutW((WordIO_t)ChP->IndexAddr,ChP->RxFIFOPtrs); /* clear Rx out ptr */ 2815 sOutW(ChP->IndexData,0); 2816 sOutW((WordIO_t)ChP->IndexAddr,ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */ 2817 sOutW(ChP->IndexData,0); 2818 ChP->TxPrioCnt = ChOff + _TXP_CNT; 2819 sOutW((WordIO_t)ChP->IndexAddr,ChP->TxPrioCnt); 2820 sOutB(ChP->IndexData,0); 2821 ChP->TxPrioPtr = ChOff + _TXP_PNTR; 2822 sOutW((WordIO_t)ChP->IndexAddr,ChP->TxPrioPtr); 2823 sOutB(ChP->IndexData,0); 2824 ChP->TxPrioBuf = ChOff + _TXP_BUF; 2825 sEnRxProcessor(ChP); /* start the Rx processor */ 2826 2827 return(TRUE); 2828} 2829 2830/*************************************************************************** 2831Function: sStopRxProcessor 2832Purpose: Stop the receive processor from processing a channel. 2833Call: sStopRxProcessor(ChP) 2834 CHANNEL_T *ChP; Ptr to channel structure 2835 2836Comments: The receive processor can be started again with sStartRxProcessor(). 2837 This function causes the receive processor to skip over the 2838 stopped channel. It does not stop it from processing other channels. 2839 2840Warnings: No context switches are allowed while executing this function. 2841 2842 Do not leave the receive processor stopped for more than one 2843 character time. 2844 2845 After calling this function a delay of 4 uS is required to ensure 2846 that the receive processor is no longer processing this channel. 2847*/ 2848void sStopRxProcessor(CHANNEL_T *ChP) 2849{ 2850 Byte_t R[4]; 2851 2852 R[0] = ChP->R[0]; 2853 R[1] = ChP->R[1]; 2854 R[2] = 0x0a; 2855 R[3] = ChP->R[3]; 2856 sOutDW(ChP->IndexAddr,*(DWord_t *)&R[0]); 2857} 2858 2859/*************************************************************************** 2860Function: sFlushRxFIFO 2861Purpose: Flush the Rx FIFO 2862Call: sFlushRxFIFO(ChP) 2863 CHANNEL_T *ChP; Ptr to channel structure 2864Return: void 2865Comments: To prevent data from being enqueued or dequeued in the Tx FIFO 2866 while it is being flushed the receive processor is stopped 2867 and the transmitter is disabled. After these operations a 2868 4 uS delay is done before clearing the pointers to allow 2869 the receive processor to stop. These items are handled inside 2870 this function. 2871Warnings: No context switches are allowed while executing this function. 2872*/ 2873void sFlushRxFIFO(CHANNEL_T *ChP) 2874{ 2875 int i; 2876 Byte_t Ch; /* channel number within AIOP */ 2877 int RxFIFOEnabled; /* TRUE if Rx FIFO enabled */ 2878 2879 if(sGetRxCnt(ChP) == 0) /* Rx FIFO empty */ 2880 return; /* don't need to flush */ 2881 2882 RxFIFOEnabled = FALSE; 2883 if(ChP->R[0x32] == 0x08) /* Rx FIFO is enabled */ 2884 { 2885 RxFIFOEnabled = TRUE; 2886 sDisRxFIFO(ChP); /* disable it */ 2887 for(i=0; i < 2000/200; i++) /* delay 2 uS to allow proc to disable FIFO*/ 2888 sInB(ChP->IntChan); /* depends on bus i/o timing */ 2889 } 2890 sGetChanStatus(ChP); /* clear any pending Rx errors in chan stat */ 2891 Ch = (Byte_t)sGetChanNum(ChP); 2892 sOutB(ChP->Cmd,Ch | RESRXFCNT); /* apply reset Rx FIFO count */ 2893 sOutB(ChP->Cmd,Ch); /* remove reset Rx FIFO count */ 2894 sOutW((WordIO_t)ChP->IndexAddr,ChP->RxFIFOPtrs); /* clear Rx out ptr */ 2895 sOutW(ChP->IndexData,0); 2896 sOutW((WordIO_t)ChP->IndexAddr,ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */ 2897 sOutW(ChP->IndexData,0); 2898 if(RxFIFOEnabled) 2899 sEnRxFIFO(ChP); /* enable Rx FIFO */ 2900} 2901 2902/*************************************************************************** 2903Function: sFlushTxFIFO 2904Purpose: Flush the Tx FIFO 2905Call: sFlushTxFIFO(ChP) 2906 CHANNEL_T *ChP; Ptr to channel structure 2907Return: void 2908Comments: To prevent data from being enqueued or dequeued in the Tx FIFO 2909 while it is being flushed the receive processor is stopped 2910 and the transmitter is disabled. After these operations a 2911 4 uS delay is done before clearing the pointers to allow 2912 the receive processor to stop. These items are handled inside 2913 this function. 2914Warnings: No context switches are allowed while executing this function. 2915*/ 2916void sFlushTxFIFO(CHANNEL_T *ChP) 2917{ 2918 int i; 2919 Byte_t Ch; /* channel number within AIOP */ 2920 int TxEnabled; /* TRUE if transmitter enabled */ 2921 2922 if(sGetTxCnt(ChP) == 0) /* Tx FIFO empty */ 2923 return; /* don't need to flush */ 2924 2925 TxEnabled = FALSE; 2926 if(ChP->TxControl[3] & TX_ENABLE) 2927 { 2928 TxEnabled = TRUE; 2929 sDisTransmit(ChP); /* disable transmitter */ 2930 } 2931 sStopRxProcessor(ChP); /* stop Rx processor */ 2932 for(i = 0; i < 4000/200; i++) /* delay 4 uS to allow proc to stop */ 2933 sInB(ChP->IntChan); /* depends on bus i/o timing */ 2934 Ch = (Byte_t)sGetChanNum(ChP); 2935 sOutB(ChP->Cmd,Ch | RESTXFCNT); /* apply reset Tx FIFO count */ 2936 sOutB(ChP->Cmd,Ch); /* remove reset Tx FIFO count */ 2937 sOutW((WordIO_t)ChP->IndexAddr,ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */ 2938 sOutW(ChP->IndexData,0); 2939 if(TxEnabled) 2940 sEnTransmit(ChP); /* enable transmitter */ 2941 sStartRxProcessor(ChP); /* restart Rx processor */ 2942} 2943 2944/*************************************************************************** 2945Function: sWriteTxPrioByte 2946Purpose: Write a byte of priority transmit data to a channel 2947Call: sWriteTxPrioByte(ChP,Data) 2948 CHANNEL_T *ChP; Ptr to channel structure 2949 Byte_t Data; The transmit data byte 2950 2951Return: int: 1 if the bytes is successfully written, otherwise 0. 2952 2953Comments: The priority byte is transmitted before any data in the Tx FIFO. 2954 2955Warnings: No context switches are allowed while executing this function. 2956*/ 2957int sWriteTxPrioByte(CHANNEL_T *ChP, Byte_t Data) 2958{ 2959 Byte_t DWBuf[4]; /* buffer for double word writes */ 2960 Word_t *WordPtr; /* must be far because Win SS != DS */ 2961 register DWordIO_t IndexAddr; 2962 2963 if(sGetTxCnt(ChP) > 1) /* write it to Tx priority buffer */ 2964 { 2965 IndexAddr = ChP->IndexAddr; 2966 sOutW((WordIO_t)IndexAddr,ChP->TxPrioCnt); /* get priority buffer status */ 2967 if(sInB((ByteIO_t)ChP->IndexData) & PRI_PEND) /* priority buffer busy */ 2968 return(0); /* nothing sent */ 2969 2970 WordPtr = (Word_t *)(&DWBuf[0]); 2971 *WordPtr = ChP->TxPrioBuf; /* data byte address */ 2972 2973 DWBuf[2] = Data; /* data byte value */ 2974 sOutDW(IndexAddr,*((DWord_t *)(&DWBuf[0]))); /* write it out */ 2975 2976 *WordPtr = ChP->TxPrioCnt; /* Tx priority count address */ 2977 2978 DWBuf[2] = PRI_PEND + 1; /* indicate 1 byte pending */ 2979 DWBuf[3] = 0; /* priority buffer pointer */ 2980 sOutDW(IndexAddr,*((DWord_t *)(&DWBuf[0]))); /* write it out */ 2981 } 2982 else /* write it to Tx FIFO */ 2983 { 2984 sWriteTxByte(sGetTxRxDataIO(ChP),Data); 2985 } 2986 return(1); /* 1 byte sent */ 2987} 2988 2989/*************************************************************************** 2990Function: sEnInterrupts 2991Purpose: Enable one or more interrupts for a channel 2992Call: sEnInterrupts(ChP,Flags) 2993 CHANNEL_T *ChP; Ptr to channel structure 2994 Word_t Flags: Interrupt enable flags, can be any combination 2995 of the following flags: 2996 TXINT_EN: Interrupt on Tx FIFO empty 2997 RXINT_EN: Interrupt on Rx FIFO at trigger level (see 2998 sSetRxTrigger()) 2999 SRCINT_EN: Interrupt on SRC (Special Rx Condition) 3000 MCINT_EN: Interrupt on modem input change 3001 CHANINT_EN: Allow channel interrupt signal to the AIOP's 3002 Interrupt Channel Register. 3003Return: void 3004Comments: If an interrupt enable flag is set in Flags, that interrupt will be 3005 enabled. If an interrupt enable flag is not set in Flags, that 3006 interrupt will not be changed. Interrupts can be disabled with 3007 function sDisInterrupts(). 3008 3009 This function sets the appropriate bit for the channel in the AIOP's 3010 Interrupt Mask Register if the CHANINT_EN flag is set. This allows 3011 this channel's bit to be set in the AIOP's Interrupt Channel Register. 3012 3013 Interrupts must also be globally enabled before channel interrupts 3014 will be passed on to the host. This is done with function 3015 sEnGlobalInt(). 3016 3017 In some cases it may be desirable to disable interrupts globally but 3018 enable channel interrupts. This would allow the global interrupt 3019 status register to be used to determine which AIOPs need service. 3020*/ 3021void sEnInterrupts(CHANNEL_T *ChP,Word_t Flags) 3022{ 3023 Byte_t Mask; /* Interrupt Mask Register */ 3024 3025 ChP->RxControl[2] |= 3026 ((Byte_t)Flags & (RXINT_EN | SRCINT_EN | MCINT_EN)); 3027 3028 sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->RxControl[0]); 3029 3030 ChP->TxControl[2] |= ((Byte_t)Flags & TXINT_EN); 3031 3032 sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->TxControl[0]); 3033 3034 if(Flags & CHANINT_EN) 3035 { 3036 Mask = sInB(ChP->IntMask) | sBitMapSetTbl[ChP->ChanNum]; 3037 sOutB(ChP->IntMask,Mask); 3038 } 3039} 3040 3041/*************************************************************************** 3042Function: sDisInterrupts 3043Purpose: Disable one or more interrupts for a channel 3044Call: sDisInterrupts(ChP,Flags) 3045 CHANNEL_T *ChP; Ptr to channel structure 3046 Word_t Flags: Interrupt flags, can be any combination 3047 of the following flags: 3048 TXINT_EN: Interrupt on Tx FIFO empty 3049 RXINT_EN: Interrupt on Rx FIFO at trigger level (see 3050 sSetRxTrigger()) 3051 SRCINT_EN: Interrupt on SRC (Special Rx Condition) 3052 MCINT_EN: Interrupt on modem input change 3053 CHANINT_EN: Disable channel interrupt signal to the 3054 AIOP's Interrupt Channel Register. 3055Return: void 3056Comments: If an interrupt flag is set in Flags, that interrupt will be 3057 disabled. If an interrupt flag is not set in Flags, that 3058 interrupt will not be changed. Interrupts can be enabled with 3059 function sEnInterrupts(). 3060 3061 This function clears the appropriate bit for the channel in the AIOP's 3062 Interrupt Mask Register if the CHANINT_EN flag is set. This blocks 3063 this channel's bit from being set in the AIOP's Interrupt Channel 3064 Register. 3065*/ 3066void sDisInterrupts(CHANNEL_T *ChP,Word_t Flags) 3067{ 3068 Byte_t Mask; /* Interrupt Mask Register */ 3069 3070 ChP->RxControl[2] &= 3071 ~((Byte_t)Flags & (RXINT_EN | SRCINT_EN | MCINT_EN)); 3072 sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->RxControl[0]); 3073 ChP->TxControl[2] &= ~((Byte_t)Flags & TXINT_EN); 3074 sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->TxControl[0]); 3075 3076 if(Flags & CHANINT_EN) 3077 { 3078 Mask = sInB(ChP->IntMask) & sBitMapClrTbl[ChP->ChanNum]; 3079 sOutB(ChP->IntMask,Mask); 3080 } 3081} 3082