18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * RocketPort device driver for Linux 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Written by Theodore Ts'o, 1995, 1996, 1997, 1998, 1999, 2000. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2003 by Comtrol, Inc. 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci/* 118c2ecf20Sopenharmony_ci * Kernel Synchronization: 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * This driver has 2 kernel control paths - exception handlers (calls into the driver 148c2ecf20Sopenharmony_ci * from user mode) and the timer bottom half (tasklet). This is a polled driver, interrupts 158c2ecf20Sopenharmony_ci * are not used. 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * Critical data: 188c2ecf20Sopenharmony_ci * - rp_table[], accessed through passed "info" pointers, is a global (static) array of 198c2ecf20Sopenharmony_ci * serial port state information and the xmit_buf circular buffer. Protected by 208c2ecf20Sopenharmony_ci * a per port spinlock. 218c2ecf20Sopenharmony_ci * - xmit_flags[], an array of ints indexed by line (port) number, indicating that there 228c2ecf20Sopenharmony_ci * is data to be transmitted. Protected by atomic bit operations. 238c2ecf20Sopenharmony_ci * - rp_num_ports, int indicating number of open ports, protected by atomic operations. 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * rp_write() and rp_write_char() functions use a per port semaphore to protect against 268c2ecf20Sopenharmony_ci * simultaneous access to the same port by more than one process. 278c2ecf20Sopenharmony_ci */ 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci/****** Defines ******/ 308c2ecf20Sopenharmony_ci#define ROCKET_PARANOIA_CHECK 318c2ecf20Sopenharmony_ci#define ROCKET_DISABLE_SIMUSAGE 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#undef ROCKET_SOFT_FLOW 348c2ecf20Sopenharmony_ci#undef ROCKET_DEBUG_OPEN 358c2ecf20Sopenharmony_ci#undef ROCKET_DEBUG_INTR 368c2ecf20Sopenharmony_ci#undef ROCKET_DEBUG_WRITE 378c2ecf20Sopenharmony_ci#undef ROCKET_DEBUG_FLOW 388c2ecf20Sopenharmony_ci#undef ROCKET_DEBUG_THROTTLE 398c2ecf20Sopenharmony_ci#undef ROCKET_DEBUG_WAIT_UNTIL_SENT 408c2ecf20Sopenharmony_ci#undef ROCKET_DEBUG_RECEIVE 418c2ecf20Sopenharmony_ci#undef ROCKET_DEBUG_HANGUP 428c2ecf20Sopenharmony_ci#undef REV_PCI_ORDER 438c2ecf20Sopenharmony_ci#undef ROCKET_DEBUG_IO 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#define POLL_PERIOD (HZ/100) /* Polling period .01 seconds (10ms) */ 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/****** Kernel includes ******/ 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#include <linux/module.h> 508c2ecf20Sopenharmony_ci#include <linux/errno.h> 518c2ecf20Sopenharmony_ci#include <linux/major.h> 528c2ecf20Sopenharmony_ci#include <linux/kernel.h> 538c2ecf20Sopenharmony_ci#include <linux/signal.h> 548c2ecf20Sopenharmony_ci#include <linux/slab.h> 558c2ecf20Sopenharmony_ci#include <linux/mm.h> 568c2ecf20Sopenharmony_ci#include <linux/sched.h> 578c2ecf20Sopenharmony_ci#include <linux/timer.h> 588c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 598c2ecf20Sopenharmony_ci#include <linux/tty.h> 608c2ecf20Sopenharmony_ci#include <linux/tty_driver.h> 618c2ecf20Sopenharmony_ci#include <linux/tty_flip.h> 628c2ecf20Sopenharmony_ci#include <linux/serial.h> 638c2ecf20Sopenharmony_ci#include <linux/string.h> 648c2ecf20Sopenharmony_ci#include <linux/fcntl.h> 658c2ecf20Sopenharmony_ci#include <linux/ptrace.h> 668c2ecf20Sopenharmony_ci#include <linux/mutex.h> 678c2ecf20Sopenharmony_ci#include <linux/ioport.h> 688c2ecf20Sopenharmony_ci#include <linux/delay.h> 698c2ecf20Sopenharmony_ci#include <linux/completion.h> 708c2ecf20Sopenharmony_ci#include <linux/wait.h> 718c2ecf20Sopenharmony_ci#include <linux/pci.h> 728c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 738c2ecf20Sopenharmony_ci#include <linux/atomic.h> 748c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 758c2ecf20Sopenharmony_ci#include <linux/bitops.h> 768c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 778c2ecf20Sopenharmony_ci#include <linux/init.h> 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci/****** RocketPort includes ******/ 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci#include "rocket_int.h" 828c2ecf20Sopenharmony_ci#include "rocket.h" 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci#define ROCKET_VERSION "2.09" 858c2ecf20Sopenharmony_ci#define ROCKET_DATE "12-June-2003" 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci/****** RocketPort Local Variables ******/ 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic void rp_do_poll(struct timer_list *unused); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic struct tty_driver *rocket_driver; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic struct rocket_version driver_version = { 948c2ecf20Sopenharmony_ci ROCKET_VERSION, ROCKET_DATE 958c2ecf20Sopenharmony_ci}; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic struct r_port *rp_table[MAX_RP_PORTS]; /* The main repository of serial port state information. */ 988c2ecf20Sopenharmony_cistatic unsigned int xmit_flags[NUM_BOARDS]; /* Bit significant, indicates port had data to transmit. */ 998c2ecf20Sopenharmony_ci /* eg. Bit 0 indicates port 0 has xmit data, ... */ 1008c2ecf20Sopenharmony_cistatic atomic_t rp_num_ports_open; /* Number of serial ports open */ 1018c2ecf20Sopenharmony_cistatic DEFINE_TIMER(rocket_timer, rp_do_poll); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic unsigned long board1; /* ISA addresses, retrieved from rocketport.conf */ 1048c2ecf20Sopenharmony_cistatic unsigned long board2; 1058c2ecf20Sopenharmony_cistatic unsigned long board3; 1068c2ecf20Sopenharmony_cistatic unsigned long board4; 1078c2ecf20Sopenharmony_cistatic unsigned long controller; 1088c2ecf20Sopenharmony_cistatic bool support_low_speed; 1098c2ecf20Sopenharmony_cistatic unsigned long modem1; 1108c2ecf20Sopenharmony_cistatic unsigned long modem2; 1118c2ecf20Sopenharmony_cistatic unsigned long modem3; 1128c2ecf20Sopenharmony_cistatic unsigned long modem4; 1138c2ecf20Sopenharmony_cistatic unsigned long pc104_1[8]; 1148c2ecf20Sopenharmony_cistatic unsigned long pc104_2[8]; 1158c2ecf20Sopenharmony_cistatic unsigned long pc104_3[8]; 1168c2ecf20Sopenharmony_cistatic unsigned long pc104_4[8]; 1178c2ecf20Sopenharmony_cistatic unsigned long *pc104[4] = { pc104_1, pc104_2, pc104_3, pc104_4 }; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cistatic int rp_baud_base[NUM_BOARDS]; /* Board config info (Someday make a per-board structure) */ 1208c2ecf20Sopenharmony_cistatic unsigned long rcktpt_io_addr[NUM_BOARDS]; 1218c2ecf20Sopenharmony_cistatic int rcktpt_type[NUM_BOARDS]; 1228c2ecf20Sopenharmony_cistatic int is_PCI[NUM_BOARDS]; 1238c2ecf20Sopenharmony_cistatic rocketModel_t rocketModel[NUM_BOARDS]; 1248c2ecf20Sopenharmony_cistatic int max_board; 1258c2ecf20Sopenharmony_cistatic const struct tty_port_operations rocket_port_ops; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci/* 1288c2ecf20Sopenharmony_ci * The following arrays define the interrupt bits corresponding to each AIOP. 1298c2ecf20Sopenharmony_ci * These bits are different between the ISA and regular PCI boards and the 1308c2ecf20Sopenharmony_ci * Universal PCI boards. 1318c2ecf20Sopenharmony_ci */ 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistatic Word_t aiop_intr_bits[AIOP_CTL_SIZE] = { 1348c2ecf20Sopenharmony_ci AIOP_INTR_BIT_0, 1358c2ecf20Sopenharmony_ci AIOP_INTR_BIT_1, 1368c2ecf20Sopenharmony_ci AIOP_INTR_BIT_2, 1378c2ecf20Sopenharmony_ci AIOP_INTR_BIT_3 1388c2ecf20Sopenharmony_ci}; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 1418c2ecf20Sopenharmony_cistatic Word_t upci_aiop_intr_bits[AIOP_CTL_SIZE] = { 1428c2ecf20Sopenharmony_ci UPCI_AIOP_INTR_BIT_0, 1438c2ecf20Sopenharmony_ci UPCI_AIOP_INTR_BIT_1, 1448c2ecf20Sopenharmony_ci UPCI_AIOP_INTR_BIT_2, 1458c2ecf20Sopenharmony_ci UPCI_AIOP_INTR_BIT_3 1468c2ecf20Sopenharmony_ci}; 1478c2ecf20Sopenharmony_ci#endif 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic Byte_t RData[RDATASIZE] = { 1508c2ecf20Sopenharmony_ci 0x00, 0x09, 0xf6, 0x82, 1518c2ecf20Sopenharmony_ci 0x02, 0x09, 0x86, 0xfb, 1528c2ecf20Sopenharmony_ci 0x04, 0x09, 0x00, 0x0a, 1538c2ecf20Sopenharmony_ci 0x06, 0x09, 0x01, 0x0a, 1548c2ecf20Sopenharmony_ci 0x08, 0x09, 0x8a, 0x13, 1558c2ecf20Sopenharmony_ci 0x0a, 0x09, 0xc5, 0x11, 1568c2ecf20Sopenharmony_ci 0x0c, 0x09, 0x86, 0x85, 1578c2ecf20Sopenharmony_ci 0x0e, 0x09, 0x20, 0x0a, 1588c2ecf20Sopenharmony_ci 0x10, 0x09, 0x21, 0x0a, 1598c2ecf20Sopenharmony_ci 0x12, 0x09, 0x41, 0xff, 1608c2ecf20Sopenharmony_ci 0x14, 0x09, 0x82, 0x00, 1618c2ecf20Sopenharmony_ci 0x16, 0x09, 0x82, 0x7b, 1628c2ecf20Sopenharmony_ci 0x18, 0x09, 0x8a, 0x7d, 1638c2ecf20Sopenharmony_ci 0x1a, 0x09, 0x88, 0x81, 1648c2ecf20Sopenharmony_ci 0x1c, 0x09, 0x86, 0x7a, 1658c2ecf20Sopenharmony_ci 0x1e, 0x09, 0x84, 0x81, 1668c2ecf20Sopenharmony_ci 0x20, 0x09, 0x82, 0x7c, 1678c2ecf20Sopenharmony_ci 0x22, 0x09, 0x0a, 0x0a 1688c2ecf20Sopenharmony_ci}; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic Byte_t RRegData[RREGDATASIZE] = { 1718c2ecf20Sopenharmony_ci 0x00, 0x09, 0xf6, 0x82, /* 00: Stop Rx processor */ 1728c2ecf20Sopenharmony_ci 0x08, 0x09, 0x8a, 0x13, /* 04: Tx software flow control */ 1738c2ecf20Sopenharmony_ci 0x0a, 0x09, 0xc5, 0x11, /* 08: XON char */ 1748c2ecf20Sopenharmony_ci 0x0c, 0x09, 0x86, 0x85, /* 0c: XANY */ 1758c2ecf20Sopenharmony_ci 0x12, 0x09, 0x41, 0xff, /* 10: Rx mask char */ 1768c2ecf20Sopenharmony_ci 0x14, 0x09, 0x82, 0x00, /* 14: Compare/Ignore #0 */ 1778c2ecf20Sopenharmony_ci 0x16, 0x09, 0x82, 0x7b, /* 18: Compare #1 */ 1788c2ecf20Sopenharmony_ci 0x18, 0x09, 0x8a, 0x7d, /* 1c: Compare #2 */ 1798c2ecf20Sopenharmony_ci 0x1a, 0x09, 0x88, 0x81, /* 20: Interrupt #1 */ 1808c2ecf20Sopenharmony_ci 0x1c, 0x09, 0x86, 0x7a, /* 24: Ignore/Replace #1 */ 1818c2ecf20Sopenharmony_ci 0x1e, 0x09, 0x84, 0x81, /* 28: Interrupt #2 */ 1828c2ecf20Sopenharmony_ci 0x20, 0x09, 0x82, 0x7c, /* 2c: Ignore/Replace #2 */ 1838c2ecf20Sopenharmony_ci 0x22, 0x09, 0x0a, 0x0a /* 30: Rx FIFO Enable */ 1848c2ecf20Sopenharmony_ci}; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistatic CONTROLLER_T sController[CTL_SIZE] = { 1878c2ecf20Sopenharmony_ci {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, 1888c2ecf20Sopenharmony_ci {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}, 1898c2ecf20Sopenharmony_ci {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, 1908c2ecf20Sopenharmony_ci {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}, 1918c2ecf20Sopenharmony_ci {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, 1928c2ecf20Sopenharmony_ci {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}, 1938c2ecf20Sopenharmony_ci {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, 1948c2ecf20Sopenharmony_ci {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}} 1958c2ecf20Sopenharmony_ci}; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cistatic Byte_t sBitMapClrTbl[8] = { 1988c2ecf20Sopenharmony_ci 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f 1998c2ecf20Sopenharmony_ci}; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic Byte_t sBitMapSetTbl[8] = { 2028c2ecf20Sopenharmony_ci 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 2038c2ecf20Sopenharmony_ci}; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistatic int sClockPrescale = 0x14; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci/* 2088c2ecf20Sopenharmony_ci * Line number is the ttySIx number (x), the Minor number. We 2098c2ecf20Sopenharmony_ci * assign them sequentially, starting at zero. The following 2108c2ecf20Sopenharmony_ci * array keeps track of the line number assigned to a given board/aiop/channel. 2118c2ecf20Sopenharmony_ci */ 2128c2ecf20Sopenharmony_cistatic unsigned char lineNumbers[MAX_RP_PORTS]; 2138c2ecf20Sopenharmony_cistatic unsigned long nextLineNumber; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci/***** RocketPort Static Prototypes *********/ 2168c2ecf20Sopenharmony_cistatic int __init init_ISA(int i); 2178c2ecf20Sopenharmony_cistatic void rp_wait_until_sent(struct tty_struct *tty, int timeout); 2188c2ecf20Sopenharmony_cistatic void rp_flush_buffer(struct tty_struct *tty); 2198c2ecf20Sopenharmony_cistatic unsigned char GetLineNumber(int ctrl, int aiop, int ch); 2208c2ecf20Sopenharmony_cistatic unsigned char SetLineNumber(int ctrl, int aiop, int ch); 2218c2ecf20Sopenharmony_cistatic void rp_start(struct tty_struct *tty); 2228c2ecf20Sopenharmony_cistatic int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum, 2238c2ecf20Sopenharmony_ci int ChanNum); 2248c2ecf20Sopenharmony_cistatic void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode); 2258c2ecf20Sopenharmony_cistatic void sFlushRxFIFO(CHANNEL_T * ChP); 2268c2ecf20Sopenharmony_cistatic void sFlushTxFIFO(CHANNEL_T * ChP); 2278c2ecf20Sopenharmony_cistatic void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags); 2288c2ecf20Sopenharmony_cistatic void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags); 2298c2ecf20Sopenharmony_cistatic void sModemReset(CONTROLLER_T * CtlP, int chan, int on); 2308c2ecf20Sopenharmony_cistatic void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on); 2318c2ecf20Sopenharmony_cistatic int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data); 2328c2ecf20Sopenharmony_cistatic int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO, 2338c2ecf20Sopenharmony_ci ByteIO_t * AiopIOList, int AiopIOListSize, 2348c2ecf20Sopenharmony_ci int IRQNum, Byte_t Frequency, int PeriodicOnly); 2358c2ecf20Sopenharmony_cistatic int sReadAiopID(ByteIO_t io); 2368c2ecf20Sopenharmony_cistatic int sReadAiopNumChan(WordIO_t io); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ciMODULE_AUTHOR("Theodore Ts'o"); 2398c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Comtrol RocketPort driver"); 2408c2ecf20Sopenharmony_cimodule_param_hw(board1, ulong, ioport, 0); 2418c2ecf20Sopenharmony_ciMODULE_PARM_DESC(board1, "I/O port for (ISA) board #1"); 2428c2ecf20Sopenharmony_cimodule_param_hw(board2, ulong, ioport, 0); 2438c2ecf20Sopenharmony_ciMODULE_PARM_DESC(board2, "I/O port for (ISA) board #2"); 2448c2ecf20Sopenharmony_cimodule_param_hw(board3, ulong, ioport, 0); 2458c2ecf20Sopenharmony_ciMODULE_PARM_DESC(board3, "I/O port for (ISA) board #3"); 2468c2ecf20Sopenharmony_cimodule_param_hw(board4, ulong, ioport, 0); 2478c2ecf20Sopenharmony_ciMODULE_PARM_DESC(board4, "I/O port for (ISA) board #4"); 2488c2ecf20Sopenharmony_cimodule_param_hw(controller, ulong, ioport, 0); 2498c2ecf20Sopenharmony_ciMODULE_PARM_DESC(controller, "I/O port for (ISA) rocketport controller"); 2508c2ecf20Sopenharmony_cimodule_param(support_low_speed, bool, 0); 2518c2ecf20Sopenharmony_ciMODULE_PARM_DESC(support_low_speed, "1 means support 50 baud, 0 means support 460400 baud"); 2528c2ecf20Sopenharmony_cimodule_param(modem1, ulong, 0); 2538c2ecf20Sopenharmony_ciMODULE_PARM_DESC(modem1, "1 means (ISA) board #1 is a RocketModem"); 2548c2ecf20Sopenharmony_cimodule_param(modem2, ulong, 0); 2558c2ecf20Sopenharmony_ciMODULE_PARM_DESC(modem2, "1 means (ISA) board #2 is a RocketModem"); 2568c2ecf20Sopenharmony_cimodule_param(modem3, ulong, 0); 2578c2ecf20Sopenharmony_ciMODULE_PARM_DESC(modem3, "1 means (ISA) board #3 is a RocketModem"); 2588c2ecf20Sopenharmony_cimodule_param(modem4, ulong, 0); 2598c2ecf20Sopenharmony_ciMODULE_PARM_DESC(modem4, "1 means (ISA) board #4 is a RocketModem"); 2608c2ecf20Sopenharmony_cimodule_param_array(pc104_1, ulong, NULL, 0); 2618c2ecf20Sopenharmony_ciMODULE_PARM_DESC(pc104_1, "set interface types for ISA(PC104) board #1 (e.g. pc104_1=232,232,485,485,..."); 2628c2ecf20Sopenharmony_cimodule_param_array(pc104_2, ulong, NULL, 0); 2638c2ecf20Sopenharmony_ciMODULE_PARM_DESC(pc104_2, "set interface types for ISA(PC104) board #2 (e.g. pc104_2=232,232,485,485,..."); 2648c2ecf20Sopenharmony_cimodule_param_array(pc104_3, ulong, NULL, 0); 2658c2ecf20Sopenharmony_ciMODULE_PARM_DESC(pc104_3, "set interface types for ISA(PC104) board #3 (e.g. pc104_3=232,232,485,485,..."); 2668c2ecf20Sopenharmony_cimodule_param_array(pc104_4, ulong, NULL, 0); 2678c2ecf20Sopenharmony_ciMODULE_PARM_DESC(pc104_4, "set interface types for ISA(PC104) board #4 (e.g. pc104_4=232,232,485,485,..."); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cistatic int __init rp_init(void); 2708c2ecf20Sopenharmony_cistatic void rp_cleanup_module(void); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_cimodule_init(rp_init); 2738c2ecf20Sopenharmony_cimodule_exit(rp_cleanup_module); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci/*************************************************************************/ 2798c2ecf20Sopenharmony_ci/* Module code starts here */ 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cistatic inline int rocket_paranoia_check(struct r_port *info, 2828c2ecf20Sopenharmony_ci const char *routine) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci#ifdef ROCKET_PARANOIA_CHECK 2858c2ecf20Sopenharmony_ci if (!info) 2868c2ecf20Sopenharmony_ci return 1; 2878c2ecf20Sopenharmony_ci if (info->magic != RPORT_MAGIC) { 2888c2ecf20Sopenharmony_ci printk(KERN_WARNING "Warning: bad magic number for rocketport " 2898c2ecf20Sopenharmony_ci "struct in %s\n", routine); 2908c2ecf20Sopenharmony_ci return 1; 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci#endif 2938c2ecf20Sopenharmony_ci return 0; 2948c2ecf20Sopenharmony_ci} 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci/* Serial port receive data function. Called (from timer poll) when an AIOPIC signals 2988c2ecf20Sopenharmony_ci * that receive data is present on a serial port. Pulls data from FIFO, moves it into the 2998c2ecf20Sopenharmony_ci * tty layer. 3008c2ecf20Sopenharmony_ci */ 3018c2ecf20Sopenharmony_cistatic void rp_do_receive(struct r_port *info, CHANNEL_t *cp, 3028c2ecf20Sopenharmony_ci unsigned int ChanStatus) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci unsigned int CharNStat; 3058c2ecf20Sopenharmony_ci int ToRecv, wRecv, space; 3068c2ecf20Sopenharmony_ci unsigned char *cbuf; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci ToRecv = sGetRxCnt(cp); 3098c2ecf20Sopenharmony_ci#ifdef ROCKET_DEBUG_INTR 3108c2ecf20Sopenharmony_ci printk(KERN_INFO "rp_do_receive(%d)...\n", ToRecv); 3118c2ecf20Sopenharmony_ci#endif 3128c2ecf20Sopenharmony_ci if (ToRecv == 0) 3138c2ecf20Sopenharmony_ci return; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci /* 3168c2ecf20Sopenharmony_ci * if status indicates there are errored characters in the 3178c2ecf20Sopenharmony_ci * FIFO, then enter status mode (a word in FIFO holds 3188c2ecf20Sopenharmony_ci * character and status). 3198c2ecf20Sopenharmony_ci */ 3208c2ecf20Sopenharmony_ci if (ChanStatus & (RXFOVERFL | RXBREAK | RXFRAME | RXPARITY)) { 3218c2ecf20Sopenharmony_ci if (!(ChanStatus & STATMODE)) { 3228c2ecf20Sopenharmony_ci#ifdef ROCKET_DEBUG_RECEIVE 3238c2ecf20Sopenharmony_ci printk(KERN_INFO "Entering STATMODE...\n"); 3248c2ecf20Sopenharmony_ci#endif 3258c2ecf20Sopenharmony_ci ChanStatus |= STATMODE; 3268c2ecf20Sopenharmony_ci sEnRxStatusMode(cp); 3278c2ecf20Sopenharmony_ci } 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci /* 3318c2ecf20Sopenharmony_ci * if we previously entered status mode, then read down the 3328c2ecf20Sopenharmony_ci * FIFO one word at a time, pulling apart the character and 3338c2ecf20Sopenharmony_ci * the status. Update error counters depending on status 3348c2ecf20Sopenharmony_ci */ 3358c2ecf20Sopenharmony_ci if (ChanStatus & STATMODE) { 3368c2ecf20Sopenharmony_ci#ifdef ROCKET_DEBUG_RECEIVE 3378c2ecf20Sopenharmony_ci printk(KERN_INFO "Ignore %x, read %x...\n", 3388c2ecf20Sopenharmony_ci info->ignore_status_mask, info->read_status_mask); 3398c2ecf20Sopenharmony_ci#endif 3408c2ecf20Sopenharmony_ci while (ToRecv) { 3418c2ecf20Sopenharmony_ci char flag; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci CharNStat = sInW(sGetTxRxDataIO(cp)); 3448c2ecf20Sopenharmony_ci#ifdef ROCKET_DEBUG_RECEIVE 3458c2ecf20Sopenharmony_ci printk(KERN_INFO "%x...\n", CharNStat); 3468c2ecf20Sopenharmony_ci#endif 3478c2ecf20Sopenharmony_ci if (CharNStat & STMBREAKH) 3488c2ecf20Sopenharmony_ci CharNStat &= ~(STMFRAMEH | STMPARITYH); 3498c2ecf20Sopenharmony_ci if (CharNStat & info->ignore_status_mask) { 3508c2ecf20Sopenharmony_ci ToRecv--; 3518c2ecf20Sopenharmony_ci continue; 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci CharNStat &= info->read_status_mask; 3548c2ecf20Sopenharmony_ci if (CharNStat & STMBREAKH) 3558c2ecf20Sopenharmony_ci flag = TTY_BREAK; 3568c2ecf20Sopenharmony_ci else if (CharNStat & STMPARITYH) 3578c2ecf20Sopenharmony_ci flag = TTY_PARITY; 3588c2ecf20Sopenharmony_ci else if (CharNStat & STMFRAMEH) 3598c2ecf20Sopenharmony_ci flag = TTY_FRAME; 3608c2ecf20Sopenharmony_ci else if (CharNStat & STMRCVROVRH) 3618c2ecf20Sopenharmony_ci flag = TTY_OVERRUN; 3628c2ecf20Sopenharmony_ci else 3638c2ecf20Sopenharmony_ci flag = TTY_NORMAL; 3648c2ecf20Sopenharmony_ci tty_insert_flip_char(&info->port, CharNStat & 0xff, 3658c2ecf20Sopenharmony_ci flag); 3668c2ecf20Sopenharmony_ci ToRecv--; 3678c2ecf20Sopenharmony_ci } 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci /* 3708c2ecf20Sopenharmony_ci * after we've emptied the FIFO in status mode, turn 3718c2ecf20Sopenharmony_ci * status mode back off 3728c2ecf20Sopenharmony_ci */ 3738c2ecf20Sopenharmony_ci if (sGetRxCnt(cp) == 0) { 3748c2ecf20Sopenharmony_ci#ifdef ROCKET_DEBUG_RECEIVE 3758c2ecf20Sopenharmony_ci printk(KERN_INFO "Status mode off.\n"); 3768c2ecf20Sopenharmony_ci#endif 3778c2ecf20Sopenharmony_ci sDisRxStatusMode(cp); 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci } else { 3808c2ecf20Sopenharmony_ci /* 3818c2ecf20Sopenharmony_ci * we aren't in status mode, so read down the FIFO two 3828c2ecf20Sopenharmony_ci * characters at time by doing repeated word IO 3838c2ecf20Sopenharmony_ci * transfer. 3848c2ecf20Sopenharmony_ci */ 3858c2ecf20Sopenharmony_ci space = tty_prepare_flip_string(&info->port, &cbuf, ToRecv); 3868c2ecf20Sopenharmony_ci if (space < ToRecv) { 3878c2ecf20Sopenharmony_ci#ifdef ROCKET_DEBUG_RECEIVE 3888c2ecf20Sopenharmony_ci printk(KERN_INFO "rp_do_receive:insufficient space ToRecv=%d space=%d\n", ToRecv, space); 3898c2ecf20Sopenharmony_ci#endif 3908c2ecf20Sopenharmony_ci if (space <= 0) 3918c2ecf20Sopenharmony_ci return; 3928c2ecf20Sopenharmony_ci ToRecv = space; 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci wRecv = ToRecv >> 1; 3958c2ecf20Sopenharmony_ci if (wRecv) 3968c2ecf20Sopenharmony_ci sInStrW(sGetTxRxDataIO(cp), (unsigned short *) cbuf, wRecv); 3978c2ecf20Sopenharmony_ci if (ToRecv & 1) 3988c2ecf20Sopenharmony_ci cbuf[ToRecv - 1] = sInB(sGetTxRxDataIO(cp)); 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci /* Push the data up to the tty layer */ 4018c2ecf20Sopenharmony_ci tty_flip_buffer_push(&info->port); 4028c2ecf20Sopenharmony_ci} 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci/* 4058c2ecf20Sopenharmony_ci * Serial port transmit data function. Called from the timer polling loop as a 4068c2ecf20Sopenharmony_ci * result of a bit set in xmit_flags[], indicating data (from the tty layer) is ready 4078c2ecf20Sopenharmony_ci * to be sent out the serial port. Data is buffered in rp_table[line].xmit_buf, it is 4088c2ecf20Sopenharmony_ci * moved to the port's xmit FIFO. *info is critical data, protected by spinlocks. 4098c2ecf20Sopenharmony_ci */ 4108c2ecf20Sopenharmony_cistatic void rp_do_transmit(struct r_port *info) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci int c; 4138c2ecf20Sopenharmony_ci CHANNEL_t *cp = &info->channel; 4148c2ecf20Sopenharmony_ci struct tty_struct *tty; 4158c2ecf20Sopenharmony_ci unsigned long flags; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci#ifdef ROCKET_DEBUG_INTR 4188c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s\n", __func__); 4198c2ecf20Sopenharmony_ci#endif 4208c2ecf20Sopenharmony_ci if (!info) 4218c2ecf20Sopenharmony_ci return; 4228c2ecf20Sopenharmony_ci tty = tty_port_tty_get(&info->port); 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci if (tty == NULL) { 4258c2ecf20Sopenharmony_ci printk(KERN_WARNING "rp: WARNING %s called with tty==NULL\n", __func__); 4268c2ecf20Sopenharmony_ci clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); 4278c2ecf20Sopenharmony_ci return; 4288c2ecf20Sopenharmony_ci } 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci spin_lock_irqsave(&info->slock, flags); 4318c2ecf20Sopenharmony_ci info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci /* Loop sending data to FIFO until done or FIFO full */ 4348c2ecf20Sopenharmony_ci while (1) { 4358c2ecf20Sopenharmony_ci if (tty->stopped) 4368c2ecf20Sopenharmony_ci break; 4378c2ecf20Sopenharmony_ci c = min(info->xmit_fifo_room, info->xmit_cnt); 4388c2ecf20Sopenharmony_ci c = min(c, XMIT_BUF_SIZE - info->xmit_tail); 4398c2ecf20Sopenharmony_ci if (c <= 0 || info->xmit_fifo_room <= 0) 4408c2ecf20Sopenharmony_ci break; 4418c2ecf20Sopenharmony_ci sOutStrW(sGetTxRxDataIO(cp), (unsigned short *) (info->xmit_buf + info->xmit_tail), c / 2); 4428c2ecf20Sopenharmony_ci if (c & 1) 4438c2ecf20Sopenharmony_ci sOutB(sGetTxRxDataIO(cp), info->xmit_buf[info->xmit_tail + c - 1]); 4448c2ecf20Sopenharmony_ci info->xmit_tail += c; 4458c2ecf20Sopenharmony_ci info->xmit_tail &= XMIT_BUF_SIZE - 1; 4468c2ecf20Sopenharmony_ci info->xmit_cnt -= c; 4478c2ecf20Sopenharmony_ci info->xmit_fifo_room -= c; 4488c2ecf20Sopenharmony_ci#ifdef ROCKET_DEBUG_INTR 4498c2ecf20Sopenharmony_ci printk(KERN_INFO "tx %d chars...\n", c); 4508c2ecf20Sopenharmony_ci#endif 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci if (info->xmit_cnt == 0) 4548c2ecf20Sopenharmony_ci clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci if (info->xmit_cnt < WAKEUP_CHARS) { 4578c2ecf20Sopenharmony_ci tty_wakeup(tty); 4588c2ecf20Sopenharmony_ci#ifdef ROCKETPORT_HAVE_POLL_WAIT 4598c2ecf20Sopenharmony_ci wake_up_interruptible(&tty->poll_wait); 4608c2ecf20Sopenharmony_ci#endif 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&info->slock, flags); 4648c2ecf20Sopenharmony_ci tty_kref_put(tty); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci#ifdef ROCKET_DEBUG_INTR 4678c2ecf20Sopenharmony_ci printk(KERN_DEBUG "(%d,%d,%d,%d)...\n", info->xmit_cnt, info->xmit_head, 4688c2ecf20Sopenharmony_ci info->xmit_tail, info->xmit_fifo_room); 4698c2ecf20Sopenharmony_ci#endif 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci/* 4738c2ecf20Sopenharmony_ci * Called when a serial port signals it has read data in it's RX FIFO. 4748c2ecf20Sopenharmony_ci * It checks what interrupts are pending and services them, including 4758c2ecf20Sopenharmony_ci * receiving serial data. 4768c2ecf20Sopenharmony_ci */ 4778c2ecf20Sopenharmony_cistatic void rp_handle_port(struct r_port *info) 4788c2ecf20Sopenharmony_ci{ 4798c2ecf20Sopenharmony_ci CHANNEL_t *cp; 4808c2ecf20Sopenharmony_ci unsigned int IntMask, ChanStatus; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci if (!info) 4838c2ecf20Sopenharmony_ci return; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci if (!tty_port_initialized(&info->port)) { 4868c2ecf20Sopenharmony_ci printk(KERN_WARNING "rp: WARNING: rp_handle_port called with " 4878c2ecf20Sopenharmony_ci "info->flags & NOT_INIT\n"); 4888c2ecf20Sopenharmony_ci return; 4898c2ecf20Sopenharmony_ci } 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci cp = &info->channel; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci IntMask = sGetChanIntID(cp) & info->intmask; 4948c2ecf20Sopenharmony_ci#ifdef ROCKET_DEBUG_INTR 4958c2ecf20Sopenharmony_ci printk(KERN_INFO "rp_interrupt %02x...\n", IntMask); 4968c2ecf20Sopenharmony_ci#endif 4978c2ecf20Sopenharmony_ci ChanStatus = sGetChanStatus(cp); 4988c2ecf20Sopenharmony_ci if (IntMask & RXF_TRIG) { /* Rx FIFO trigger level */ 4998c2ecf20Sopenharmony_ci rp_do_receive(info, cp, ChanStatus); 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ci if (IntMask & DELTA_CD) { /* CD change */ 5028c2ecf20Sopenharmony_ci#if (defined(ROCKET_DEBUG_OPEN) || defined(ROCKET_DEBUG_INTR) || defined(ROCKET_DEBUG_HANGUP)) 5038c2ecf20Sopenharmony_ci printk(KERN_INFO "ttyR%d CD now %s...\n", info->line, 5048c2ecf20Sopenharmony_ci (ChanStatus & CD_ACT) ? "on" : "off"); 5058c2ecf20Sopenharmony_ci#endif 5068c2ecf20Sopenharmony_ci if (!(ChanStatus & CD_ACT) && info->cd_status) { 5078c2ecf20Sopenharmony_ci#ifdef ROCKET_DEBUG_HANGUP 5088c2ecf20Sopenharmony_ci printk(KERN_INFO "CD drop, calling hangup.\n"); 5098c2ecf20Sopenharmony_ci#endif 5108c2ecf20Sopenharmony_ci tty_port_tty_hangup(&info->port, false); 5118c2ecf20Sopenharmony_ci } 5128c2ecf20Sopenharmony_ci info->cd_status = (ChanStatus & CD_ACT) ? 1 : 0; 5138c2ecf20Sopenharmony_ci wake_up_interruptible(&info->port.open_wait); 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci#ifdef ROCKET_DEBUG_INTR 5168c2ecf20Sopenharmony_ci if (IntMask & DELTA_CTS) { /* CTS change */ 5178c2ecf20Sopenharmony_ci printk(KERN_INFO "CTS change...\n"); 5188c2ecf20Sopenharmony_ci } 5198c2ecf20Sopenharmony_ci if (IntMask & DELTA_DSR) { /* DSR change */ 5208c2ecf20Sopenharmony_ci printk(KERN_INFO "DSR change...\n"); 5218c2ecf20Sopenharmony_ci } 5228c2ecf20Sopenharmony_ci#endif 5238c2ecf20Sopenharmony_ci} 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci/* 5268c2ecf20Sopenharmony_ci * The top level polling routine. Repeats every 1/100 HZ (10ms). 5278c2ecf20Sopenharmony_ci */ 5288c2ecf20Sopenharmony_cistatic void rp_do_poll(struct timer_list *unused) 5298c2ecf20Sopenharmony_ci{ 5308c2ecf20Sopenharmony_ci CONTROLLER_t *ctlp; 5318c2ecf20Sopenharmony_ci int ctrl, aiop, ch, line; 5328c2ecf20Sopenharmony_ci unsigned int xmitmask, i; 5338c2ecf20Sopenharmony_ci unsigned int CtlMask; 5348c2ecf20Sopenharmony_ci unsigned char AiopMask; 5358c2ecf20Sopenharmony_ci Word_t bit; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci /* Walk through all the boards (ctrl's) */ 5388c2ecf20Sopenharmony_ci for (ctrl = 0; ctrl < max_board; ctrl++) { 5398c2ecf20Sopenharmony_ci if (rcktpt_io_addr[ctrl] <= 0) 5408c2ecf20Sopenharmony_ci continue; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci /* Get a ptr to the board's control struct */ 5438c2ecf20Sopenharmony_ci ctlp = sCtlNumToCtlPtr(ctrl); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci /* Get the interrupt status from the board */ 5468c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 5478c2ecf20Sopenharmony_ci if (ctlp->BusType == isPCI) 5488c2ecf20Sopenharmony_ci CtlMask = sPCIGetControllerIntStatus(ctlp); 5498c2ecf20Sopenharmony_ci else 5508c2ecf20Sopenharmony_ci#endif 5518c2ecf20Sopenharmony_ci CtlMask = sGetControllerIntStatus(ctlp); 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci /* Check if any AIOP read bits are set */ 5548c2ecf20Sopenharmony_ci for (aiop = 0; CtlMask; aiop++) { 5558c2ecf20Sopenharmony_ci bit = ctlp->AiopIntrBits[aiop]; 5568c2ecf20Sopenharmony_ci if (CtlMask & bit) { 5578c2ecf20Sopenharmony_ci CtlMask &= ~bit; 5588c2ecf20Sopenharmony_ci AiopMask = sGetAiopIntStatus(ctlp, aiop); 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci /* Check if any port read bits are set */ 5618c2ecf20Sopenharmony_ci for (ch = 0; AiopMask; AiopMask >>= 1, ch++) { 5628c2ecf20Sopenharmony_ci if (AiopMask & 1) { 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci /* Get the line number (/dev/ttyRx number). */ 5658c2ecf20Sopenharmony_ci /* Read the data from the port. */ 5668c2ecf20Sopenharmony_ci line = GetLineNumber(ctrl, aiop, ch); 5678c2ecf20Sopenharmony_ci rp_handle_port(rp_table[line]); 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci } 5708c2ecf20Sopenharmony_ci } 5718c2ecf20Sopenharmony_ci } 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci xmitmask = xmit_flags[ctrl]; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci /* 5768c2ecf20Sopenharmony_ci * xmit_flags contains bit-significant flags, indicating there is data 5778c2ecf20Sopenharmony_ci * to xmit on the port. Bit 0 is port 0 on this board, bit 1 is port 5788c2ecf20Sopenharmony_ci * 1, ... (32 total possible). The variable i has the aiop and ch 5798c2ecf20Sopenharmony_ci * numbers encoded in it (port 0-7 are aiop0, 8-15 are aiop1, etc). 5808c2ecf20Sopenharmony_ci */ 5818c2ecf20Sopenharmony_ci if (xmitmask) { 5828c2ecf20Sopenharmony_ci for (i = 0; i < rocketModel[ctrl].numPorts; i++) { 5838c2ecf20Sopenharmony_ci if (xmitmask & (1 << i)) { 5848c2ecf20Sopenharmony_ci aiop = (i & 0x18) >> 3; 5858c2ecf20Sopenharmony_ci ch = i & 0x07; 5868c2ecf20Sopenharmony_ci line = GetLineNumber(ctrl, aiop, ch); 5878c2ecf20Sopenharmony_ci rp_do_transmit(rp_table[line]); 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci } 5918c2ecf20Sopenharmony_ci } 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci /* 5948c2ecf20Sopenharmony_ci * Reset the timer so we get called at the next clock tick (10ms). 5958c2ecf20Sopenharmony_ci */ 5968c2ecf20Sopenharmony_ci if (atomic_read(&rp_num_ports_open)) 5978c2ecf20Sopenharmony_ci mod_timer(&rocket_timer, jiffies + POLL_PERIOD); 5988c2ecf20Sopenharmony_ci} 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci/* 6018c2ecf20Sopenharmony_ci * Initializes the r_port structure for a port, as well as enabling the port on 6028c2ecf20Sopenharmony_ci * the board. 6038c2ecf20Sopenharmony_ci * Inputs: board, aiop, chan numbers 6048c2ecf20Sopenharmony_ci */ 6058c2ecf20Sopenharmony_cistatic void __init 6068c2ecf20Sopenharmony_ciinit_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev) 6078c2ecf20Sopenharmony_ci{ 6088c2ecf20Sopenharmony_ci unsigned rocketMode; 6098c2ecf20Sopenharmony_ci struct r_port *info; 6108c2ecf20Sopenharmony_ci int line; 6118c2ecf20Sopenharmony_ci CONTROLLER_T *ctlp; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci /* Get the next available line number */ 6148c2ecf20Sopenharmony_ci line = SetLineNumber(board, aiop, chan); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci ctlp = sCtlNumToCtlPtr(board); 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci /* Get a r_port struct for the port, fill it in and save it globally, indexed by line number */ 6198c2ecf20Sopenharmony_ci info = kzalloc(sizeof (struct r_port), GFP_KERNEL); 6208c2ecf20Sopenharmony_ci if (!info) { 6218c2ecf20Sopenharmony_ci printk(KERN_ERR "Couldn't allocate info struct for line #%d\n", 6228c2ecf20Sopenharmony_ci line); 6238c2ecf20Sopenharmony_ci return; 6248c2ecf20Sopenharmony_ci } 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci info->magic = RPORT_MAGIC; 6278c2ecf20Sopenharmony_ci info->line = line; 6288c2ecf20Sopenharmony_ci info->ctlp = ctlp; 6298c2ecf20Sopenharmony_ci info->board = board; 6308c2ecf20Sopenharmony_ci info->aiop = aiop; 6318c2ecf20Sopenharmony_ci info->chan = chan; 6328c2ecf20Sopenharmony_ci tty_port_init(&info->port); 6338c2ecf20Sopenharmony_ci info->port.ops = &rocket_port_ops; 6348c2ecf20Sopenharmony_ci info->flags &= ~ROCKET_MODE_MASK; 6358c2ecf20Sopenharmony_ci if (board < ARRAY_SIZE(pc104) && line < ARRAY_SIZE(pc104_1)) 6368c2ecf20Sopenharmony_ci switch (pc104[board][line]) { 6378c2ecf20Sopenharmony_ci case 422: 6388c2ecf20Sopenharmony_ci info->flags |= ROCKET_MODE_RS422; 6398c2ecf20Sopenharmony_ci break; 6408c2ecf20Sopenharmony_ci case 485: 6418c2ecf20Sopenharmony_ci info->flags |= ROCKET_MODE_RS485; 6428c2ecf20Sopenharmony_ci break; 6438c2ecf20Sopenharmony_ci case 232: 6448c2ecf20Sopenharmony_ci default: 6458c2ecf20Sopenharmony_ci info->flags |= ROCKET_MODE_RS232; 6468c2ecf20Sopenharmony_ci break; 6478c2ecf20Sopenharmony_ci } 6488c2ecf20Sopenharmony_ci else 6498c2ecf20Sopenharmony_ci info->flags |= ROCKET_MODE_RS232; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci info->intmask = RXF_TRIG | TXFIFO_MT | SRC_INT | DELTA_CD | DELTA_CTS | DELTA_DSR; 6528c2ecf20Sopenharmony_ci if (sInitChan(ctlp, &info->channel, aiop, chan) == 0) { 6538c2ecf20Sopenharmony_ci printk(KERN_ERR "RocketPort sInitChan(%d, %d, %d) failed!\n", 6548c2ecf20Sopenharmony_ci board, aiop, chan); 6558c2ecf20Sopenharmony_ci tty_port_destroy(&info->port); 6568c2ecf20Sopenharmony_ci kfree(info); 6578c2ecf20Sopenharmony_ci return; 6588c2ecf20Sopenharmony_ci } 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci rocketMode = info->flags & ROCKET_MODE_MASK; 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci if ((info->flags & ROCKET_RTS_TOGGLE) || (rocketMode == ROCKET_MODE_RS485)) 6638c2ecf20Sopenharmony_ci sEnRTSToggle(&info->channel); 6648c2ecf20Sopenharmony_ci else 6658c2ecf20Sopenharmony_ci sDisRTSToggle(&info->channel); 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci if (ctlp->boardType == ROCKET_TYPE_PC104) { 6688c2ecf20Sopenharmony_ci switch (rocketMode) { 6698c2ecf20Sopenharmony_ci case ROCKET_MODE_RS485: 6708c2ecf20Sopenharmony_ci sSetInterfaceMode(&info->channel, InterfaceModeRS485); 6718c2ecf20Sopenharmony_ci break; 6728c2ecf20Sopenharmony_ci case ROCKET_MODE_RS422: 6738c2ecf20Sopenharmony_ci sSetInterfaceMode(&info->channel, InterfaceModeRS422); 6748c2ecf20Sopenharmony_ci break; 6758c2ecf20Sopenharmony_ci case ROCKET_MODE_RS232: 6768c2ecf20Sopenharmony_ci default: 6778c2ecf20Sopenharmony_ci if (info->flags & ROCKET_RTS_TOGGLE) 6788c2ecf20Sopenharmony_ci sSetInterfaceMode(&info->channel, InterfaceModeRS232T); 6798c2ecf20Sopenharmony_ci else 6808c2ecf20Sopenharmony_ci sSetInterfaceMode(&info->channel, InterfaceModeRS232); 6818c2ecf20Sopenharmony_ci break; 6828c2ecf20Sopenharmony_ci } 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci spin_lock_init(&info->slock); 6858c2ecf20Sopenharmony_ci mutex_init(&info->write_mtx); 6868c2ecf20Sopenharmony_ci rp_table[line] = info; 6878c2ecf20Sopenharmony_ci tty_port_register_device(&info->port, rocket_driver, line, 6888c2ecf20Sopenharmony_ci pci_dev ? &pci_dev->dev : NULL); 6898c2ecf20Sopenharmony_ci} 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci/* 6928c2ecf20Sopenharmony_ci * Configures a rocketport port according to its termio settings. Called from 6938c2ecf20Sopenharmony_ci * user mode into the driver (exception handler). *info CD manipulation is spinlock protected. 6948c2ecf20Sopenharmony_ci */ 6958c2ecf20Sopenharmony_cistatic void configure_r_port(struct tty_struct *tty, struct r_port *info, 6968c2ecf20Sopenharmony_ci struct ktermios *old_termios) 6978c2ecf20Sopenharmony_ci{ 6988c2ecf20Sopenharmony_ci unsigned cflag; 6998c2ecf20Sopenharmony_ci unsigned long flags; 7008c2ecf20Sopenharmony_ci unsigned rocketMode; 7018c2ecf20Sopenharmony_ci int bits, baud, divisor; 7028c2ecf20Sopenharmony_ci CHANNEL_t *cp; 7038c2ecf20Sopenharmony_ci struct ktermios *t = &tty->termios; 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci cp = &info->channel; 7068c2ecf20Sopenharmony_ci cflag = t->c_cflag; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci /* Byte size and parity */ 7098c2ecf20Sopenharmony_ci if ((cflag & CSIZE) == CS8) { 7108c2ecf20Sopenharmony_ci sSetData8(cp); 7118c2ecf20Sopenharmony_ci bits = 10; 7128c2ecf20Sopenharmony_ci } else { 7138c2ecf20Sopenharmony_ci sSetData7(cp); 7148c2ecf20Sopenharmony_ci bits = 9; 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci if (cflag & CSTOPB) { 7178c2ecf20Sopenharmony_ci sSetStop2(cp); 7188c2ecf20Sopenharmony_ci bits++; 7198c2ecf20Sopenharmony_ci } else { 7208c2ecf20Sopenharmony_ci sSetStop1(cp); 7218c2ecf20Sopenharmony_ci } 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci if (cflag & PARENB) { 7248c2ecf20Sopenharmony_ci sEnParity(cp); 7258c2ecf20Sopenharmony_ci bits++; 7268c2ecf20Sopenharmony_ci if (cflag & PARODD) { 7278c2ecf20Sopenharmony_ci sSetOddParity(cp); 7288c2ecf20Sopenharmony_ci } else { 7298c2ecf20Sopenharmony_ci sSetEvenParity(cp); 7308c2ecf20Sopenharmony_ci } 7318c2ecf20Sopenharmony_ci } else { 7328c2ecf20Sopenharmony_ci sDisParity(cp); 7338c2ecf20Sopenharmony_ci } 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci /* baud rate */ 7368c2ecf20Sopenharmony_ci baud = tty_get_baud_rate(tty); 7378c2ecf20Sopenharmony_ci if (!baud) 7388c2ecf20Sopenharmony_ci baud = 9600; 7398c2ecf20Sopenharmony_ci divisor = ((rp_baud_base[info->board] + (baud >> 1)) / baud) - 1; 7408c2ecf20Sopenharmony_ci if ((divisor >= 8192 || divisor < 0) && old_termios) { 7418c2ecf20Sopenharmony_ci baud = tty_termios_baud_rate(old_termios); 7428c2ecf20Sopenharmony_ci if (!baud) 7438c2ecf20Sopenharmony_ci baud = 9600; 7448c2ecf20Sopenharmony_ci divisor = (rp_baud_base[info->board] / baud) - 1; 7458c2ecf20Sopenharmony_ci } 7468c2ecf20Sopenharmony_ci if (divisor >= 8192 || divisor < 0) { 7478c2ecf20Sopenharmony_ci baud = 9600; 7488c2ecf20Sopenharmony_ci divisor = (rp_baud_base[info->board] / baud) - 1; 7498c2ecf20Sopenharmony_ci } 7508c2ecf20Sopenharmony_ci info->cps = baud / bits; 7518c2ecf20Sopenharmony_ci sSetBaud(cp, divisor); 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci /* FIXME: Should really back compute a baud rate from the divisor */ 7548c2ecf20Sopenharmony_ci tty_encode_baud_rate(tty, baud, baud); 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci if (cflag & CRTSCTS) { 7578c2ecf20Sopenharmony_ci info->intmask |= DELTA_CTS; 7588c2ecf20Sopenharmony_ci sEnCTSFlowCtl(cp); 7598c2ecf20Sopenharmony_ci } else { 7608c2ecf20Sopenharmony_ci info->intmask &= ~DELTA_CTS; 7618c2ecf20Sopenharmony_ci sDisCTSFlowCtl(cp); 7628c2ecf20Sopenharmony_ci } 7638c2ecf20Sopenharmony_ci if (cflag & CLOCAL) { 7648c2ecf20Sopenharmony_ci info->intmask &= ~DELTA_CD; 7658c2ecf20Sopenharmony_ci } else { 7668c2ecf20Sopenharmony_ci spin_lock_irqsave(&info->slock, flags); 7678c2ecf20Sopenharmony_ci if (sGetChanStatus(cp) & CD_ACT) 7688c2ecf20Sopenharmony_ci info->cd_status = 1; 7698c2ecf20Sopenharmony_ci else 7708c2ecf20Sopenharmony_ci info->cd_status = 0; 7718c2ecf20Sopenharmony_ci info->intmask |= DELTA_CD; 7728c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&info->slock, flags); 7738c2ecf20Sopenharmony_ci } 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci /* 7768c2ecf20Sopenharmony_ci * Handle software flow control in the board 7778c2ecf20Sopenharmony_ci */ 7788c2ecf20Sopenharmony_ci#ifdef ROCKET_SOFT_FLOW 7798c2ecf20Sopenharmony_ci if (I_IXON(tty)) { 7808c2ecf20Sopenharmony_ci sEnTxSoftFlowCtl(cp); 7818c2ecf20Sopenharmony_ci if (I_IXANY(tty)) { 7828c2ecf20Sopenharmony_ci sEnIXANY(cp); 7838c2ecf20Sopenharmony_ci } else { 7848c2ecf20Sopenharmony_ci sDisIXANY(cp); 7858c2ecf20Sopenharmony_ci } 7868c2ecf20Sopenharmony_ci sSetTxXONChar(cp, START_CHAR(tty)); 7878c2ecf20Sopenharmony_ci sSetTxXOFFChar(cp, STOP_CHAR(tty)); 7888c2ecf20Sopenharmony_ci } else { 7898c2ecf20Sopenharmony_ci sDisTxSoftFlowCtl(cp); 7908c2ecf20Sopenharmony_ci sDisIXANY(cp); 7918c2ecf20Sopenharmony_ci sClrTxXOFF(cp); 7928c2ecf20Sopenharmony_ci } 7938c2ecf20Sopenharmony_ci#endif 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci /* 7968c2ecf20Sopenharmony_ci * Set up ignore/read mask words 7978c2ecf20Sopenharmony_ci */ 7988c2ecf20Sopenharmony_ci info->read_status_mask = STMRCVROVRH | 0xFF; 7998c2ecf20Sopenharmony_ci if (I_INPCK(tty)) 8008c2ecf20Sopenharmony_ci info->read_status_mask |= STMFRAMEH | STMPARITYH; 8018c2ecf20Sopenharmony_ci if (I_BRKINT(tty) || I_PARMRK(tty)) 8028c2ecf20Sopenharmony_ci info->read_status_mask |= STMBREAKH; 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci /* 8058c2ecf20Sopenharmony_ci * Characters to ignore 8068c2ecf20Sopenharmony_ci */ 8078c2ecf20Sopenharmony_ci info->ignore_status_mask = 0; 8088c2ecf20Sopenharmony_ci if (I_IGNPAR(tty)) 8098c2ecf20Sopenharmony_ci info->ignore_status_mask |= STMFRAMEH | STMPARITYH; 8108c2ecf20Sopenharmony_ci if (I_IGNBRK(tty)) { 8118c2ecf20Sopenharmony_ci info->ignore_status_mask |= STMBREAKH; 8128c2ecf20Sopenharmony_ci /* 8138c2ecf20Sopenharmony_ci * If we're ignoring parity and break indicators, 8148c2ecf20Sopenharmony_ci * ignore overruns too. (For real raw support). 8158c2ecf20Sopenharmony_ci */ 8168c2ecf20Sopenharmony_ci if (I_IGNPAR(tty)) 8178c2ecf20Sopenharmony_ci info->ignore_status_mask |= STMRCVROVRH; 8188c2ecf20Sopenharmony_ci } 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci rocketMode = info->flags & ROCKET_MODE_MASK; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci if ((info->flags & ROCKET_RTS_TOGGLE) 8238c2ecf20Sopenharmony_ci || (rocketMode == ROCKET_MODE_RS485)) 8248c2ecf20Sopenharmony_ci sEnRTSToggle(cp); 8258c2ecf20Sopenharmony_ci else 8268c2ecf20Sopenharmony_ci sDisRTSToggle(cp); 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci sSetRTS(&info->channel); 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci if (cp->CtlP->boardType == ROCKET_TYPE_PC104) { 8318c2ecf20Sopenharmony_ci switch (rocketMode) { 8328c2ecf20Sopenharmony_ci case ROCKET_MODE_RS485: 8338c2ecf20Sopenharmony_ci sSetInterfaceMode(cp, InterfaceModeRS485); 8348c2ecf20Sopenharmony_ci break; 8358c2ecf20Sopenharmony_ci case ROCKET_MODE_RS422: 8368c2ecf20Sopenharmony_ci sSetInterfaceMode(cp, InterfaceModeRS422); 8378c2ecf20Sopenharmony_ci break; 8388c2ecf20Sopenharmony_ci case ROCKET_MODE_RS232: 8398c2ecf20Sopenharmony_ci default: 8408c2ecf20Sopenharmony_ci if (info->flags & ROCKET_RTS_TOGGLE) 8418c2ecf20Sopenharmony_ci sSetInterfaceMode(cp, InterfaceModeRS232T); 8428c2ecf20Sopenharmony_ci else 8438c2ecf20Sopenharmony_ci sSetInterfaceMode(cp, InterfaceModeRS232); 8448c2ecf20Sopenharmony_ci break; 8458c2ecf20Sopenharmony_ci } 8468c2ecf20Sopenharmony_ci } 8478c2ecf20Sopenharmony_ci} 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_cistatic int carrier_raised(struct tty_port *port) 8508c2ecf20Sopenharmony_ci{ 8518c2ecf20Sopenharmony_ci struct r_port *info = container_of(port, struct r_port, port); 8528c2ecf20Sopenharmony_ci return (sGetChanStatusLo(&info->channel) & CD_ACT) ? 1 : 0; 8538c2ecf20Sopenharmony_ci} 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_cistatic void dtr_rts(struct tty_port *port, int on) 8568c2ecf20Sopenharmony_ci{ 8578c2ecf20Sopenharmony_ci struct r_port *info = container_of(port, struct r_port, port); 8588c2ecf20Sopenharmony_ci if (on) { 8598c2ecf20Sopenharmony_ci sSetDTR(&info->channel); 8608c2ecf20Sopenharmony_ci sSetRTS(&info->channel); 8618c2ecf20Sopenharmony_ci } else { 8628c2ecf20Sopenharmony_ci sClrDTR(&info->channel); 8638c2ecf20Sopenharmony_ci sClrRTS(&info->channel); 8648c2ecf20Sopenharmony_ci } 8658c2ecf20Sopenharmony_ci} 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci/* 8688c2ecf20Sopenharmony_ci * Exception handler that opens a serial port. Creates xmit_buf storage, fills in 8698c2ecf20Sopenharmony_ci * port's r_port struct. Initializes the port hardware. 8708c2ecf20Sopenharmony_ci */ 8718c2ecf20Sopenharmony_cistatic int rp_open(struct tty_struct *tty, struct file *filp) 8728c2ecf20Sopenharmony_ci{ 8738c2ecf20Sopenharmony_ci struct r_port *info; 8748c2ecf20Sopenharmony_ci struct tty_port *port; 8758c2ecf20Sopenharmony_ci int retval; 8768c2ecf20Sopenharmony_ci CHANNEL_t *cp; 8778c2ecf20Sopenharmony_ci unsigned long page; 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci info = rp_table[tty->index]; 8808c2ecf20Sopenharmony_ci if (info == NULL) 8818c2ecf20Sopenharmony_ci return -ENXIO; 8828c2ecf20Sopenharmony_ci port = &info->port; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci page = __get_free_page(GFP_KERNEL); 8858c2ecf20Sopenharmony_ci if (!page) 8868c2ecf20Sopenharmony_ci return -ENOMEM; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci /* 8898c2ecf20Sopenharmony_ci * We must not sleep from here until the port is marked fully in use. 8908c2ecf20Sopenharmony_ci */ 8918c2ecf20Sopenharmony_ci if (info->xmit_buf) 8928c2ecf20Sopenharmony_ci free_page(page); 8938c2ecf20Sopenharmony_ci else 8948c2ecf20Sopenharmony_ci info->xmit_buf = (unsigned char *) page; 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci tty->driver_data = info; 8978c2ecf20Sopenharmony_ci tty_port_tty_set(port, tty); 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci if (port->count++ == 0) { 9008c2ecf20Sopenharmony_ci atomic_inc(&rp_num_ports_open); 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci#ifdef ROCKET_DEBUG_OPEN 9038c2ecf20Sopenharmony_ci printk(KERN_INFO "rocket mod++ = %d...\n", 9048c2ecf20Sopenharmony_ci atomic_read(&rp_num_ports_open)); 9058c2ecf20Sopenharmony_ci#endif 9068c2ecf20Sopenharmony_ci } 9078c2ecf20Sopenharmony_ci#ifdef ROCKET_DEBUG_OPEN 9088c2ecf20Sopenharmony_ci printk(KERN_INFO "rp_open ttyR%d, count=%d\n", info->line, info->port.count); 9098c2ecf20Sopenharmony_ci#endif 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci /* 9128c2ecf20Sopenharmony_ci * Info->count is now 1; so it's safe to sleep now. 9138c2ecf20Sopenharmony_ci */ 9148c2ecf20Sopenharmony_ci if (!tty_port_initialized(port)) { 9158c2ecf20Sopenharmony_ci cp = &info->channel; 9168c2ecf20Sopenharmony_ci sSetRxTrigger(cp, TRIG_1); 9178c2ecf20Sopenharmony_ci if (sGetChanStatus(cp) & CD_ACT) 9188c2ecf20Sopenharmony_ci info->cd_status = 1; 9198c2ecf20Sopenharmony_ci else 9208c2ecf20Sopenharmony_ci info->cd_status = 0; 9218c2ecf20Sopenharmony_ci sDisRxStatusMode(cp); 9228c2ecf20Sopenharmony_ci sFlushRxFIFO(cp); 9238c2ecf20Sopenharmony_ci sFlushTxFIFO(cp); 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci sEnInterrupts(cp, (TXINT_EN | MCINT_EN | RXINT_EN | SRCINT_EN | CHANINT_EN)); 9268c2ecf20Sopenharmony_ci sSetRxTrigger(cp, TRIG_1); 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci sGetChanStatus(cp); 9298c2ecf20Sopenharmony_ci sDisRxStatusMode(cp); 9308c2ecf20Sopenharmony_ci sClrTxXOFF(cp); 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci sDisCTSFlowCtl(cp); 9338c2ecf20Sopenharmony_ci sDisTxSoftFlowCtl(cp); 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci sEnRxFIFO(cp); 9368c2ecf20Sopenharmony_ci sEnTransmit(cp); 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci tty_port_set_initialized(&info->port, 1); 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci configure_r_port(tty, info, NULL); 9418c2ecf20Sopenharmony_ci if (C_BAUD(tty)) { 9428c2ecf20Sopenharmony_ci sSetDTR(cp); 9438c2ecf20Sopenharmony_ci sSetRTS(cp); 9448c2ecf20Sopenharmony_ci } 9458c2ecf20Sopenharmony_ci } 9468c2ecf20Sopenharmony_ci /* Starts (or resets) the maint polling loop */ 9478c2ecf20Sopenharmony_ci mod_timer(&rocket_timer, jiffies + POLL_PERIOD); 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci retval = tty_port_block_til_ready(port, tty, filp); 9508c2ecf20Sopenharmony_ci if (retval) { 9518c2ecf20Sopenharmony_ci#ifdef ROCKET_DEBUG_OPEN 9528c2ecf20Sopenharmony_ci printk(KERN_INFO "rp_open returning after block_til_ready with %d\n", retval); 9538c2ecf20Sopenharmony_ci#endif 9548c2ecf20Sopenharmony_ci return retval; 9558c2ecf20Sopenharmony_ci } 9568c2ecf20Sopenharmony_ci return 0; 9578c2ecf20Sopenharmony_ci} 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci/* 9608c2ecf20Sopenharmony_ci * Exception handler that closes a serial port. info->port.count is considered critical. 9618c2ecf20Sopenharmony_ci */ 9628c2ecf20Sopenharmony_cistatic void rp_close(struct tty_struct *tty, struct file *filp) 9638c2ecf20Sopenharmony_ci{ 9648c2ecf20Sopenharmony_ci struct r_port *info = tty->driver_data; 9658c2ecf20Sopenharmony_ci struct tty_port *port = &info->port; 9668c2ecf20Sopenharmony_ci int timeout; 9678c2ecf20Sopenharmony_ci CHANNEL_t *cp; 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci if (rocket_paranoia_check(info, "rp_close")) 9708c2ecf20Sopenharmony_ci return; 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci#ifdef ROCKET_DEBUG_OPEN 9738c2ecf20Sopenharmony_ci printk(KERN_INFO "rp_close ttyR%d, count = %d\n", info->line, info->port.count); 9748c2ecf20Sopenharmony_ci#endif 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci if (tty_port_close_start(port, tty, filp) == 0) 9778c2ecf20Sopenharmony_ci return; 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci mutex_lock(&port->mutex); 9808c2ecf20Sopenharmony_ci cp = &info->channel; 9818c2ecf20Sopenharmony_ci /* 9828c2ecf20Sopenharmony_ci * Before we drop DTR, make sure the UART transmitter 9838c2ecf20Sopenharmony_ci * has completely drained; this is especially 9848c2ecf20Sopenharmony_ci * important if there is a transmit FIFO! 9858c2ecf20Sopenharmony_ci */ 9868c2ecf20Sopenharmony_ci timeout = (sGetTxCnt(cp) + 1) * HZ / info->cps; 9878c2ecf20Sopenharmony_ci if (timeout == 0) 9888c2ecf20Sopenharmony_ci timeout = 1; 9898c2ecf20Sopenharmony_ci rp_wait_until_sent(tty, timeout); 9908c2ecf20Sopenharmony_ci clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci sDisTransmit(cp); 9938c2ecf20Sopenharmony_ci sDisInterrupts(cp, (TXINT_EN | MCINT_EN | RXINT_EN | SRCINT_EN | CHANINT_EN)); 9948c2ecf20Sopenharmony_ci sDisCTSFlowCtl(cp); 9958c2ecf20Sopenharmony_ci sDisTxSoftFlowCtl(cp); 9968c2ecf20Sopenharmony_ci sClrTxXOFF(cp); 9978c2ecf20Sopenharmony_ci sFlushRxFIFO(cp); 9988c2ecf20Sopenharmony_ci sFlushTxFIFO(cp); 9998c2ecf20Sopenharmony_ci sClrRTS(cp); 10008c2ecf20Sopenharmony_ci if (C_HUPCL(tty)) 10018c2ecf20Sopenharmony_ci sClrDTR(cp); 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci rp_flush_buffer(tty); 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci tty_ldisc_flush(tty); 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci /* We can't yet use tty_port_close_end as the buffer handling in this 10108c2ecf20Sopenharmony_ci driver is a bit different to the usual */ 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci if (port->blocked_open) { 10138c2ecf20Sopenharmony_ci if (port->close_delay) { 10148c2ecf20Sopenharmony_ci msleep_interruptible(jiffies_to_msecs(port->close_delay)); 10158c2ecf20Sopenharmony_ci } 10168c2ecf20Sopenharmony_ci wake_up_interruptible(&port->open_wait); 10178c2ecf20Sopenharmony_ci } else { 10188c2ecf20Sopenharmony_ci if (info->xmit_buf) { 10198c2ecf20Sopenharmony_ci free_page((unsigned long) info->xmit_buf); 10208c2ecf20Sopenharmony_ci info->xmit_buf = NULL; 10218c2ecf20Sopenharmony_ci } 10228c2ecf20Sopenharmony_ci } 10238c2ecf20Sopenharmony_ci spin_lock_irq(&port->lock); 10248c2ecf20Sopenharmony_ci tty->closing = 0; 10258c2ecf20Sopenharmony_ci spin_unlock_irq(&port->lock); 10268c2ecf20Sopenharmony_ci tty_port_set_initialized(port, 0); 10278c2ecf20Sopenharmony_ci tty_port_set_active(port, 0); 10288c2ecf20Sopenharmony_ci mutex_unlock(&port->mutex); 10298c2ecf20Sopenharmony_ci tty_port_tty_set(port, NULL); 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci atomic_dec(&rp_num_ports_open); 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci#ifdef ROCKET_DEBUG_OPEN 10348c2ecf20Sopenharmony_ci printk(KERN_INFO "rocket mod-- = %d...\n", 10358c2ecf20Sopenharmony_ci atomic_read(&rp_num_ports_open)); 10368c2ecf20Sopenharmony_ci printk(KERN_INFO "rp_close ttyR%d complete shutdown\n", info->line); 10378c2ecf20Sopenharmony_ci#endif 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci} 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_cistatic void rp_set_termios(struct tty_struct *tty, 10428c2ecf20Sopenharmony_ci struct ktermios *old_termios) 10438c2ecf20Sopenharmony_ci{ 10448c2ecf20Sopenharmony_ci struct r_port *info = tty->driver_data; 10458c2ecf20Sopenharmony_ci CHANNEL_t *cp; 10468c2ecf20Sopenharmony_ci unsigned cflag; 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci if (rocket_paranoia_check(info, "rp_set_termios")) 10498c2ecf20Sopenharmony_ci return; 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci cflag = tty->termios.c_cflag; 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci /* 10548c2ecf20Sopenharmony_ci * This driver doesn't support CS5 or CS6 10558c2ecf20Sopenharmony_ci */ 10568c2ecf20Sopenharmony_ci if (((cflag & CSIZE) == CS5) || ((cflag & CSIZE) == CS6)) 10578c2ecf20Sopenharmony_ci tty->termios.c_cflag = 10588c2ecf20Sopenharmony_ci ((cflag & ~CSIZE) | (old_termios->c_cflag & CSIZE)); 10598c2ecf20Sopenharmony_ci /* Or CMSPAR */ 10608c2ecf20Sopenharmony_ci tty->termios.c_cflag &= ~CMSPAR; 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci configure_r_port(tty, info, old_termios); 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci cp = &info->channel; 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci /* Handle transition to B0 status */ 10678c2ecf20Sopenharmony_ci if ((old_termios->c_cflag & CBAUD) && !C_BAUD(tty)) { 10688c2ecf20Sopenharmony_ci sClrDTR(cp); 10698c2ecf20Sopenharmony_ci sClrRTS(cp); 10708c2ecf20Sopenharmony_ci } 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci /* Handle transition away from B0 status */ 10738c2ecf20Sopenharmony_ci if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) { 10748c2ecf20Sopenharmony_ci sSetRTS(cp); 10758c2ecf20Sopenharmony_ci sSetDTR(cp); 10768c2ecf20Sopenharmony_ci } 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) 10798c2ecf20Sopenharmony_ci rp_start(tty); 10808c2ecf20Sopenharmony_ci} 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_cistatic int rp_break(struct tty_struct *tty, int break_state) 10838c2ecf20Sopenharmony_ci{ 10848c2ecf20Sopenharmony_ci struct r_port *info = tty->driver_data; 10858c2ecf20Sopenharmony_ci unsigned long flags; 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci if (rocket_paranoia_check(info, "rp_break")) 10888c2ecf20Sopenharmony_ci return -EINVAL; 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci spin_lock_irqsave(&info->slock, flags); 10918c2ecf20Sopenharmony_ci if (break_state == -1) 10928c2ecf20Sopenharmony_ci sSendBreak(&info->channel); 10938c2ecf20Sopenharmony_ci else 10948c2ecf20Sopenharmony_ci sClrBreak(&info->channel); 10958c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&info->slock, flags); 10968c2ecf20Sopenharmony_ci return 0; 10978c2ecf20Sopenharmony_ci} 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci/* 11008c2ecf20Sopenharmony_ci * sGetChanRI used to be a macro in rocket_int.h. When the functionality for 11018c2ecf20Sopenharmony_ci * the UPCI boards was added, it was decided to make this a function because 11028c2ecf20Sopenharmony_ci * the macro was getting too complicated. All cases except the first one 11038c2ecf20Sopenharmony_ci * (UPCIRingInd) are taken directly from the original macro. 11048c2ecf20Sopenharmony_ci */ 11058c2ecf20Sopenharmony_cistatic int sGetChanRI(CHANNEL_T * ChP) 11068c2ecf20Sopenharmony_ci{ 11078c2ecf20Sopenharmony_ci CONTROLLER_t *CtlP = ChP->CtlP; 11088c2ecf20Sopenharmony_ci int ChanNum = ChP->ChanNum; 11098c2ecf20Sopenharmony_ci int RingInd = 0; 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci if (CtlP->UPCIRingInd) 11128c2ecf20Sopenharmony_ci RingInd = !(sInB(CtlP->UPCIRingInd) & sBitMapSetTbl[ChanNum]); 11138c2ecf20Sopenharmony_ci else if (CtlP->AltChanRingIndicator) 11148c2ecf20Sopenharmony_ci RingInd = sInB((ByteIO_t) (ChP->ChanStat + 8)) & DSR_ACT; 11158c2ecf20Sopenharmony_ci else if (CtlP->boardType == ROCKET_TYPE_PC104) 11168c2ecf20Sopenharmony_ci RingInd = !(sInB(CtlP->AiopIO[3]) & sBitMapSetTbl[ChanNum]); 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci return RingInd; 11198c2ecf20Sopenharmony_ci} 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci/********************************************************************************************/ 11228c2ecf20Sopenharmony_ci/* Here are the routines used by rp_ioctl. These are all called from exception handlers. */ 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci/* 11258c2ecf20Sopenharmony_ci * Returns the state of the serial modem control lines. These next 2 functions 11268c2ecf20Sopenharmony_ci * are the way kernel versions > 2.5 handle modem control lines rather than IOCTLs. 11278c2ecf20Sopenharmony_ci */ 11288c2ecf20Sopenharmony_cistatic int rp_tiocmget(struct tty_struct *tty) 11298c2ecf20Sopenharmony_ci{ 11308c2ecf20Sopenharmony_ci struct r_port *info = tty->driver_data; 11318c2ecf20Sopenharmony_ci unsigned int control, result, ChanStatus; 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci ChanStatus = sGetChanStatusLo(&info->channel); 11348c2ecf20Sopenharmony_ci control = info->channel.TxControl[3]; 11358c2ecf20Sopenharmony_ci result = ((control & SET_RTS) ? TIOCM_RTS : 0) | 11368c2ecf20Sopenharmony_ci ((control & SET_DTR) ? TIOCM_DTR : 0) | 11378c2ecf20Sopenharmony_ci ((ChanStatus & CD_ACT) ? TIOCM_CAR : 0) | 11388c2ecf20Sopenharmony_ci (sGetChanRI(&info->channel) ? TIOCM_RNG : 0) | 11398c2ecf20Sopenharmony_ci ((ChanStatus & DSR_ACT) ? TIOCM_DSR : 0) | 11408c2ecf20Sopenharmony_ci ((ChanStatus & CTS_ACT) ? TIOCM_CTS : 0); 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci return result; 11438c2ecf20Sopenharmony_ci} 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci/* 11468c2ecf20Sopenharmony_ci * Sets the modem control lines 11478c2ecf20Sopenharmony_ci */ 11488c2ecf20Sopenharmony_cistatic int rp_tiocmset(struct tty_struct *tty, 11498c2ecf20Sopenharmony_ci unsigned int set, unsigned int clear) 11508c2ecf20Sopenharmony_ci{ 11518c2ecf20Sopenharmony_ci struct r_port *info = tty->driver_data; 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci if (set & TIOCM_RTS) 11548c2ecf20Sopenharmony_ci info->channel.TxControl[3] |= SET_RTS; 11558c2ecf20Sopenharmony_ci if (set & TIOCM_DTR) 11568c2ecf20Sopenharmony_ci info->channel.TxControl[3] |= SET_DTR; 11578c2ecf20Sopenharmony_ci if (clear & TIOCM_RTS) 11588c2ecf20Sopenharmony_ci info->channel.TxControl[3] &= ~SET_RTS; 11598c2ecf20Sopenharmony_ci if (clear & TIOCM_DTR) 11608c2ecf20Sopenharmony_ci info->channel.TxControl[3] &= ~SET_DTR; 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci out32(info->channel.IndexAddr, info->channel.TxControl); 11638c2ecf20Sopenharmony_ci return 0; 11648c2ecf20Sopenharmony_ci} 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_cistatic int get_config(struct r_port *info, struct rocket_config __user *retinfo) 11678c2ecf20Sopenharmony_ci{ 11688c2ecf20Sopenharmony_ci struct rocket_config tmp; 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci memset(&tmp, 0, sizeof (tmp)); 11718c2ecf20Sopenharmony_ci mutex_lock(&info->port.mutex); 11728c2ecf20Sopenharmony_ci tmp.line = info->line; 11738c2ecf20Sopenharmony_ci tmp.flags = info->flags; 11748c2ecf20Sopenharmony_ci tmp.close_delay = info->port.close_delay; 11758c2ecf20Sopenharmony_ci tmp.closing_wait = info->port.closing_wait; 11768c2ecf20Sopenharmony_ci tmp.port = rcktpt_io_addr[(info->line >> 5) & 3]; 11778c2ecf20Sopenharmony_ci mutex_unlock(&info->port.mutex); 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci if (copy_to_user(retinfo, &tmp, sizeof (*retinfo))) 11808c2ecf20Sopenharmony_ci return -EFAULT; 11818c2ecf20Sopenharmony_ci return 0; 11828c2ecf20Sopenharmony_ci} 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_cistatic int set_config(struct tty_struct *tty, struct r_port *info, 11858c2ecf20Sopenharmony_ci struct rocket_config __user *new_info) 11868c2ecf20Sopenharmony_ci{ 11878c2ecf20Sopenharmony_ci struct rocket_config new_serial; 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci if (copy_from_user(&new_serial, new_info, sizeof (new_serial))) 11908c2ecf20Sopenharmony_ci return -EFAULT; 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci mutex_lock(&info->port.mutex); 11938c2ecf20Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 11948c2ecf20Sopenharmony_ci { 11958c2ecf20Sopenharmony_ci if ((new_serial.flags & ~ROCKET_USR_MASK) != (info->flags & ~ROCKET_USR_MASK)) { 11968c2ecf20Sopenharmony_ci mutex_unlock(&info->port.mutex); 11978c2ecf20Sopenharmony_ci return -EPERM; 11988c2ecf20Sopenharmony_ci } 11998c2ecf20Sopenharmony_ci info->flags = ((info->flags & ~ROCKET_USR_MASK) | (new_serial.flags & ROCKET_USR_MASK)); 12008c2ecf20Sopenharmony_ci mutex_unlock(&info->port.mutex); 12018c2ecf20Sopenharmony_ci return 0; 12028c2ecf20Sopenharmony_ci } 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci if ((new_serial.flags ^ info->flags) & ROCKET_SPD_MASK) { 12058c2ecf20Sopenharmony_ci /* warn about deprecation, unless clearing */ 12068c2ecf20Sopenharmony_ci if (new_serial.flags & ROCKET_SPD_MASK) 12078c2ecf20Sopenharmony_ci dev_warn_ratelimited(tty->dev, "use of SPD flags is deprecated\n"); 12088c2ecf20Sopenharmony_ci } 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci info->flags = ((info->flags & ~ROCKET_FLAGS) | (new_serial.flags & ROCKET_FLAGS)); 12118c2ecf20Sopenharmony_ci info->port.close_delay = new_serial.close_delay; 12128c2ecf20Sopenharmony_ci info->port.closing_wait = new_serial.closing_wait; 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci mutex_unlock(&info->port.mutex); 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci configure_r_port(tty, info, NULL); 12178c2ecf20Sopenharmony_ci return 0; 12188c2ecf20Sopenharmony_ci} 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci/* 12218c2ecf20Sopenharmony_ci * This function fills in a rocket_ports struct with information 12228c2ecf20Sopenharmony_ci * about what boards/ports are in the system. This info is passed 12238c2ecf20Sopenharmony_ci * to user space. See setrocket.c where the info is used to create 12248c2ecf20Sopenharmony_ci * the /dev/ttyRx ports. 12258c2ecf20Sopenharmony_ci */ 12268c2ecf20Sopenharmony_cistatic int get_ports(struct r_port *info, struct rocket_ports __user *retports) 12278c2ecf20Sopenharmony_ci{ 12288c2ecf20Sopenharmony_ci struct rocket_ports *tmp; 12298c2ecf20Sopenharmony_ci int board, ret = 0; 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); 12328c2ecf20Sopenharmony_ci if (!tmp) 12338c2ecf20Sopenharmony_ci return -ENOMEM; 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci tmp->tty_major = rocket_driver->major; 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci for (board = 0; board < 4; board++) { 12388c2ecf20Sopenharmony_ci tmp->rocketModel[board].model = rocketModel[board].model; 12398c2ecf20Sopenharmony_ci strcpy(tmp->rocketModel[board].modelString, 12408c2ecf20Sopenharmony_ci rocketModel[board].modelString); 12418c2ecf20Sopenharmony_ci tmp->rocketModel[board].numPorts = rocketModel[board].numPorts; 12428c2ecf20Sopenharmony_ci tmp->rocketModel[board].loadrm2 = rocketModel[board].loadrm2; 12438c2ecf20Sopenharmony_ci tmp->rocketModel[board].startingPortNumber = 12448c2ecf20Sopenharmony_ci rocketModel[board].startingPortNumber; 12458c2ecf20Sopenharmony_ci } 12468c2ecf20Sopenharmony_ci if (copy_to_user(retports, tmp, sizeof(*retports))) 12478c2ecf20Sopenharmony_ci ret = -EFAULT; 12488c2ecf20Sopenharmony_ci kfree(tmp); 12498c2ecf20Sopenharmony_ci return ret; 12508c2ecf20Sopenharmony_ci} 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_cistatic int reset_rm2(struct r_port *info, void __user *arg) 12538c2ecf20Sopenharmony_ci{ 12548c2ecf20Sopenharmony_ci int reset; 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 12578c2ecf20Sopenharmony_ci return -EPERM; 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci if (copy_from_user(&reset, arg, sizeof (int))) 12608c2ecf20Sopenharmony_ci return -EFAULT; 12618c2ecf20Sopenharmony_ci if (reset) 12628c2ecf20Sopenharmony_ci reset = 1; 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_ci if (rcktpt_type[info->board] != ROCKET_TYPE_MODEMII && 12658c2ecf20Sopenharmony_ci rcktpt_type[info->board] != ROCKET_TYPE_MODEMIII) 12668c2ecf20Sopenharmony_ci return -EINVAL; 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci if (info->ctlp->BusType == isISA) 12698c2ecf20Sopenharmony_ci sModemReset(info->ctlp, info->chan, reset); 12708c2ecf20Sopenharmony_ci else 12718c2ecf20Sopenharmony_ci sPCIModemReset(info->ctlp, info->chan, reset); 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci return 0; 12748c2ecf20Sopenharmony_ci} 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_cistatic int get_version(struct r_port *info, struct rocket_version __user *retvers) 12778c2ecf20Sopenharmony_ci{ 12788c2ecf20Sopenharmony_ci if (copy_to_user(retvers, &driver_version, sizeof (*retvers))) 12798c2ecf20Sopenharmony_ci return -EFAULT; 12808c2ecf20Sopenharmony_ci return 0; 12818c2ecf20Sopenharmony_ci} 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci/* IOCTL call handler into the driver */ 12848c2ecf20Sopenharmony_cistatic int rp_ioctl(struct tty_struct *tty, 12858c2ecf20Sopenharmony_ci unsigned int cmd, unsigned long arg) 12868c2ecf20Sopenharmony_ci{ 12878c2ecf20Sopenharmony_ci struct r_port *info = tty->driver_data; 12888c2ecf20Sopenharmony_ci void __user *argp = (void __user *)arg; 12898c2ecf20Sopenharmony_ci int ret = 0; 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci if (cmd != RCKP_GET_PORTS && rocket_paranoia_check(info, "rp_ioctl")) 12928c2ecf20Sopenharmony_ci return -ENXIO; 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci switch (cmd) { 12958c2ecf20Sopenharmony_ci case RCKP_GET_CONFIG: 12968c2ecf20Sopenharmony_ci dev_warn_ratelimited(tty->dev, 12978c2ecf20Sopenharmony_ci "RCKP_GET_CONFIG option is deprecated\n"); 12988c2ecf20Sopenharmony_ci ret = get_config(info, argp); 12998c2ecf20Sopenharmony_ci break; 13008c2ecf20Sopenharmony_ci case RCKP_SET_CONFIG: 13018c2ecf20Sopenharmony_ci dev_warn_ratelimited(tty->dev, 13028c2ecf20Sopenharmony_ci "RCKP_SET_CONFIG option is deprecated\n"); 13038c2ecf20Sopenharmony_ci ret = set_config(tty, info, argp); 13048c2ecf20Sopenharmony_ci break; 13058c2ecf20Sopenharmony_ci case RCKP_GET_PORTS: 13068c2ecf20Sopenharmony_ci dev_warn_ratelimited(tty->dev, 13078c2ecf20Sopenharmony_ci "RCKP_GET_PORTS option is deprecated\n"); 13088c2ecf20Sopenharmony_ci ret = get_ports(info, argp); 13098c2ecf20Sopenharmony_ci break; 13108c2ecf20Sopenharmony_ci case RCKP_RESET_RM2: 13118c2ecf20Sopenharmony_ci dev_warn_ratelimited(tty->dev, 13128c2ecf20Sopenharmony_ci "RCKP_RESET_RM2 option is deprecated\n"); 13138c2ecf20Sopenharmony_ci ret = reset_rm2(info, argp); 13148c2ecf20Sopenharmony_ci break; 13158c2ecf20Sopenharmony_ci case RCKP_GET_VERSION: 13168c2ecf20Sopenharmony_ci dev_warn_ratelimited(tty->dev, 13178c2ecf20Sopenharmony_ci "RCKP_GET_VERSION option is deprecated\n"); 13188c2ecf20Sopenharmony_ci ret = get_version(info, argp); 13198c2ecf20Sopenharmony_ci break; 13208c2ecf20Sopenharmony_ci default: 13218c2ecf20Sopenharmony_ci ret = -ENOIOCTLCMD; 13228c2ecf20Sopenharmony_ci } 13238c2ecf20Sopenharmony_ci return ret; 13248c2ecf20Sopenharmony_ci} 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_cistatic void rp_send_xchar(struct tty_struct *tty, char ch) 13278c2ecf20Sopenharmony_ci{ 13288c2ecf20Sopenharmony_ci struct r_port *info = tty->driver_data; 13298c2ecf20Sopenharmony_ci CHANNEL_t *cp; 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci if (rocket_paranoia_check(info, "rp_send_xchar")) 13328c2ecf20Sopenharmony_ci return; 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci cp = &info->channel; 13358c2ecf20Sopenharmony_ci if (sGetTxCnt(cp)) 13368c2ecf20Sopenharmony_ci sWriteTxPrioByte(cp, ch); 13378c2ecf20Sopenharmony_ci else 13388c2ecf20Sopenharmony_ci sWriteTxByte(sGetTxRxDataIO(cp), ch); 13398c2ecf20Sopenharmony_ci} 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_cistatic void rp_throttle(struct tty_struct *tty) 13428c2ecf20Sopenharmony_ci{ 13438c2ecf20Sopenharmony_ci struct r_port *info = tty->driver_data; 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci#ifdef ROCKET_DEBUG_THROTTLE 13468c2ecf20Sopenharmony_ci printk(KERN_INFO "throttle %s ....\n", tty->name); 13478c2ecf20Sopenharmony_ci#endif 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci if (rocket_paranoia_check(info, "rp_throttle")) 13508c2ecf20Sopenharmony_ci return; 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci if (I_IXOFF(tty)) 13538c2ecf20Sopenharmony_ci rp_send_xchar(tty, STOP_CHAR(tty)); 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci sClrRTS(&info->channel); 13568c2ecf20Sopenharmony_ci} 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_cistatic void rp_unthrottle(struct tty_struct *tty) 13598c2ecf20Sopenharmony_ci{ 13608c2ecf20Sopenharmony_ci struct r_port *info = tty->driver_data; 13618c2ecf20Sopenharmony_ci#ifdef ROCKET_DEBUG_THROTTLE 13628c2ecf20Sopenharmony_ci printk(KERN_INFO "unthrottle %s ....\n", tty->name); 13638c2ecf20Sopenharmony_ci#endif 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci if (rocket_paranoia_check(info, "rp_unthrottle")) 13668c2ecf20Sopenharmony_ci return; 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci if (I_IXOFF(tty)) 13698c2ecf20Sopenharmony_ci rp_send_xchar(tty, START_CHAR(tty)); 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ci sSetRTS(&info->channel); 13728c2ecf20Sopenharmony_ci} 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci/* 13758c2ecf20Sopenharmony_ci * ------------------------------------------------------------ 13768c2ecf20Sopenharmony_ci * rp_stop() and rp_start() 13778c2ecf20Sopenharmony_ci * 13788c2ecf20Sopenharmony_ci * This routines are called before setting or resetting tty->stopped. 13798c2ecf20Sopenharmony_ci * They enable or disable transmitter interrupts, as necessary. 13808c2ecf20Sopenharmony_ci * ------------------------------------------------------------ 13818c2ecf20Sopenharmony_ci */ 13828c2ecf20Sopenharmony_cistatic void rp_stop(struct tty_struct *tty) 13838c2ecf20Sopenharmony_ci{ 13848c2ecf20Sopenharmony_ci struct r_port *info = tty->driver_data; 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci#ifdef ROCKET_DEBUG_FLOW 13878c2ecf20Sopenharmony_ci printk(KERN_INFO "stop %s: %d %d....\n", tty->name, 13888c2ecf20Sopenharmony_ci info->xmit_cnt, info->xmit_fifo_room); 13898c2ecf20Sopenharmony_ci#endif 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci if (rocket_paranoia_check(info, "rp_stop")) 13928c2ecf20Sopenharmony_ci return; 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci if (sGetTxCnt(&info->channel)) 13958c2ecf20Sopenharmony_ci sDisTransmit(&info->channel); 13968c2ecf20Sopenharmony_ci} 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_cistatic void rp_start(struct tty_struct *tty) 13998c2ecf20Sopenharmony_ci{ 14008c2ecf20Sopenharmony_ci struct r_port *info = tty->driver_data; 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci#ifdef ROCKET_DEBUG_FLOW 14038c2ecf20Sopenharmony_ci printk(KERN_INFO "start %s: %d %d....\n", tty->name, 14048c2ecf20Sopenharmony_ci info->xmit_cnt, info->xmit_fifo_room); 14058c2ecf20Sopenharmony_ci#endif 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci if (rocket_paranoia_check(info, "rp_stop")) 14088c2ecf20Sopenharmony_ci return; 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci sEnTransmit(&info->channel); 14118c2ecf20Sopenharmony_ci set_bit((info->aiop * 8) + info->chan, 14128c2ecf20Sopenharmony_ci (void *) &xmit_flags[info->board]); 14138c2ecf20Sopenharmony_ci} 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci/* 14168c2ecf20Sopenharmony_ci * rp_wait_until_sent() --- wait until the transmitter is empty 14178c2ecf20Sopenharmony_ci */ 14188c2ecf20Sopenharmony_cistatic void rp_wait_until_sent(struct tty_struct *tty, int timeout) 14198c2ecf20Sopenharmony_ci{ 14208c2ecf20Sopenharmony_ci struct r_port *info = tty->driver_data; 14218c2ecf20Sopenharmony_ci CHANNEL_t *cp; 14228c2ecf20Sopenharmony_ci unsigned long orig_jiffies; 14238c2ecf20Sopenharmony_ci int check_time, exit_time; 14248c2ecf20Sopenharmony_ci int txcnt; 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci if (rocket_paranoia_check(info, "rp_wait_until_sent")) 14278c2ecf20Sopenharmony_ci return; 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci cp = &info->channel; 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci orig_jiffies = jiffies; 14328c2ecf20Sopenharmony_ci#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT 14338c2ecf20Sopenharmony_ci printk(KERN_INFO "In %s(%d) (jiff=%lu)...\n", __func__, timeout, 14348c2ecf20Sopenharmony_ci jiffies); 14358c2ecf20Sopenharmony_ci printk(KERN_INFO "cps=%d...\n", info->cps); 14368c2ecf20Sopenharmony_ci#endif 14378c2ecf20Sopenharmony_ci while (1) { 14388c2ecf20Sopenharmony_ci txcnt = sGetTxCnt(cp); 14398c2ecf20Sopenharmony_ci if (!txcnt) { 14408c2ecf20Sopenharmony_ci if (sGetChanStatusLo(cp) & TXSHRMT) 14418c2ecf20Sopenharmony_ci break; 14428c2ecf20Sopenharmony_ci check_time = (HZ / info->cps) / 5; 14438c2ecf20Sopenharmony_ci } else { 14448c2ecf20Sopenharmony_ci check_time = HZ * txcnt / info->cps; 14458c2ecf20Sopenharmony_ci } 14468c2ecf20Sopenharmony_ci if (timeout) { 14478c2ecf20Sopenharmony_ci exit_time = orig_jiffies + timeout - jiffies; 14488c2ecf20Sopenharmony_ci if (exit_time <= 0) 14498c2ecf20Sopenharmony_ci break; 14508c2ecf20Sopenharmony_ci if (exit_time < check_time) 14518c2ecf20Sopenharmony_ci check_time = exit_time; 14528c2ecf20Sopenharmony_ci } 14538c2ecf20Sopenharmony_ci if (check_time == 0) 14548c2ecf20Sopenharmony_ci check_time = 1; 14558c2ecf20Sopenharmony_ci#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT 14568c2ecf20Sopenharmony_ci printk(KERN_INFO "txcnt = %d (jiff=%lu,check=%d)...\n", txcnt, 14578c2ecf20Sopenharmony_ci jiffies, check_time); 14588c2ecf20Sopenharmony_ci#endif 14598c2ecf20Sopenharmony_ci msleep_interruptible(jiffies_to_msecs(check_time)); 14608c2ecf20Sopenharmony_ci if (signal_pending(current)) 14618c2ecf20Sopenharmony_ci break; 14628c2ecf20Sopenharmony_ci } 14638c2ecf20Sopenharmony_ci __set_current_state(TASK_RUNNING); 14648c2ecf20Sopenharmony_ci#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT 14658c2ecf20Sopenharmony_ci printk(KERN_INFO "txcnt = %d (jiff=%lu)...done\n", txcnt, jiffies); 14668c2ecf20Sopenharmony_ci#endif 14678c2ecf20Sopenharmony_ci} 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci/* 14708c2ecf20Sopenharmony_ci * rp_hangup() --- called by tty_hangup() when a hangup is signaled. 14718c2ecf20Sopenharmony_ci */ 14728c2ecf20Sopenharmony_cistatic void rp_hangup(struct tty_struct *tty) 14738c2ecf20Sopenharmony_ci{ 14748c2ecf20Sopenharmony_ci CHANNEL_t *cp; 14758c2ecf20Sopenharmony_ci struct r_port *info = tty->driver_data; 14768c2ecf20Sopenharmony_ci unsigned long flags; 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci if (rocket_paranoia_check(info, "rp_hangup")) 14798c2ecf20Sopenharmony_ci return; 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci#if (defined(ROCKET_DEBUG_OPEN) || defined(ROCKET_DEBUG_HANGUP)) 14828c2ecf20Sopenharmony_ci printk(KERN_INFO "rp_hangup of ttyR%d...\n", info->line); 14838c2ecf20Sopenharmony_ci#endif 14848c2ecf20Sopenharmony_ci rp_flush_buffer(tty); 14858c2ecf20Sopenharmony_ci spin_lock_irqsave(&info->port.lock, flags); 14868c2ecf20Sopenharmony_ci if (info->port.count) 14878c2ecf20Sopenharmony_ci atomic_dec(&rp_num_ports_open); 14888c2ecf20Sopenharmony_ci clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); 14898c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&info->port.lock, flags); 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci tty_port_hangup(&info->port); 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci cp = &info->channel; 14948c2ecf20Sopenharmony_ci sDisRxFIFO(cp); 14958c2ecf20Sopenharmony_ci sDisTransmit(cp); 14968c2ecf20Sopenharmony_ci sDisInterrupts(cp, (TXINT_EN | MCINT_EN | RXINT_EN | SRCINT_EN | CHANINT_EN)); 14978c2ecf20Sopenharmony_ci sDisCTSFlowCtl(cp); 14988c2ecf20Sopenharmony_ci sDisTxSoftFlowCtl(cp); 14998c2ecf20Sopenharmony_ci sClrTxXOFF(cp); 15008c2ecf20Sopenharmony_ci tty_port_set_initialized(&info->port, 0); 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci wake_up_interruptible(&info->port.open_wait); 15038c2ecf20Sopenharmony_ci} 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci/* 15068c2ecf20Sopenharmony_ci * Exception handler - write char routine. The RocketPort driver uses a 15078c2ecf20Sopenharmony_ci * double-buffering strategy, with the twist that if the in-memory CPU 15088c2ecf20Sopenharmony_ci * buffer is empty, and there's space in the transmit FIFO, the 15098c2ecf20Sopenharmony_ci * writing routines will write directly to transmit FIFO. 15108c2ecf20Sopenharmony_ci * Write buffer and counters protected by spinlocks 15118c2ecf20Sopenharmony_ci */ 15128c2ecf20Sopenharmony_cistatic int rp_put_char(struct tty_struct *tty, unsigned char ch) 15138c2ecf20Sopenharmony_ci{ 15148c2ecf20Sopenharmony_ci struct r_port *info = tty->driver_data; 15158c2ecf20Sopenharmony_ci CHANNEL_t *cp; 15168c2ecf20Sopenharmony_ci unsigned long flags; 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci if (rocket_paranoia_check(info, "rp_put_char")) 15198c2ecf20Sopenharmony_ci return 0; 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci /* 15228c2ecf20Sopenharmony_ci * Grab the port write mutex, locking out other processes that try to 15238c2ecf20Sopenharmony_ci * write to this port 15248c2ecf20Sopenharmony_ci */ 15258c2ecf20Sopenharmony_ci mutex_lock(&info->write_mtx); 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_ci#ifdef ROCKET_DEBUG_WRITE 15288c2ecf20Sopenharmony_ci printk(KERN_INFO "rp_put_char %c...\n", ch); 15298c2ecf20Sopenharmony_ci#endif 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci spin_lock_irqsave(&info->slock, flags); 15328c2ecf20Sopenharmony_ci cp = &info->channel; 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci if (!tty->stopped && info->xmit_fifo_room == 0) 15358c2ecf20Sopenharmony_ci info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp); 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci if (tty->stopped || info->xmit_fifo_room == 0 || info->xmit_cnt != 0) { 15388c2ecf20Sopenharmony_ci info->xmit_buf[info->xmit_head++] = ch; 15398c2ecf20Sopenharmony_ci info->xmit_head &= XMIT_BUF_SIZE - 1; 15408c2ecf20Sopenharmony_ci info->xmit_cnt++; 15418c2ecf20Sopenharmony_ci set_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); 15428c2ecf20Sopenharmony_ci } else { 15438c2ecf20Sopenharmony_ci sOutB(sGetTxRxDataIO(cp), ch); 15448c2ecf20Sopenharmony_ci info->xmit_fifo_room--; 15458c2ecf20Sopenharmony_ci } 15468c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&info->slock, flags); 15478c2ecf20Sopenharmony_ci mutex_unlock(&info->write_mtx); 15488c2ecf20Sopenharmony_ci return 1; 15498c2ecf20Sopenharmony_ci} 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_ci/* 15528c2ecf20Sopenharmony_ci * Exception handler - write routine, called when user app writes to the device. 15538c2ecf20Sopenharmony_ci * A per port write mutex is used to protect from another process writing to 15548c2ecf20Sopenharmony_ci * this port at the same time. This other process could be running on the other CPU 15558c2ecf20Sopenharmony_ci * or get control of the CPU if the copy_from_user() blocks due to a page fault (swapped out). 15568c2ecf20Sopenharmony_ci * Spinlocks protect the info xmit members. 15578c2ecf20Sopenharmony_ci */ 15588c2ecf20Sopenharmony_cistatic int rp_write(struct tty_struct *tty, 15598c2ecf20Sopenharmony_ci const unsigned char *buf, int count) 15608c2ecf20Sopenharmony_ci{ 15618c2ecf20Sopenharmony_ci struct r_port *info = tty->driver_data; 15628c2ecf20Sopenharmony_ci CHANNEL_t *cp; 15638c2ecf20Sopenharmony_ci const unsigned char *b; 15648c2ecf20Sopenharmony_ci int c, retval = 0; 15658c2ecf20Sopenharmony_ci unsigned long flags; 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci if (count <= 0 || rocket_paranoia_check(info, "rp_write")) 15688c2ecf20Sopenharmony_ci return 0; 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&info->write_mtx)) 15718c2ecf20Sopenharmony_ci return -ERESTARTSYS; 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci#ifdef ROCKET_DEBUG_WRITE 15748c2ecf20Sopenharmony_ci printk(KERN_INFO "rp_write %d chars...\n", count); 15758c2ecf20Sopenharmony_ci#endif 15768c2ecf20Sopenharmony_ci cp = &info->channel; 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci if (!tty->stopped && info->xmit_fifo_room < count) 15798c2ecf20Sopenharmony_ci info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp); 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_ci /* 15828c2ecf20Sopenharmony_ci * If the write queue for the port is empty, and there is FIFO space, stuff bytes 15838c2ecf20Sopenharmony_ci * into FIFO. Use the write queue for temp storage. 15848c2ecf20Sopenharmony_ci */ 15858c2ecf20Sopenharmony_ci if (!tty->stopped && info->xmit_cnt == 0 && info->xmit_fifo_room > 0) { 15868c2ecf20Sopenharmony_ci c = min(count, info->xmit_fifo_room); 15878c2ecf20Sopenharmony_ci b = buf; 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci /* Push data into FIFO, 2 bytes at a time */ 15908c2ecf20Sopenharmony_ci sOutStrW(sGetTxRxDataIO(cp), (unsigned short *) b, c / 2); 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci /* If there is a byte remaining, write it */ 15938c2ecf20Sopenharmony_ci if (c & 1) 15948c2ecf20Sopenharmony_ci sOutB(sGetTxRxDataIO(cp), b[c - 1]); 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci retval += c; 15978c2ecf20Sopenharmony_ci buf += c; 15988c2ecf20Sopenharmony_ci count -= c; 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci spin_lock_irqsave(&info->slock, flags); 16018c2ecf20Sopenharmony_ci info->xmit_fifo_room -= c; 16028c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&info->slock, flags); 16038c2ecf20Sopenharmony_ci } 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci /* If count is zero, we wrote it all and are done */ 16068c2ecf20Sopenharmony_ci if (!count) 16078c2ecf20Sopenharmony_ci goto end; 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci /* Write remaining data into the port's xmit_buf */ 16108c2ecf20Sopenharmony_ci while (1) { 16118c2ecf20Sopenharmony_ci /* Hung up ? */ 16128c2ecf20Sopenharmony_ci if (!tty_port_active(&info->port)) 16138c2ecf20Sopenharmony_ci goto end; 16148c2ecf20Sopenharmony_ci c = min(count, XMIT_BUF_SIZE - info->xmit_cnt - 1); 16158c2ecf20Sopenharmony_ci c = min(c, XMIT_BUF_SIZE - info->xmit_head); 16168c2ecf20Sopenharmony_ci if (c <= 0) 16178c2ecf20Sopenharmony_ci break; 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci b = buf; 16208c2ecf20Sopenharmony_ci memcpy(info->xmit_buf + info->xmit_head, b, c); 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_ci spin_lock_irqsave(&info->slock, flags); 16238c2ecf20Sopenharmony_ci info->xmit_head = 16248c2ecf20Sopenharmony_ci (info->xmit_head + c) & (XMIT_BUF_SIZE - 1); 16258c2ecf20Sopenharmony_ci info->xmit_cnt += c; 16268c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&info->slock, flags); 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci buf += c; 16298c2ecf20Sopenharmony_ci count -= c; 16308c2ecf20Sopenharmony_ci retval += c; 16318c2ecf20Sopenharmony_ci } 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ci if ((retval > 0) && !tty->stopped) 16348c2ecf20Sopenharmony_ci set_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_ciend: 16378c2ecf20Sopenharmony_ci if (info->xmit_cnt < WAKEUP_CHARS) { 16388c2ecf20Sopenharmony_ci tty_wakeup(tty); 16398c2ecf20Sopenharmony_ci#ifdef ROCKETPORT_HAVE_POLL_WAIT 16408c2ecf20Sopenharmony_ci wake_up_interruptible(&tty->poll_wait); 16418c2ecf20Sopenharmony_ci#endif 16428c2ecf20Sopenharmony_ci } 16438c2ecf20Sopenharmony_ci mutex_unlock(&info->write_mtx); 16448c2ecf20Sopenharmony_ci return retval; 16458c2ecf20Sopenharmony_ci} 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci/* 16488c2ecf20Sopenharmony_ci * Return the number of characters that can be sent. We estimate 16498c2ecf20Sopenharmony_ci * only using the in-memory transmit buffer only, and ignore the 16508c2ecf20Sopenharmony_ci * potential space in the transmit FIFO. 16518c2ecf20Sopenharmony_ci */ 16528c2ecf20Sopenharmony_cistatic int rp_write_room(struct tty_struct *tty) 16538c2ecf20Sopenharmony_ci{ 16548c2ecf20Sopenharmony_ci struct r_port *info = tty->driver_data; 16558c2ecf20Sopenharmony_ci int ret; 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_ci if (rocket_paranoia_check(info, "rp_write_room")) 16588c2ecf20Sopenharmony_ci return 0; 16598c2ecf20Sopenharmony_ci 16608c2ecf20Sopenharmony_ci ret = XMIT_BUF_SIZE - info->xmit_cnt - 1; 16618c2ecf20Sopenharmony_ci if (ret < 0) 16628c2ecf20Sopenharmony_ci ret = 0; 16638c2ecf20Sopenharmony_ci#ifdef ROCKET_DEBUG_WRITE 16648c2ecf20Sopenharmony_ci printk(KERN_INFO "rp_write_room returns %d...\n", ret); 16658c2ecf20Sopenharmony_ci#endif 16668c2ecf20Sopenharmony_ci return ret; 16678c2ecf20Sopenharmony_ci} 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_ci/* 16708c2ecf20Sopenharmony_ci * Return the number of characters in the buffer. Again, this only 16718c2ecf20Sopenharmony_ci * counts those characters in the in-memory transmit buffer. 16728c2ecf20Sopenharmony_ci */ 16738c2ecf20Sopenharmony_cistatic int rp_chars_in_buffer(struct tty_struct *tty) 16748c2ecf20Sopenharmony_ci{ 16758c2ecf20Sopenharmony_ci struct r_port *info = tty->driver_data; 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci if (rocket_paranoia_check(info, "rp_chars_in_buffer")) 16788c2ecf20Sopenharmony_ci return 0; 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_ci#ifdef ROCKET_DEBUG_WRITE 16818c2ecf20Sopenharmony_ci printk(KERN_INFO "rp_chars_in_buffer returns %d...\n", info->xmit_cnt); 16828c2ecf20Sopenharmony_ci#endif 16838c2ecf20Sopenharmony_ci return info->xmit_cnt; 16848c2ecf20Sopenharmony_ci} 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_ci/* 16878c2ecf20Sopenharmony_ci * Flushes the TX fifo for a port, deletes data in the xmit_buf stored in the 16888c2ecf20Sopenharmony_ci * r_port struct for the port. Note that spinlock are used to protect info members, 16898c2ecf20Sopenharmony_ci * do not call this function if the spinlock is already held. 16908c2ecf20Sopenharmony_ci */ 16918c2ecf20Sopenharmony_cistatic void rp_flush_buffer(struct tty_struct *tty) 16928c2ecf20Sopenharmony_ci{ 16938c2ecf20Sopenharmony_ci struct r_port *info = tty->driver_data; 16948c2ecf20Sopenharmony_ci CHANNEL_t *cp; 16958c2ecf20Sopenharmony_ci unsigned long flags; 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci if (rocket_paranoia_check(info, "rp_flush_buffer")) 16988c2ecf20Sopenharmony_ci return; 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_ci spin_lock_irqsave(&info->slock, flags); 17018c2ecf20Sopenharmony_ci info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; 17028c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&info->slock, flags); 17038c2ecf20Sopenharmony_ci 17048c2ecf20Sopenharmony_ci#ifdef ROCKETPORT_HAVE_POLL_WAIT 17058c2ecf20Sopenharmony_ci wake_up_interruptible(&tty->poll_wait); 17068c2ecf20Sopenharmony_ci#endif 17078c2ecf20Sopenharmony_ci tty_wakeup(tty); 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_ci cp = &info->channel; 17108c2ecf20Sopenharmony_ci sFlushTxFIFO(cp); 17118c2ecf20Sopenharmony_ci} 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_cistatic const struct pci_device_id rocket_pci_ids[] = { 17168c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP4QUAD) }, 17178c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP8OCTA) }, 17188c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_URP8OCTA) }, 17198c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP8INTF) }, 17208c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_URP8INTF) }, 17218c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP8J) }, 17228c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP4J) }, 17238c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP8SNI) }, 17248c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP16SNI) }, 17258c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP16INTF) }, 17268c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_URP16INTF) }, 17278c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_CRP16INTF) }, 17288c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP32INTF) }, 17298c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_URP32INTF) }, 17308c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RPP4) }, 17318c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RPP8) }, 17328c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP2_232) }, 17338c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP2_422) }, 17348c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP6M) }, 17358c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP4M) }, 17368c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_UPCI_RM3_8PORT) }, 17378c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_UPCI_RM3_4PORT) }, 17388c2ecf20Sopenharmony_ci { } 17398c2ecf20Sopenharmony_ci}; 17408c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, rocket_pci_ids); 17418c2ecf20Sopenharmony_ci 17428c2ecf20Sopenharmony_ci/* Resets the speaker controller on RocketModem II and III devices */ 17438c2ecf20Sopenharmony_cistatic void rmSpeakerReset(CONTROLLER_T * CtlP, unsigned long model) 17448c2ecf20Sopenharmony_ci{ 17458c2ecf20Sopenharmony_ci ByteIO_t addr; 17468c2ecf20Sopenharmony_ci 17478c2ecf20Sopenharmony_ci /* RocketModem II speaker control is at the 8th port location of offset 0x40 */ 17488c2ecf20Sopenharmony_ci if ((model == MODEL_RP4M) || (model == MODEL_RP6M)) { 17498c2ecf20Sopenharmony_ci addr = CtlP->AiopIO[0] + 0x4F; 17508c2ecf20Sopenharmony_ci sOutB(addr, 0); 17518c2ecf20Sopenharmony_ci } 17528c2ecf20Sopenharmony_ci 17538c2ecf20Sopenharmony_ci /* RocketModem III speaker control is at the 1st port location of offset 0x80 */ 17548c2ecf20Sopenharmony_ci if ((model == MODEL_UPCI_RM3_8PORT) 17558c2ecf20Sopenharmony_ci || (model == MODEL_UPCI_RM3_4PORT)) { 17568c2ecf20Sopenharmony_ci addr = CtlP->AiopIO[0] + 0x88; 17578c2ecf20Sopenharmony_ci sOutB(addr, 0); 17588c2ecf20Sopenharmony_ci } 17598c2ecf20Sopenharmony_ci} 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_ci/*************************************************************************** 17628c2ecf20Sopenharmony_ciFunction: sPCIInitController 17638c2ecf20Sopenharmony_ciPurpose: Initialization of controller global registers and controller 17648c2ecf20Sopenharmony_ci structure. 17658c2ecf20Sopenharmony_ciCall: sPCIInitController(CtlP,CtlNum,AiopIOList,AiopIOListSize, 17668c2ecf20Sopenharmony_ci IRQNum,Frequency,PeriodicOnly) 17678c2ecf20Sopenharmony_ci CONTROLLER_T *CtlP; Ptr to controller structure 17688c2ecf20Sopenharmony_ci int CtlNum; Controller number 17698c2ecf20Sopenharmony_ci ByteIO_t *AiopIOList; List of I/O addresses for each AIOP. 17708c2ecf20Sopenharmony_ci This list must be in the order the AIOPs will be found on the 17718c2ecf20Sopenharmony_ci controller. Once an AIOP in the list is not found, it is 17728c2ecf20Sopenharmony_ci assumed that there are no more AIOPs on the controller. 17738c2ecf20Sopenharmony_ci int AiopIOListSize; Number of addresses in AiopIOList 17748c2ecf20Sopenharmony_ci int IRQNum; Interrupt Request number. Can be any of the following: 17758c2ecf20Sopenharmony_ci 0: Disable global interrupts 17768c2ecf20Sopenharmony_ci 3: IRQ 3 17778c2ecf20Sopenharmony_ci 4: IRQ 4 17788c2ecf20Sopenharmony_ci 5: IRQ 5 17798c2ecf20Sopenharmony_ci 9: IRQ 9 17808c2ecf20Sopenharmony_ci 10: IRQ 10 17818c2ecf20Sopenharmony_ci 11: IRQ 11 17828c2ecf20Sopenharmony_ci 12: IRQ 12 17838c2ecf20Sopenharmony_ci 15: IRQ 15 17848c2ecf20Sopenharmony_ci Byte_t Frequency: A flag identifying the frequency 17858c2ecf20Sopenharmony_ci of the periodic interrupt, can be any one of the following: 17868c2ecf20Sopenharmony_ci FREQ_DIS - periodic interrupt disabled 17878c2ecf20Sopenharmony_ci FREQ_137HZ - 137 Hertz 17888c2ecf20Sopenharmony_ci FREQ_69HZ - 69 Hertz 17898c2ecf20Sopenharmony_ci FREQ_34HZ - 34 Hertz 17908c2ecf20Sopenharmony_ci FREQ_17HZ - 17 Hertz 17918c2ecf20Sopenharmony_ci FREQ_9HZ - 9 Hertz 17928c2ecf20Sopenharmony_ci FREQ_4HZ - 4 Hertz 17938c2ecf20Sopenharmony_ci If IRQNum is set to 0 the Frequency parameter is 17948c2ecf20Sopenharmony_ci overidden, it is forced to a value of FREQ_DIS. 17958c2ecf20Sopenharmony_ci int PeriodicOnly: 1 if all interrupts except the periodic 17968c2ecf20Sopenharmony_ci interrupt are to be blocked. 17978c2ecf20Sopenharmony_ci 0 is both the periodic interrupt and 17988c2ecf20Sopenharmony_ci other channel interrupts are allowed. 17998c2ecf20Sopenharmony_ci If IRQNum is set to 0 the PeriodicOnly parameter is 18008c2ecf20Sopenharmony_ci overidden, it is forced to a value of 0. 18018c2ecf20Sopenharmony_ciReturn: int: Number of AIOPs on the controller, or CTLID_NULL if controller 18028c2ecf20Sopenharmony_ci initialization failed. 18038c2ecf20Sopenharmony_ci 18048c2ecf20Sopenharmony_ciComments: 18058c2ecf20Sopenharmony_ci If periodic interrupts are to be disabled but AIOP interrupts 18068c2ecf20Sopenharmony_ci are allowed, set Frequency to FREQ_DIS and PeriodicOnly to 0. 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_ci If interrupts are to be completely disabled set IRQNum to 0. 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_ci Setting Frequency to FREQ_DIS and PeriodicOnly to 1 is an 18118c2ecf20Sopenharmony_ci invalid combination. 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_ci This function performs initialization of global interrupt modes, 18148c2ecf20Sopenharmony_ci but it does not actually enable global interrupts. To enable 18158c2ecf20Sopenharmony_ci and disable global interrupts use functions sEnGlobalInt() and 18168c2ecf20Sopenharmony_ci sDisGlobalInt(). Enabling of global interrupts is normally not 18178c2ecf20Sopenharmony_ci done until all other initializations are complete. 18188c2ecf20Sopenharmony_ci 18198c2ecf20Sopenharmony_ci Even if interrupts are globally enabled, they must also be 18208c2ecf20Sopenharmony_ci individually enabled for each channel that is to generate 18218c2ecf20Sopenharmony_ci interrupts. 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_ciWarnings: No range checking on any of the parameters is done. 18248c2ecf20Sopenharmony_ci 18258c2ecf20Sopenharmony_ci No context switches are allowed while executing this function. 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_ci After this function all AIOPs on the controller are disabled, 18288c2ecf20Sopenharmony_ci they can be enabled with sEnAiop(). 18298c2ecf20Sopenharmony_ci*/ 18308c2ecf20Sopenharmony_cistatic int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum, 18318c2ecf20Sopenharmony_ci ByteIO_t * AiopIOList, int AiopIOListSize, 18328c2ecf20Sopenharmony_ci WordIO_t ConfigIO, int IRQNum, Byte_t Frequency, 18338c2ecf20Sopenharmony_ci int PeriodicOnly, int altChanRingIndicator, 18348c2ecf20Sopenharmony_ci int UPCIRingInd) 18358c2ecf20Sopenharmony_ci{ 18368c2ecf20Sopenharmony_ci int i; 18378c2ecf20Sopenharmony_ci ByteIO_t io; 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_ci CtlP->AltChanRingIndicator = altChanRingIndicator; 18408c2ecf20Sopenharmony_ci CtlP->UPCIRingInd = UPCIRingInd; 18418c2ecf20Sopenharmony_ci CtlP->CtlNum = CtlNum; 18428c2ecf20Sopenharmony_ci CtlP->CtlID = CTLID_0001; /* controller release 1 */ 18438c2ecf20Sopenharmony_ci CtlP->BusType = isPCI; /* controller release 1 */ 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_ci if (ConfigIO) { 18468c2ecf20Sopenharmony_ci CtlP->isUPCI = 1; 18478c2ecf20Sopenharmony_ci CtlP->PCIIO = ConfigIO + _PCI_9030_INT_CTRL; 18488c2ecf20Sopenharmony_ci CtlP->PCIIO2 = ConfigIO + _PCI_9030_GPIO_CTRL; 18498c2ecf20Sopenharmony_ci CtlP->AiopIntrBits = upci_aiop_intr_bits; 18508c2ecf20Sopenharmony_ci } else { 18518c2ecf20Sopenharmony_ci CtlP->isUPCI = 0; 18528c2ecf20Sopenharmony_ci CtlP->PCIIO = 18538c2ecf20Sopenharmony_ci (WordIO_t) ((ByteIO_t) AiopIOList[0] + _PCI_INT_FUNC); 18548c2ecf20Sopenharmony_ci CtlP->AiopIntrBits = aiop_intr_bits; 18558c2ecf20Sopenharmony_ci } 18568c2ecf20Sopenharmony_ci 18578c2ecf20Sopenharmony_ci sPCIControllerEOI(CtlP); /* clear EOI if warm init */ 18588c2ecf20Sopenharmony_ci /* Init AIOPs */ 18598c2ecf20Sopenharmony_ci CtlP->NumAiop = 0; 18608c2ecf20Sopenharmony_ci for (i = 0; i < AiopIOListSize; i++) { 18618c2ecf20Sopenharmony_ci io = AiopIOList[i]; 18628c2ecf20Sopenharmony_ci CtlP->AiopIO[i] = (WordIO_t) io; 18638c2ecf20Sopenharmony_ci CtlP->AiopIntChanIO[i] = io + _INT_CHAN; 18648c2ecf20Sopenharmony_ci 18658c2ecf20Sopenharmony_ci CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */ 18668c2ecf20Sopenharmony_ci if (CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */ 18678c2ecf20Sopenharmony_ci break; /* done looking for AIOPs */ 18688c2ecf20Sopenharmony_ci 18698c2ecf20Sopenharmony_ci CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t) io); /* num channels in AIOP */ 18708c2ecf20Sopenharmony_ci sOutW((WordIO_t) io + _INDX_ADDR, _CLK_PRE); /* clock prescaler */ 18718c2ecf20Sopenharmony_ci sOutB(io + _INDX_DATA, sClockPrescale); 18728c2ecf20Sopenharmony_ci CtlP->NumAiop++; /* bump count of AIOPs */ 18738c2ecf20Sopenharmony_ci } 18748c2ecf20Sopenharmony_ci 18758c2ecf20Sopenharmony_ci if (CtlP->NumAiop == 0) 18768c2ecf20Sopenharmony_ci return (-1); 18778c2ecf20Sopenharmony_ci else 18788c2ecf20Sopenharmony_ci return (CtlP->NumAiop); 18798c2ecf20Sopenharmony_ci} 18808c2ecf20Sopenharmony_ci 18818c2ecf20Sopenharmony_ci/* 18828c2ecf20Sopenharmony_ci * Called when a PCI card is found. Retrieves and stores model information, 18838c2ecf20Sopenharmony_ci * init's aiopic and serial port hardware. 18848c2ecf20Sopenharmony_ci * Inputs: i is the board number (0-n) 18858c2ecf20Sopenharmony_ci */ 18868c2ecf20Sopenharmony_cistatic __init int register_PCI(int i, struct pci_dev *dev) 18878c2ecf20Sopenharmony_ci{ 18888c2ecf20Sopenharmony_ci int num_aiops, aiop, max_num_aiops, chan; 18898c2ecf20Sopenharmony_ci unsigned int aiopio[MAX_AIOPS_PER_BOARD]; 18908c2ecf20Sopenharmony_ci CONTROLLER_t *ctlp; 18918c2ecf20Sopenharmony_ci 18928c2ecf20Sopenharmony_ci int fast_clock = 0; 18938c2ecf20Sopenharmony_ci int altChanRingIndicator = 0; 18948c2ecf20Sopenharmony_ci int ports_per_aiop = 8; 18958c2ecf20Sopenharmony_ci WordIO_t ConfigIO = 0; 18968c2ecf20Sopenharmony_ci ByteIO_t UPCIRingInd = 0; 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_ci if (!dev || !pci_match_id(rocket_pci_ids, dev) || 18998c2ecf20Sopenharmony_ci pci_enable_device(dev) || i >= NUM_BOARDS) 19008c2ecf20Sopenharmony_ci return 0; 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_ci rcktpt_io_addr[i] = pci_resource_start(dev, 0); 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_ci rcktpt_type[i] = ROCKET_TYPE_NORMAL; 19058c2ecf20Sopenharmony_ci rocketModel[i].loadrm2 = 0; 19068c2ecf20Sopenharmony_ci rocketModel[i].startingPortNumber = nextLineNumber; 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_ci /* Depending on the model, set up some config variables */ 19098c2ecf20Sopenharmony_ci switch (dev->device) { 19108c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_RP4QUAD: 19118c2ecf20Sopenharmony_ci max_num_aiops = 1; 19128c2ecf20Sopenharmony_ci ports_per_aiop = 4; 19138c2ecf20Sopenharmony_ci rocketModel[i].model = MODEL_RP4QUAD; 19148c2ecf20Sopenharmony_ci strcpy(rocketModel[i].modelString, "RocketPort 4 port w/quad cable"); 19158c2ecf20Sopenharmony_ci rocketModel[i].numPorts = 4; 19168c2ecf20Sopenharmony_ci break; 19178c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_RP8OCTA: 19188c2ecf20Sopenharmony_ci max_num_aiops = 1; 19198c2ecf20Sopenharmony_ci rocketModel[i].model = MODEL_RP8OCTA; 19208c2ecf20Sopenharmony_ci strcpy(rocketModel[i].modelString, "RocketPort 8 port w/octa cable"); 19218c2ecf20Sopenharmony_ci rocketModel[i].numPorts = 8; 19228c2ecf20Sopenharmony_ci break; 19238c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_URP8OCTA: 19248c2ecf20Sopenharmony_ci max_num_aiops = 1; 19258c2ecf20Sopenharmony_ci rocketModel[i].model = MODEL_UPCI_RP8OCTA; 19268c2ecf20Sopenharmony_ci strcpy(rocketModel[i].modelString, "RocketPort UPCI 8 port w/octa cable"); 19278c2ecf20Sopenharmony_ci rocketModel[i].numPorts = 8; 19288c2ecf20Sopenharmony_ci break; 19298c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_RP8INTF: 19308c2ecf20Sopenharmony_ci max_num_aiops = 1; 19318c2ecf20Sopenharmony_ci rocketModel[i].model = MODEL_RP8INTF; 19328c2ecf20Sopenharmony_ci strcpy(rocketModel[i].modelString, "RocketPort 8 port w/external I/F"); 19338c2ecf20Sopenharmony_ci rocketModel[i].numPorts = 8; 19348c2ecf20Sopenharmony_ci break; 19358c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_URP8INTF: 19368c2ecf20Sopenharmony_ci max_num_aiops = 1; 19378c2ecf20Sopenharmony_ci rocketModel[i].model = MODEL_UPCI_RP8INTF; 19388c2ecf20Sopenharmony_ci strcpy(rocketModel[i].modelString, "RocketPort UPCI 8 port w/external I/F"); 19398c2ecf20Sopenharmony_ci rocketModel[i].numPorts = 8; 19408c2ecf20Sopenharmony_ci break; 19418c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_RP8J: 19428c2ecf20Sopenharmony_ci max_num_aiops = 1; 19438c2ecf20Sopenharmony_ci rocketModel[i].model = MODEL_RP8J; 19448c2ecf20Sopenharmony_ci strcpy(rocketModel[i].modelString, "RocketPort 8 port w/RJ11 connectors"); 19458c2ecf20Sopenharmony_ci rocketModel[i].numPorts = 8; 19468c2ecf20Sopenharmony_ci break; 19478c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_RP4J: 19488c2ecf20Sopenharmony_ci max_num_aiops = 1; 19498c2ecf20Sopenharmony_ci ports_per_aiop = 4; 19508c2ecf20Sopenharmony_ci rocketModel[i].model = MODEL_RP4J; 19518c2ecf20Sopenharmony_ci strcpy(rocketModel[i].modelString, "RocketPort 4 port w/RJ45 connectors"); 19528c2ecf20Sopenharmony_ci rocketModel[i].numPorts = 4; 19538c2ecf20Sopenharmony_ci break; 19548c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_RP8SNI: 19558c2ecf20Sopenharmony_ci max_num_aiops = 1; 19568c2ecf20Sopenharmony_ci rocketModel[i].model = MODEL_RP8SNI; 19578c2ecf20Sopenharmony_ci strcpy(rocketModel[i].modelString, "RocketPort 8 port w/ custom DB78"); 19588c2ecf20Sopenharmony_ci rocketModel[i].numPorts = 8; 19598c2ecf20Sopenharmony_ci break; 19608c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_RP16SNI: 19618c2ecf20Sopenharmony_ci max_num_aiops = 2; 19628c2ecf20Sopenharmony_ci rocketModel[i].model = MODEL_RP16SNI; 19638c2ecf20Sopenharmony_ci strcpy(rocketModel[i].modelString, "RocketPort 16 port w/ custom DB78"); 19648c2ecf20Sopenharmony_ci rocketModel[i].numPorts = 16; 19658c2ecf20Sopenharmony_ci break; 19668c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_RP16INTF: 19678c2ecf20Sopenharmony_ci max_num_aiops = 2; 19688c2ecf20Sopenharmony_ci rocketModel[i].model = MODEL_RP16INTF; 19698c2ecf20Sopenharmony_ci strcpy(rocketModel[i].modelString, "RocketPort 16 port w/external I/F"); 19708c2ecf20Sopenharmony_ci rocketModel[i].numPorts = 16; 19718c2ecf20Sopenharmony_ci break; 19728c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_URP16INTF: 19738c2ecf20Sopenharmony_ci max_num_aiops = 2; 19748c2ecf20Sopenharmony_ci rocketModel[i].model = MODEL_UPCI_RP16INTF; 19758c2ecf20Sopenharmony_ci strcpy(rocketModel[i].modelString, "RocketPort UPCI 16 port w/external I/F"); 19768c2ecf20Sopenharmony_ci rocketModel[i].numPorts = 16; 19778c2ecf20Sopenharmony_ci break; 19788c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_CRP16INTF: 19798c2ecf20Sopenharmony_ci max_num_aiops = 2; 19808c2ecf20Sopenharmony_ci rocketModel[i].model = MODEL_CPCI_RP16INTF; 19818c2ecf20Sopenharmony_ci strcpy(rocketModel[i].modelString, "RocketPort Compact PCI 16 port w/external I/F"); 19828c2ecf20Sopenharmony_ci rocketModel[i].numPorts = 16; 19838c2ecf20Sopenharmony_ci break; 19848c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_RP32INTF: 19858c2ecf20Sopenharmony_ci max_num_aiops = 4; 19868c2ecf20Sopenharmony_ci rocketModel[i].model = MODEL_RP32INTF; 19878c2ecf20Sopenharmony_ci strcpy(rocketModel[i].modelString, "RocketPort 32 port w/external I/F"); 19888c2ecf20Sopenharmony_ci rocketModel[i].numPorts = 32; 19898c2ecf20Sopenharmony_ci break; 19908c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_URP32INTF: 19918c2ecf20Sopenharmony_ci max_num_aiops = 4; 19928c2ecf20Sopenharmony_ci rocketModel[i].model = MODEL_UPCI_RP32INTF; 19938c2ecf20Sopenharmony_ci strcpy(rocketModel[i].modelString, "RocketPort UPCI 32 port w/external I/F"); 19948c2ecf20Sopenharmony_ci rocketModel[i].numPorts = 32; 19958c2ecf20Sopenharmony_ci break; 19968c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_RPP4: 19978c2ecf20Sopenharmony_ci max_num_aiops = 1; 19988c2ecf20Sopenharmony_ci ports_per_aiop = 4; 19998c2ecf20Sopenharmony_ci altChanRingIndicator++; 20008c2ecf20Sopenharmony_ci fast_clock++; 20018c2ecf20Sopenharmony_ci rocketModel[i].model = MODEL_RPP4; 20028c2ecf20Sopenharmony_ci strcpy(rocketModel[i].modelString, "RocketPort Plus 4 port"); 20038c2ecf20Sopenharmony_ci rocketModel[i].numPorts = 4; 20048c2ecf20Sopenharmony_ci break; 20058c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_RPP8: 20068c2ecf20Sopenharmony_ci max_num_aiops = 2; 20078c2ecf20Sopenharmony_ci ports_per_aiop = 4; 20088c2ecf20Sopenharmony_ci altChanRingIndicator++; 20098c2ecf20Sopenharmony_ci fast_clock++; 20108c2ecf20Sopenharmony_ci rocketModel[i].model = MODEL_RPP8; 20118c2ecf20Sopenharmony_ci strcpy(rocketModel[i].modelString, "RocketPort Plus 8 port"); 20128c2ecf20Sopenharmony_ci rocketModel[i].numPorts = 8; 20138c2ecf20Sopenharmony_ci break; 20148c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_RP2_232: 20158c2ecf20Sopenharmony_ci max_num_aiops = 1; 20168c2ecf20Sopenharmony_ci ports_per_aiop = 2; 20178c2ecf20Sopenharmony_ci altChanRingIndicator++; 20188c2ecf20Sopenharmony_ci fast_clock++; 20198c2ecf20Sopenharmony_ci rocketModel[i].model = MODEL_RP2_232; 20208c2ecf20Sopenharmony_ci strcpy(rocketModel[i].modelString, "RocketPort Plus 2 port RS232"); 20218c2ecf20Sopenharmony_ci rocketModel[i].numPorts = 2; 20228c2ecf20Sopenharmony_ci break; 20238c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_RP2_422: 20248c2ecf20Sopenharmony_ci max_num_aiops = 1; 20258c2ecf20Sopenharmony_ci ports_per_aiop = 2; 20268c2ecf20Sopenharmony_ci altChanRingIndicator++; 20278c2ecf20Sopenharmony_ci fast_clock++; 20288c2ecf20Sopenharmony_ci rocketModel[i].model = MODEL_RP2_422; 20298c2ecf20Sopenharmony_ci strcpy(rocketModel[i].modelString, "RocketPort Plus 2 port RS422"); 20308c2ecf20Sopenharmony_ci rocketModel[i].numPorts = 2; 20318c2ecf20Sopenharmony_ci break; 20328c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_RP6M: 20338c2ecf20Sopenharmony_ci 20348c2ecf20Sopenharmony_ci max_num_aiops = 1; 20358c2ecf20Sopenharmony_ci ports_per_aiop = 6; 20368c2ecf20Sopenharmony_ci 20378c2ecf20Sopenharmony_ci /* If revision is 1, the rocketmodem flash must be loaded. 20388c2ecf20Sopenharmony_ci * If it is 2 it is a "socketed" version. */ 20398c2ecf20Sopenharmony_ci if (dev->revision == 1) { 20408c2ecf20Sopenharmony_ci rcktpt_type[i] = ROCKET_TYPE_MODEMII; 20418c2ecf20Sopenharmony_ci rocketModel[i].loadrm2 = 1; 20428c2ecf20Sopenharmony_ci } else { 20438c2ecf20Sopenharmony_ci rcktpt_type[i] = ROCKET_TYPE_MODEM; 20448c2ecf20Sopenharmony_ci } 20458c2ecf20Sopenharmony_ci 20468c2ecf20Sopenharmony_ci rocketModel[i].model = MODEL_RP6M; 20478c2ecf20Sopenharmony_ci strcpy(rocketModel[i].modelString, "RocketModem 6 port"); 20488c2ecf20Sopenharmony_ci rocketModel[i].numPorts = 6; 20498c2ecf20Sopenharmony_ci break; 20508c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_RP4M: 20518c2ecf20Sopenharmony_ci max_num_aiops = 1; 20528c2ecf20Sopenharmony_ci ports_per_aiop = 4; 20538c2ecf20Sopenharmony_ci if (dev->revision == 1) { 20548c2ecf20Sopenharmony_ci rcktpt_type[i] = ROCKET_TYPE_MODEMII; 20558c2ecf20Sopenharmony_ci rocketModel[i].loadrm2 = 1; 20568c2ecf20Sopenharmony_ci } else { 20578c2ecf20Sopenharmony_ci rcktpt_type[i] = ROCKET_TYPE_MODEM; 20588c2ecf20Sopenharmony_ci } 20598c2ecf20Sopenharmony_ci 20608c2ecf20Sopenharmony_ci rocketModel[i].model = MODEL_RP4M; 20618c2ecf20Sopenharmony_ci strcpy(rocketModel[i].modelString, "RocketModem 4 port"); 20628c2ecf20Sopenharmony_ci rocketModel[i].numPorts = 4; 20638c2ecf20Sopenharmony_ci break; 20648c2ecf20Sopenharmony_ci default: 20658c2ecf20Sopenharmony_ci max_num_aiops = 0; 20668c2ecf20Sopenharmony_ci break; 20678c2ecf20Sopenharmony_ci } 20688c2ecf20Sopenharmony_ci 20698c2ecf20Sopenharmony_ci /* 20708c2ecf20Sopenharmony_ci * Check for UPCI boards. 20718c2ecf20Sopenharmony_ci */ 20728c2ecf20Sopenharmony_ci 20738c2ecf20Sopenharmony_ci switch (dev->device) { 20748c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_URP32INTF: 20758c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_URP8INTF: 20768c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_URP16INTF: 20778c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_CRP16INTF: 20788c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_URP8OCTA: 20798c2ecf20Sopenharmony_ci rcktpt_io_addr[i] = pci_resource_start(dev, 2); 20808c2ecf20Sopenharmony_ci ConfigIO = pci_resource_start(dev, 1); 20818c2ecf20Sopenharmony_ci if (dev->device == PCI_DEVICE_ID_URP8OCTA) { 20828c2ecf20Sopenharmony_ci UPCIRingInd = rcktpt_io_addr[i] + _PCI_9030_RING_IND; 20838c2ecf20Sopenharmony_ci 20848c2ecf20Sopenharmony_ci /* 20858c2ecf20Sopenharmony_ci * Check for octa or quad cable. 20868c2ecf20Sopenharmony_ci */ 20878c2ecf20Sopenharmony_ci if (! 20888c2ecf20Sopenharmony_ci (sInW(ConfigIO + _PCI_9030_GPIO_CTRL) & 20898c2ecf20Sopenharmony_ci PCI_GPIO_CTRL_8PORT)) { 20908c2ecf20Sopenharmony_ci ports_per_aiop = 4; 20918c2ecf20Sopenharmony_ci rocketModel[i].numPorts = 4; 20928c2ecf20Sopenharmony_ci } 20938c2ecf20Sopenharmony_ci } 20948c2ecf20Sopenharmony_ci break; 20958c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_UPCI_RM3_8PORT: 20968c2ecf20Sopenharmony_ci max_num_aiops = 1; 20978c2ecf20Sopenharmony_ci rocketModel[i].model = MODEL_UPCI_RM3_8PORT; 20988c2ecf20Sopenharmony_ci strcpy(rocketModel[i].modelString, "RocketModem III 8 port"); 20998c2ecf20Sopenharmony_ci rocketModel[i].numPorts = 8; 21008c2ecf20Sopenharmony_ci rcktpt_io_addr[i] = pci_resource_start(dev, 2); 21018c2ecf20Sopenharmony_ci UPCIRingInd = rcktpt_io_addr[i] + _PCI_9030_RING_IND; 21028c2ecf20Sopenharmony_ci ConfigIO = pci_resource_start(dev, 1); 21038c2ecf20Sopenharmony_ci rcktpt_type[i] = ROCKET_TYPE_MODEMIII; 21048c2ecf20Sopenharmony_ci break; 21058c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_UPCI_RM3_4PORT: 21068c2ecf20Sopenharmony_ci max_num_aiops = 1; 21078c2ecf20Sopenharmony_ci rocketModel[i].model = MODEL_UPCI_RM3_4PORT; 21088c2ecf20Sopenharmony_ci strcpy(rocketModel[i].modelString, "RocketModem III 4 port"); 21098c2ecf20Sopenharmony_ci rocketModel[i].numPorts = 4; 21108c2ecf20Sopenharmony_ci rcktpt_io_addr[i] = pci_resource_start(dev, 2); 21118c2ecf20Sopenharmony_ci UPCIRingInd = rcktpt_io_addr[i] + _PCI_9030_RING_IND; 21128c2ecf20Sopenharmony_ci ConfigIO = pci_resource_start(dev, 1); 21138c2ecf20Sopenharmony_ci rcktpt_type[i] = ROCKET_TYPE_MODEMIII; 21148c2ecf20Sopenharmony_ci break; 21158c2ecf20Sopenharmony_ci default: 21168c2ecf20Sopenharmony_ci break; 21178c2ecf20Sopenharmony_ci } 21188c2ecf20Sopenharmony_ci 21198c2ecf20Sopenharmony_ci if (fast_clock) { 21208c2ecf20Sopenharmony_ci sClockPrescale = 0x12; /* mod 2 (divide by 3) */ 21218c2ecf20Sopenharmony_ci rp_baud_base[i] = 921600; 21228c2ecf20Sopenharmony_ci } else { 21238c2ecf20Sopenharmony_ci /* 21248c2ecf20Sopenharmony_ci * If support_low_speed is set, use the slow clock 21258c2ecf20Sopenharmony_ci * prescale, which supports 50 bps 21268c2ecf20Sopenharmony_ci */ 21278c2ecf20Sopenharmony_ci if (support_low_speed) { 21288c2ecf20Sopenharmony_ci /* mod 9 (divide by 10) prescale */ 21298c2ecf20Sopenharmony_ci sClockPrescale = 0x19; 21308c2ecf20Sopenharmony_ci rp_baud_base[i] = 230400; 21318c2ecf20Sopenharmony_ci } else { 21328c2ecf20Sopenharmony_ci /* mod 4 (divide by 5) prescale */ 21338c2ecf20Sopenharmony_ci sClockPrescale = 0x14; 21348c2ecf20Sopenharmony_ci rp_baud_base[i] = 460800; 21358c2ecf20Sopenharmony_ci } 21368c2ecf20Sopenharmony_ci } 21378c2ecf20Sopenharmony_ci 21388c2ecf20Sopenharmony_ci for (aiop = 0; aiop < max_num_aiops; aiop++) 21398c2ecf20Sopenharmony_ci aiopio[aiop] = rcktpt_io_addr[i] + (aiop * 0x40); 21408c2ecf20Sopenharmony_ci ctlp = sCtlNumToCtlPtr(i); 21418c2ecf20Sopenharmony_ci num_aiops = sPCIInitController(ctlp, i, aiopio, max_num_aiops, ConfigIO, 0, FREQ_DIS, 0, altChanRingIndicator, UPCIRingInd); 21428c2ecf20Sopenharmony_ci for (aiop = 0; aiop < max_num_aiops; aiop++) 21438c2ecf20Sopenharmony_ci ctlp->AiopNumChan[aiop] = ports_per_aiop; 21448c2ecf20Sopenharmony_ci 21458c2ecf20Sopenharmony_ci dev_info(&dev->dev, "comtrol PCI controller #%d found at " 21468c2ecf20Sopenharmony_ci "address %04lx, %d AIOP(s) (%s), creating ttyR%d - %ld\n", 21478c2ecf20Sopenharmony_ci i, rcktpt_io_addr[i], num_aiops, rocketModel[i].modelString, 21488c2ecf20Sopenharmony_ci rocketModel[i].startingPortNumber, 21498c2ecf20Sopenharmony_ci rocketModel[i].startingPortNumber + rocketModel[i].numPorts-1); 21508c2ecf20Sopenharmony_ci 21518c2ecf20Sopenharmony_ci if (num_aiops <= 0) { 21528c2ecf20Sopenharmony_ci rcktpt_io_addr[i] = 0; 21538c2ecf20Sopenharmony_ci return (0); 21548c2ecf20Sopenharmony_ci } 21558c2ecf20Sopenharmony_ci is_PCI[i] = 1; 21568c2ecf20Sopenharmony_ci 21578c2ecf20Sopenharmony_ci /* Reset the AIOPIC, init the serial ports */ 21588c2ecf20Sopenharmony_ci for (aiop = 0; aiop < num_aiops; aiop++) { 21598c2ecf20Sopenharmony_ci sResetAiopByNum(ctlp, aiop); 21608c2ecf20Sopenharmony_ci for (chan = 0; chan < ports_per_aiop; chan++) 21618c2ecf20Sopenharmony_ci init_r_port(i, aiop, chan, dev); 21628c2ecf20Sopenharmony_ci } 21638c2ecf20Sopenharmony_ci 21648c2ecf20Sopenharmony_ci /* Rocket modems must be reset */ 21658c2ecf20Sopenharmony_ci if ((rcktpt_type[i] == ROCKET_TYPE_MODEM) || 21668c2ecf20Sopenharmony_ci (rcktpt_type[i] == ROCKET_TYPE_MODEMII) || 21678c2ecf20Sopenharmony_ci (rcktpt_type[i] == ROCKET_TYPE_MODEMIII)) { 21688c2ecf20Sopenharmony_ci for (chan = 0; chan < ports_per_aiop; chan++) 21698c2ecf20Sopenharmony_ci sPCIModemReset(ctlp, chan, 1); 21708c2ecf20Sopenharmony_ci msleep(500); 21718c2ecf20Sopenharmony_ci for (chan = 0; chan < ports_per_aiop; chan++) 21728c2ecf20Sopenharmony_ci sPCIModemReset(ctlp, chan, 0); 21738c2ecf20Sopenharmony_ci msleep(500); 21748c2ecf20Sopenharmony_ci rmSpeakerReset(ctlp, rocketModel[i].model); 21758c2ecf20Sopenharmony_ci } 21768c2ecf20Sopenharmony_ci return (1); 21778c2ecf20Sopenharmony_ci} 21788c2ecf20Sopenharmony_ci 21798c2ecf20Sopenharmony_ci/* 21808c2ecf20Sopenharmony_ci * Probes for PCI cards, inits them if found 21818c2ecf20Sopenharmony_ci * Input: board_found = number of ISA boards already found, or the 21828c2ecf20Sopenharmony_ci * starting board number 21838c2ecf20Sopenharmony_ci * Returns: Number of PCI boards found 21848c2ecf20Sopenharmony_ci */ 21858c2ecf20Sopenharmony_cistatic int __init init_PCI(int boards_found) 21868c2ecf20Sopenharmony_ci{ 21878c2ecf20Sopenharmony_ci struct pci_dev *dev = NULL; 21888c2ecf20Sopenharmony_ci int count = 0; 21898c2ecf20Sopenharmony_ci 21908c2ecf20Sopenharmony_ci /* Work through the PCI device list, pulling out ours */ 21918c2ecf20Sopenharmony_ci while ((dev = pci_get_device(PCI_VENDOR_ID_RP, PCI_ANY_ID, dev))) { 21928c2ecf20Sopenharmony_ci if (register_PCI(count + boards_found, dev)) 21938c2ecf20Sopenharmony_ci count++; 21948c2ecf20Sopenharmony_ci } 21958c2ecf20Sopenharmony_ci return (count); 21968c2ecf20Sopenharmony_ci} 21978c2ecf20Sopenharmony_ci 21988c2ecf20Sopenharmony_ci#endif /* CONFIG_PCI */ 21998c2ecf20Sopenharmony_ci 22008c2ecf20Sopenharmony_ci/* 22018c2ecf20Sopenharmony_ci * Probes for ISA cards 22028c2ecf20Sopenharmony_ci * Input: i = the board number to look for 22038c2ecf20Sopenharmony_ci * Returns: 1 if board found, 0 else 22048c2ecf20Sopenharmony_ci */ 22058c2ecf20Sopenharmony_cistatic int __init init_ISA(int i) 22068c2ecf20Sopenharmony_ci{ 22078c2ecf20Sopenharmony_ci int num_aiops, num_chan = 0, total_num_chan = 0; 22088c2ecf20Sopenharmony_ci int aiop, chan; 22098c2ecf20Sopenharmony_ci unsigned int aiopio[MAX_AIOPS_PER_BOARD]; 22108c2ecf20Sopenharmony_ci CONTROLLER_t *ctlp; 22118c2ecf20Sopenharmony_ci char *type_string; 22128c2ecf20Sopenharmony_ci 22138c2ecf20Sopenharmony_ci /* If io_addr is zero, no board configured */ 22148c2ecf20Sopenharmony_ci if (rcktpt_io_addr[i] == 0) 22158c2ecf20Sopenharmony_ci return (0); 22168c2ecf20Sopenharmony_ci 22178c2ecf20Sopenharmony_ci /* Reserve the IO region */ 22188c2ecf20Sopenharmony_ci if (!request_region(rcktpt_io_addr[i], 64, "Comtrol RocketPort")) { 22198c2ecf20Sopenharmony_ci printk(KERN_ERR "Unable to reserve IO region for configured " 22208c2ecf20Sopenharmony_ci "ISA RocketPort at address 0x%lx, board not " 22218c2ecf20Sopenharmony_ci "installed...\n", rcktpt_io_addr[i]); 22228c2ecf20Sopenharmony_ci rcktpt_io_addr[i] = 0; 22238c2ecf20Sopenharmony_ci return (0); 22248c2ecf20Sopenharmony_ci } 22258c2ecf20Sopenharmony_ci 22268c2ecf20Sopenharmony_ci ctlp = sCtlNumToCtlPtr(i); 22278c2ecf20Sopenharmony_ci 22288c2ecf20Sopenharmony_ci ctlp->boardType = rcktpt_type[i]; 22298c2ecf20Sopenharmony_ci 22308c2ecf20Sopenharmony_ci switch (rcktpt_type[i]) { 22318c2ecf20Sopenharmony_ci case ROCKET_TYPE_PC104: 22328c2ecf20Sopenharmony_ci type_string = "(PC104)"; 22338c2ecf20Sopenharmony_ci break; 22348c2ecf20Sopenharmony_ci case ROCKET_TYPE_MODEM: 22358c2ecf20Sopenharmony_ci type_string = "(RocketModem)"; 22368c2ecf20Sopenharmony_ci break; 22378c2ecf20Sopenharmony_ci case ROCKET_TYPE_MODEMII: 22388c2ecf20Sopenharmony_ci type_string = "(RocketModem II)"; 22398c2ecf20Sopenharmony_ci break; 22408c2ecf20Sopenharmony_ci default: 22418c2ecf20Sopenharmony_ci type_string = ""; 22428c2ecf20Sopenharmony_ci break; 22438c2ecf20Sopenharmony_ci } 22448c2ecf20Sopenharmony_ci 22458c2ecf20Sopenharmony_ci /* 22468c2ecf20Sopenharmony_ci * If support_low_speed is set, use the slow clock prescale, 22478c2ecf20Sopenharmony_ci * which supports 50 bps 22488c2ecf20Sopenharmony_ci */ 22498c2ecf20Sopenharmony_ci if (support_low_speed) { 22508c2ecf20Sopenharmony_ci sClockPrescale = 0x19; /* mod 9 (divide by 10) prescale */ 22518c2ecf20Sopenharmony_ci rp_baud_base[i] = 230400; 22528c2ecf20Sopenharmony_ci } else { 22538c2ecf20Sopenharmony_ci sClockPrescale = 0x14; /* mod 4 (divide by 5) prescale */ 22548c2ecf20Sopenharmony_ci rp_baud_base[i] = 460800; 22558c2ecf20Sopenharmony_ci } 22568c2ecf20Sopenharmony_ci 22578c2ecf20Sopenharmony_ci for (aiop = 0; aiop < MAX_AIOPS_PER_BOARD; aiop++) 22588c2ecf20Sopenharmony_ci aiopio[aiop] = rcktpt_io_addr[i] + (aiop * 0x400); 22598c2ecf20Sopenharmony_ci 22608c2ecf20Sopenharmony_ci num_aiops = sInitController(ctlp, i, controller + (i * 0x400), aiopio, MAX_AIOPS_PER_BOARD, 0, FREQ_DIS, 0); 22618c2ecf20Sopenharmony_ci 22628c2ecf20Sopenharmony_ci if (ctlp->boardType == ROCKET_TYPE_PC104) { 22638c2ecf20Sopenharmony_ci sEnAiop(ctlp, 2); /* only one AIOPIC, but these */ 22648c2ecf20Sopenharmony_ci sEnAiop(ctlp, 3); /* CSels used for other stuff */ 22658c2ecf20Sopenharmony_ci } 22668c2ecf20Sopenharmony_ci 22678c2ecf20Sopenharmony_ci /* If something went wrong initing the AIOP's release the ISA IO memory */ 22688c2ecf20Sopenharmony_ci if (num_aiops <= 0) { 22698c2ecf20Sopenharmony_ci release_region(rcktpt_io_addr[i], 64); 22708c2ecf20Sopenharmony_ci rcktpt_io_addr[i] = 0; 22718c2ecf20Sopenharmony_ci return (0); 22728c2ecf20Sopenharmony_ci } 22738c2ecf20Sopenharmony_ci 22748c2ecf20Sopenharmony_ci rocketModel[i].startingPortNumber = nextLineNumber; 22758c2ecf20Sopenharmony_ci 22768c2ecf20Sopenharmony_ci for (aiop = 0; aiop < num_aiops; aiop++) { 22778c2ecf20Sopenharmony_ci sResetAiopByNum(ctlp, aiop); 22788c2ecf20Sopenharmony_ci sEnAiop(ctlp, aiop); 22798c2ecf20Sopenharmony_ci num_chan = sGetAiopNumChan(ctlp, aiop); 22808c2ecf20Sopenharmony_ci total_num_chan += num_chan; 22818c2ecf20Sopenharmony_ci for (chan = 0; chan < num_chan; chan++) 22828c2ecf20Sopenharmony_ci init_r_port(i, aiop, chan, NULL); 22838c2ecf20Sopenharmony_ci } 22848c2ecf20Sopenharmony_ci is_PCI[i] = 0; 22858c2ecf20Sopenharmony_ci if ((rcktpt_type[i] == ROCKET_TYPE_MODEM) || (rcktpt_type[i] == ROCKET_TYPE_MODEMII)) { 22868c2ecf20Sopenharmony_ci num_chan = sGetAiopNumChan(ctlp, 0); 22878c2ecf20Sopenharmony_ci total_num_chan = num_chan; 22888c2ecf20Sopenharmony_ci for (chan = 0; chan < num_chan; chan++) 22898c2ecf20Sopenharmony_ci sModemReset(ctlp, chan, 1); 22908c2ecf20Sopenharmony_ci msleep(500); 22918c2ecf20Sopenharmony_ci for (chan = 0; chan < num_chan; chan++) 22928c2ecf20Sopenharmony_ci sModemReset(ctlp, chan, 0); 22938c2ecf20Sopenharmony_ci msleep(500); 22948c2ecf20Sopenharmony_ci strcpy(rocketModel[i].modelString, "RocketModem ISA"); 22958c2ecf20Sopenharmony_ci } else { 22968c2ecf20Sopenharmony_ci strcpy(rocketModel[i].modelString, "RocketPort ISA"); 22978c2ecf20Sopenharmony_ci } 22988c2ecf20Sopenharmony_ci rocketModel[i].numPorts = total_num_chan; 22998c2ecf20Sopenharmony_ci rocketModel[i].model = MODEL_ISA; 23008c2ecf20Sopenharmony_ci 23018c2ecf20Sopenharmony_ci printk(KERN_INFO "RocketPort ISA card #%d found at 0x%lx - %d AIOPs %s\n", 23028c2ecf20Sopenharmony_ci i, rcktpt_io_addr[i], num_aiops, type_string); 23038c2ecf20Sopenharmony_ci 23048c2ecf20Sopenharmony_ci printk(KERN_INFO "Installing %s, creating /dev/ttyR%d - %ld\n", 23058c2ecf20Sopenharmony_ci rocketModel[i].modelString, 23068c2ecf20Sopenharmony_ci rocketModel[i].startingPortNumber, 23078c2ecf20Sopenharmony_ci rocketModel[i].startingPortNumber + 23088c2ecf20Sopenharmony_ci rocketModel[i].numPorts - 1); 23098c2ecf20Sopenharmony_ci 23108c2ecf20Sopenharmony_ci return (1); 23118c2ecf20Sopenharmony_ci} 23128c2ecf20Sopenharmony_ci 23138c2ecf20Sopenharmony_cistatic const struct tty_operations rocket_ops = { 23148c2ecf20Sopenharmony_ci .open = rp_open, 23158c2ecf20Sopenharmony_ci .close = rp_close, 23168c2ecf20Sopenharmony_ci .write = rp_write, 23178c2ecf20Sopenharmony_ci .put_char = rp_put_char, 23188c2ecf20Sopenharmony_ci .write_room = rp_write_room, 23198c2ecf20Sopenharmony_ci .chars_in_buffer = rp_chars_in_buffer, 23208c2ecf20Sopenharmony_ci .flush_buffer = rp_flush_buffer, 23218c2ecf20Sopenharmony_ci .ioctl = rp_ioctl, 23228c2ecf20Sopenharmony_ci .throttle = rp_throttle, 23238c2ecf20Sopenharmony_ci .unthrottle = rp_unthrottle, 23248c2ecf20Sopenharmony_ci .set_termios = rp_set_termios, 23258c2ecf20Sopenharmony_ci .stop = rp_stop, 23268c2ecf20Sopenharmony_ci .start = rp_start, 23278c2ecf20Sopenharmony_ci .hangup = rp_hangup, 23288c2ecf20Sopenharmony_ci .break_ctl = rp_break, 23298c2ecf20Sopenharmony_ci .send_xchar = rp_send_xchar, 23308c2ecf20Sopenharmony_ci .wait_until_sent = rp_wait_until_sent, 23318c2ecf20Sopenharmony_ci .tiocmget = rp_tiocmget, 23328c2ecf20Sopenharmony_ci .tiocmset = rp_tiocmset, 23338c2ecf20Sopenharmony_ci}; 23348c2ecf20Sopenharmony_ci 23358c2ecf20Sopenharmony_cistatic const struct tty_port_operations rocket_port_ops = { 23368c2ecf20Sopenharmony_ci .carrier_raised = carrier_raised, 23378c2ecf20Sopenharmony_ci .dtr_rts = dtr_rts, 23388c2ecf20Sopenharmony_ci}; 23398c2ecf20Sopenharmony_ci 23408c2ecf20Sopenharmony_ci/* 23418c2ecf20Sopenharmony_ci * The module "startup" routine; it's run when the module is loaded. 23428c2ecf20Sopenharmony_ci */ 23438c2ecf20Sopenharmony_cistatic int __init rp_init(void) 23448c2ecf20Sopenharmony_ci{ 23458c2ecf20Sopenharmony_ci int ret = -ENOMEM, pci_boards_found, isa_boards_found, i; 23468c2ecf20Sopenharmony_ci 23478c2ecf20Sopenharmony_ci printk(KERN_INFO "RocketPort device driver module, version %s, %s\n", 23488c2ecf20Sopenharmony_ci ROCKET_VERSION, ROCKET_DATE); 23498c2ecf20Sopenharmony_ci 23508c2ecf20Sopenharmony_ci rocket_driver = alloc_tty_driver(MAX_RP_PORTS); 23518c2ecf20Sopenharmony_ci if (!rocket_driver) 23528c2ecf20Sopenharmony_ci goto err; 23538c2ecf20Sopenharmony_ci 23548c2ecf20Sopenharmony_ci /* 23558c2ecf20Sopenharmony_ci * If board 1 is non-zero, there is at least one ISA configured. If controller is 23568c2ecf20Sopenharmony_ci * zero, use the default controller IO address of board1 + 0x40. 23578c2ecf20Sopenharmony_ci */ 23588c2ecf20Sopenharmony_ci if (board1) { 23598c2ecf20Sopenharmony_ci if (controller == 0) 23608c2ecf20Sopenharmony_ci controller = board1 + 0x40; 23618c2ecf20Sopenharmony_ci } else { 23628c2ecf20Sopenharmony_ci controller = 0; /* Used as a flag, meaning no ISA boards */ 23638c2ecf20Sopenharmony_ci } 23648c2ecf20Sopenharmony_ci 23658c2ecf20Sopenharmony_ci /* If an ISA card is configured, reserve the 4 byte IO space for the Mudbac controller */ 23668c2ecf20Sopenharmony_ci if (controller && (!request_region(controller, 4, "Comtrol RocketPort"))) { 23678c2ecf20Sopenharmony_ci printk(KERN_ERR "Unable to reserve IO region for first " 23688c2ecf20Sopenharmony_ci "configured ISA RocketPort controller 0x%lx. " 23698c2ecf20Sopenharmony_ci "Driver exiting\n", controller); 23708c2ecf20Sopenharmony_ci ret = -EBUSY; 23718c2ecf20Sopenharmony_ci goto err_tty; 23728c2ecf20Sopenharmony_ci } 23738c2ecf20Sopenharmony_ci 23748c2ecf20Sopenharmony_ci /* Store ISA variable retrieved from command line or .conf file. */ 23758c2ecf20Sopenharmony_ci rcktpt_io_addr[0] = board1; 23768c2ecf20Sopenharmony_ci rcktpt_io_addr[1] = board2; 23778c2ecf20Sopenharmony_ci rcktpt_io_addr[2] = board3; 23788c2ecf20Sopenharmony_ci rcktpt_io_addr[3] = board4; 23798c2ecf20Sopenharmony_ci 23808c2ecf20Sopenharmony_ci rcktpt_type[0] = modem1 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL; 23818c2ecf20Sopenharmony_ci rcktpt_type[0] = pc104_1[0] ? ROCKET_TYPE_PC104 : rcktpt_type[0]; 23828c2ecf20Sopenharmony_ci rcktpt_type[1] = modem2 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL; 23838c2ecf20Sopenharmony_ci rcktpt_type[1] = pc104_2[0] ? ROCKET_TYPE_PC104 : rcktpt_type[1]; 23848c2ecf20Sopenharmony_ci rcktpt_type[2] = modem3 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL; 23858c2ecf20Sopenharmony_ci rcktpt_type[2] = pc104_3[0] ? ROCKET_TYPE_PC104 : rcktpt_type[2]; 23868c2ecf20Sopenharmony_ci rcktpt_type[3] = modem4 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL; 23878c2ecf20Sopenharmony_ci rcktpt_type[3] = pc104_4[0] ? ROCKET_TYPE_PC104 : rcktpt_type[3]; 23888c2ecf20Sopenharmony_ci 23898c2ecf20Sopenharmony_ci /* 23908c2ecf20Sopenharmony_ci * Set up the tty driver structure and then register this 23918c2ecf20Sopenharmony_ci * driver with the tty layer. 23928c2ecf20Sopenharmony_ci */ 23938c2ecf20Sopenharmony_ci 23948c2ecf20Sopenharmony_ci rocket_driver->flags = TTY_DRIVER_DYNAMIC_DEV; 23958c2ecf20Sopenharmony_ci rocket_driver->name = "ttyR"; 23968c2ecf20Sopenharmony_ci rocket_driver->driver_name = "Comtrol RocketPort"; 23978c2ecf20Sopenharmony_ci rocket_driver->major = TTY_ROCKET_MAJOR; 23988c2ecf20Sopenharmony_ci rocket_driver->minor_start = 0; 23998c2ecf20Sopenharmony_ci rocket_driver->type = TTY_DRIVER_TYPE_SERIAL; 24008c2ecf20Sopenharmony_ci rocket_driver->subtype = SERIAL_TYPE_NORMAL; 24018c2ecf20Sopenharmony_ci rocket_driver->init_termios = tty_std_termios; 24028c2ecf20Sopenharmony_ci rocket_driver->init_termios.c_cflag = 24038c2ecf20Sopenharmony_ci B9600 | CS8 | CREAD | HUPCL | CLOCAL; 24048c2ecf20Sopenharmony_ci rocket_driver->init_termios.c_ispeed = 9600; 24058c2ecf20Sopenharmony_ci rocket_driver->init_termios.c_ospeed = 9600; 24068c2ecf20Sopenharmony_ci#ifdef ROCKET_SOFT_FLOW 24078c2ecf20Sopenharmony_ci rocket_driver->flags |= TTY_DRIVER_REAL_RAW; 24088c2ecf20Sopenharmony_ci#endif 24098c2ecf20Sopenharmony_ci tty_set_operations(rocket_driver, &rocket_ops); 24108c2ecf20Sopenharmony_ci 24118c2ecf20Sopenharmony_ci ret = tty_register_driver(rocket_driver); 24128c2ecf20Sopenharmony_ci if (ret < 0) { 24138c2ecf20Sopenharmony_ci printk(KERN_ERR "Couldn't install tty RocketPort driver\n"); 24148c2ecf20Sopenharmony_ci goto err_controller; 24158c2ecf20Sopenharmony_ci } 24168c2ecf20Sopenharmony_ci 24178c2ecf20Sopenharmony_ci#ifdef ROCKET_DEBUG_OPEN 24188c2ecf20Sopenharmony_ci printk(KERN_INFO "RocketPort driver is major %d\n", rocket_driver.major); 24198c2ecf20Sopenharmony_ci#endif 24208c2ecf20Sopenharmony_ci 24218c2ecf20Sopenharmony_ci /* 24228c2ecf20Sopenharmony_ci * OK, let's probe each of the controllers looking for boards. Any boards found 24238c2ecf20Sopenharmony_ci * will be initialized here. 24248c2ecf20Sopenharmony_ci */ 24258c2ecf20Sopenharmony_ci isa_boards_found = 0; 24268c2ecf20Sopenharmony_ci pci_boards_found = 0; 24278c2ecf20Sopenharmony_ci 24288c2ecf20Sopenharmony_ci for (i = 0; i < NUM_BOARDS; i++) { 24298c2ecf20Sopenharmony_ci if (init_ISA(i)) 24308c2ecf20Sopenharmony_ci isa_boards_found++; 24318c2ecf20Sopenharmony_ci } 24328c2ecf20Sopenharmony_ci 24338c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 24348c2ecf20Sopenharmony_ci if (isa_boards_found < NUM_BOARDS) 24358c2ecf20Sopenharmony_ci pci_boards_found = init_PCI(isa_boards_found); 24368c2ecf20Sopenharmony_ci#endif 24378c2ecf20Sopenharmony_ci 24388c2ecf20Sopenharmony_ci max_board = pci_boards_found + isa_boards_found; 24398c2ecf20Sopenharmony_ci 24408c2ecf20Sopenharmony_ci if (max_board == 0) { 24418c2ecf20Sopenharmony_ci printk(KERN_ERR "No rocketport ports found; unloading driver\n"); 24428c2ecf20Sopenharmony_ci ret = -ENXIO; 24438c2ecf20Sopenharmony_ci goto err_ttyu; 24448c2ecf20Sopenharmony_ci } 24458c2ecf20Sopenharmony_ci 24468c2ecf20Sopenharmony_ci return 0; 24478c2ecf20Sopenharmony_cierr_ttyu: 24488c2ecf20Sopenharmony_ci tty_unregister_driver(rocket_driver); 24498c2ecf20Sopenharmony_cierr_controller: 24508c2ecf20Sopenharmony_ci if (controller) 24518c2ecf20Sopenharmony_ci release_region(controller, 4); 24528c2ecf20Sopenharmony_cierr_tty: 24538c2ecf20Sopenharmony_ci put_tty_driver(rocket_driver); 24548c2ecf20Sopenharmony_cierr: 24558c2ecf20Sopenharmony_ci return ret; 24568c2ecf20Sopenharmony_ci} 24578c2ecf20Sopenharmony_ci 24588c2ecf20Sopenharmony_ci 24598c2ecf20Sopenharmony_cistatic void rp_cleanup_module(void) 24608c2ecf20Sopenharmony_ci{ 24618c2ecf20Sopenharmony_ci int retval; 24628c2ecf20Sopenharmony_ci int i; 24638c2ecf20Sopenharmony_ci 24648c2ecf20Sopenharmony_ci del_timer_sync(&rocket_timer); 24658c2ecf20Sopenharmony_ci 24668c2ecf20Sopenharmony_ci retval = tty_unregister_driver(rocket_driver); 24678c2ecf20Sopenharmony_ci if (retval) 24688c2ecf20Sopenharmony_ci printk(KERN_ERR "Error %d while trying to unregister " 24698c2ecf20Sopenharmony_ci "rocketport driver\n", -retval); 24708c2ecf20Sopenharmony_ci 24718c2ecf20Sopenharmony_ci for (i = 0; i < MAX_RP_PORTS; i++) 24728c2ecf20Sopenharmony_ci if (rp_table[i]) { 24738c2ecf20Sopenharmony_ci tty_unregister_device(rocket_driver, i); 24748c2ecf20Sopenharmony_ci tty_port_destroy(&rp_table[i]->port); 24758c2ecf20Sopenharmony_ci kfree(rp_table[i]); 24768c2ecf20Sopenharmony_ci } 24778c2ecf20Sopenharmony_ci 24788c2ecf20Sopenharmony_ci put_tty_driver(rocket_driver); 24798c2ecf20Sopenharmony_ci 24808c2ecf20Sopenharmony_ci for (i = 0; i < NUM_BOARDS; i++) { 24818c2ecf20Sopenharmony_ci if (rcktpt_io_addr[i] <= 0 || is_PCI[i]) 24828c2ecf20Sopenharmony_ci continue; 24838c2ecf20Sopenharmony_ci release_region(rcktpt_io_addr[i], 64); 24848c2ecf20Sopenharmony_ci } 24858c2ecf20Sopenharmony_ci if (controller) 24868c2ecf20Sopenharmony_ci release_region(controller, 4); 24878c2ecf20Sopenharmony_ci} 24888c2ecf20Sopenharmony_ci 24898c2ecf20Sopenharmony_ci/*************************************************************************** 24908c2ecf20Sopenharmony_ciFunction: sInitController 24918c2ecf20Sopenharmony_ciPurpose: Initialization of controller global registers and controller 24928c2ecf20Sopenharmony_ci structure. 24938c2ecf20Sopenharmony_ciCall: sInitController(CtlP,CtlNum,MudbacIO,AiopIOList,AiopIOListSize, 24948c2ecf20Sopenharmony_ci IRQNum,Frequency,PeriodicOnly) 24958c2ecf20Sopenharmony_ci CONTROLLER_T *CtlP; Ptr to controller structure 24968c2ecf20Sopenharmony_ci int CtlNum; Controller number 24978c2ecf20Sopenharmony_ci ByteIO_t MudbacIO; Mudbac base I/O address. 24988c2ecf20Sopenharmony_ci ByteIO_t *AiopIOList; List of I/O addresses for each AIOP. 24998c2ecf20Sopenharmony_ci This list must be in the order the AIOPs will be found on the 25008c2ecf20Sopenharmony_ci controller. Once an AIOP in the list is not found, it is 25018c2ecf20Sopenharmony_ci assumed that there are no more AIOPs on the controller. 25028c2ecf20Sopenharmony_ci int AiopIOListSize; Number of addresses in AiopIOList 25038c2ecf20Sopenharmony_ci int IRQNum; Interrupt Request number. Can be any of the following: 25048c2ecf20Sopenharmony_ci 0: Disable global interrupts 25058c2ecf20Sopenharmony_ci 3: IRQ 3 25068c2ecf20Sopenharmony_ci 4: IRQ 4 25078c2ecf20Sopenharmony_ci 5: IRQ 5 25088c2ecf20Sopenharmony_ci 9: IRQ 9 25098c2ecf20Sopenharmony_ci 10: IRQ 10 25108c2ecf20Sopenharmony_ci 11: IRQ 11 25118c2ecf20Sopenharmony_ci 12: IRQ 12 25128c2ecf20Sopenharmony_ci 15: IRQ 15 25138c2ecf20Sopenharmony_ci Byte_t Frequency: A flag identifying the frequency 25148c2ecf20Sopenharmony_ci of the periodic interrupt, can be any one of the following: 25158c2ecf20Sopenharmony_ci FREQ_DIS - periodic interrupt disabled 25168c2ecf20Sopenharmony_ci FREQ_137HZ - 137 Hertz 25178c2ecf20Sopenharmony_ci FREQ_69HZ - 69 Hertz 25188c2ecf20Sopenharmony_ci FREQ_34HZ - 34 Hertz 25198c2ecf20Sopenharmony_ci FREQ_17HZ - 17 Hertz 25208c2ecf20Sopenharmony_ci FREQ_9HZ - 9 Hertz 25218c2ecf20Sopenharmony_ci FREQ_4HZ - 4 Hertz 25228c2ecf20Sopenharmony_ci If IRQNum is set to 0 the Frequency parameter is 25238c2ecf20Sopenharmony_ci overidden, it is forced to a value of FREQ_DIS. 25248c2ecf20Sopenharmony_ci int PeriodicOnly: 1 if all interrupts except the periodic 25258c2ecf20Sopenharmony_ci interrupt are to be blocked. 25268c2ecf20Sopenharmony_ci 0 is both the periodic interrupt and 25278c2ecf20Sopenharmony_ci other channel interrupts are allowed. 25288c2ecf20Sopenharmony_ci If IRQNum is set to 0 the PeriodicOnly parameter is 25298c2ecf20Sopenharmony_ci overidden, it is forced to a value of 0. 25308c2ecf20Sopenharmony_ciReturn: int: Number of AIOPs on the controller, or CTLID_NULL if controller 25318c2ecf20Sopenharmony_ci initialization failed. 25328c2ecf20Sopenharmony_ci 25338c2ecf20Sopenharmony_ciComments: 25348c2ecf20Sopenharmony_ci If periodic interrupts are to be disabled but AIOP interrupts 25358c2ecf20Sopenharmony_ci are allowed, set Frequency to FREQ_DIS and PeriodicOnly to 0. 25368c2ecf20Sopenharmony_ci 25378c2ecf20Sopenharmony_ci If interrupts are to be completely disabled set IRQNum to 0. 25388c2ecf20Sopenharmony_ci 25398c2ecf20Sopenharmony_ci Setting Frequency to FREQ_DIS and PeriodicOnly to 1 is an 25408c2ecf20Sopenharmony_ci invalid combination. 25418c2ecf20Sopenharmony_ci 25428c2ecf20Sopenharmony_ci This function performs initialization of global interrupt modes, 25438c2ecf20Sopenharmony_ci but it does not actually enable global interrupts. To enable 25448c2ecf20Sopenharmony_ci and disable global interrupts use functions sEnGlobalInt() and 25458c2ecf20Sopenharmony_ci sDisGlobalInt(). Enabling of global interrupts is normally not 25468c2ecf20Sopenharmony_ci done until all other initializations are complete. 25478c2ecf20Sopenharmony_ci 25488c2ecf20Sopenharmony_ci Even if interrupts are globally enabled, they must also be 25498c2ecf20Sopenharmony_ci individually enabled for each channel that is to generate 25508c2ecf20Sopenharmony_ci interrupts. 25518c2ecf20Sopenharmony_ci 25528c2ecf20Sopenharmony_ciWarnings: No range checking on any of the parameters is done. 25538c2ecf20Sopenharmony_ci 25548c2ecf20Sopenharmony_ci No context switches are allowed while executing this function. 25558c2ecf20Sopenharmony_ci 25568c2ecf20Sopenharmony_ci After this function all AIOPs on the controller are disabled, 25578c2ecf20Sopenharmony_ci they can be enabled with sEnAiop(). 25588c2ecf20Sopenharmony_ci*/ 25598c2ecf20Sopenharmony_cistatic int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO, 25608c2ecf20Sopenharmony_ci ByteIO_t * AiopIOList, int AiopIOListSize, 25618c2ecf20Sopenharmony_ci int IRQNum, Byte_t Frequency, int PeriodicOnly) 25628c2ecf20Sopenharmony_ci{ 25638c2ecf20Sopenharmony_ci int i; 25648c2ecf20Sopenharmony_ci ByteIO_t io; 25658c2ecf20Sopenharmony_ci int done; 25668c2ecf20Sopenharmony_ci 25678c2ecf20Sopenharmony_ci CtlP->AiopIntrBits = aiop_intr_bits; 25688c2ecf20Sopenharmony_ci CtlP->AltChanRingIndicator = 0; 25698c2ecf20Sopenharmony_ci CtlP->CtlNum = CtlNum; 25708c2ecf20Sopenharmony_ci CtlP->CtlID = CTLID_0001; /* controller release 1 */ 25718c2ecf20Sopenharmony_ci CtlP->BusType = isISA; 25728c2ecf20Sopenharmony_ci CtlP->MBaseIO = MudbacIO; 25738c2ecf20Sopenharmony_ci CtlP->MReg1IO = MudbacIO + 1; 25748c2ecf20Sopenharmony_ci CtlP->MReg2IO = MudbacIO + 2; 25758c2ecf20Sopenharmony_ci CtlP->MReg3IO = MudbacIO + 3; 25768c2ecf20Sopenharmony_ci#if 1 25778c2ecf20Sopenharmony_ci CtlP->MReg2 = 0; /* interrupt disable */ 25788c2ecf20Sopenharmony_ci CtlP->MReg3 = 0; /* no periodic interrupts */ 25798c2ecf20Sopenharmony_ci#else 25808c2ecf20Sopenharmony_ci if (sIRQMap[IRQNum] == 0) { /* interrupts globally disabled */ 25818c2ecf20Sopenharmony_ci CtlP->MReg2 = 0; /* interrupt disable */ 25828c2ecf20Sopenharmony_ci CtlP->MReg3 = 0; /* no periodic interrupts */ 25838c2ecf20Sopenharmony_ci } else { 25848c2ecf20Sopenharmony_ci CtlP->MReg2 = sIRQMap[IRQNum]; /* set IRQ number */ 25858c2ecf20Sopenharmony_ci CtlP->MReg3 = Frequency; /* set frequency */ 25868c2ecf20Sopenharmony_ci if (PeriodicOnly) { /* periodic interrupt only */ 25878c2ecf20Sopenharmony_ci CtlP->MReg3 |= PERIODIC_ONLY; 25888c2ecf20Sopenharmony_ci } 25898c2ecf20Sopenharmony_ci } 25908c2ecf20Sopenharmony_ci#endif 25918c2ecf20Sopenharmony_ci sOutB(CtlP->MReg2IO, CtlP->MReg2); 25928c2ecf20Sopenharmony_ci sOutB(CtlP->MReg3IO, CtlP->MReg3); 25938c2ecf20Sopenharmony_ci sControllerEOI(CtlP); /* clear EOI if warm init */ 25948c2ecf20Sopenharmony_ci /* Init AIOPs */ 25958c2ecf20Sopenharmony_ci CtlP->NumAiop = 0; 25968c2ecf20Sopenharmony_ci for (i = done = 0; i < AiopIOListSize; i++) { 25978c2ecf20Sopenharmony_ci io = AiopIOList[i]; 25988c2ecf20Sopenharmony_ci CtlP->AiopIO[i] = (WordIO_t) io; 25998c2ecf20Sopenharmony_ci CtlP->AiopIntChanIO[i] = io + _INT_CHAN; 26008c2ecf20Sopenharmony_ci sOutB(CtlP->MReg2IO, CtlP->MReg2 | (i & 0x03)); /* AIOP index */ 26018c2ecf20Sopenharmony_ci sOutB(MudbacIO, (Byte_t) (io >> 6)); /* set up AIOP I/O in MUDBAC */ 26028c2ecf20Sopenharmony_ci if (done) 26038c2ecf20Sopenharmony_ci continue; 26048c2ecf20Sopenharmony_ci sEnAiop(CtlP, i); /* enable the AIOP */ 26058c2ecf20Sopenharmony_ci CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */ 26068c2ecf20Sopenharmony_ci if (CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */ 26078c2ecf20Sopenharmony_ci done = 1; /* done looking for AIOPs */ 26088c2ecf20Sopenharmony_ci else { 26098c2ecf20Sopenharmony_ci CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t) io); /* num channels in AIOP */ 26108c2ecf20Sopenharmony_ci sOutW((WordIO_t) io + _INDX_ADDR, _CLK_PRE); /* clock prescaler */ 26118c2ecf20Sopenharmony_ci sOutB(io + _INDX_DATA, sClockPrescale); 26128c2ecf20Sopenharmony_ci CtlP->NumAiop++; /* bump count of AIOPs */ 26138c2ecf20Sopenharmony_ci } 26148c2ecf20Sopenharmony_ci sDisAiop(CtlP, i); /* disable AIOP */ 26158c2ecf20Sopenharmony_ci } 26168c2ecf20Sopenharmony_ci 26178c2ecf20Sopenharmony_ci if (CtlP->NumAiop == 0) 26188c2ecf20Sopenharmony_ci return (-1); 26198c2ecf20Sopenharmony_ci else 26208c2ecf20Sopenharmony_ci return (CtlP->NumAiop); 26218c2ecf20Sopenharmony_ci} 26228c2ecf20Sopenharmony_ci 26238c2ecf20Sopenharmony_ci/*************************************************************************** 26248c2ecf20Sopenharmony_ciFunction: sReadAiopID 26258c2ecf20Sopenharmony_ciPurpose: Read the AIOP idenfication number directly from an AIOP. 26268c2ecf20Sopenharmony_ciCall: sReadAiopID(io) 26278c2ecf20Sopenharmony_ci ByteIO_t io: AIOP base I/O address 26288c2ecf20Sopenharmony_ciReturn: int: Flag AIOPID_XXXX if a valid AIOP is found, where X 26298c2ecf20Sopenharmony_ci is replace by an identifying number. 26308c2ecf20Sopenharmony_ci Flag AIOPID_NULL if no valid AIOP is found 26318c2ecf20Sopenharmony_ciWarnings: No context switches are allowed while executing this function. 26328c2ecf20Sopenharmony_ci 26338c2ecf20Sopenharmony_ci*/ 26348c2ecf20Sopenharmony_cistatic int sReadAiopID(ByteIO_t io) 26358c2ecf20Sopenharmony_ci{ 26368c2ecf20Sopenharmony_ci Byte_t AiopID; /* ID byte from AIOP */ 26378c2ecf20Sopenharmony_ci 26388c2ecf20Sopenharmony_ci sOutB(io + _CMD_REG, RESET_ALL); /* reset AIOP */ 26398c2ecf20Sopenharmony_ci sOutB(io + _CMD_REG, 0x0); 26408c2ecf20Sopenharmony_ci AiopID = sInW(io + _CHN_STAT0) & 0x07; 26418c2ecf20Sopenharmony_ci if (AiopID == 0x06) 26428c2ecf20Sopenharmony_ci return (1); 26438c2ecf20Sopenharmony_ci else /* AIOP does not exist */ 26448c2ecf20Sopenharmony_ci return (-1); 26458c2ecf20Sopenharmony_ci} 26468c2ecf20Sopenharmony_ci 26478c2ecf20Sopenharmony_ci/*************************************************************************** 26488c2ecf20Sopenharmony_ciFunction: sReadAiopNumChan 26498c2ecf20Sopenharmony_ciPurpose: Read the number of channels available in an AIOP directly from 26508c2ecf20Sopenharmony_ci an AIOP. 26518c2ecf20Sopenharmony_ciCall: sReadAiopNumChan(io) 26528c2ecf20Sopenharmony_ci WordIO_t io: AIOP base I/O address 26538c2ecf20Sopenharmony_ciReturn: int: The number of channels available 26548c2ecf20Sopenharmony_ciComments: The number of channels is determined by write/reads from identical 26558c2ecf20Sopenharmony_ci offsets within the SRAM address spaces for channels 0 and 4. 26568c2ecf20Sopenharmony_ci If the channel 4 space is mirrored to channel 0 it is a 4 channel 26578c2ecf20Sopenharmony_ci AIOP, otherwise it is an 8 channel. 26588c2ecf20Sopenharmony_ciWarnings: No context switches are allowed while executing this function. 26598c2ecf20Sopenharmony_ci*/ 26608c2ecf20Sopenharmony_cistatic int sReadAiopNumChan(WordIO_t io) 26618c2ecf20Sopenharmony_ci{ 26628c2ecf20Sopenharmony_ci Word_t x; 26638c2ecf20Sopenharmony_ci static Byte_t R[4] = { 0x00, 0x00, 0x34, 0x12 }; 26648c2ecf20Sopenharmony_ci 26658c2ecf20Sopenharmony_ci /* write to chan 0 SRAM */ 26668c2ecf20Sopenharmony_ci out32((DWordIO_t) io + _INDX_ADDR, R); 26678c2ecf20Sopenharmony_ci sOutW(io + _INDX_ADDR, 0); /* read from SRAM, chan 0 */ 26688c2ecf20Sopenharmony_ci x = sInW(io + _INDX_DATA); 26698c2ecf20Sopenharmony_ci sOutW(io + _INDX_ADDR, 0x4000); /* read from SRAM, chan 4 */ 26708c2ecf20Sopenharmony_ci if (x != sInW(io + _INDX_DATA)) /* if different must be 8 chan */ 26718c2ecf20Sopenharmony_ci return (8); 26728c2ecf20Sopenharmony_ci else 26738c2ecf20Sopenharmony_ci return (4); 26748c2ecf20Sopenharmony_ci} 26758c2ecf20Sopenharmony_ci 26768c2ecf20Sopenharmony_ci/*************************************************************************** 26778c2ecf20Sopenharmony_ciFunction: sInitChan 26788c2ecf20Sopenharmony_ciPurpose: Initialization of a channel and channel structure 26798c2ecf20Sopenharmony_ciCall: sInitChan(CtlP,ChP,AiopNum,ChanNum) 26808c2ecf20Sopenharmony_ci CONTROLLER_T *CtlP; Ptr to controller structure 26818c2ecf20Sopenharmony_ci CHANNEL_T *ChP; Ptr to channel structure 26828c2ecf20Sopenharmony_ci int AiopNum; AIOP number within controller 26838c2ecf20Sopenharmony_ci int ChanNum; Channel number within AIOP 26848c2ecf20Sopenharmony_ciReturn: int: 1 if initialization succeeded, 0 if it fails because channel 26858c2ecf20Sopenharmony_ci number exceeds number of channels available in AIOP. 26868c2ecf20Sopenharmony_ciComments: This function must be called before a channel can be used. 26878c2ecf20Sopenharmony_ciWarnings: No range checking on any of the parameters is done. 26888c2ecf20Sopenharmony_ci 26898c2ecf20Sopenharmony_ci No context switches are allowed while executing this function. 26908c2ecf20Sopenharmony_ci*/ 26918c2ecf20Sopenharmony_cistatic int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum, 26928c2ecf20Sopenharmony_ci int ChanNum) 26938c2ecf20Sopenharmony_ci{ 26948c2ecf20Sopenharmony_ci int i; 26958c2ecf20Sopenharmony_ci WordIO_t AiopIO; 26968c2ecf20Sopenharmony_ci WordIO_t ChIOOff; 26978c2ecf20Sopenharmony_ci Byte_t *ChR; 26988c2ecf20Sopenharmony_ci Word_t ChOff; 26998c2ecf20Sopenharmony_ci static Byte_t R[4]; 27008c2ecf20Sopenharmony_ci int brd9600; 27018c2ecf20Sopenharmony_ci 27028c2ecf20Sopenharmony_ci if (ChanNum >= CtlP->AiopNumChan[AiopNum]) 27038c2ecf20Sopenharmony_ci return 0; /* exceeds num chans in AIOP */ 27048c2ecf20Sopenharmony_ci 27058c2ecf20Sopenharmony_ci /* Channel, AIOP, and controller identifiers */ 27068c2ecf20Sopenharmony_ci ChP->CtlP = CtlP; 27078c2ecf20Sopenharmony_ci ChP->ChanID = CtlP->AiopID[AiopNum]; 27088c2ecf20Sopenharmony_ci ChP->AiopNum = AiopNum; 27098c2ecf20Sopenharmony_ci ChP->ChanNum = ChanNum; 27108c2ecf20Sopenharmony_ci 27118c2ecf20Sopenharmony_ci /* Global direct addresses */ 27128c2ecf20Sopenharmony_ci AiopIO = CtlP->AiopIO[AiopNum]; 27138c2ecf20Sopenharmony_ci ChP->Cmd = (ByteIO_t) AiopIO + _CMD_REG; 27148c2ecf20Sopenharmony_ci ChP->IntChan = (ByteIO_t) AiopIO + _INT_CHAN; 27158c2ecf20Sopenharmony_ci ChP->IntMask = (ByteIO_t) AiopIO + _INT_MASK; 27168c2ecf20Sopenharmony_ci ChP->IndexAddr = (DWordIO_t) AiopIO + _INDX_ADDR; 27178c2ecf20Sopenharmony_ci ChP->IndexData = AiopIO + _INDX_DATA; 27188c2ecf20Sopenharmony_ci 27198c2ecf20Sopenharmony_ci /* Channel direct addresses */ 27208c2ecf20Sopenharmony_ci ChIOOff = AiopIO + ChP->ChanNum * 2; 27218c2ecf20Sopenharmony_ci ChP->TxRxData = ChIOOff + _TD0; 27228c2ecf20Sopenharmony_ci ChP->ChanStat = ChIOOff + _CHN_STAT0; 27238c2ecf20Sopenharmony_ci ChP->TxRxCount = ChIOOff + _FIFO_CNT0; 27248c2ecf20Sopenharmony_ci ChP->IntID = (ByteIO_t) AiopIO + ChP->ChanNum + _INT_ID0; 27258c2ecf20Sopenharmony_ci 27268c2ecf20Sopenharmony_ci /* Initialize the channel from the RData array */ 27278c2ecf20Sopenharmony_ci for (i = 0; i < RDATASIZE; i += 4) { 27288c2ecf20Sopenharmony_ci R[0] = RData[i]; 27298c2ecf20Sopenharmony_ci R[1] = RData[i + 1] + 0x10 * ChanNum; 27308c2ecf20Sopenharmony_ci R[2] = RData[i + 2]; 27318c2ecf20Sopenharmony_ci R[3] = RData[i + 3]; 27328c2ecf20Sopenharmony_ci out32(ChP->IndexAddr, R); 27338c2ecf20Sopenharmony_ci } 27348c2ecf20Sopenharmony_ci 27358c2ecf20Sopenharmony_ci ChR = ChP->R; 27368c2ecf20Sopenharmony_ci for (i = 0; i < RREGDATASIZE; i += 4) { 27378c2ecf20Sopenharmony_ci ChR[i] = RRegData[i]; 27388c2ecf20Sopenharmony_ci ChR[i + 1] = RRegData[i + 1] + 0x10 * ChanNum; 27398c2ecf20Sopenharmony_ci ChR[i + 2] = RRegData[i + 2]; 27408c2ecf20Sopenharmony_ci ChR[i + 3] = RRegData[i + 3]; 27418c2ecf20Sopenharmony_ci } 27428c2ecf20Sopenharmony_ci 27438c2ecf20Sopenharmony_ci /* Indexed registers */ 27448c2ecf20Sopenharmony_ci ChOff = (Word_t) ChanNum *0x1000; 27458c2ecf20Sopenharmony_ci 27468c2ecf20Sopenharmony_ci if (sClockPrescale == 0x14) 27478c2ecf20Sopenharmony_ci brd9600 = 47; 27488c2ecf20Sopenharmony_ci else 27498c2ecf20Sopenharmony_ci brd9600 = 23; 27508c2ecf20Sopenharmony_ci 27518c2ecf20Sopenharmony_ci ChP->BaudDiv[0] = (Byte_t) (ChOff + _BAUD); 27528c2ecf20Sopenharmony_ci ChP->BaudDiv[1] = (Byte_t) ((ChOff + _BAUD) >> 8); 27538c2ecf20Sopenharmony_ci ChP->BaudDiv[2] = (Byte_t) brd9600; 27548c2ecf20Sopenharmony_ci ChP->BaudDiv[3] = (Byte_t) (brd9600 >> 8); 27558c2ecf20Sopenharmony_ci out32(ChP->IndexAddr, ChP->BaudDiv); 27568c2ecf20Sopenharmony_ci 27578c2ecf20Sopenharmony_ci ChP->TxControl[0] = (Byte_t) (ChOff + _TX_CTRL); 27588c2ecf20Sopenharmony_ci ChP->TxControl[1] = (Byte_t) ((ChOff + _TX_CTRL) >> 8); 27598c2ecf20Sopenharmony_ci ChP->TxControl[2] = 0; 27608c2ecf20Sopenharmony_ci ChP->TxControl[3] = 0; 27618c2ecf20Sopenharmony_ci out32(ChP->IndexAddr, ChP->TxControl); 27628c2ecf20Sopenharmony_ci 27638c2ecf20Sopenharmony_ci ChP->RxControl[0] = (Byte_t) (ChOff + _RX_CTRL); 27648c2ecf20Sopenharmony_ci ChP->RxControl[1] = (Byte_t) ((ChOff + _RX_CTRL) >> 8); 27658c2ecf20Sopenharmony_ci ChP->RxControl[2] = 0; 27668c2ecf20Sopenharmony_ci ChP->RxControl[3] = 0; 27678c2ecf20Sopenharmony_ci out32(ChP->IndexAddr, ChP->RxControl); 27688c2ecf20Sopenharmony_ci 27698c2ecf20Sopenharmony_ci ChP->TxEnables[0] = (Byte_t) (ChOff + _TX_ENBLS); 27708c2ecf20Sopenharmony_ci ChP->TxEnables[1] = (Byte_t) ((ChOff + _TX_ENBLS) >> 8); 27718c2ecf20Sopenharmony_ci ChP->TxEnables[2] = 0; 27728c2ecf20Sopenharmony_ci ChP->TxEnables[3] = 0; 27738c2ecf20Sopenharmony_ci out32(ChP->IndexAddr, ChP->TxEnables); 27748c2ecf20Sopenharmony_ci 27758c2ecf20Sopenharmony_ci ChP->TxCompare[0] = (Byte_t) (ChOff + _TXCMP1); 27768c2ecf20Sopenharmony_ci ChP->TxCompare[1] = (Byte_t) ((ChOff + _TXCMP1) >> 8); 27778c2ecf20Sopenharmony_ci ChP->TxCompare[2] = 0; 27788c2ecf20Sopenharmony_ci ChP->TxCompare[3] = 0; 27798c2ecf20Sopenharmony_ci out32(ChP->IndexAddr, ChP->TxCompare); 27808c2ecf20Sopenharmony_ci 27818c2ecf20Sopenharmony_ci ChP->TxReplace1[0] = (Byte_t) (ChOff + _TXREP1B1); 27828c2ecf20Sopenharmony_ci ChP->TxReplace1[1] = (Byte_t) ((ChOff + _TXREP1B1) >> 8); 27838c2ecf20Sopenharmony_ci ChP->TxReplace1[2] = 0; 27848c2ecf20Sopenharmony_ci ChP->TxReplace1[3] = 0; 27858c2ecf20Sopenharmony_ci out32(ChP->IndexAddr, ChP->TxReplace1); 27868c2ecf20Sopenharmony_ci 27878c2ecf20Sopenharmony_ci ChP->TxReplace2[0] = (Byte_t) (ChOff + _TXREP2); 27888c2ecf20Sopenharmony_ci ChP->TxReplace2[1] = (Byte_t) ((ChOff + _TXREP2) >> 8); 27898c2ecf20Sopenharmony_ci ChP->TxReplace2[2] = 0; 27908c2ecf20Sopenharmony_ci ChP->TxReplace2[3] = 0; 27918c2ecf20Sopenharmony_ci out32(ChP->IndexAddr, ChP->TxReplace2); 27928c2ecf20Sopenharmony_ci 27938c2ecf20Sopenharmony_ci ChP->TxFIFOPtrs = ChOff + _TXF_OUTP; 27948c2ecf20Sopenharmony_ci ChP->TxFIFO = ChOff + _TX_FIFO; 27958c2ecf20Sopenharmony_ci 27968c2ecf20Sopenharmony_ci sOutB(ChP->Cmd, (Byte_t) ChanNum | RESTXFCNT); /* apply reset Tx FIFO count */ 27978c2ecf20Sopenharmony_ci sOutB(ChP->Cmd, (Byte_t) ChanNum); /* remove reset Tx FIFO count */ 27988c2ecf20Sopenharmony_ci sOutW((WordIO_t) ChP->IndexAddr, ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */ 27998c2ecf20Sopenharmony_ci sOutW(ChP->IndexData, 0); 28008c2ecf20Sopenharmony_ci ChP->RxFIFOPtrs = ChOff + _RXF_OUTP; 28018c2ecf20Sopenharmony_ci ChP->RxFIFO = ChOff + _RX_FIFO; 28028c2ecf20Sopenharmony_ci 28038c2ecf20Sopenharmony_ci sOutB(ChP->Cmd, (Byte_t) ChanNum | RESRXFCNT); /* apply reset Rx FIFO count */ 28048c2ecf20Sopenharmony_ci sOutB(ChP->Cmd, (Byte_t) ChanNum); /* remove reset Rx FIFO count */ 28058c2ecf20Sopenharmony_ci sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs); /* clear Rx out ptr */ 28068c2ecf20Sopenharmony_ci sOutW(ChP->IndexData, 0); 28078c2ecf20Sopenharmony_ci sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */ 28088c2ecf20Sopenharmony_ci sOutW(ChP->IndexData, 0); 28098c2ecf20Sopenharmony_ci ChP->TxPrioCnt = ChOff + _TXP_CNT; 28108c2ecf20Sopenharmony_ci sOutW((WordIO_t) ChP->IndexAddr, ChP->TxPrioCnt); 28118c2ecf20Sopenharmony_ci sOutB(ChP->IndexData, 0); 28128c2ecf20Sopenharmony_ci ChP->TxPrioPtr = ChOff + _TXP_PNTR; 28138c2ecf20Sopenharmony_ci sOutW((WordIO_t) ChP->IndexAddr, ChP->TxPrioPtr); 28148c2ecf20Sopenharmony_ci sOutB(ChP->IndexData, 0); 28158c2ecf20Sopenharmony_ci ChP->TxPrioBuf = ChOff + _TXP_BUF; 28168c2ecf20Sopenharmony_ci sEnRxProcessor(ChP); /* start the Rx processor */ 28178c2ecf20Sopenharmony_ci 28188c2ecf20Sopenharmony_ci return 1; 28198c2ecf20Sopenharmony_ci} 28208c2ecf20Sopenharmony_ci 28218c2ecf20Sopenharmony_ci/*************************************************************************** 28228c2ecf20Sopenharmony_ciFunction: sStopRxProcessor 28238c2ecf20Sopenharmony_ciPurpose: Stop the receive processor from processing a channel. 28248c2ecf20Sopenharmony_ciCall: sStopRxProcessor(ChP) 28258c2ecf20Sopenharmony_ci CHANNEL_T *ChP; Ptr to channel structure 28268c2ecf20Sopenharmony_ci 28278c2ecf20Sopenharmony_ciComments: The receive processor can be started again with sStartRxProcessor(). 28288c2ecf20Sopenharmony_ci This function causes the receive processor to skip over the 28298c2ecf20Sopenharmony_ci stopped channel. It does not stop it from processing other channels. 28308c2ecf20Sopenharmony_ci 28318c2ecf20Sopenharmony_ciWarnings: No context switches are allowed while executing this function. 28328c2ecf20Sopenharmony_ci 28338c2ecf20Sopenharmony_ci Do not leave the receive processor stopped for more than one 28348c2ecf20Sopenharmony_ci character time. 28358c2ecf20Sopenharmony_ci 28368c2ecf20Sopenharmony_ci After calling this function a delay of 4 uS is required to ensure 28378c2ecf20Sopenharmony_ci that the receive processor is no longer processing this channel. 28388c2ecf20Sopenharmony_ci*/ 28398c2ecf20Sopenharmony_cistatic void sStopRxProcessor(CHANNEL_T * ChP) 28408c2ecf20Sopenharmony_ci{ 28418c2ecf20Sopenharmony_ci Byte_t R[4]; 28428c2ecf20Sopenharmony_ci 28438c2ecf20Sopenharmony_ci R[0] = ChP->R[0]; 28448c2ecf20Sopenharmony_ci R[1] = ChP->R[1]; 28458c2ecf20Sopenharmony_ci R[2] = 0x0a; 28468c2ecf20Sopenharmony_ci R[3] = ChP->R[3]; 28478c2ecf20Sopenharmony_ci out32(ChP->IndexAddr, R); 28488c2ecf20Sopenharmony_ci} 28498c2ecf20Sopenharmony_ci 28508c2ecf20Sopenharmony_ci/*************************************************************************** 28518c2ecf20Sopenharmony_ciFunction: sFlushRxFIFO 28528c2ecf20Sopenharmony_ciPurpose: Flush the Rx FIFO 28538c2ecf20Sopenharmony_ciCall: sFlushRxFIFO(ChP) 28548c2ecf20Sopenharmony_ci CHANNEL_T *ChP; Ptr to channel structure 28558c2ecf20Sopenharmony_ciReturn: void 28568c2ecf20Sopenharmony_ciComments: To prevent data from being enqueued or dequeued in the Tx FIFO 28578c2ecf20Sopenharmony_ci while it is being flushed the receive processor is stopped 28588c2ecf20Sopenharmony_ci and the transmitter is disabled. After these operations a 28598c2ecf20Sopenharmony_ci 4 uS delay is done before clearing the pointers to allow 28608c2ecf20Sopenharmony_ci the receive processor to stop. These items are handled inside 28618c2ecf20Sopenharmony_ci this function. 28628c2ecf20Sopenharmony_ciWarnings: No context switches are allowed while executing this function. 28638c2ecf20Sopenharmony_ci*/ 28648c2ecf20Sopenharmony_cistatic void sFlushRxFIFO(CHANNEL_T * ChP) 28658c2ecf20Sopenharmony_ci{ 28668c2ecf20Sopenharmony_ci int i; 28678c2ecf20Sopenharmony_ci Byte_t Ch; /* channel number within AIOP */ 28688c2ecf20Sopenharmony_ci int RxFIFOEnabled; /* 1 if Rx FIFO enabled */ 28698c2ecf20Sopenharmony_ci 28708c2ecf20Sopenharmony_ci if (sGetRxCnt(ChP) == 0) /* Rx FIFO empty */ 28718c2ecf20Sopenharmony_ci return; /* don't need to flush */ 28728c2ecf20Sopenharmony_ci 28738c2ecf20Sopenharmony_ci RxFIFOEnabled = 0; 28748c2ecf20Sopenharmony_ci if (ChP->R[0x32] == 0x08) { /* Rx FIFO is enabled */ 28758c2ecf20Sopenharmony_ci RxFIFOEnabled = 1; 28768c2ecf20Sopenharmony_ci sDisRxFIFO(ChP); /* disable it */ 28778c2ecf20Sopenharmony_ci for (i = 0; i < 2000 / 200; i++) /* delay 2 uS to allow proc to disable FIFO */ 28788c2ecf20Sopenharmony_ci sInB(ChP->IntChan); /* depends on bus i/o timing */ 28798c2ecf20Sopenharmony_ci } 28808c2ecf20Sopenharmony_ci sGetChanStatus(ChP); /* clear any pending Rx errors in chan stat */ 28818c2ecf20Sopenharmony_ci Ch = (Byte_t) sGetChanNum(ChP); 28828c2ecf20Sopenharmony_ci sOutB(ChP->Cmd, Ch | RESRXFCNT); /* apply reset Rx FIFO count */ 28838c2ecf20Sopenharmony_ci sOutB(ChP->Cmd, Ch); /* remove reset Rx FIFO count */ 28848c2ecf20Sopenharmony_ci sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs); /* clear Rx out ptr */ 28858c2ecf20Sopenharmony_ci sOutW(ChP->IndexData, 0); 28868c2ecf20Sopenharmony_ci sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */ 28878c2ecf20Sopenharmony_ci sOutW(ChP->IndexData, 0); 28888c2ecf20Sopenharmony_ci if (RxFIFOEnabled) 28898c2ecf20Sopenharmony_ci sEnRxFIFO(ChP); /* enable Rx FIFO */ 28908c2ecf20Sopenharmony_ci} 28918c2ecf20Sopenharmony_ci 28928c2ecf20Sopenharmony_ci/*************************************************************************** 28938c2ecf20Sopenharmony_ciFunction: sFlushTxFIFO 28948c2ecf20Sopenharmony_ciPurpose: Flush the Tx FIFO 28958c2ecf20Sopenharmony_ciCall: sFlushTxFIFO(ChP) 28968c2ecf20Sopenharmony_ci CHANNEL_T *ChP; Ptr to channel structure 28978c2ecf20Sopenharmony_ciReturn: void 28988c2ecf20Sopenharmony_ciComments: To prevent data from being enqueued or dequeued in the Tx FIFO 28998c2ecf20Sopenharmony_ci while it is being flushed the receive processor is stopped 29008c2ecf20Sopenharmony_ci and the transmitter is disabled. After these operations a 29018c2ecf20Sopenharmony_ci 4 uS delay is done before clearing the pointers to allow 29028c2ecf20Sopenharmony_ci the receive processor to stop. These items are handled inside 29038c2ecf20Sopenharmony_ci this function. 29048c2ecf20Sopenharmony_ciWarnings: No context switches are allowed while executing this function. 29058c2ecf20Sopenharmony_ci*/ 29068c2ecf20Sopenharmony_cistatic void sFlushTxFIFO(CHANNEL_T * ChP) 29078c2ecf20Sopenharmony_ci{ 29088c2ecf20Sopenharmony_ci int i; 29098c2ecf20Sopenharmony_ci Byte_t Ch; /* channel number within AIOP */ 29108c2ecf20Sopenharmony_ci int TxEnabled; /* 1 if transmitter enabled */ 29118c2ecf20Sopenharmony_ci 29128c2ecf20Sopenharmony_ci if (sGetTxCnt(ChP) == 0) /* Tx FIFO empty */ 29138c2ecf20Sopenharmony_ci return; /* don't need to flush */ 29148c2ecf20Sopenharmony_ci 29158c2ecf20Sopenharmony_ci TxEnabled = 0; 29168c2ecf20Sopenharmony_ci if (ChP->TxControl[3] & TX_ENABLE) { 29178c2ecf20Sopenharmony_ci TxEnabled = 1; 29188c2ecf20Sopenharmony_ci sDisTransmit(ChP); /* disable transmitter */ 29198c2ecf20Sopenharmony_ci } 29208c2ecf20Sopenharmony_ci sStopRxProcessor(ChP); /* stop Rx processor */ 29218c2ecf20Sopenharmony_ci for (i = 0; i < 4000 / 200; i++) /* delay 4 uS to allow proc to stop */ 29228c2ecf20Sopenharmony_ci sInB(ChP->IntChan); /* depends on bus i/o timing */ 29238c2ecf20Sopenharmony_ci Ch = (Byte_t) sGetChanNum(ChP); 29248c2ecf20Sopenharmony_ci sOutB(ChP->Cmd, Ch | RESTXFCNT); /* apply reset Tx FIFO count */ 29258c2ecf20Sopenharmony_ci sOutB(ChP->Cmd, Ch); /* remove reset Tx FIFO count */ 29268c2ecf20Sopenharmony_ci sOutW((WordIO_t) ChP->IndexAddr, ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */ 29278c2ecf20Sopenharmony_ci sOutW(ChP->IndexData, 0); 29288c2ecf20Sopenharmony_ci if (TxEnabled) 29298c2ecf20Sopenharmony_ci sEnTransmit(ChP); /* enable transmitter */ 29308c2ecf20Sopenharmony_ci sStartRxProcessor(ChP); /* restart Rx processor */ 29318c2ecf20Sopenharmony_ci} 29328c2ecf20Sopenharmony_ci 29338c2ecf20Sopenharmony_ci/*************************************************************************** 29348c2ecf20Sopenharmony_ciFunction: sWriteTxPrioByte 29358c2ecf20Sopenharmony_ciPurpose: Write a byte of priority transmit data to a channel 29368c2ecf20Sopenharmony_ciCall: sWriteTxPrioByte(ChP,Data) 29378c2ecf20Sopenharmony_ci CHANNEL_T *ChP; Ptr to channel structure 29388c2ecf20Sopenharmony_ci Byte_t Data; The transmit data byte 29398c2ecf20Sopenharmony_ci 29408c2ecf20Sopenharmony_ciReturn: int: 1 if the bytes is successfully written, otherwise 0. 29418c2ecf20Sopenharmony_ci 29428c2ecf20Sopenharmony_ciComments: The priority byte is transmitted before any data in the Tx FIFO. 29438c2ecf20Sopenharmony_ci 29448c2ecf20Sopenharmony_ciWarnings: No context switches are allowed while executing this function. 29458c2ecf20Sopenharmony_ci*/ 29468c2ecf20Sopenharmony_cistatic int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data) 29478c2ecf20Sopenharmony_ci{ 29488c2ecf20Sopenharmony_ci Byte_t DWBuf[4]; /* buffer for double word writes */ 29498c2ecf20Sopenharmony_ci Word_t *WordPtr; /* must be far because Win SS != DS */ 29508c2ecf20Sopenharmony_ci register DWordIO_t IndexAddr; 29518c2ecf20Sopenharmony_ci 29528c2ecf20Sopenharmony_ci if (sGetTxCnt(ChP) > 1) { /* write it to Tx priority buffer */ 29538c2ecf20Sopenharmony_ci IndexAddr = ChP->IndexAddr; 29548c2ecf20Sopenharmony_ci sOutW((WordIO_t) IndexAddr, ChP->TxPrioCnt); /* get priority buffer status */ 29558c2ecf20Sopenharmony_ci if (sInB((ByteIO_t) ChP->IndexData) & PRI_PEND) /* priority buffer busy */ 29568c2ecf20Sopenharmony_ci return (0); /* nothing sent */ 29578c2ecf20Sopenharmony_ci 29588c2ecf20Sopenharmony_ci WordPtr = (Word_t *) (&DWBuf[0]); 29598c2ecf20Sopenharmony_ci *WordPtr = ChP->TxPrioBuf; /* data byte address */ 29608c2ecf20Sopenharmony_ci 29618c2ecf20Sopenharmony_ci DWBuf[2] = Data; /* data byte value */ 29628c2ecf20Sopenharmony_ci out32(IndexAddr, DWBuf); /* write it out */ 29638c2ecf20Sopenharmony_ci 29648c2ecf20Sopenharmony_ci *WordPtr = ChP->TxPrioCnt; /* Tx priority count address */ 29658c2ecf20Sopenharmony_ci 29668c2ecf20Sopenharmony_ci DWBuf[2] = PRI_PEND + 1; /* indicate 1 byte pending */ 29678c2ecf20Sopenharmony_ci DWBuf[3] = 0; /* priority buffer pointer */ 29688c2ecf20Sopenharmony_ci out32(IndexAddr, DWBuf); /* write it out */ 29698c2ecf20Sopenharmony_ci } else { /* write it to Tx FIFO */ 29708c2ecf20Sopenharmony_ci 29718c2ecf20Sopenharmony_ci sWriteTxByte(sGetTxRxDataIO(ChP), Data); 29728c2ecf20Sopenharmony_ci } 29738c2ecf20Sopenharmony_ci return (1); /* 1 byte sent */ 29748c2ecf20Sopenharmony_ci} 29758c2ecf20Sopenharmony_ci 29768c2ecf20Sopenharmony_ci/*************************************************************************** 29778c2ecf20Sopenharmony_ciFunction: sEnInterrupts 29788c2ecf20Sopenharmony_ciPurpose: Enable one or more interrupts for a channel 29798c2ecf20Sopenharmony_ciCall: sEnInterrupts(ChP,Flags) 29808c2ecf20Sopenharmony_ci CHANNEL_T *ChP; Ptr to channel structure 29818c2ecf20Sopenharmony_ci Word_t Flags: Interrupt enable flags, can be any combination 29828c2ecf20Sopenharmony_ci of the following flags: 29838c2ecf20Sopenharmony_ci TXINT_EN: Interrupt on Tx FIFO empty 29848c2ecf20Sopenharmony_ci RXINT_EN: Interrupt on Rx FIFO at trigger level (see 29858c2ecf20Sopenharmony_ci sSetRxTrigger()) 29868c2ecf20Sopenharmony_ci SRCINT_EN: Interrupt on SRC (Special Rx Condition) 29878c2ecf20Sopenharmony_ci MCINT_EN: Interrupt on modem input change 29888c2ecf20Sopenharmony_ci CHANINT_EN: Allow channel interrupt signal to the AIOP's 29898c2ecf20Sopenharmony_ci Interrupt Channel Register. 29908c2ecf20Sopenharmony_ciReturn: void 29918c2ecf20Sopenharmony_ciComments: If an interrupt enable flag is set in Flags, that interrupt will be 29928c2ecf20Sopenharmony_ci enabled. If an interrupt enable flag is not set in Flags, that 29938c2ecf20Sopenharmony_ci interrupt will not be changed. Interrupts can be disabled with 29948c2ecf20Sopenharmony_ci function sDisInterrupts(). 29958c2ecf20Sopenharmony_ci 29968c2ecf20Sopenharmony_ci This function sets the appropriate bit for the channel in the AIOP's 29978c2ecf20Sopenharmony_ci Interrupt Mask Register if the CHANINT_EN flag is set. This allows 29988c2ecf20Sopenharmony_ci this channel's bit to be set in the AIOP's Interrupt Channel Register. 29998c2ecf20Sopenharmony_ci 30008c2ecf20Sopenharmony_ci Interrupts must also be globally enabled before channel interrupts 30018c2ecf20Sopenharmony_ci will be passed on to the host. This is done with function 30028c2ecf20Sopenharmony_ci sEnGlobalInt(). 30038c2ecf20Sopenharmony_ci 30048c2ecf20Sopenharmony_ci In some cases it may be desirable to disable interrupts globally but 30058c2ecf20Sopenharmony_ci enable channel interrupts. This would allow the global interrupt 30068c2ecf20Sopenharmony_ci status register to be used to determine which AIOPs need service. 30078c2ecf20Sopenharmony_ci*/ 30088c2ecf20Sopenharmony_cistatic void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags) 30098c2ecf20Sopenharmony_ci{ 30108c2ecf20Sopenharmony_ci Byte_t Mask; /* Interrupt Mask Register */ 30118c2ecf20Sopenharmony_ci 30128c2ecf20Sopenharmony_ci ChP->RxControl[2] |= 30138c2ecf20Sopenharmony_ci ((Byte_t) Flags & (RXINT_EN | SRCINT_EN | MCINT_EN)); 30148c2ecf20Sopenharmony_ci 30158c2ecf20Sopenharmony_ci out32(ChP->IndexAddr, ChP->RxControl); 30168c2ecf20Sopenharmony_ci 30178c2ecf20Sopenharmony_ci ChP->TxControl[2] |= ((Byte_t) Flags & TXINT_EN); 30188c2ecf20Sopenharmony_ci 30198c2ecf20Sopenharmony_ci out32(ChP->IndexAddr, ChP->TxControl); 30208c2ecf20Sopenharmony_ci 30218c2ecf20Sopenharmony_ci if (Flags & CHANINT_EN) { 30228c2ecf20Sopenharmony_ci Mask = sInB(ChP->IntMask) | sBitMapSetTbl[ChP->ChanNum]; 30238c2ecf20Sopenharmony_ci sOutB(ChP->IntMask, Mask); 30248c2ecf20Sopenharmony_ci } 30258c2ecf20Sopenharmony_ci} 30268c2ecf20Sopenharmony_ci 30278c2ecf20Sopenharmony_ci/*************************************************************************** 30288c2ecf20Sopenharmony_ciFunction: sDisInterrupts 30298c2ecf20Sopenharmony_ciPurpose: Disable one or more interrupts for a channel 30308c2ecf20Sopenharmony_ciCall: sDisInterrupts(ChP,Flags) 30318c2ecf20Sopenharmony_ci CHANNEL_T *ChP; Ptr to channel structure 30328c2ecf20Sopenharmony_ci Word_t Flags: Interrupt flags, can be any combination 30338c2ecf20Sopenharmony_ci of the following flags: 30348c2ecf20Sopenharmony_ci TXINT_EN: Interrupt on Tx FIFO empty 30358c2ecf20Sopenharmony_ci RXINT_EN: Interrupt on Rx FIFO at trigger level (see 30368c2ecf20Sopenharmony_ci sSetRxTrigger()) 30378c2ecf20Sopenharmony_ci SRCINT_EN: Interrupt on SRC (Special Rx Condition) 30388c2ecf20Sopenharmony_ci MCINT_EN: Interrupt on modem input change 30398c2ecf20Sopenharmony_ci CHANINT_EN: Disable channel interrupt signal to the 30408c2ecf20Sopenharmony_ci AIOP's Interrupt Channel Register. 30418c2ecf20Sopenharmony_ciReturn: void 30428c2ecf20Sopenharmony_ciComments: If an interrupt flag is set in Flags, that interrupt will be 30438c2ecf20Sopenharmony_ci disabled. If an interrupt flag is not set in Flags, that 30448c2ecf20Sopenharmony_ci interrupt will not be changed. Interrupts can be enabled with 30458c2ecf20Sopenharmony_ci function sEnInterrupts(). 30468c2ecf20Sopenharmony_ci 30478c2ecf20Sopenharmony_ci This function clears the appropriate bit for the channel in the AIOP's 30488c2ecf20Sopenharmony_ci Interrupt Mask Register if the CHANINT_EN flag is set. This blocks 30498c2ecf20Sopenharmony_ci this channel's bit from being set in the AIOP's Interrupt Channel 30508c2ecf20Sopenharmony_ci Register. 30518c2ecf20Sopenharmony_ci*/ 30528c2ecf20Sopenharmony_cistatic void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags) 30538c2ecf20Sopenharmony_ci{ 30548c2ecf20Sopenharmony_ci Byte_t Mask; /* Interrupt Mask Register */ 30558c2ecf20Sopenharmony_ci 30568c2ecf20Sopenharmony_ci ChP->RxControl[2] &= 30578c2ecf20Sopenharmony_ci ~((Byte_t) Flags & (RXINT_EN | SRCINT_EN | MCINT_EN)); 30588c2ecf20Sopenharmony_ci out32(ChP->IndexAddr, ChP->RxControl); 30598c2ecf20Sopenharmony_ci ChP->TxControl[2] &= ~((Byte_t) Flags & TXINT_EN); 30608c2ecf20Sopenharmony_ci out32(ChP->IndexAddr, ChP->TxControl); 30618c2ecf20Sopenharmony_ci 30628c2ecf20Sopenharmony_ci if (Flags & CHANINT_EN) { 30638c2ecf20Sopenharmony_ci Mask = sInB(ChP->IntMask) & sBitMapClrTbl[ChP->ChanNum]; 30648c2ecf20Sopenharmony_ci sOutB(ChP->IntMask, Mask); 30658c2ecf20Sopenharmony_ci } 30668c2ecf20Sopenharmony_ci} 30678c2ecf20Sopenharmony_ci 30688c2ecf20Sopenharmony_cistatic void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode) 30698c2ecf20Sopenharmony_ci{ 30708c2ecf20Sopenharmony_ci sOutB(ChP->CtlP->AiopIO[2], (mode & 0x18) | ChP->ChanNum); 30718c2ecf20Sopenharmony_ci} 30728c2ecf20Sopenharmony_ci 30738c2ecf20Sopenharmony_ci/* 30748c2ecf20Sopenharmony_ci * Not an official SSCI function, but how to reset RocketModems. 30758c2ecf20Sopenharmony_ci * ISA bus version 30768c2ecf20Sopenharmony_ci */ 30778c2ecf20Sopenharmony_cistatic void sModemReset(CONTROLLER_T * CtlP, int chan, int on) 30788c2ecf20Sopenharmony_ci{ 30798c2ecf20Sopenharmony_ci ByteIO_t addr; 30808c2ecf20Sopenharmony_ci Byte_t val; 30818c2ecf20Sopenharmony_ci 30828c2ecf20Sopenharmony_ci addr = CtlP->AiopIO[0] + 0x400; 30838c2ecf20Sopenharmony_ci val = sInB(CtlP->MReg3IO); 30848c2ecf20Sopenharmony_ci /* if AIOP[1] is not enabled, enable it */ 30858c2ecf20Sopenharmony_ci if ((val & 2) == 0) { 30868c2ecf20Sopenharmony_ci val = sInB(CtlP->MReg2IO); 30878c2ecf20Sopenharmony_ci sOutB(CtlP->MReg2IO, (val & 0xfc) | (1 & 0x03)); 30888c2ecf20Sopenharmony_ci sOutB(CtlP->MBaseIO, (unsigned char) (addr >> 6)); 30898c2ecf20Sopenharmony_ci } 30908c2ecf20Sopenharmony_ci 30918c2ecf20Sopenharmony_ci sEnAiop(CtlP, 1); 30928c2ecf20Sopenharmony_ci if (!on) 30938c2ecf20Sopenharmony_ci addr += 8; 30948c2ecf20Sopenharmony_ci sOutB(addr + chan, 0); /* apply or remove reset */ 30958c2ecf20Sopenharmony_ci sDisAiop(CtlP, 1); 30968c2ecf20Sopenharmony_ci} 30978c2ecf20Sopenharmony_ci 30988c2ecf20Sopenharmony_ci/* 30998c2ecf20Sopenharmony_ci * Not an official SSCI function, but how to reset RocketModems. 31008c2ecf20Sopenharmony_ci * PCI bus version 31018c2ecf20Sopenharmony_ci */ 31028c2ecf20Sopenharmony_cistatic void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on) 31038c2ecf20Sopenharmony_ci{ 31048c2ecf20Sopenharmony_ci ByteIO_t addr; 31058c2ecf20Sopenharmony_ci 31068c2ecf20Sopenharmony_ci addr = CtlP->AiopIO[0] + 0x40; /* 2nd AIOP */ 31078c2ecf20Sopenharmony_ci if (!on) 31088c2ecf20Sopenharmony_ci addr += 8; 31098c2ecf20Sopenharmony_ci sOutB(addr + chan, 0); /* apply or remove reset */ 31108c2ecf20Sopenharmony_ci} 31118c2ecf20Sopenharmony_ci 31128c2ecf20Sopenharmony_ci/* Returns the line number given the controller (board), aiop and channel number */ 31138c2ecf20Sopenharmony_cistatic unsigned char GetLineNumber(int ctrl, int aiop, int ch) 31148c2ecf20Sopenharmony_ci{ 31158c2ecf20Sopenharmony_ci return lineNumbers[(ctrl << 5) | (aiop << 3) | ch]; 31168c2ecf20Sopenharmony_ci} 31178c2ecf20Sopenharmony_ci 31188c2ecf20Sopenharmony_ci/* 31198c2ecf20Sopenharmony_ci * Stores the line number associated with a given controller (board), aiop 31208c2ecf20Sopenharmony_ci * and channel number. 31218c2ecf20Sopenharmony_ci * Returns: The line number assigned 31228c2ecf20Sopenharmony_ci */ 31238c2ecf20Sopenharmony_cistatic unsigned char SetLineNumber(int ctrl, int aiop, int ch) 31248c2ecf20Sopenharmony_ci{ 31258c2ecf20Sopenharmony_ci lineNumbers[(ctrl << 5) | (aiop << 3) | ch] = nextLineNumber++; 31268c2ecf20Sopenharmony_ci return (nextLineNumber - 1); 31278c2ecf20Sopenharmony_ci} 3128