1e3b3d0f5SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0+ 2a6afd9f3SGreg Kroah-Hartman /*****************************************************************************/ 3a6afd9f3SGreg Kroah-Hartman /* 4a6afd9f3SGreg Kroah-Hartman * moxa.c -- MOXA Intellio family multiport serial driver. 5a6afd9f3SGreg Kroah-Hartman * 6a6afd9f3SGreg Kroah-Hartman * Copyright (C) 1999-2000 Moxa Technologies (support@moxa.com). 7a6afd9f3SGreg Kroah-Hartman * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com> 8a6afd9f3SGreg Kroah-Hartman * 9a6afd9f3SGreg Kroah-Hartman * This code is loosely based on the Linux serial driver, written by 10a6afd9f3SGreg Kroah-Hartman * Linus Torvalds, Theodore T'so and others. 11a6afd9f3SGreg Kroah-Hartman */ 12a6afd9f3SGreg Kroah-Hartman 13a6afd9f3SGreg Kroah-Hartman /* 14a6afd9f3SGreg Kroah-Hartman * MOXA Intellio Series Driver 15a6afd9f3SGreg Kroah-Hartman * for : LINUX 16a6afd9f3SGreg Kroah-Hartman * date : 1999/1/7 17a6afd9f3SGreg Kroah-Hartman * version : 5.1 18a6afd9f3SGreg Kroah-Hartman */ 19a6afd9f3SGreg Kroah-Hartman 20a6afd9f3SGreg Kroah-Hartman #include <linux/module.h> 21a6afd9f3SGreg Kroah-Hartman #include <linux/types.h> 22a6afd9f3SGreg Kroah-Hartman #include <linux/mm.h> 23a6afd9f3SGreg Kroah-Hartman #include <linux/ioport.h> 24a6afd9f3SGreg Kroah-Hartman #include <linux/errno.h> 25a6afd9f3SGreg Kroah-Hartman #include <linux/firmware.h> 26a6afd9f3SGreg Kroah-Hartman #include <linux/signal.h> 27a6afd9f3SGreg Kroah-Hartman #include <linux/sched.h> 28a6afd9f3SGreg Kroah-Hartman #include <linux/timer.h> 29a6afd9f3SGreg Kroah-Hartman #include <linux/interrupt.h> 30a6afd9f3SGreg Kroah-Hartman #include <linux/tty.h> 31a6afd9f3SGreg Kroah-Hartman #include <linux/tty_flip.h> 32a6afd9f3SGreg Kroah-Hartman #include <linux/major.h> 33a6afd9f3SGreg Kroah-Hartman #include <linux/string.h> 34a6afd9f3SGreg Kroah-Hartman #include <linux/fcntl.h> 35a6afd9f3SGreg Kroah-Hartman #include <linux/ptrace.h> 36a6afd9f3SGreg Kroah-Hartman #include <linux/serial.h> 37a6afd9f3SGreg Kroah-Hartman #include <linux/tty_driver.h> 38a6afd9f3SGreg Kroah-Hartman #include <linux/delay.h> 39a6afd9f3SGreg Kroah-Hartman #include <linux/pci.h> 40a6afd9f3SGreg Kroah-Hartman #include <linux/init.h> 41a6afd9f3SGreg Kroah-Hartman #include <linux/bitops.h> 42a6afd9f3SGreg Kroah-Hartman #include <linux/slab.h> 435a3c6b25SManuel Zerpies #include <linux/ratelimit.h> 44a6afd9f3SGreg Kroah-Hartman 45a6afd9f3SGreg Kroah-Hartman #include <asm/io.h> 467c0f6ba6SLinus Torvalds #include <linux/uaccess.h> 47a6afd9f3SGreg Kroah-Hartman 48b55c8aa6SJiri Slaby #define MOXA 0x400 49b55c8aa6SJiri Slaby #define MOXA_GET_IQUEUE (MOXA + 1) /* get input buffered count */ 50b55c8aa6SJiri Slaby #define MOXA_GET_OQUEUE (MOXA + 2) /* get output buffered count */ 51b55c8aa6SJiri Slaby #define MOXA_GETDATACOUNT (MOXA + 23) 52b55c8aa6SJiri Slaby #define MOXA_GET_IOQUEUE (MOXA + 27) 53b55c8aa6SJiri Slaby #define MOXA_FLUSH_QUEUE (MOXA + 28) 54b55c8aa6SJiri Slaby #define MOXA_GETMSTATUS (MOXA + 65) 55b55c8aa6SJiri Slaby 56b55c8aa6SJiri Slaby /* 57b55c8aa6SJiri Slaby * System Configuration 58b55c8aa6SJiri Slaby */ 59b55c8aa6SJiri Slaby 60b55c8aa6SJiri Slaby #define Magic_code 0x404 61b55c8aa6SJiri Slaby 62b55c8aa6SJiri Slaby /* 63b55c8aa6SJiri Slaby * for C218 BIOS initialization 64b55c8aa6SJiri Slaby */ 65b55c8aa6SJiri Slaby #define C218_ConfBase 0x800 66b55c8aa6SJiri Slaby #define C218_status (C218_ConfBase + 0) /* BIOS running status */ 67b55c8aa6SJiri Slaby #define C218_diag (C218_ConfBase + 2) /* diagnostic status */ 68b55c8aa6SJiri Slaby #define C218_key (C218_ConfBase + 4) /* WORD (0x218 for C218) */ 69b55c8aa6SJiri Slaby #define C218DLoad_len (C218_ConfBase + 6) /* WORD */ 70b55c8aa6SJiri Slaby #define C218check_sum (C218_ConfBase + 8) /* BYTE */ 71b55c8aa6SJiri Slaby #define C218chksum_ok (C218_ConfBase + 0x0a) /* BYTE (1:ok) */ 72b55c8aa6SJiri Slaby #define C218_TestRx (C218_ConfBase + 0x10) /* 8 bytes for 8 ports */ 73b55c8aa6SJiri Slaby #define C218_TestTx (C218_ConfBase + 0x18) /* 8 bytes for 8 ports */ 74b55c8aa6SJiri Slaby #define C218_RXerr (C218_ConfBase + 0x20) /* 8 bytes for 8 ports */ 75b55c8aa6SJiri Slaby #define C218_ErrFlag (C218_ConfBase + 0x28) /* 8 bytes for 8 ports */ 76b55c8aa6SJiri Slaby 77b55c8aa6SJiri Slaby #define C218_LoadBuf 0x0F00 78b55c8aa6SJiri Slaby #define C218_KeyCode 0x218 79b55c8aa6SJiri Slaby #define CP204J_KeyCode 0x204 80b55c8aa6SJiri Slaby 81b55c8aa6SJiri Slaby /* 82b55c8aa6SJiri Slaby * for C320 BIOS initialization 83b55c8aa6SJiri Slaby */ 84b55c8aa6SJiri Slaby #define C320_ConfBase 0x800 85b55c8aa6SJiri Slaby #define C320_LoadBuf 0x0f00 86b55c8aa6SJiri Slaby #define STS_init 0x05 /* for C320_status */ 87b55c8aa6SJiri Slaby 88b55c8aa6SJiri Slaby #define C320_status C320_ConfBase + 0 /* BIOS running status */ 89b55c8aa6SJiri Slaby #define C320_diag C320_ConfBase + 2 /* diagnostic status */ 90b55c8aa6SJiri Slaby #define C320_key C320_ConfBase + 4 /* WORD (0320H for C320) */ 91b55c8aa6SJiri Slaby #define C320DLoad_len C320_ConfBase + 6 /* WORD */ 92b55c8aa6SJiri Slaby #define C320check_sum C320_ConfBase + 8 /* WORD */ 93b55c8aa6SJiri Slaby #define C320chksum_ok C320_ConfBase + 0x0a /* WORD (1:ok) */ 94b55c8aa6SJiri Slaby #define C320bapi_len C320_ConfBase + 0x0c /* WORD */ 95b55c8aa6SJiri Slaby #define C320UART_no C320_ConfBase + 0x0e /* WORD */ 96b55c8aa6SJiri Slaby 97b55c8aa6SJiri Slaby #define C320_KeyCode 0x320 98b55c8aa6SJiri Slaby 99b55c8aa6SJiri Slaby #define FixPage_addr 0x0000 /* starting addr of static page */ 100b55c8aa6SJiri Slaby #define DynPage_addr 0x2000 /* starting addr of dynamic page */ 101b55c8aa6SJiri Slaby #define C218_start 0x3000 /* starting addr of C218 BIOS prg */ 102b55c8aa6SJiri Slaby #define Control_reg 0x1ff0 /* select page and reset control */ 103b55c8aa6SJiri Slaby #define HW_reset 0x80 104b55c8aa6SJiri Slaby 105b55c8aa6SJiri Slaby /* 106b55c8aa6SJiri Slaby * Function Codes 107b55c8aa6SJiri Slaby */ 108b55c8aa6SJiri Slaby #define FC_CardReset 0x80 109b55c8aa6SJiri Slaby #define FC_ChannelReset 1 /* C320 firmware not supported */ 110b55c8aa6SJiri Slaby #define FC_EnableCH 2 111b55c8aa6SJiri Slaby #define FC_DisableCH 3 112b55c8aa6SJiri Slaby #define FC_SetParam 4 113b55c8aa6SJiri Slaby #define FC_SetMode 5 114b55c8aa6SJiri Slaby #define FC_SetRate 6 115b55c8aa6SJiri Slaby #define FC_LineControl 7 116b55c8aa6SJiri Slaby #define FC_LineStatus 8 117b55c8aa6SJiri Slaby #define FC_XmitControl 9 118b55c8aa6SJiri Slaby #define FC_FlushQueue 10 119b55c8aa6SJiri Slaby #define FC_SendBreak 11 120b55c8aa6SJiri Slaby #define FC_StopBreak 12 121b55c8aa6SJiri Slaby #define FC_LoopbackON 13 122b55c8aa6SJiri Slaby #define FC_LoopbackOFF 14 123b55c8aa6SJiri Slaby #define FC_ClrIrqTable 15 124b55c8aa6SJiri Slaby #define FC_SendXon 16 125b55c8aa6SJiri Slaby #define FC_SetTermIrq 17 /* C320 firmware not supported */ 126b55c8aa6SJiri Slaby #define FC_SetCntIrq 18 /* C320 firmware not supported */ 127b55c8aa6SJiri Slaby #define FC_SetBreakIrq 19 128b55c8aa6SJiri Slaby #define FC_SetLineIrq 20 129b55c8aa6SJiri Slaby #define FC_SetFlowCtl 21 130b55c8aa6SJiri Slaby #define FC_GenIrq 22 131b55c8aa6SJiri Slaby #define FC_InCD180 23 132b55c8aa6SJiri Slaby #define FC_OutCD180 24 133b55c8aa6SJiri Slaby #define FC_InUARTreg 23 134b55c8aa6SJiri Slaby #define FC_OutUARTreg 24 135b55c8aa6SJiri Slaby #define FC_SetXonXoff 25 136b55c8aa6SJiri Slaby #define FC_OutCD180CCR 26 137b55c8aa6SJiri Slaby #define FC_ExtIQueue 27 138b55c8aa6SJiri Slaby #define FC_ExtOQueue 28 139b55c8aa6SJiri Slaby #define FC_ClrLineIrq 29 140b55c8aa6SJiri Slaby #define FC_HWFlowCtl 30 141b55c8aa6SJiri Slaby #define FC_GetClockRate 35 142b55c8aa6SJiri Slaby #define FC_SetBaud 36 143b55c8aa6SJiri Slaby #define FC_SetDataMode 41 144b55c8aa6SJiri Slaby #define FC_GetCCSR 43 145b55c8aa6SJiri Slaby #define FC_GetDataError 45 146b55c8aa6SJiri Slaby #define FC_RxControl 50 147b55c8aa6SJiri Slaby #define FC_ImmSend 51 148b55c8aa6SJiri Slaby #define FC_SetXonState 52 149b55c8aa6SJiri Slaby #define FC_SetXoffState 53 150b55c8aa6SJiri Slaby #define FC_SetRxFIFOTrig 54 151b55c8aa6SJiri Slaby #define FC_SetTxFIFOCnt 55 152b55c8aa6SJiri Slaby #define FC_UnixRate 56 153b55c8aa6SJiri Slaby #define FC_UnixResetTimer 57 154b55c8aa6SJiri Slaby 155b55c8aa6SJiri Slaby #define RxFIFOTrig1 0 156b55c8aa6SJiri Slaby #define RxFIFOTrig4 1 157b55c8aa6SJiri Slaby #define RxFIFOTrig8 2 158b55c8aa6SJiri Slaby #define RxFIFOTrig14 3 159b55c8aa6SJiri Slaby 160b55c8aa6SJiri Slaby /* 161b55c8aa6SJiri Slaby * Dual-Ported RAM 162b55c8aa6SJiri Slaby */ 163b55c8aa6SJiri Slaby #define DRAM_global 0 164b55c8aa6SJiri Slaby #define INT_data (DRAM_global + 0) 165b55c8aa6SJiri Slaby #define Config_base (DRAM_global + 0x108) 166b55c8aa6SJiri Slaby 167b55c8aa6SJiri Slaby #define IRQindex (INT_data + 0) 168b55c8aa6SJiri Slaby #define IRQpending (INT_data + 4) 169b55c8aa6SJiri Slaby #define IRQtable (INT_data + 8) 170b55c8aa6SJiri Slaby 171b55c8aa6SJiri Slaby /* 172b55c8aa6SJiri Slaby * Interrupt Status 173b55c8aa6SJiri Slaby */ 174b55c8aa6SJiri Slaby #define IntrRx 0x01 /* receiver data O.K. */ 175b55c8aa6SJiri Slaby #define IntrTx 0x02 /* transmit buffer empty */ 176b55c8aa6SJiri Slaby #define IntrFunc 0x04 /* function complete */ 177b55c8aa6SJiri Slaby #define IntrBreak 0x08 /* received break */ 178b55c8aa6SJiri Slaby #define IntrLine 0x10 /* line status change 179b55c8aa6SJiri Slaby for transmitter */ 180b55c8aa6SJiri Slaby #define IntrIntr 0x20 /* received INTR code */ 181b55c8aa6SJiri Slaby #define IntrQuit 0x40 /* received QUIT code */ 182b55c8aa6SJiri Slaby #define IntrEOF 0x80 /* received EOF code */ 183b55c8aa6SJiri Slaby 184b55c8aa6SJiri Slaby #define IntrRxTrigger 0x100 /* rx data count reach trigger value */ 185b55c8aa6SJiri Slaby #define IntrTxTrigger 0x200 /* tx data count below trigger value */ 186b55c8aa6SJiri Slaby 187b55c8aa6SJiri Slaby #define Magic_no (Config_base + 0) 188b55c8aa6SJiri Slaby #define Card_model_no (Config_base + 2) 189b55c8aa6SJiri Slaby #define Total_ports (Config_base + 4) 190b55c8aa6SJiri Slaby #define Module_cnt (Config_base + 8) 191b55c8aa6SJiri Slaby #define Module_no (Config_base + 10) 192b55c8aa6SJiri Slaby #define Timer_10ms (Config_base + 14) 193b55c8aa6SJiri Slaby #define Disable_IRQ (Config_base + 20) 194b55c8aa6SJiri Slaby #define TMS320_PORT1 (Config_base + 22) 195b55c8aa6SJiri Slaby #define TMS320_PORT2 (Config_base + 24) 196b55c8aa6SJiri Slaby #define TMS320_CLOCK (Config_base + 26) 197b55c8aa6SJiri Slaby 198b55c8aa6SJiri Slaby /* 199b55c8aa6SJiri Slaby * DATA BUFFER in DRAM 200b55c8aa6SJiri Slaby */ 201b55c8aa6SJiri Slaby #define Extern_table 0x400 /* Base address of the external table 202b55c8aa6SJiri Slaby (24 words * 64) total 3K bytes 203b55c8aa6SJiri Slaby (24 words * 128) total 6K bytes */ 204b55c8aa6SJiri Slaby #define Extern_size 0x60 /* 96 bytes */ 205b55c8aa6SJiri Slaby #define RXrptr 0x00 /* read pointer for RX buffer */ 206b55c8aa6SJiri Slaby #define RXwptr 0x02 /* write pointer for RX buffer */ 207b55c8aa6SJiri Slaby #define TXrptr 0x04 /* read pointer for TX buffer */ 208b55c8aa6SJiri Slaby #define TXwptr 0x06 /* write pointer for TX buffer */ 209b55c8aa6SJiri Slaby #define HostStat 0x08 /* IRQ flag and general flag */ 210b55c8aa6SJiri Slaby #define FlagStat 0x0A 211b55c8aa6SJiri Slaby #define FlowControl 0x0C /* B7 B6 B5 B4 B3 B2 B1 B0 */ 212b55c8aa6SJiri Slaby /* x x x x | | | | */ 213b55c8aa6SJiri Slaby /* | | | + CTS flow */ 214b55c8aa6SJiri Slaby /* | | +--- RTS flow */ 215b55c8aa6SJiri Slaby /* | +------ TX Xon/Xoff */ 216b55c8aa6SJiri Slaby /* +--------- RX Xon/Xoff */ 217b55c8aa6SJiri Slaby #define Break_cnt 0x0E /* received break count */ 218b55c8aa6SJiri Slaby #define CD180TXirq 0x10 /* if non-0: enable TX irq */ 219b55c8aa6SJiri Slaby #define RX_mask 0x12 220b55c8aa6SJiri Slaby #define TX_mask 0x14 221b55c8aa6SJiri Slaby #define Ofs_rxb 0x16 222b55c8aa6SJiri Slaby #define Ofs_txb 0x18 223b55c8aa6SJiri Slaby #define Page_rxb 0x1A 224b55c8aa6SJiri Slaby #define Page_txb 0x1C 225b55c8aa6SJiri Slaby #define EndPage_rxb 0x1E 226b55c8aa6SJiri Slaby #define EndPage_txb 0x20 227b55c8aa6SJiri Slaby #define Data_error 0x22 228b55c8aa6SJiri Slaby #define RxTrigger 0x28 229b55c8aa6SJiri Slaby #define TxTrigger 0x2a 230b55c8aa6SJiri Slaby 231b55c8aa6SJiri Slaby #define rRXwptr 0x34 232b55c8aa6SJiri Slaby #define Low_water 0x36 233b55c8aa6SJiri Slaby 234b55c8aa6SJiri Slaby #define FuncCode 0x40 235b55c8aa6SJiri Slaby #define FuncArg 0x42 236b55c8aa6SJiri Slaby #define FuncArg1 0x44 237b55c8aa6SJiri Slaby 238b55c8aa6SJiri Slaby #define C218rx_size 0x2000 /* 8K bytes */ 239b55c8aa6SJiri Slaby #define C218tx_size 0x8000 /* 32K bytes */ 240b55c8aa6SJiri Slaby 241b55c8aa6SJiri Slaby #define C218rx_mask (C218rx_size - 1) 242b55c8aa6SJiri Slaby #define C218tx_mask (C218tx_size - 1) 243b55c8aa6SJiri Slaby 244b55c8aa6SJiri Slaby #define C320p8rx_size 0x2000 245b55c8aa6SJiri Slaby #define C320p8tx_size 0x8000 246b55c8aa6SJiri Slaby #define C320p8rx_mask (C320p8rx_size - 1) 247b55c8aa6SJiri Slaby #define C320p8tx_mask (C320p8tx_size - 1) 248b55c8aa6SJiri Slaby 249b55c8aa6SJiri Slaby #define C320p16rx_size 0x2000 250b55c8aa6SJiri Slaby #define C320p16tx_size 0x4000 251b55c8aa6SJiri Slaby #define C320p16rx_mask (C320p16rx_size - 1) 252b55c8aa6SJiri Slaby #define C320p16tx_mask (C320p16tx_size - 1) 253b55c8aa6SJiri Slaby 254b55c8aa6SJiri Slaby #define C320p24rx_size 0x2000 255b55c8aa6SJiri Slaby #define C320p24tx_size 0x2000 256b55c8aa6SJiri Slaby #define C320p24rx_mask (C320p24rx_size - 1) 257b55c8aa6SJiri Slaby #define C320p24tx_mask (C320p24tx_size - 1) 258b55c8aa6SJiri Slaby 259b55c8aa6SJiri Slaby #define C320p32rx_size 0x1000 260b55c8aa6SJiri Slaby #define C320p32tx_size 0x1000 261b55c8aa6SJiri Slaby #define C320p32rx_mask (C320p32rx_size - 1) 262b55c8aa6SJiri Slaby #define C320p32tx_mask (C320p32tx_size - 1) 263b55c8aa6SJiri Slaby 264b55c8aa6SJiri Slaby #define Page_size 0x2000U 265b55c8aa6SJiri Slaby #define Page_mask (Page_size - 1) 266b55c8aa6SJiri Slaby #define C218rx_spage 3 267b55c8aa6SJiri Slaby #define C218tx_spage 4 268b55c8aa6SJiri Slaby #define C218rx_pageno 1 269b55c8aa6SJiri Slaby #define C218tx_pageno 4 270b55c8aa6SJiri Slaby #define C218buf_pageno 5 271b55c8aa6SJiri Slaby 272b55c8aa6SJiri Slaby #define C320p8rx_spage 3 273b55c8aa6SJiri Slaby #define C320p8tx_spage 4 274b55c8aa6SJiri Slaby #define C320p8rx_pgno 1 275b55c8aa6SJiri Slaby #define C320p8tx_pgno 4 276b55c8aa6SJiri Slaby #define C320p8buf_pgno 5 277b55c8aa6SJiri Slaby 278b55c8aa6SJiri Slaby #define C320p16rx_spage 3 279b55c8aa6SJiri Slaby #define C320p16tx_spage 4 280b55c8aa6SJiri Slaby #define C320p16rx_pgno 1 281b55c8aa6SJiri Slaby #define C320p16tx_pgno 2 282b55c8aa6SJiri Slaby #define C320p16buf_pgno 3 283b55c8aa6SJiri Slaby 284b55c8aa6SJiri Slaby #define C320p24rx_spage 3 285b55c8aa6SJiri Slaby #define C320p24tx_spage 4 286b55c8aa6SJiri Slaby #define C320p24rx_pgno 1 287b55c8aa6SJiri Slaby #define C320p24tx_pgno 1 288b55c8aa6SJiri Slaby #define C320p24buf_pgno 2 289b55c8aa6SJiri Slaby 290b55c8aa6SJiri Slaby #define C320p32rx_spage 3 291b55c8aa6SJiri Slaby #define C320p32tx_ofs C320p32rx_size 292b55c8aa6SJiri Slaby #define C320p32tx_spage 3 293b55c8aa6SJiri Slaby #define C320p32buf_pgno 1 294b55c8aa6SJiri Slaby 295b55c8aa6SJiri Slaby /* 296b55c8aa6SJiri Slaby * Host Status 297b55c8aa6SJiri Slaby */ 298b55c8aa6SJiri Slaby #define WakeupRx 0x01 299b55c8aa6SJiri Slaby #define WakeupTx 0x02 300b55c8aa6SJiri Slaby #define WakeupBreak 0x08 301b55c8aa6SJiri Slaby #define WakeupLine 0x10 302b55c8aa6SJiri Slaby #define WakeupIntr 0x20 303b55c8aa6SJiri Slaby #define WakeupQuit 0x40 304b55c8aa6SJiri Slaby #define WakeupEOF 0x80 /* used in VTIME control */ 305b55c8aa6SJiri Slaby #define WakeupRxTrigger 0x100 306b55c8aa6SJiri Slaby #define WakeupTxTrigger 0x200 307b55c8aa6SJiri Slaby /* 308b55c8aa6SJiri Slaby * Flag status 309b55c8aa6SJiri Slaby */ 310b55c8aa6SJiri Slaby #define Rx_over 0x01 311b55c8aa6SJiri Slaby #define Xoff_state 0x02 312b55c8aa6SJiri Slaby #define Tx_flowOff 0x04 313b55c8aa6SJiri Slaby #define Tx_enable 0x08 314b55c8aa6SJiri Slaby #define CTS_state 0x10 315b55c8aa6SJiri Slaby #define DSR_state 0x20 316b55c8aa6SJiri Slaby #define DCD_state 0x80 317b55c8aa6SJiri Slaby /* 318b55c8aa6SJiri Slaby * FlowControl 319b55c8aa6SJiri Slaby */ 320b55c8aa6SJiri Slaby #define CTS_FlowCtl 1 321b55c8aa6SJiri Slaby #define RTS_FlowCtl 2 322b55c8aa6SJiri Slaby #define Tx_FlowCtl 4 323b55c8aa6SJiri Slaby #define Rx_FlowCtl 8 324b55c8aa6SJiri Slaby #define IXM_IXANY 0x10 325b55c8aa6SJiri Slaby 326b55c8aa6SJiri Slaby #define LowWater 128 327b55c8aa6SJiri Slaby 328b55c8aa6SJiri Slaby #define DTR_ON 1 329b55c8aa6SJiri Slaby #define RTS_ON 2 330b55c8aa6SJiri Slaby #define CTS_ON 1 331b55c8aa6SJiri Slaby #define DSR_ON 2 332b55c8aa6SJiri Slaby #define DCD_ON 8 333b55c8aa6SJiri Slaby 334b55c8aa6SJiri Slaby /* mode definition */ 335b55c8aa6SJiri Slaby #define MX_CS8 0x03 336b55c8aa6SJiri Slaby #define MX_CS7 0x02 337b55c8aa6SJiri Slaby #define MX_CS6 0x01 338b55c8aa6SJiri Slaby #define MX_CS5 0x00 339b55c8aa6SJiri Slaby 340b55c8aa6SJiri Slaby #define MX_STOP1 0x00 341b55c8aa6SJiri Slaby #define MX_STOP15 0x04 342b55c8aa6SJiri Slaby #define MX_STOP2 0x08 343b55c8aa6SJiri Slaby 344b55c8aa6SJiri Slaby #define MX_PARNONE 0x00 345b55c8aa6SJiri Slaby #define MX_PAREVEN 0x40 346b55c8aa6SJiri Slaby #define MX_PARODD 0xC0 347b55c8aa6SJiri Slaby #define MX_PARMARK 0xA0 348b55c8aa6SJiri Slaby #define MX_PARSPACE 0x20 349a6afd9f3SGreg Kroah-Hartman 350a6afd9f3SGreg Kroah-Hartman #define MOXA_VERSION "6.0k" 351a6afd9f3SGreg Kroah-Hartman 352a6afd9f3SGreg Kroah-Hartman #define MOXA_FW_HDRLEN 32 353a6afd9f3SGreg Kroah-Hartman 354a6afd9f3SGreg Kroah-Hartman #define MOXAMAJOR 172 355a6afd9f3SGreg Kroah-Hartman 356a6afd9f3SGreg Kroah-Hartman #define MAX_BOARDS 4 /* Don't change this value */ 357a6afd9f3SGreg Kroah-Hartman #define MAX_PORTS_PER_BOARD 32 /* Don't change this value */ 358a6afd9f3SGreg Kroah-Hartman #define MAX_PORTS (MAX_BOARDS * MAX_PORTS_PER_BOARD) 359a6afd9f3SGreg Kroah-Hartman 360a6afd9f3SGreg Kroah-Hartman #define MOXA_IS_320(brd) ((brd)->boardType == MOXA_BOARD_C320_ISA || \ 361a6afd9f3SGreg Kroah-Hartman (brd)->boardType == MOXA_BOARD_C320_PCI) 362a6afd9f3SGreg Kroah-Hartman 363a6afd9f3SGreg Kroah-Hartman /* 364a6afd9f3SGreg Kroah-Hartman * Define the Moxa PCI vendor and device IDs. 365a6afd9f3SGreg Kroah-Hartman */ 366a6afd9f3SGreg Kroah-Hartman #define MOXA_BUS_TYPE_ISA 0 367a6afd9f3SGreg Kroah-Hartman #define MOXA_BUS_TYPE_PCI 1 368a6afd9f3SGreg Kroah-Hartman 369a6afd9f3SGreg Kroah-Hartman enum { 370a6afd9f3SGreg Kroah-Hartman MOXA_BOARD_C218_PCI = 1, 371a6afd9f3SGreg Kroah-Hartman MOXA_BOARD_C218_ISA, 372a6afd9f3SGreg Kroah-Hartman MOXA_BOARD_C320_PCI, 373a6afd9f3SGreg Kroah-Hartman MOXA_BOARD_C320_ISA, 374a6afd9f3SGreg Kroah-Hartman MOXA_BOARD_CP204J, 375a6afd9f3SGreg Kroah-Hartman }; 376a6afd9f3SGreg Kroah-Hartman 377a6afd9f3SGreg Kroah-Hartman static char *moxa_brdname[] = 378a6afd9f3SGreg Kroah-Hartman { 379a6afd9f3SGreg Kroah-Hartman "C218 Turbo PCI series", 380a6afd9f3SGreg Kroah-Hartman "C218 Turbo ISA series", 381a6afd9f3SGreg Kroah-Hartman "C320 Turbo PCI series", 382a6afd9f3SGreg Kroah-Hartman "C320 Turbo ISA series", 383a6afd9f3SGreg Kroah-Hartman "CP-204J series", 384a6afd9f3SGreg Kroah-Hartman }; 385a6afd9f3SGreg Kroah-Hartman 386a6afd9f3SGreg Kroah-Hartman #ifdef CONFIG_PCI 38750bd842bSArvind Yadav static const struct pci_device_id moxa_pcibrds[] = { 388a6afd9f3SGreg Kroah-Hartman { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C218), 389a6afd9f3SGreg Kroah-Hartman .driver_data = MOXA_BOARD_C218_PCI }, 390a6afd9f3SGreg Kroah-Hartman { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C320), 391a6afd9f3SGreg Kroah-Hartman .driver_data = MOXA_BOARD_C320_PCI }, 392a6afd9f3SGreg Kroah-Hartman { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP204J), 393a6afd9f3SGreg Kroah-Hartman .driver_data = MOXA_BOARD_CP204J }, 394a6afd9f3SGreg Kroah-Hartman { 0 } 395a6afd9f3SGreg Kroah-Hartman }; 396a6afd9f3SGreg Kroah-Hartman MODULE_DEVICE_TABLE(pci, moxa_pcibrds); 397a6afd9f3SGreg Kroah-Hartman #endif /* CONFIG_PCI */ 398a6afd9f3SGreg Kroah-Hartman 399a6afd9f3SGreg Kroah-Hartman struct moxa_port; 400a6afd9f3SGreg Kroah-Hartman 401a6afd9f3SGreg Kroah-Hartman static struct moxa_board_conf { 402a6afd9f3SGreg Kroah-Hartman int boardType; 403a6afd9f3SGreg Kroah-Hartman int numPorts; 404a6afd9f3SGreg Kroah-Hartman int busType; 405a6afd9f3SGreg Kroah-Hartman 406a6afd9f3SGreg Kroah-Hartman unsigned int ready; 407a6afd9f3SGreg Kroah-Hartman 408a6afd9f3SGreg Kroah-Hartman struct moxa_port *ports; 409a6afd9f3SGreg Kroah-Hartman 410a6afd9f3SGreg Kroah-Hartman void __iomem *basemem; 411a6afd9f3SGreg Kroah-Hartman void __iomem *intNdx; 412a6afd9f3SGreg Kroah-Hartman void __iomem *intPend; 413a6afd9f3SGreg Kroah-Hartman void __iomem *intTable; 414a6afd9f3SGreg Kroah-Hartman } moxa_boards[MAX_BOARDS]; 415a6afd9f3SGreg Kroah-Hartman 416a6afd9f3SGreg Kroah-Hartman struct mxser_mstatus { 417a6afd9f3SGreg Kroah-Hartman tcflag_t cflag; 418a6afd9f3SGreg Kroah-Hartman int cts; 419a6afd9f3SGreg Kroah-Hartman int dsr; 420a6afd9f3SGreg Kroah-Hartman int ri; 421a6afd9f3SGreg Kroah-Hartman int dcd; 422a6afd9f3SGreg Kroah-Hartman }; 423a6afd9f3SGreg Kroah-Hartman 424a6afd9f3SGreg Kroah-Hartman struct moxaq_str { 425a6afd9f3SGreg Kroah-Hartman int inq; 426a6afd9f3SGreg Kroah-Hartman int outq; 427a6afd9f3SGreg Kroah-Hartman }; 428a6afd9f3SGreg Kroah-Hartman 429a6afd9f3SGreg Kroah-Hartman struct moxa_port { 430a6afd9f3SGreg Kroah-Hartman struct tty_port port; 431a6afd9f3SGreg Kroah-Hartman struct moxa_board_conf *board; 432a6afd9f3SGreg Kroah-Hartman void __iomem *tableAddr; 433a6afd9f3SGreg Kroah-Hartman 434a6afd9f3SGreg Kroah-Hartman int type; 435a6afd9f3SGreg Kroah-Hartman int cflag; 436a6afd9f3SGreg Kroah-Hartman unsigned long statusflags; 437a6afd9f3SGreg Kroah-Hartman 438a6afd9f3SGreg Kroah-Hartman u8 DCDState; /* Protected by the port lock */ 439a6afd9f3SGreg Kroah-Hartman u8 lineCtrl; 440a6afd9f3SGreg Kroah-Hartman u8 lowChkFlag; 441a6afd9f3SGreg Kroah-Hartman }; 442a6afd9f3SGreg Kroah-Hartman 443a6afd9f3SGreg Kroah-Hartman struct mon_str { 444a6afd9f3SGreg Kroah-Hartman int tick; 445a6afd9f3SGreg Kroah-Hartman int rxcnt[MAX_PORTS]; 446a6afd9f3SGreg Kroah-Hartman int txcnt[MAX_PORTS]; 447a6afd9f3SGreg Kroah-Hartman }; 448a6afd9f3SGreg Kroah-Hartman 449a6afd9f3SGreg Kroah-Hartman /* statusflags */ 450a6afd9f3SGreg Kroah-Hartman #define TXSTOPPED 1 451a6afd9f3SGreg Kroah-Hartman #define LOWWAIT 2 452a6afd9f3SGreg Kroah-Hartman #define EMPTYWAIT 3 453a6afd9f3SGreg Kroah-Hartman 454a6afd9f3SGreg Kroah-Hartman 455a6afd9f3SGreg Kroah-Hartman #define WAKEUP_CHARS 256 456a6afd9f3SGreg Kroah-Hartman 457a6afd9f3SGreg Kroah-Hartman static int ttymajor = MOXAMAJOR; 458a6afd9f3SGreg Kroah-Hartman static struct mon_str moxaLog; 459a6afd9f3SGreg Kroah-Hartman static unsigned int moxaFuncTout = HZ / 2; 460a6afd9f3SGreg Kroah-Hartman static unsigned int moxaLowWaterChk; 461a6afd9f3SGreg Kroah-Hartman static DEFINE_MUTEX(moxa_openlock); 462a6afd9f3SGreg Kroah-Hartman static DEFINE_SPINLOCK(moxa_lock); 463a6afd9f3SGreg Kroah-Hartman 464a6afd9f3SGreg Kroah-Hartman static unsigned long baseaddr[MAX_BOARDS]; 465a6afd9f3SGreg Kroah-Hartman static unsigned int type[MAX_BOARDS]; 466a6afd9f3SGreg Kroah-Hartman static unsigned int numports[MAX_BOARDS]; 467793be898SJiri Slaby static struct tty_port moxa_service_port; 468a6afd9f3SGreg Kroah-Hartman 469a6afd9f3SGreg Kroah-Hartman MODULE_AUTHOR("William Chen"); 470a6afd9f3SGreg Kroah-Hartman MODULE_DESCRIPTION("MOXA Intellio Family Multiport Board Device Driver"); 471a6afd9f3SGreg Kroah-Hartman MODULE_LICENSE("GPL"); 472a6afd9f3SGreg Kroah-Hartman MODULE_FIRMWARE("c218tunx.cod"); 473a6afd9f3SGreg Kroah-Hartman MODULE_FIRMWARE("cp204unx.cod"); 474a6afd9f3SGreg Kroah-Hartman MODULE_FIRMWARE("c320tunx.cod"); 475a6afd9f3SGreg Kroah-Hartman 476a6afd9f3SGreg Kroah-Hartman module_param_array(type, uint, NULL, 0); 477a6afd9f3SGreg Kroah-Hartman MODULE_PARM_DESC(type, "card type: C218=2, C320=4"); 4783b60daf8SDavid Howells module_param_hw_array(baseaddr, ulong, ioport, NULL, 0); 479a6afd9f3SGreg Kroah-Hartman MODULE_PARM_DESC(baseaddr, "base address"); 480a6afd9f3SGreg Kroah-Hartman module_param_array(numports, uint, NULL, 0); 481a6afd9f3SGreg Kroah-Hartman MODULE_PARM_DESC(numports, "numports (ignored for C218)"); 482a6afd9f3SGreg Kroah-Hartman 483a6afd9f3SGreg Kroah-Hartman module_param(ttymajor, int, 0); 484a6afd9f3SGreg Kroah-Hartman 485a6afd9f3SGreg Kroah-Hartman /* 486a6afd9f3SGreg Kroah-Hartman * static functions: 487a6afd9f3SGreg Kroah-Hartman */ 488a6afd9f3SGreg Kroah-Hartman static int moxa_open(struct tty_struct *, struct file *); 489a6afd9f3SGreg Kroah-Hartman static void moxa_close(struct tty_struct *, struct file *); 490*69851e4aSJiri Slaby (SUSE) static int moxa_write(struct tty_struct *, const u8 *, int); 49103b3b1a2SJiri Slaby static unsigned int moxa_write_room(struct tty_struct *); 492a6afd9f3SGreg Kroah-Hartman static void moxa_flush_buffer(struct tty_struct *); 493fff4ef17SJiri Slaby static unsigned int moxa_chars_in_buffer(struct tty_struct *); 494a8c11c15SIlpo Järvinen static void moxa_set_termios(struct tty_struct *, const struct ktermios *); 495a6afd9f3SGreg Kroah-Hartman static void moxa_stop(struct tty_struct *); 496a6afd9f3SGreg Kroah-Hartman static void moxa_start(struct tty_struct *); 497a6afd9f3SGreg Kroah-Hartman static void moxa_hangup(struct tty_struct *); 498a6afd9f3SGreg Kroah-Hartman static int moxa_tiocmget(struct tty_struct *tty); 499a6afd9f3SGreg Kroah-Hartman static int moxa_tiocmset(struct tty_struct *tty, 500a6afd9f3SGreg Kroah-Hartman unsigned int set, unsigned int clear); 50124ed960aSKees Cook static void moxa_poll(struct timer_list *); 502a8c11c15SIlpo Järvinen static void moxa_set_tty_param(struct tty_struct *, const struct ktermios *); 503a6afd9f3SGreg Kroah-Hartman static void moxa_shutdown(struct tty_port *); 504b300fb26SIlpo Järvinen static bool moxa_carrier_raised(struct tty_port *); 5055d420399SIlpo Järvinen static void moxa_dtr_rts(struct tty_port *, bool); 506a6afd9f3SGreg Kroah-Hartman /* 507a6afd9f3SGreg Kroah-Hartman * moxa board interface functions: 508a6afd9f3SGreg Kroah-Hartman */ 509a6afd9f3SGreg Kroah-Hartman static void MoxaPortEnable(struct moxa_port *); 510a6afd9f3SGreg Kroah-Hartman static void MoxaPortDisable(struct moxa_port *); 511a6afd9f3SGreg Kroah-Hartman static int MoxaPortSetTermio(struct moxa_port *, struct ktermios *, speed_t); 5125d420399SIlpo Järvinen static int MoxaPortGetLineOut(struct moxa_port *, bool *, bool *); 5135d420399SIlpo Järvinen static void MoxaPortLineCtrl(struct moxa_port *, bool, bool); 514a6afd9f3SGreg Kroah-Hartman static void MoxaPortFlowCtrl(struct moxa_port *, int, int, int, int, int); 515a6afd9f3SGreg Kroah-Hartman static int MoxaPortLineStatus(struct moxa_port *); 516a6afd9f3SGreg Kroah-Hartman static void MoxaPortFlushData(struct moxa_port *, int); 517a6afd9f3SGreg Kroah-Hartman static int MoxaPortWriteData(struct tty_struct *, const unsigned char *, int); 518a6afd9f3SGreg Kroah-Hartman static int MoxaPortReadData(struct moxa_port *); 519fff4ef17SJiri Slaby static unsigned int MoxaPortTxQueue(struct moxa_port *); 520a6afd9f3SGreg Kroah-Hartman static int MoxaPortRxQueue(struct moxa_port *); 52103b3b1a2SJiri Slaby static unsigned int MoxaPortTxFree(struct moxa_port *); 522a6afd9f3SGreg Kroah-Hartman static void MoxaPortTxDisable(struct moxa_port *); 523a6afd9f3SGreg Kroah-Hartman static void MoxaPortTxEnable(struct moxa_port *); 5241c729ab1SAl Viro static int moxa_get_serial_info(struct tty_struct *, struct serial_struct *); 5251c729ab1SAl Viro static int moxa_set_serial_info(struct tty_struct *, struct serial_struct *); 526a6afd9f3SGreg Kroah-Hartman static void MoxaSetFifo(struct moxa_port *port, int enable); 527a6afd9f3SGreg Kroah-Hartman 528a6afd9f3SGreg Kroah-Hartman /* 529a6afd9f3SGreg Kroah-Hartman * I/O functions 530a6afd9f3SGreg Kroah-Hartman */ 531a6afd9f3SGreg Kroah-Hartman 532a6afd9f3SGreg Kroah-Hartman static DEFINE_SPINLOCK(moxafunc_lock); 533a6afd9f3SGreg Kroah-Hartman 534a6afd9f3SGreg Kroah-Hartman static void moxa_wait_finish(void __iomem *ofsAddr) 535a6afd9f3SGreg Kroah-Hartman { 536a6afd9f3SGreg Kroah-Hartman unsigned long end = jiffies + moxaFuncTout; 537a6afd9f3SGreg Kroah-Hartman 538a6afd9f3SGreg Kroah-Hartman while (readw(ofsAddr + FuncCode) != 0) 539a6afd9f3SGreg Kroah-Hartman if (time_after(jiffies, end)) 540a6afd9f3SGreg Kroah-Hartman return; 5415a3c6b25SManuel Zerpies if (readw(ofsAddr + FuncCode) != 0) 5425a3c6b25SManuel Zerpies printk_ratelimited(KERN_WARNING "moxa function expired\n"); 543a6afd9f3SGreg Kroah-Hartman } 544a6afd9f3SGreg Kroah-Hartman 545a6afd9f3SGreg Kroah-Hartman static void moxafunc(void __iomem *ofsAddr, u16 cmd, u16 arg) 546a6afd9f3SGreg Kroah-Hartman { 547a6afd9f3SGreg Kroah-Hartman unsigned long flags; 548a6afd9f3SGreg Kroah-Hartman spin_lock_irqsave(&moxafunc_lock, flags); 549a6afd9f3SGreg Kroah-Hartman writew(arg, ofsAddr + FuncArg); 550a6afd9f3SGreg Kroah-Hartman writew(cmd, ofsAddr + FuncCode); 551a6afd9f3SGreg Kroah-Hartman moxa_wait_finish(ofsAddr); 552a6afd9f3SGreg Kroah-Hartman spin_unlock_irqrestore(&moxafunc_lock, flags); 553a6afd9f3SGreg Kroah-Hartman } 554a6afd9f3SGreg Kroah-Hartman 555a6afd9f3SGreg Kroah-Hartman static int moxafuncret(void __iomem *ofsAddr, u16 cmd, u16 arg) 556a6afd9f3SGreg Kroah-Hartman { 557a6afd9f3SGreg Kroah-Hartman unsigned long flags; 558a6afd9f3SGreg Kroah-Hartman u16 ret; 559a6afd9f3SGreg Kroah-Hartman spin_lock_irqsave(&moxafunc_lock, flags); 560a6afd9f3SGreg Kroah-Hartman writew(arg, ofsAddr + FuncArg); 561a6afd9f3SGreg Kroah-Hartman writew(cmd, ofsAddr + FuncCode); 562a6afd9f3SGreg Kroah-Hartman moxa_wait_finish(ofsAddr); 563a6afd9f3SGreg Kroah-Hartman ret = readw(ofsAddr + FuncArg); 564a6afd9f3SGreg Kroah-Hartman spin_unlock_irqrestore(&moxafunc_lock, flags); 565a6afd9f3SGreg Kroah-Hartman return ret; 566a6afd9f3SGreg Kroah-Hartman } 567a6afd9f3SGreg Kroah-Hartman 568a6afd9f3SGreg Kroah-Hartman static void moxa_low_water_check(void __iomem *ofsAddr) 569a6afd9f3SGreg Kroah-Hartman { 570a6afd9f3SGreg Kroah-Hartman u16 rptr, wptr, mask, len; 571a6afd9f3SGreg Kroah-Hartman 572a6afd9f3SGreg Kroah-Hartman if (readb(ofsAddr + FlagStat) & Xoff_state) { 573a6afd9f3SGreg Kroah-Hartman rptr = readw(ofsAddr + RXrptr); 574a6afd9f3SGreg Kroah-Hartman wptr = readw(ofsAddr + RXwptr); 575a6afd9f3SGreg Kroah-Hartman mask = readw(ofsAddr + RX_mask); 576a6afd9f3SGreg Kroah-Hartman len = (wptr - rptr) & mask; 577a6afd9f3SGreg Kroah-Hartman if (len <= Low_water) 578a6afd9f3SGreg Kroah-Hartman moxafunc(ofsAddr, FC_SendXon, 0); 579a6afd9f3SGreg Kroah-Hartman } 580a6afd9f3SGreg Kroah-Hartman } 581a6afd9f3SGreg Kroah-Hartman 582a6afd9f3SGreg Kroah-Hartman /* 583a6afd9f3SGreg Kroah-Hartman * TTY operations 584a6afd9f3SGreg Kroah-Hartman */ 585a6afd9f3SGreg Kroah-Hartman 586a6afd9f3SGreg Kroah-Hartman static int moxa_ioctl(struct tty_struct *tty, 587a6afd9f3SGreg Kroah-Hartman unsigned int cmd, unsigned long arg) 588a6afd9f3SGreg Kroah-Hartman { 589a6afd9f3SGreg Kroah-Hartman struct moxa_port *ch = tty->driver_data; 590a6afd9f3SGreg Kroah-Hartman void __user *argp = (void __user *)arg; 591a6afd9f3SGreg Kroah-Hartman int status, ret = 0; 592a6afd9f3SGreg Kroah-Hartman 593a6afd9f3SGreg Kroah-Hartman if (tty->index == MAX_PORTS) { 594a6afd9f3SGreg Kroah-Hartman if (cmd != MOXA_GETDATACOUNT && cmd != MOXA_GET_IOQUEUE && 595a6afd9f3SGreg Kroah-Hartman cmd != MOXA_GETMSTATUS) 596a6afd9f3SGreg Kroah-Hartman return -EINVAL; 597a6afd9f3SGreg Kroah-Hartman } else if (!ch) 598a6afd9f3SGreg Kroah-Hartman return -ENODEV; 599a6afd9f3SGreg Kroah-Hartman 600a6afd9f3SGreg Kroah-Hartman switch (cmd) { 601a6afd9f3SGreg Kroah-Hartman case MOXA_GETDATACOUNT: 602a6afd9f3SGreg Kroah-Hartman moxaLog.tick = jiffies; 603a6afd9f3SGreg Kroah-Hartman if (copy_to_user(argp, &moxaLog, sizeof(moxaLog))) 604a6afd9f3SGreg Kroah-Hartman ret = -EFAULT; 605a6afd9f3SGreg Kroah-Hartman break; 606a6afd9f3SGreg Kroah-Hartman case MOXA_FLUSH_QUEUE: 607a6afd9f3SGreg Kroah-Hartman MoxaPortFlushData(ch, arg); 608a6afd9f3SGreg Kroah-Hartman break; 609a6afd9f3SGreg Kroah-Hartman case MOXA_GET_IOQUEUE: { 610a6afd9f3SGreg Kroah-Hartman struct moxaq_str __user *argm = argp; 611a6afd9f3SGreg Kroah-Hartman struct moxaq_str tmp; 612a6afd9f3SGreg Kroah-Hartman struct moxa_port *p; 613a6afd9f3SGreg Kroah-Hartman unsigned int i, j; 614a6afd9f3SGreg Kroah-Hartman 615a6afd9f3SGreg Kroah-Hartman for (i = 0; i < MAX_BOARDS; i++) { 616a6afd9f3SGreg Kroah-Hartman p = moxa_boards[i].ports; 617a6afd9f3SGreg Kroah-Hartman for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) { 618a6afd9f3SGreg Kroah-Hartman memset(&tmp, 0, sizeof(tmp)); 619a6afd9f3SGreg Kroah-Hartman spin_lock_bh(&moxa_lock); 620a6afd9f3SGreg Kroah-Hartman if (moxa_boards[i].ready) { 621a6afd9f3SGreg Kroah-Hartman tmp.inq = MoxaPortRxQueue(p); 622a6afd9f3SGreg Kroah-Hartman tmp.outq = MoxaPortTxQueue(p); 623a6afd9f3SGreg Kroah-Hartman } 624a6afd9f3SGreg Kroah-Hartman spin_unlock_bh(&moxa_lock); 625a6afd9f3SGreg Kroah-Hartman if (copy_to_user(argm, &tmp, sizeof(tmp))) 626a6afd9f3SGreg Kroah-Hartman return -EFAULT; 627a6afd9f3SGreg Kroah-Hartman } 628a6afd9f3SGreg Kroah-Hartman } 629a6afd9f3SGreg Kroah-Hartman break; 630a6afd9f3SGreg Kroah-Hartman } case MOXA_GET_OQUEUE: 631a6afd9f3SGreg Kroah-Hartman status = MoxaPortTxQueue(ch); 632a6afd9f3SGreg Kroah-Hartman ret = put_user(status, (unsigned long __user *)argp); 633a6afd9f3SGreg Kroah-Hartman break; 634a6afd9f3SGreg Kroah-Hartman case MOXA_GET_IQUEUE: 635a6afd9f3SGreg Kroah-Hartman status = MoxaPortRxQueue(ch); 636a6afd9f3SGreg Kroah-Hartman ret = put_user(status, (unsigned long __user *)argp); 637a6afd9f3SGreg Kroah-Hartman break; 638a6afd9f3SGreg Kroah-Hartman case MOXA_GETMSTATUS: { 639a6afd9f3SGreg Kroah-Hartman struct mxser_mstatus __user *argm = argp; 640a6afd9f3SGreg Kroah-Hartman struct mxser_mstatus tmp; 641a6afd9f3SGreg Kroah-Hartman struct moxa_port *p; 642a6afd9f3SGreg Kroah-Hartman unsigned int i, j; 643a6afd9f3SGreg Kroah-Hartman 644a6afd9f3SGreg Kroah-Hartman for (i = 0; i < MAX_BOARDS; i++) { 645a6afd9f3SGreg Kroah-Hartman p = moxa_boards[i].ports; 646a6afd9f3SGreg Kroah-Hartman for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) { 647a6afd9f3SGreg Kroah-Hartman struct tty_struct *ttyp; 648a6afd9f3SGreg Kroah-Hartman memset(&tmp, 0, sizeof(tmp)); 649a6afd9f3SGreg Kroah-Hartman spin_lock_bh(&moxa_lock); 650a6afd9f3SGreg Kroah-Hartman if (!moxa_boards[i].ready) { 651a6afd9f3SGreg Kroah-Hartman spin_unlock_bh(&moxa_lock); 652a6afd9f3SGreg Kroah-Hartman goto copy; 653a6afd9f3SGreg Kroah-Hartman } 654a6afd9f3SGreg Kroah-Hartman 655a6afd9f3SGreg Kroah-Hartman status = MoxaPortLineStatus(p); 656a6afd9f3SGreg Kroah-Hartman spin_unlock_bh(&moxa_lock); 657a6afd9f3SGreg Kroah-Hartman 658a6afd9f3SGreg Kroah-Hartman if (status & 1) 659a6afd9f3SGreg Kroah-Hartman tmp.cts = 1; 660a6afd9f3SGreg Kroah-Hartman if (status & 2) 661a6afd9f3SGreg Kroah-Hartman tmp.dsr = 1; 662a6afd9f3SGreg Kroah-Hartman if (status & 4) 663a6afd9f3SGreg Kroah-Hartman tmp.dcd = 1; 664a6afd9f3SGreg Kroah-Hartman 665a6afd9f3SGreg Kroah-Hartman ttyp = tty_port_tty_get(&p->port); 666adc8d746SAlan Cox if (!ttyp) 667a6afd9f3SGreg Kroah-Hartman tmp.cflag = p->cflag; 668a6afd9f3SGreg Kroah-Hartman else 669adc8d746SAlan Cox tmp.cflag = ttyp->termios.c_cflag; 670df43daaaSJulia Lawall tty_kref_put(ttyp); 671a6afd9f3SGreg Kroah-Hartman copy: 672a6afd9f3SGreg Kroah-Hartman if (copy_to_user(argm, &tmp, sizeof(tmp))) 673a6afd9f3SGreg Kroah-Hartman return -EFAULT; 674a6afd9f3SGreg Kroah-Hartman } 675a6afd9f3SGreg Kroah-Hartman } 676a6afd9f3SGreg Kroah-Hartman break; 677a6afd9f3SGreg Kroah-Hartman } 678a6afd9f3SGreg Kroah-Hartman default: 679a6afd9f3SGreg Kroah-Hartman ret = -ENOIOCTLCMD; 680a6afd9f3SGreg Kroah-Hartman } 681a6afd9f3SGreg Kroah-Hartman return ret; 682a6afd9f3SGreg Kroah-Hartman } 683a6afd9f3SGreg Kroah-Hartman 684a6afd9f3SGreg Kroah-Hartman static int moxa_break_ctl(struct tty_struct *tty, int state) 685a6afd9f3SGreg Kroah-Hartman { 686a6afd9f3SGreg Kroah-Hartman struct moxa_port *port = tty->driver_data; 687a6afd9f3SGreg Kroah-Hartman 688a6afd9f3SGreg Kroah-Hartman moxafunc(port->tableAddr, state ? FC_SendBreak : FC_StopBreak, 689a6afd9f3SGreg Kroah-Hartman Magic_code); 690a6afd9f3SGreg Kroah-Hartman return 0; 691a6afd9f3SGreg Kroah-Hartman } 692a6afd9f3SGreg Kroah-Hartman 693a6afd9f3SGreg Kroah-Hartman static const struct tty_operations moxa_ops = { 694a6afd9f3SGreg Kroah-Hartman .open = moxa_open, 695a6afd9f3SGreg Kroah-Hartman .close = moxa_close, 696a6afd9f3SGreg Kroah-Hartman .write = moxa_write, 697a6afd9f3SGreg Kroah-Hartman .write_room = moxa_write_room, 698a6afd9f3SGreg Kroah-Hartman .flush_buffer = moxa_flush_buffer, 699a6afd9f3SGreg Kroah-Hartman .chars_in_buffer = moxa_chars_in_buffer, 700a6afd9f3SGreg Kroah-Hartman .ioctl = moxa_ioctl, 701a6afd9f3SGreg Kroah-Hartman .set_termios = moxa_set_termios, 702a6afd9f3SGreg Kroah-Hartman .stop = moxa_stop, 703a6afd9f3SGreg Kroah-Hartman .start = moxa_start, 704a6afd9f3SGreg Kroah-Hartman .hangup = moxa_hangup, 705a6afd9f3SGreg Kroah-Hartman .break_ctl = moxa_break_ctl, 706a6afd9f3SGreg Kroah-Hartman .tiocmget = moxa_tiocmget, 707a6afd9f3SGreg Kroah-Hartman .tiocmset = moxa_tiocmset, 7081c729ab1SAl Viro .set_serial = moxa_set_serial_info, 7091c729ab1SAl Viro .get_serial = moxa_get_serial_info, 710a6afd9f3SGreg Kroah-Hartman }; 711a6afd9f3SGreg Kroah-Hartman 712a6afd9f3SGreg Kroah-Hartman static const struct tty_port_operations moxa_port_ops = { 713a6afd9f3SGreg Kroah-Hartman .carrier_raised = moxa_carrier_raised, 714a6afd9f3SGreg Kroah-Hartman .dtr_rts = moxa_dtr_rts, 715a6afd9f3SGreg Kroah-Hartman .shutdown = moxa_shutdown, 716a6afd9f3SGreg Kroah-Hartman }; 717a6afd9f3SGreg Kroah-Hartman 718a6afd9f3SGreg Kroah-Hartman static struct tty_driver *moxaDriver; 7191d27e3e2SKees Cook static DEFINE_TIMER(moxaTimer, moxa_poll); 720a6afd9f3SGreg Kroah-Hartman 721a6afd9f3SGreg Kroah-Hartman /* 722a6afd9f3SGreg Kroah-Hartman * HW init 723a6afd9f3SGreg Kroah-Hartman */ 724a6afd9f3SGreg Kroah-Hartman 725a6afd9f3SGreg Kroah-Hartman static int moxa_check_fw_model(struct moxa_board_conf *brd, u8 model) 726a6afd9f3SGreg Kroah-Hartman { 727a6afd9f3SGreg Kroah-Hartman switch (brd->boardType) { 728a6afd9f3SGreg Kroah-Hartman case MOXA_BOARD_C218_ISA: 729a6afd9f3SGreg Kroah-Hartman case MOXA_BOARD_C218_PCI: 730a6afd9f3SGreg Kroah-Hartman if (model != 1) 731a6afd9f3SGreg Kroah-Hartman goto err; 732a6afd9f3SGreg Kroah-Hartman break; 733a6afd9f3SGreg Kroah-Hartman case MOXA_BOARD_CP204J: 734a6afd9f3SGreg Kroah-Hartman if (model != 3) 735a6afd9f3SGreg Kroah-Hartman goto err; 736a6afd9f3SGreg Kroah-Hartman break; 737a6afd9f3SGreg Kroah-Hartman default: 738a6afd9f3SGreg Kroah-Hartman if (model != 2) 739a6afd9f3SGreg Kroah-Hartman goto err; 740a6afd9f3SGreg Kroah-Hartman break; 741a6afd9f3SGreg Kroah-Hartman } 742a6afd9f3SGreg Kroah-Hartman return 0; 743a6afd9f3SGreg Kroah-Hartman err: 744a6afd9f3SGreg Kroah-Hartman return -EINVAL; 745a6afd9f3SGreg Kroah-Hartman } 746a6afd9f3SGreg Kroah-Hartman 747a6afd9f3SGreg Kroah-Hartman static int moxa_check_fw(const void *ptr) 748a6afd9f3SGreg Kroah-Hartman { 749a6afd9f3SGreg Kroah-Hartman const __le16 *lptr = ptr; 750a6afd9f3SGreg Kroah-Hartman 751a6afd9f3SGreg Kroah-Hartman if (*lptr != cpu_to_le16(0x7980)) 752a6afd9f3SGreg Kroah-Hartman return -EINVAL; 753a6afd9f3SGreg Kroah-Hartman 754a6afd9f3SGreg Kroah-Hartman return 0; 755a6afd9f3SGreg Kroah-Hartman } 756a6afd9f3SGreg Kroah-Hartman 757a6afd9f3SGreg Kroah-Hartman static int moxa_load_bios(struct moxa_board_conf *brd, const u8 *buf, 758a6afd9f3SGreg Kroah-Hartman size_t len) 759a6afd9f3SGreg Kroah-Hartman { 760a6afd9f3SGreg Kroah-Hartman void __iomem *baseAddr = brd->basemem; 761a6afd9f3SGreg Kroah-Hartman u16 tmp; 762a6afd9f3SGreg Kroah-Hartman 763a6afd9f3SGreg Kroah-Hartman writeb(HW_reset, baseAddr + Control_reg); /* reset */ 764a6afd9f3SGreg Kroah-Hartman msleep(10); 765a6afd9f3SGreg Kroah-Hartman memset_io(baseAddr, 0, 4096); 766a6afd9f3SGreg Kroah-Hartman memcpy_toio(baseAddr, buf, len); /* download BIOS */ 767a6afd9f3SGreg Kroah-Hartman writeb(0, baseAddr + Control_reg); /* restart */ 768a6afd9f3SGreg Kroah-Hartman 769a6afd9f3SGreg Kroah-Hartman msleep(2000); 770a6afd9f3SGreg Kroah-Hartman 771a6afd9f3SGreg Kroah-Hartman switch (brd->boardType) { 772a6afd9f3SGreg Kroah-Hartman case MOXA_BOARD_C218_ISA: 773a6afd9f3SGreg Kroah-Hartman case MOXA_BOARD_C218_PCI: 774a6afd9f3SGreg Kroah-Hartman tmp = readw(baseAddr + C218_key); 775a6afd9f3SGreg Kroah-Hartman if (tmp != C218_KeyCode) 776a6afd9f3SGreg Kroah-Hartman goto err; 777a6afd9f3SGreg Kroah-Hartman break; 778a6afd9f3SGreg Kroah-Hartman case MOXA_BOARD_CP204J: 779a6afd9f3SGreg Kroah-Hartman tmp = readw(baseAddr + C218_key); 780a6afd9f3SGreg Kroah-Hartman if (tmp != CP204J_KeyCode) 781a6afd9f3SGreg Kroah-Hartman goto err; 782a6afd9f3SGreg Kroah-Hartman break; 783a6afd9f3SGreg Kroah-Hartman default: 784a6afd9f3SGreg Kroah-Hartman tmp = readw(baseAddr + C320_key); 785a6afd9f3SGreg Kroah-Hartman if (tmp != C320_KeyCode) 786a6afd9f3SGreg Kroah-Hartman goto err; 787a6afd9f3SGreg Kroah-Hartman tmp = readw(baseAddr + C320_status); 788a6afd9f3SGreg Kroah-Hartman if (tmp != STS_init) { 789a6afd9f3SGreg Kroah-Hartman printk(KERN_ERR "MOXA: bios upload failed -- CPU/Basic " 790a6afd9f3SGreg Kroah-Hartman "module not found\n"); 791a6afd9f3SGreg Kroah-Hartman return -EIO; 792a6afd9f3SGreg Kroah-Hartman } 793a6afd9f3SGreg Kroah-Hartman break; 794a6afd9f3SGreg Kroah-Hartman } 795a6afd9f3SGreg Kroah-Hartman 796a6afd9f3SGreg Kroah-Hartman return 0; 797a6afd9f3SGreg Kroah-Hartman err: 798a6afd9f3SGreg Kroah-Hartman printk(KERN_ERR "MOXA: bios upload failed -- board not found\n"); 799a6afd9f3SGreg Kroah-Hartman return -EIO; 800a6afd9f3SGreg Kroah-Hartman } 801a6afd9f3SGreg Kroah-Hartman 802a6afd9f3SGreg Kroah-Hartman static int moxa_load_320b(struct moxa_board_conf *brd, const u8 *ptr, 803a6afd9f3SGreg Kroah-Hartman size_t len) 804a6afd9f3SGreg Kroah-Hartman { 805a6afd9f3SGreg Kroah-Hartman void __iomem *baseAddr = brd->basemem; 806a6afd9f3SGreg Kroah-Hartman 807a6afd9f3SGreg Kroah-Hartman if (len < 7168) { 808a6afd9f3SGreg Kroah-Hartman printk(KERN_ERR "MOXA: invalid 320 bios -- too short\n"); 809a6afd9f3SGreg Kroah-Hartman return -EINVAL; 810a6afd9f3SGreg Kroah-Hartman } 811a6afd9f3SGreg Kroah-Hartman 812a6afd9f3SGreg Kroah-Hartman writew(len - 7168 - 2, baseAddr + C320bapi_len); 813a6afd9f3SGreg Kroah-Hartman writeb(1, baseAddr + Control_reg); /* Select Page 1 */ 814a6afd9f3SGreg Kroah-Hartman memcpy_toio(baseAddr + DynPage_addr, ptr, 7168); 815a6afd9f3SGreg Kroah-Hartman writeb(2, baseAddr + Control_reg); /* Select Page 2 */ 816a6afd9f3SGreg Kroah-Hartman memcpy_toio(baseAddr + DynPage_addr, ptr + 7168, len - 7168); 817a6afd9f3SGreg Kroah-Hartman 818a6afd9f3SGreg Kroah-Hartman return 0; 819a6afd9f3SGreg Kroah-Hartman } 820a6afd9f3SGreg Kroah-Hartman 821a6afd9f3SGreg Kroah-Hartman static int moxa_real_load_code(struct moxa_board_conf *brd, const void *ptr, 822a6afd9f3SGreg Kroah-Hartman size_t len) 823a6afd9f3SGreg Kroah-Hartman { 824a6afd9f3SGreg Kroah-Hartman void __iomem *baseAddr = brd->basemem; 825a6afd9f3SGreg Kroah-Hartman const __le16 *uptr = ptr; 826a6afd9f3SGreg Kroah-Hartman size_t wlen, len2, j; 827a6afd9f3SGreg Kroah-Hartman unsigned long key, loadbuf, loadlen, checksum, checksum_ok; 828a6afd9f3SGreg Kroah-Hartman unsigned int i, retry; 829a6afd9f3SGreg Kroah-Hartman u16 usum, keycode; 830a6afd9f3SGreg Kroah-Hartman 831a6afd9f3SGreg Kroah-Hartman keycode = (brd->boardType == MOXA_BOARD_CP204J) ? CP204J_KeyCode : 832a6afd9f3SGreg Kroah-Hartman C218_KeyCode; 833a6afd9f3SGreg Kroah-Hartman 834a6afd9f3SGreg Kroah-Hartman switch (brd->boardType) { 835a6afd9f3SGreg Kroah-Hartman case MOXA_BOARD_CP204J: 836a6afd9f3SGreg Kroah-Hartman case MOXA_BOARD_C218_ISA: 837a6afd9f3SGreg Kroah-Hartman case MOXA_BOARD_C218_PCI: 838a6afd9f3SGreg Kroah-Hartman key = C218_key; 839a6afd9f3SGreg Kroah-Hartman loadbuf = C218_LoadBuf; 840a6afd9f3SGreg Kroah-Hartman loadlen = C218DLoad_len; 841a6afd9f3SGreg Kroah-Hartman checksum = C218check_sum; 842a6afd9f3SGreg Kroah-Hartman checksum_ok = C218chksum_ok; 843a6afd9f3SGreg Kroah-Hartman break; 844a6afd9f3SGreg Kroah-Hartman default: 845a6afd9f3SGreg Kroah-Hartman key = C320_key; 846a6afd9f3SGreg Kroah-Hartman keycode = C320_KeyCode; 847a6afd9f3SGreg Kroah-Hartman loadbuf = C320_LoadBuf; 848a6afd9f3SGreg Kroah-Hartman loadlen = C320DLoad_len; 849a6afd9f3SGreg Kroah-Hartman checksum = C320check_sum; 850a6afd9f3SGreg Kroah-Hartman checksum_ok = C320chksum_ok; 851a6afd9f3SGreg Kroah-Hartman break; 852a6afd9f3SGreg Kroah-Hartman } 853a6afd9f3SGreg Kroah-Hartman 854a6afd9f3SGreg Kroah-Hartman usum = 0; 855a6afd9f3SGreg Kroah-Hartman wlen = len >> 1; 856a6afd9f3SGreg Kroah-Hartman for (i = 0; i < wlen; i++) 857a6afd9f3SGreg Kroah-Hartman usum += le16_to_cpu(uptr[i]); 858a6afd9f3SGreg Kroah-Hartman retry = 0; 859a6afd9f3SGreg Kroah-Hartman do { 860a6afd9f3SGreg Kroah-Hartman wlen = len >> 1; 861a6afd9f3SGreg Kroah-Hartman j = 0; 862a6afd9f3SGreg Kroah-Hartman while (wlen) { 863a6afd9f3SGreg Kroah-Hartman len2 = (wlen > 2048) ? 2048 : wlen; 864a6afd9f3SGreg Kroah-Hartman wlen -= len2; 865a6afd9f3SGreg Kroah-Hartman memcpy_toio(baseAddr + loadbuf, ptr + j, len2 << 1); 866a6afd9f3SGreg Kroah-Hartman j += len2 << 1; 867a6afd9f3SGreg Kroah-Hartman 868a6afd9f3SGreg Kroah-Hartman writew(len2, baseAddr + loadlen); 869a6afd9f3SGreg Kroah-Hartman writew(0, baseAddr + key); 870a6afd9f3SGreg Kroah-Hartman for (i = 0; i < 100; i++) { 871a6afd9f3SGreg Kroah-Hartman if (readw(baseAddr + key) == keycode) 872a6afd9f3SGreg Kroah-Hartman break; 873a6afd9f3SGreg Kroah-Hartman msleep(10); 874a6afd9f3SGreg Kroah-Hartman } 875a6afd9f3SGreg Kroah-Hartman if (readw(baseAddr + key) != keycode) 876a6afd9f3SGreg Kroah-Hartman return -EIO; 877a6afd9f3SGreg Kroah-Hartman } 878a6afd9f3SGreg Kroah-Hartman writew(0, baseAddr + loadlen); 879a6afd9f3SGreg Kroah-Hartman writew(usum, baseAddr + checksum); 880a6afd9f3SGreg Kroah-Hartman writew(0, baseAddr + key); 881a6afd9f3SGreg Kroah-Hartman for (i = 0; i < 100; i++) { 882a6afd9f3SGreg Kroah-Hartman if (readw(baseAddr + key) == keycode) 883a6afd9f3SGreg Kroah-Hartman break; 884a6afd9f3SGreg Kroah-Hartman msleep(10); 885a6afd9f3SGreg Kroah-Hartman } 886a6afd9f3SGreg Kroah-Hartman retry++; 887a6afd9f3SGreg Kroah-Hartman } while ((readb(baseAddr + checksum_ok) != 1) && (retry < 3)); 888a6afd9f3SGreg Kroah-Hartman if (readb(baseAddr + checksum_ok) != 1) 889a6afd9f3SGreg Kroah-Hartman return -EIO; 890a6afd9f3SGreg Kroah-Hartman 891a6afd9f3SGreg Kroah-Hartman writew(0, baseAddr + key); 892a6afd9f3SGreg Kroah-Hartman for (i = 0; i < 600; i++) { 893a6afd9f3SGreg Kroah-Hartman if (readw(baseAddr + Magic_no) == Magic_code) 894a6afd9f3SGreg Kroah-Hartman break; 895a6afd9f3SGreg Kroah-Hartman msleep(10); 896a6afd9f3SGreg Kroah-Hartman } 897a6afd9f3SGreg Kroah-Hartman if (readw(baseAddr + Magic_no) != Magic_code) 898a6afd9f3SGreg Kroah-Hartman return -EIO; 899a6afd9f3SGreg Kroah-Hartman 900a6afd9f3SGreg Kroah-Hartman if (MOXA_IS_320(brd)) { 901a6afd9f3SGreg Kroah-Hartman if (brd->busType == MOXA_BUS_TYPE_PCI) { /* ASIC board */ 902a6afd9f3SGreg Kroah-Hartman writew(0x3800, baseAddr + TMS320_PORT1); 903a6afd9f3SGreg Kroah-Hartman writew(0x3900, baseAddr + TMS320_PORT2); 904a6afd9f3SGreg Kroah-Hartman writew(28499, baseAddr + TMS320_CLOCK); 905a6afd9f3SGreg Kroah-Hartman } else { 906a6afd9f3SGreg Kroah-Hartman writew(0x3200, baseAddr + TMS320_PORT1); 907a6afd9f3SGreg Kroah-Hartman writew(0x3400, baseAddr + TMS320_PORT2); 908a6afd9f3SGreg Kroah-Hartman writew(19999, baseAddr + TMS320_CLOCK); 909a6afd9f3SGreg Kroah-Hartman } 910a6afd9f3SGreg Kroah-Hartman } 911a6afd9f3SGreg Kroah-Hartman writew(1, baseAddr + Disable_IRQ); 912a6afd9f3SGreg Kroah-Hartman writew(0, baseAddr + Magic_no); 913a6afd9f3SGreg Kroah-Hartman for (i = 0; i < 500; i++) { 914a6afd9f3SGreg Kroah-Hartman if (readw(baseAddr + Magic_no) == Magic_code) 915a6afd9f3SGreg Kroah-Hartman break; 916a6afd9f3SGreg Kroah-Hartman msleep(10); 917a6afd9f3SGreg Kroah-Hartman } 918a6afd9f3SGreg Kroah-Hartman if (readw(baseAddr + Magic_no) != Magic_code) 919a6afd9f3SGreg Kroah-Hartman return -EIO; 920a6afd9f3SGreg Kroah-Hartman 921a6afd9f3SGreg Kroah-Hartman if (MOXA_IS_320(brd)) { 922a6afd9f3SGreg Kroah-Hartman j = readw(baseAddr + Module_cnt); 923a6afd9f3SGreg Kroah-Hartman if (j <= 0) 924a6afd9f3SGreg Kroah-Hartman return -EIO; 925a6afd9f3SGreg Kroah-Hartman brd->numPorts = j * 8; 926a6afd9f3SGreg Kroah-Hartman writew(j, baseAddr + Module_no); 927a6afd9f3SGreg Kroah-Hartman writew(0, baseAddr + Magic_no); 928a6afd9f3SGreg Kroah-Hartman for (i = 0; i < 600; i++) { 929a6afd9f3SGreg Kroah-Hartman if (readw(baseAddr + Magic_no) == Magic_code) 930a6afd9f3SGreg Kroah-Hartman break; 931a6afd9f3SGreg Kroah-Hartman msleep(10); 932a6afd9f3SGreg Kroah-Hartman } 933a6afd9f3SGreg Kroah-Hartman if (readw(baseAddr + Magic_no) != Magic_code) 934a6afd9f3SGreg Kroah-Hartman return -EIO; 935a6afd9f3SGreg Kroah-Hartman } 936a6afd9f3SGreg Kroah-Hartman brd->intNdx = baseAddr + IRQindex; 937a6afd9f3SGreg Kroah-Hartman brd->intPend = baseAddr + IRQpending; 938a6afd9f3SGreg Kroah-Hartman brd->intTable = baseAddr + IRQtable; 939a6afd9f3SGreg Kroah-Hartman 940a6afd9f3SGreg Kroah-Hartman return 0; 941a6afd9f3SGreg Kroah-Hartman } 942a6afd9f3SGreg Kroah-Hartman 943a6afd9f3SGreg Kroah-Hartman static int moxa_load_code(struct moxa_board_conf *brd, const void *ptr, 944a6afd9f3SGreg Kroah-Hartman size_t len) 945a6afd9f3SGreg Kroah-Hartman { 946a6afd9f3SGreg Kroah-Hartman void __iomem *ofsAddr, *baseAddr = brd->basemem; 947a6afd9f3SGreg Kroah-Hartman struct moxa_port *port; 948a6afd9f3SGreg Kroah-Hartman int retval, i; 949a6afd9f3SGreg Kroah-Hartman 950a6afd9f3SGreg Kroah-Hartman if (len % 2) { 951a6afd9f3SGreg Kroah-Hartman printk(KERN_ERR "MOXA: bios length is not even\n"); 952a6afd9f3SGreg Kroah-Hartman return -EINVAL; 953a6afd9f3SGreg Kroah-Hartman } 954a6afd9f3SGreg Kroah-Hartman 955a6afd9f3SGreg Kroah-Hartman retval = moxa_real_load_code(brd, ptr, len); /* may change numPorts */ 956a6afd9f3SGreg Kroah-Hartman if (retval) 957a6afd9f3SGreg Kroah-Hartman return retval; 958a6afd9f3SGreg Kroah-Hartman 959a6afd9f3SGreg Kroah-Hartman switch (brd->boardType) { 960a6afd9f3SGreg Kroah-Hartman case MOXA_BOARD_C218_ISA: 961a6afd9f3SGreg Kroah-Hartman case MOXA_BOARD_C218_PCI: 962a6afd9f3SGreg Kroah-Hartman case MOXA_BOARD_CP204J: 963a6afd9f3SGreg Kroah-Hartman port = brd->ports; 964a6afd9f3SGreg Kroah-Hartman for (i = 0; i < brd->numPorts; i++, port++) { 965a6afd9f3SGreg Kroah-Hartman port->board = brd; 966a6afd9f3SGreg Kroah-Hartman port->DCDState = 0; 967a6afd9f3SGreg Kroah-Hartman port->tableAddr = baseAddr + Extern_table + 968a6afd9f3SGreg Kroah-Hartman Extern_size * i; 969a6afd9f3SGreg Kroah-Hartman ofsAddr = port->tableAddr; 970a6afd9f3SGreg Kroah-Hartman writew(C218rx_mask, ofsAddr + RX_mask); 971a6afd9f3SGreg Kroah-Hartman writew(C218tx_mask, ofsAddr + TX_mask); 972a6afd9f3SGreg Kroah-Hartman writew(C218rx_spage + i * C218buf_pageno, ofsAddr + Page_rxb); 973a6afd9f3SGreg Kroah-Hartman writew(readw(ofsAddr + Page_rxb) + C218rx_pageno, ofsAddr + EndPage_rxb); 974a6afd9f3SGreg Kroah-Hartman 975a6afd9f3SGreg Kroah-Hartman writew(C218tx_spage + i * C218buf_pageno, ofsAddr + Page_txb); 976a6afd9f3SGreg Kroah-Hartman writew(readw(ofsAddr + Page_txb) + C218tx_pageno, ofsAddr + EndPage_txb); 977a6afd9f3SGreg Kroah-Hartman 978a6afd9f3SGreg Kroah-Hartman } 979a6afd9f3SGreg Kroah-Hartman break; 980a6afd9f3SGreg Kroah-Hartman default: 981a6afd9f3SGreg Kroah-Hartman port = brd->ports; 982a6afd9f3SGreg Kroah-Hartman for (i = 0; i < brd->numPorts; i++, port++) { 983a6afd9f3SGreg Kroah-Hartman port->board = brd; 984a6afd9f3SGreg Kroah-Hartman port->DCDState = 0; 985a6afd9f3SGreg Kroah-Hartman port->tableAddr = baseAddr + Extern_table + 986a6afd9f3SGreg Kroah-Hartman Extern_size * i; 987a6afd9f3SGreg Kroah-Hartman ofsAddr = port->tableAddr; 988a6afd9f3SGreg Kroah-Hartman switch (brd->numPorts) { 989a6afd9f3SGreg Kroah-Hartman case 8: 990a6afd9f3SGreg Kroah-Hartman writew(C320p8rx_mask, ofsAddr + RX_mask); 991a6afd9f3SGreg Kroah-Hartman writew(C320p8tx_mask, ofsAddr + TX_mask); 992a6afd9f3SGreg Kroah-Hartman writew(C320p8rx_spage + i * C320p8buf_pgno, ofsAddr + Page_rxb); 993a6afd9f3SGreg Kroah-Hartman writew(readw(ofsAddr + Page_rxb) + C320p8rx_pgno, ofsAddr + EndPage_rxb); 994a6afd9f3SGreg Kroah-Hartman writew(C320p8tx_spage + i * C320p8buf_pgno, ofsAddr + Page_txb); 995a6afd9f3SGreg Kroah-Hartman writew(readw(ofsAddr + Page_txb) + C320p8tx_pgno, ofsAddr + EndPage_txb); 996a6afd9f3SGreg Kroah-Hartman 997a6afd9f3SGreg Kroah-Hartman break; 998a6afd9f3SGreg Kroah-Hartman case 16: 999a6afd9f3SGreg Kroah-Hartman writew(C320p16rx_mask, ofsAddr + RX_mask); 1000a6afd9f3SGreg Kroah-Hartman writew(C320p16tx_mask, ofsAddr + TX_mask); 1001a6afd9f3SGreg Kroah-Hartman writew(C320p16rx_spage + i * C320p16buf_pgno, ofsAddr + Page_rxb); 1002a6afd9f3SGreg Kroah-Hartman writew(readw(ofsAddr + Page_rxb) + C320p16rx_pgno, ofsAddr + EndPage_rxb); 1003a6afd9f3SGreg Kroah-Hartman writew(C320p16tx_spage + i * C320p16buf_pgno, ofsAddr + Page_txb); 1004a6afd9f3SGreg Kroah-Hartman writew(readw(ofsAddr + Page_txb) + C320p16tx_pgno, ofsAddr + EndPage_txb); 1005a6afd9f3SGreg Kroah-Hartman break; 1006a6afd9f3SGreg Kroah-Hartman 1007a6afd9f3SGreg Kroah-Hartman case 24: 1008a6afd9f3SGreg Kroah-Hartman writew(C320p24rx_mask, ofsAddr + RX_mask); 1009a6afd9f3SGreg Kroah-Hartman writew(C320p24tx_mask, ofsAddr + TX_mask); 1010a6afd9f3SGreg Kroah-Hartman writew(C320p24rx_spage + i * C320p24buf_pgno, ofsAddr + Page_rxb); 1011a6afd9f3SGreg Kroah-Hartman writew(readw(ofsAddr + Page_rxb) + C320p24rx_pgno, ofsAddr + EndPage_rxb); 1012a6afd9f3SGreg Kroah-Hartman writew(C320p24tx_spage + i * C320p24buf_pgno, ofsAddr + Page_txb); 1013a6afd9f3SGreg Kroah-Hartman writew(readw(ofsAddr + Page_txb), ofsAddr + EndPage_txb); 1014a6afd9f3SGreg Kroah-Hartman break; 1015a6afd9f3SGreg Kroah-Hartman case 32: 1016a6afd9f3SGreg Kroah-Hartman writew(C320p32rx_mask, ofsAddr + RX_mask); 1017a6afd9f3SGreg Kroah-Hartman writew(C320p32tx_mask, ofsAddr + TX_mask); 1018a6afd9f3SGreg Kroah-Hartman writew(C320p32tx_ofs, ofsAddr + Ofs_txb); 1019a6afd9f3SGreg Kroah-Hartman writew(C320p32rx_spage + i * C320p32buf_pgno, ofsAddr + Page_rxb); 1020a6afd9f3SGreg Kroah-Hartman writew(readb(ofsAddr + Page_rxb), ofsAddr + EndPage_rxb); 1021a6afd9f3SGreg Kroah-Hartman writew(C320p32tx_spage + i * C320p32buf_pgno, ofsAddr + Page_txb); 1022a6afd9f3SGreg Kroah-Hartman writew(readw(ofsAddr + Page_txb), ofsAddr + EndPage_txb); 1023a6afd9f3SGreg Kroah-Hartman break; 1024a6afd9f3SGreg Kroah-Hartman } 1025a6afd9f3SGreg Kroah-Hartman } 1026a6afd9f3SGreg Kroah-Hartman break; 1027a6afd9f3SGreg Kroah-Hartman } 1028a6afd9f3SGreg Kroah-Hartman return 0; 1029a6afd9f3SGreg Kroah-Hartman } 1030a6afd9f3SGreg Kroah-Hartman 1031a6afd9f3SGreg Kroah-Hartman static int moxa_load_fw(struct moxa_board_conf *brd, const struct firmware *fw) 1032a6afd9f3SGreg Kroah-Hartman { 1033a6afd9f3SGreg Kroah-Hartman const void *ptr = fw->data; 1034a6afd9f3SGreg Kroah-Hartman char rsn[64]; 1035a6afd9f3SGreg Kroah-Hartman u16 lens[5]; 1036a6afd9f3SGreg Kroah-Hartman size_t len; 1037a6afd9f3SGreg Kroah-Hartman unsigned int a, lenp, lencnt; 1038a6afd9f3SGreg Kroah-Hartman int ret = -EINVAL; 1039a6afd9f3SGreg Kroah-Hartman struct { 1040a6afd9f3SGreg Kroah-Hartman __le32 magic; /* 0x34303430 */ 1041a6afd9f3SGreg Kroah-Hartman u8 reserved1[2]; 1042a6afd9f3SGreg Kroah-Hartman u8 type; /* UNIX = 3 */ 1043a6afd9f3SGreg Kroah-Hartman u8 model; /* C218T=1, C320T=2, CP204=3 */ 1044a6afd9f3SGreg Kroah-Hartman u8 reserved2[8]; 1045a6afd9f3SGreg Kroah-Hartman __le16 len[5]; 1046a6afd9f3SGreg Kroah-Hartman } const *hdr = ptr; 1047a6afd9f3SGreg Kroah-Hartman 1048a6afd9f3SGreg Kroah-Hartman BUILD_BUG_ON(ARRAY_SIZE(hdr->len) != ARRAY_SIZE(lens)); 1049a6afd9f3SGreg Kroah-Hartman 1050a6afd9f3SGreg Kroah-Hartman if (fw->size < MOXA_FW_HDRLEN) { 1051a6afd9f3SGreg Kroah-Hartman strcpy(rsn, "too short (even header won't fit)"); 1052a6afd9f3SGreg Kroah-Hartman goto err; 1053a6afd9f3SGreg Kroah-Hartman } 1054a6afd9f3SGreg Kroah-Hartman if (hdr->magic != cpu_to_le32(0x30343034)) { 1055a6afd9f3SGreg Kroah-Hartman sprintf(rsn, "bad magic: %.8x", le32_to_cpu(hdr->magic)); 1056a6afd9f3SGreg Kroah-Hartman goto err; 1057a6afd9f3SGreg Kroah-Hartman } 1058a6afd9f3SGreg Kroah-Hartman if (hdr->type != 3) { 1059a6afd9f3SGreg Kroah-Hartman sprintf(rsn, "not for linux, type is %u", hdr->type); 1060a6afd9f3SGreg Kroah-Hartman goto err; 1061a6afd9f3SGreg Kroah-Hartman } 1062a6afd9f3SGreg Kroah-Hartman if (moxa_check_fw_model(brd, hdr->model)) { 1063a6afd9f3SGreg Kroah-Hartman sprintf(rsn, "not for this card, model is %u", hdr->model); 1064a6afd9f3SGreg Kroah-Hartman goto err; 1065a6afd9f3SGreg Kroah-Hartman } 1066a6afd9f3SGreg Kroah-Hartman 1067a6afd9f3SGreg Kroah-Hartman len = MOXA_FW_HDRLEN; 1068a6afd9f3SGreg Kroah-Hartman lencnt = hdr->model == 2 ? 5 : 3; 1069a6afd9f3SGreg Kroah-Hartman for (a = 0; a < ARRAY_SIZE(lens); a++) { 1070a6afd9f3SGreg Kroah-Hartman lens[a] = le16_to_cpu(hdr->len[a]); 1071a6afd9f3SGreg Kroah-Hartman if (lens[a] && len + lens[a] <= fw->size && 1072a6afd9f3SGreg Kroah-Hartman moxa_check_fw(&fw->data[len])) 1073a6afd9f3SGreg Kroah-Hartman printk(KERN_WARNING "MOXA firmware: unexpected input " 1074a6afd9f3SGreg Kroah-Hartman "at offset %u, but going on\n", (u32)len); 1075a6afd9f3SGreg Kroah-Hartman if (!lens[a] && a < lencnt) { 1076a6afd9f3SGreg Kroah-Hartman sprintf(rsn, "too few entries in fw file"); 1077a6afd9f3SGreg Kroah-Hartman goto err; 1078a6afd9f3SGreg Kroah-Hartman } 1079a6afd9f3SGreg Kroah-Hartman len += lens[a]; 1080a6afd9f3SGreg Kroah-Hartman } 1081a6afd9f3SGreg Kroah-Hartman 1082a6afd9f3SGreg Kroah-Hartman if (len != fw->size) { 1083a6afd9f3SGreg Kroah-Hartman sprintf(rsn, "bad length: %u (should be %u)", (u32)fw->size, 1084a6afd9f3SGreg Kroah-Hartman (u32)len); 1085a6afd9f3SGreg Kroah-Hartman goto err; 1086a6afd9f3SGreg Kroah-Hartman } 1087a6afd9f3SGreg Kroah-Hartman 1088a6afd9f3SGreg Kroah-Hartman ptr += MOXA_FW_HDRLEN; 1089a6afd9f3SGreg Kroah-Hartman lenp = 0; /* bios */ 1090a6afd9f3SGreg Kroah-Hartman 1091a6afd9f3SGreg Kroah-Hartman strcpy(rsn, "read above"); 1092a6afd9f3SGreg Kroah-Hartman 1093a6afd9f3SGreg Kroah-Hartman ret = moxa_load_bios(brd, ptr, lens[lenp]); 1094a6afd9f3SGreg Kroah-Hartman if (ret) 1095a6afd9f3SGreg Kroah-Hartman goto err; 1096a6afd9f3SGreg Kroah-Hartman 1097a6afd9f3SGreg Kroah-Hartman /* we skip the tty section (lens[1]), since we don't need it */ 1098a6afd9f3SGreg Kroah-Hartman ptr += lens[lenp] + lens[lenp + 1]; 1099a6afd9f3SGreg Kroah-Hartman lenp += 2; /* comm */ 1100a6afd9f3SGreg Kroah-Hartman 1101a6afd9f3SGreg Kroah-Hartman if (hdr->model == 2) { 1102a6afd9f3SGreg Kroah-Hartman ret = moxa_load_320b(brd, ptr, lens[lenp]); 1103a6afd9f3SGreg Kroah-Hartman if (ret) 1104a6afd9f3SGreg Kroah-Hartman goto err; 1105a6afd9f3SGreg Kroah-Hartman /* skip another tty */ 1106a6afd9f3SGreg Kroah-Hartman ptr += lens[lenp] + lens[lenp + 1]; 1107a6afd9f3SGreg Kroah-Hartman lenp += 2; 1108a6afd9f3SGreg Kroah-Hartman } 1109a6afd9f3SGreg Kroah-Hartman 1110a6afd9f3SGreg Kroah-Hartman ret = moxa_load_code(brd, ptr, lens[lenp]); 1111a6afd9f3SGreg Kroah-Hartman if (ret) 1112a6afd9f3SGreg Kroah-Hartman goto err; 1113a6afd9f3SGreg Kroah-Hartman 1114a6afd9f3SGreg Kroah-Hartman return 0; 1115a6afd9f3SGreg Kroah-Hartman err: 1116a6afd9f3SGreg Kroah-Hartman printk(KERN_ERR "firmware failed to load, reason: %s\n", rsn); 1117a6afd9f3SGreg Kroah-Hartman return ret; 1118a6afd9f3SGreg Kroah-Hartman } 1119a6afd9f3SGreg Kroah-Hartman 1120a6afd9f3SGreg Kroah-Hartman static int moxa_init_board(struct moxa_board_conf *brd, struct device *dev) 1121a6afd9f3SGreg Kroah-Hartman { 1122a6afd9f3SGreg Kroah-Hartman const struct firmware *fw; 1123a6afd9f3SGreg Kroah-Hartman const char *file; 1124a6afd9f3SGreg Kroah-Hartman struct moxa_port *p; 1125793be898SJiri Slaby unsigned int i, first_idx; 1126a6afd9f3SGreg Kroah-Hartman int ret; 1127a6afd9f3SGreg Kroah-Hartman 1128a6afd9f3SGreg Kroah-Hartman brd->ports = kcalloc(MAX_PORTS_PER_BOARD, sizeof(*brd->ports), 1129a6afd9f3SGreg Kroah-Hartman GFP_KERNEL); 1130a6afd9f3SGreg Kroah-Hartman if (brd->ports == NULL) { 1131a6afd9f3SGreg Kroah-Hartman printk(KERN_ERR "cannot allocate memory for ports\n"); 1132a6afd9f3SGreg Kroah-Hartman ret = -ENOMEM; 1133a6afd9f3SGreg Kroah-Hartman goto err; 1134a6afd9f3SGreg Kroah-Hartman } 1135a6afd9f3SGreg Kroah-Hartman 1136a6afd9f3SGreg Kroah-Hartman for (i = 0, p = brd->ports; i < MAX_PORTS_PER_BOARD; i++, p++) { 1137a6afd9f3SGreg Kroah-Hartman tty_port_init(&p->port); 1138a6afd9f3SGreg Kroah-Hartman p->port.ops = &moxa_port_ops; 1139a6afd9f3SGreg Kroah-Hartman p->type = PORT_16550A; 1140a6afd9f3SGreg Kroah-Hartman p->cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL; 1141a6afd9f3SGreg Kroah-Hartman } 1142a6afd9f3SGreg Kroah-Hartman 1143a6afd9f3SGreg Kroah-Hartman switch (brd->boardType) { 1144a6afd9f3SGreg Kroah-Hartman case MOXA_BOARD_C218_ISA: 1145a6afd9f3SGreg Kroah-Hartman case MOXA_BOARD_C218_PCI: 1146a6afd9f3SGreg Kroah-Hartman file = "c218tunx.cod"; 1147a6afd9f3SGreg Kroah-Hartman break; 1148a6afd9f3SGreg Kroah-Hartman case MOXA_BOARD_CP204J: 1149a6afd9f3SGreg Kroah-Hartman file = "cp204unx.cod"; 1150a6afd9f3SGreg Kroah-Hartman break; 1151a6afd9f3SGreg Kroah-Hartman default: 1152a6afd9f3SGreg Kroah-Hartman file = "c320tunx.cod"; 1153a6afd9f3SGreg Kroah-Hartman break; 1154a6afd9f3SGreg Kroah-Hartman } 1155a6afd9f3SGreg Kroah-Hartman 1156a6afd9f3SGreg Kroah-Hartman ret = request_firmware(&fw, file, dev); 1157a6afd9f3SGreg Kroah-Hartman if (ret) { 1158a6afd9f3SGreg Kroah-Hartman printk(KERN_ERR "MOXA: request_firmware failed. Make sure " 1159a6afd9f3SGreg Kroah-Hartman "you've placed '%s' file into your firmware " 1160a6afd9f3SGreg Kroah-Hartman "loader directory (e.g. /lib/firmware)\n", 1161a6afd9f3SGreg Kroah-Hartman file); 1162a6afd9f3SGreg Kroah-Hartman goto err_free; 1163a6afd9f3SGreg Kroah-Hartman } 1164a6afd9f3SGreg Kroah-Hartman 1165a6afd9f3SGreg Kroah-Hartman ret = moxa_load_fw(brd, fw); 1166a6afd9f3SGreg Kroah-Hartman 1167a6afd9f3SGreg Kroah-Hartman release_firmware(fw); 1168a6afd9f3SGreg Kroah-Hartman 1169a6afd9f3SGreg Kroah-Hartman if (ret) 1170a6afd9f3SGreg Kroah-Hartman goto err_free; 1171a6afd9f3SGreg Kroah-Hartman 1172a6afd9f3SGreg Kroah-Hartman spin_lock_bh(&moxa_lock); 1173a6afd9f3SGreg Kroah-Hartman brd->ready = 1; 1174a6afd9f3SGreg Kroah-Hartman if (!timer_pending(&moxaTimer)) 1175a6afd9f3SGreg Kroah-Hartman mod_timer(&moxaTimer, jiffies + HZ / 50); 1176a6afd9f3SGreg Kroah-Hartman spin_unlock_bh(&moxa_lock); 1177a6afd9f3SGreg Kroah-Hartman 1178793be898SJiri Slaby first_idx = (brd - moxa_boards) * MAX_PORTS_PER_BOARD; 1179793be898SJiri Slaby for (i = 0; i < brd->numPorts; i++) 1180793be898SJiri Slaby tty_port_register_device(&brd->ports[i].port, moxaDriver, 1181793be898SJiri Slaby first_idx + i, dev); 1182793be898SJiri Slaby 1183a6afd9f3SGreg Kroah-Hartman return 0; 1184a6afd9f3SGreg Kroah-Hartman err_free: 1185191c5f10SJiri Slaby for (i = 0; i < MAX_PORTS_PER_BOARD; i++) 1186191c5f10SJiri Slaby tty_port_destroy(&brd->ports[i].port); 1187a6afd9f3SGreg Kroah-Hartman kfree(brd->ports); 1188a6afd9f3SGreg Kroah-Hartman err: 1189a6afd9f3SGreg Kroah-Hartman return ret; 1190a6afd9f3SGreg Kroah-Hartman } 1191a6afd9f3SGreg Kroah-Hartman 1192a6afd9f3SGreg Kroah-Hartman static void moxa_board_deinit(struct moxa_board_conf *brd) 1193a6afd9f3SGreg Kroah-Hartman { 1194793be898SJiri Slaby unsigned int a, opened, first_idx; 1195a6afd9f3SGreg Kroah-Hartman 1196a6afd9f3SGreg Kroah-Hartman mutex_lock(&moxa_openlock); 1197a6afd9f3SGreg Kroah-Hartman spin_lock_bh(&moxa_lock); 1198a6afd9f3SGreg Kroah-Hartman brd->ready = 0; 1199a6afd9f3SGreg Kroah-Hartman spin_unlock_bh(&moxa_lock); 1200a6afd9f3SGreg Kroah-Hartman 1201a6afd9f3SGreg Kroah-Hartman /* pci hot-un-plug support */ 1202a6afd9f3SGreg Kroah-Hartman for (a = 0; a < brd->numPorts; a++) 1203d41861caSPeter Hurley if (tty_port_initialized(&brd->ports[a].port)) 1204aa27a094SJiri Slaby tty_port_tty_hangup(&brd->ports[a].port, false); 1205aa27a094SJiri Slaby 1206191c5f10SJiri Slaby for (a = 0; a < MAX_PORTS_PER_BOARD; a++) 1207191c5f10SJiri Slaby tty_port_destroy(&brd->ports[a].port); 1208aa27a094SJiri Slaby 1209a6afd9f3SGreg Kroah-Hartman while (1) { 1210a6afd9f3SGreg Kroah-Hartman opened = 0; 1211a6afd9f3SGreg Kroah-Hartman for (a = 0; a < brd->numPorts; a++) 1212d41861caSPeter Hurley if (tty_port_initialized(&brd->ports[a].port)) 1213a6afd9f3SGreg Kroah-Hartman opened++; 1214a6afd9f3SGreg Kroah-Hartman mutex_unlock(&moxa_openlock); 1215a6afd9f3SGreg Kroah-Hartman if (!opened) 1216a6afd9f3SGreg Kroah-Hartman break; 1217a6afd9f3SGreg Kroah-Hartman msleep(50); 1218a6afd9f3SGreg Kroah-Hartman mutex_lock(&moxa_openlock); 1219a6afd9f3SGreg Kroah-Hartman } 1220a6afd9f3SGreg Kroah-Hartman 1221793be898SJiri Slaby first_idx = (brd - moxa_boards) * MAX_PORTS_PER_BOARD; 1222793be898SJiri Slaby for (a = 0; a < brd->numPorts; a++) 1223793be898SJiri Slaby tty_unregister_device(moxaDriver, first_idx + a); 1224793be898SJiri Slaby 1225a6afd9f3SGreg Kroah-Hartman iounmap(brd->basemem); 1226a6afd9f3SGreg Kroah-Hartman brd->basemem = NULL; 1227a6afd9f3SGreg Kroah-Hartman kfree(brd->ports); 1228a6afd9f3SGreg Kroah-Hartman } 1229a6afd9f3SGreg Kroah-Hartman 1230a6afd9f3SGreg Kroah-Hartman #ifdef CONFIG_PCI 12319671f099SBill Pemberton static int moxa_pci_probe(struct pci_dev *pdev, 1232a6afd9f3SGreg Kroah-Hartman const struct pci_device_id *ent) 1233a6afd9f3SGreg Kroah-Hartman { 1234a6afd9f3SGreg Kroah-Hartman struct moxa_board_conf *board; 1235a6afd9f3SGreg Kroah-Hartman unsigned int i; 1236a6afd9f3SGreg Kroah-Hartman int board_type = ent->driver_data; 1237a6afd9f3SGreg Kroah-Hartman int retval; 1238a6afd9f3SGreg Kroah-Hartman 1239a6afd9f3SGreg Kroah-Hartman retval = pci_enable_device(pdev); 1240a6afd9f3SGreg Kroah-Hartman if (retval) { 1241a6afd9f3SGreg Kroah-Hartman dev_err(&pdev->dev, "can't enable pci device\n"); 1242a6afd9f3SGreg Kroah-Hartman goto err; 1243a6afd9f3SGreg Kroah-Hartman } 1244a6afd9f3SGreg Kroah-Hartman 1245a6afd9f3SGreg Kroah-Hartman for (i = 0; i < MAX_BOARDS; i++) 1246a6afd9f3SGreg Kroah-Hartman if (moxa_boards[i].basemem == NULL) 1247a6afd9f3SGreg Kroah-Hartman break; 1248a6afd9f3SGreg Kroah-Hartman 1249a6afd9f3SGreg Kroah-Hartman retval = -ENODEV; 1250a6afd9f3SGreg Kroah-Hartman if (i >= MAX_BOARDS) { 1251a6afd9f3SGreg Kroah-Hartman dev_warn(&pdev->dev, "more than %u MOXA Intellio family boards " 1252a6afd9f3SGreg Kroah-Hartman "found. Board is ignored.\n", MAX_BOARDS); 1253a6afd9f3SGreg Kroah-Hartman goto err; 1254a6afd9f3SGreg Kroah-Hartman } 1255a6afd9f3SGreg Kroah-Hartman 1256a6afd9f3SGreg Kroah-Hartman board = &moxa_boards[i]; 1257a6afd9f3SGreg Kroah-Hartman 1258a6afd9f3SGreg Kroah-Hartman retval = pci_request_region(pdev, 2, "moxa-base"); 1259a6afd9f3SGreg Kroah-Hartman if (retval) { 1260a6afd9f3SGreg Kroah-Hartman dev_err(&pdev->dev, "can't request pci region 2\n"); 1261a6afd9f3SGreg Kroah-Hartman goto err; 1262a6afd9f3SGreg Kroah-Hartman } 1263a6afd9f3SGreg Kroah-Hartman 12644bdc0d67SChristoph Hellwig board->basemem = ioremap(pci_resource_start(pdev, 2), 0x4000); 1265a6afd9f3SGreg Kroah-Hartman if (board->basemem == NULL) { 1266a6afd9f3SGreg Kroah-Hartman dev_err(&pdev->dev, "can't remap io space 2\n"); 1267386d95b3SJulia Lawall retval = -ENOMEM; 1268a6afd9f3SGreg Kroah-Hartman goto err_reg; 1269a6afd9f3SGreg Kroah-Hartman } 1270a6afd9f3SGreg Kroah-Hartman 1271a6afd9f3SGreg Kroah-Hartman board->boardType = board_type; 1272a6afd9f3SGreg Kroah-Hartman switch (board_type) { 1273a6afd9f3SGreg Kroah-Hartman case MOXA_BOARD_C218_ISA: 1274a6afd9f3SGreg Kroah-Hartman case MOXA_BOARD_C218_PCI: 1275a6afd9f3SGreg Kroah-Hartman board->numPorts = 8; 1276a6afd9f3SGreg Kroah-Hartman break; 1277a6afd9f3SGreg Kroah-Hartman 1278a6afd9f3SGreg Kroah-Hartman case MOXA_BOARD_CP204J: 1279a6afd9f3SGreg Kroah-Hartman board->numPorts = 4; 1280a6afd9f3SGreg Kroah-Hartman break; 1281a6afd9f3SGreg Kroah-Hartman default: 1282a6afd9f3SGreg Kroah-Hartman board->numPorts = 0; 1283a6afd9f3SGreg Kroah-Hartman break; 1284a6afd9f3SGreg Kroah-Hartman } 1285a6afd9f3SGreg Kroah-Hartman board->busType = MOXA_BUS_TYPE_PCI; 1286a6afd9f3SGreg Kroah-Hartman 1287a6afd9f3SGreg Kroah-Hartman retval = moxa_init_board(board, &pdev->dev); 1288a6afd9f3SGreg Kroah-Hartman if (retval) 1289a6afd9f3SGreg Kroah-Hartman goto err_base; 1290a6afd9f3SGreg Kroah-Hartman 1291a6afd9f3SGreg Kroah-Hartman pci_set_drvdata(pdev, board); 1292a6afd9f3SGreg Kroah-Hartman 1293a6afd9f3SGreg Kroah-Hartman dev_info(&pdev->dev, "board '%s' ready (%u ports, firmware loaded)\n", 1294a6afd9f3SGreg Kroah-Hartman moxa_brdname[board_type - 1], board->numPorts); 1295a6afd9f3SGreg Kroah-Hartman 1296a6afd9f3SGreg Kroah-Hartman return 0; 1297a6afd9f3SGreg Kroah-Hartman err_base: 1298a6afd9f3SGreg Kroah-Hartman iounmap(board->basemem); 1299a6afd9f3SGreg Kroah-Hartman board->basemem = NULL; 1300a6afd9f3SGreg Kroah-Hartman err_reg: 1301a6afd9f3SGreg Kroah-Hartman pci_release_region(pdev, 2); 1302a6afd9f3SGreg Kroah-Hartman err: 1303a6afd9f3SGreg Kroah-Hartman return retval; 1304a6afd9f3SGreg Kroah-Hartman } 1305a6afd9f3SGreg Kroah-Hartman 1306ae8d8a14SBill Pemberton static void moxa_pci_remove(struct pci_dev *pdev) 1307a6afd9f3SGreg Kroah-Hartman { 1308a6afd9f3SGreg Kroah-Hartman struct moxa_board_conf *brd = pci_get_drvdata(pdev); 1309a6afd9f3SGreg Kroah-Hartman 1310a6afd9f3SGreg Kroah-Hartman moxa_board_deinit(brd); 1311a6afd9f3SGreg Kroah-Hartman 1312a6afd9f3SGreg Kroah-Hartman pci_release_region(pdev, 2); 1313a6afd9f3SGreg Kroah-Hartman } 1314a6afd9f3SGreg Kroah-Hartman 1315a6afd9f3SGreg Kroah-Hartman static struct pci_driver moxa_pci_driver = { 1316a6afd9f3SGreg Kroah-Hartman .name = "moxa", 1317a6afd9f3SGreg Kroah-Hartman .id_table = moxa_pcibrds, 1318a6afd9f3SGreg Kroah-Hartman .probe = moxa_pci_probe, 131991116cbaSBill Pemberton .remove = moxa_pci_remove 1320a6afd9f3SGreg Kroah-Hartman }; 1321a6afd9f3SGreg Kroah-Hartman #endif /* CONFIG_PCI */ 1322a6afd9f3SGreg Kroah-Hartman 1323a6afd9f3SGreg Kroah-Hartman static int __init moxa_init(void) 1324a6afd9f3SGreg Kroah-Hartman { 1325a6afd9f3SGreg Kroah-Hartman unsigned int isabrds = 0; 1326a6afd9f3SGreg Kroah-Hartman int retval = 0; 1327a6afd9f3SGreg Kroah-Hartman struct moxa_board_conf *brd = moxa_boards; 1328a6afd9f3SGreg Kroah-Hartman unsigned int i; 1329a6afd9f3SGreg Kroah-Hartman 1330a6afd9f3SGreg Kroah-Hartman printk(KERN_INFO "MOXA Intellio family driver version %s\n", 1331a6afd9f3SGreg Kroah-Hartman MOXA_VERSION); 1332793be898SJiri Slaby 1333793be898SJiri Slaby tty_port_init(&moxa_service_port); 1334793be898SJiri Slaby 1335793be898SJiri Slaby moxaDriver = tty_alloc_driver(MAX_PORTS + 1, 1336793be898SJiri Slaby TTY_DRIVER_REAL_RAW | 1337793be898SJiri Slaby TTY_DRIVER_DYNAMIC_DEV); 1338c3a6344aSDan Carpenter if (IS_ERR(moxaDriver)) 1339c3a6344aSDan Carpenter return PTR_ERR(moxaDriver); 1340a6afd9f3SGreg Kroah-Hartman 1341a6afd9f3SGreg Kroah-Hartman moxaDriver->name = "ttyMX"; 1342a6afd9f3SGreg Kroah-Hartman moxaDriver->major = ttymajor; 1343a6afd9f3SGreg Kroah-Hartman moxaDriver->minor_start = 0; 1344a6afd9f3SGreg Kroah-Hartman moxaDriver->type = TTY_DRIVER_TYPE_SERIAL; 1345a6afd9f3SGreg Kroah-Hartman moxaDriver->subtype = SERIAL_TYPE_NORMAL; 1346a6afd9f3SGreg Kroah-Hartman moxaDriver->init_termios = tty_std_termios; 1347a6afd9f3SGreg Kroah-Hartman moxaDriver->init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL; 1348a6afd9f3SGreg Kroah-Hartman moxaDriver->init_termios.c_ispeed = 9600; 1349a6afd9f3SGreg Kroah-Hartman moxaDriver->init_termios.c_ospeed = 9600; 1350a6afd9f3SGreg Kroah-Hartman tty_set_operations(moxaDriver, &moxa_ops); 1351793be898SJiri Slaby /* Having one more port only for ioctls is ugly */ 1352793be898SJiri Slaby tty_port_link_device(&moxa_service_port, moxaDriver, MAX_PORTS); 1353a6afd9f3SGreg Kroah-Hartman 1354a6afd9f3SGreg Kroah-Hartman if (tty_register_driver(moxaDriver)) { 1355a6afd9f3SGreg Kroah-Hartman printk(KERN_ERR "can't register MOXA Smartio tty driver!\n"); 13569f90a4ddSJiri Slaby tty_driver_kref_put(moxaDriver); 1357a6afd9f3SGreg Kroah-Hartman return -1; 1358a6afd9f3SGreg Kroah-Hartman } 1359a6afd9f3SGreg Kroah-Hartman 1360a6afd9f3SGreg Kroah-Hartman /* Find the boards defined from module args. */ 1361a6afd9f3SGreg Kroah-Hartman 1362a6afd9f3SGreg Kroah-Hartman for (i = 0; i < MAX_BOARDS; i++) { 1363a6afd9f3SGreg Kroah-Hartman if (!baseaddr[i]) 1364a6afd9f3SGreg Kroah-Hartman break; 1365a6afd9f3SGreg Kroah-Hartman if (type[i] == MOXA_BOARD_C218_ISA || 1366a6afd9f3SGreg Kroah-Hartman type[i] == MOXA_BOARD_C320_ISA) { 1367a6afd9f3SGreg Kroah-Hartman pr_debug("Moxa board %2d: %s board(baseAddr=%lx)\n", 1368a6afd9f3SGreg Kroah-Hartman isabrds + 1, moxa_brdname[type[i] - 1], 1369a6afd9f3SGreg Kroah-Hartman baseaddr[i]); 1370a6afd9f3SGreg Kroah-Hartman brd->boardType = type[i]; 1371a6afd9f3SGreg Kroah-Hartman brd->numPorts = type[i] == MOXA_BOARD_C218_ISA ? 8 : 1372a6afd9f3SGreg Kroah-Hartman numports[i]; 1373a6afd9f3SGreg Kroah-Hartman brd->busType = MOXA_BUS_TYPE_ISA; 13744bdc0d67SChristoph Hellwig brd->basemem = ioremap(baseaddr[i], 0x4000); 1375a6afd9f3SGreg Kroah-Hartman if (!brd->basemem) { 1376a6afd9f3SGreg Kroah-Hartman printk(KERN_ERR "MOXA: can't remap %lx\n", 1377a6afd9f3SGreg Kroah-Hartman baseaddr[i]); 1378a6afd9f3SGreg Kroah-Hartman continue; 1379a6afd9f3SGreg Kroah-Hartman } 1380a6afd9f3SGreg Kroah-Hartman if (moxa_init_board(brd, NULL)) { 1381a6afd9f3SGreg Kroah-Hartman iounmap(brd->basemem); 1382a6afd9f3SGreg Kroah-Hartman brd->basemem = NULL; 1383a6afd9f3SGreg Kroah-Hartman continue; 1384a6afd9f3SGreg Kroah-Hartman } 1385a6afd9f3SGreg Kroah-Hartman 1386e0525393SHans Wennborg printk(KERN_INFO "MOXA isa board found at 0x%.8lx and " 1387a6afd9f3SGreg Kroah-Hartman "ready (%u ports, firmware loaded)\n", 1388a6afd9f3SGreg Kroah-Hartman baseaddr[i], brd->numPorts); 1389a6afd9f3SGreg Kroah-Hartman 1390a6afd9f3SGreg Kroah-Hartman brd++; 1391a6afd9f3SGreg Kroah-Hartman isabrds++; 1392a6afd9f3SGreg Kroah-Hartman } 1393a6afd9f3SGreg Kroah-Hartman } 1394a6afd9f3SGreg Kroah-Hartman 1395a6afd9f3SGreg Kroah-Hartman #ifdef CONFIG_PCI 1396a6afd9f3SGreg Kroah-Hartman retval = pci_register_driver(&moxa_pci_driver); 1397a6afd9f3SGreg Kroah-Hartman if (retval) { 1398a6afd9f3SGreg Kroah-Hartman printk(KERN_ERR "Can't register MOXA pci driver!\n"); 1399a6afd9f3SGreg Kroah-Hartman if (isabrds) 1400a6afd9f3SGreg Kroah-Hartman retval = 0; 1401a6afd9f3SGreg Kroah-Hartman } 1402a6afd9f3SGreg Kroah-Hartman #endif 1403a6afd9f3SGreg Kroah-Hartman 1404a6afd9f3SGreg Kroah-Hartman return retval; 1405a6afd9f3SGreg Kroah-Hartman } 1406a6afd9f3SGreg Kroah-Hartman 1407a6afd9f3SGreg Kroah-Hartman static void __exit moxa_exit(void) 1408a6afd9f3SGreg Kroah-Hartman { 1409a6afd9f3SGreg Kroah-Hartman unsigned int i; 1410a6afd9f3SGreg Kroah-Hartman 1411a6afd9f3SGreg Kroah-Hartman #ifdef CONFIG_PCI 1412a6afd9f3SGreg Kroah-Hartman pci_unregister_driver(&moxa_pci_driver); 1413a6afd9f3SGreg Kroah-Hartman #endif 1414a6afd9f3SGreg Kroah-Hartman 1415a6afd9f3SGreg Kroah-Hartman for (i = 0; i < MAX_BOARDS; i++) /* ISA boards */ 1416a6afd9f3SGreg Kroah-Hartman if (moxa_boards[i].ready) 1417a6afd9f3SGreg Kroah-Hartman moxa_board_deinit(&moxa_boards[i]); 1418a6afd9f3SGreg Kroah-Hartman 1419a6afd9f3SGreg Kroah-Hartman del_timer_sync(&moxaTimer); 1420a6afd9f3SGreg Kroah-Hartman 14216c2e6317SJiri Slaby tty_unregister_driver(moxaDriver); 14229f90a4ddSJiri Slaby tty_driver_kref_put(moxaDriver); 1423a6afd9f3SGreg Kroah-Hartman } 1424a6afd9f3SGreg Kroah-Hartman 1425a6afd9f3SGreg Kroah-Hartman module_init(moxa_init); 1426a6afd9f3SGreg Kroah-Hartman module_exit(moxa_exit); 1427a6afd9f3SGreg Kroah-Hartman 1428a6afd9f3SGreg Kroah-Hartman static void moxa_shutdown(struct tty_port *port) 1429a6afd9f3SGreg Kroah-Hartman { 1430a6afd9f3SGreg Kroah-Hartman struct moxa_port *ch = container_of(port, struct moxa_port, port); 1431a6afd9f3SGreg Kroah-Hartman MoxaPortDisable(ch); 1432a6afd9f3SGreg Kroah-Hartman MoxaPortFlushData(ch, 2); 1433a6afd9f3SGreg Kroah-Hartman } 1434a6afd9f3SGreg Kroah-Hartman 1435b300fb26SIlpo Järvinen static bool moxa_carrier_raised(struct tty_port *port) 1436a6afd9f3SGreg Kroah-Hartman { 1437a6afd9f3SGreg Kroah-Hartman struct moxa_port *ch = container_of(port, struct moxa_port, port); 1438a6afd9f3SGreg Kroah-Hartman int dcd; 1439a6afd9f3SGreg Kroah-Hartman 1440a6afd9f3SGreg Kroah-Hartman spin_lock_irq(&port->lock); 1441a6afd9f3SGreg Kroah-Hartman dcd = ch->DCDState; 1442a6afd9f3SGreg Kroah-Hartman spin_unlock_irq(&port->lock); 1443a6afd9f3SGreg Kroah-Hartman return dcd; 1444a6afd9f3SGreg Kroah-Hartman } 1445a6afd9f3SGreg Kroah-Hartman 14462d762dabSIlpo Järvinen static void moxa_dtr_rts(struct tty_port *port, bool active) 1447a6afd9f3SGreg Kroah-Hartman { 1448a6afd9f3SGreg Kroah-Hartman struct moxa_port *ch = container_of(port, struct moxa_port, port); 14492d762dabSIlpo Järvinen MoxaPortLineCtrl(ch, active, active); 1450a6afd9f3SGreg Kroah-Hartman } 1451a6afd9f3SGreg Kroah-Hartman 1452a6afd9f3SGreg Kroah-Hartman 1453a6afd9f3SGreg Kroah-Hartman static int moxa_open(struct tty_struct *tty, struct file *filp) 1454a6afd9f3SGreg Kroah-Hartman { 1455a6afd9f3SGreg Kroah-Hartman struct moxa_board_conf *brd; 1456a6afd9f3SGreg Kroah-Hartman struct moxa_port *ch; 1457a6afd9f3SGreg Kroah-Hartman int port; 1458a6afd9f3SGreg Kroah-Hartman 1459a6afd9f3SGreg Kroah-Hartman port = tty->index; 1460a6afd9f3SGreg Kroah-Hartman if (port == MAX_PORTS) { 1461a6afd9f3SGreg Kroah-Hartman return capable(CAP_SYS_ADMIN) ? 0 : -EPERM; 1462a6afd9f3SGreg Kroah-Hartman } 1463a6afd9f3SGreg Kroah-Hartman if (mutex_lock_interruptible(&moxa_openlock)) 1464a6afd9f3SGreg Kroah-Hartman return -ERESTARTSYS; 1465a6afd9f3SGreg Kroah-Hartman brd = &moxa_boards[port / MAX_PORTS_PER_BOARD]; 1466a6afd9f3SGreg Kroah-Hartman if (!brd->ready) { 1467a6afd9f3SGreg Kroah-Hartman mutex_unlock(&moxa_openlock); 1468a6afd9f3SGreg Kroah-Hartman return -ENODEV; 1469a6afd9f3SGreg Kroah-Hartman } 1470a6afd9f3SGreg Kroah-Hartman 1471a6afd9f3SGreg Kroah-Hartman if (port % MAX_PORTS_PER_BOARD >= brd->numPorts) { 1472a6afd9f3SGreg Kroah-Hartman mutex_unlock(&moxa_openlock); 1473a6afd9f3SGreg Kroah-Hartman return -ENODEV; 1474a6afd9f3SGreg Kroah-Hartman } 1475a6afd9f3SGreg Kroah-Hartman 1476a6afd9f3SGreg Kroah-Hartman ch = &brd->ports[port % MAX_PORTS_PER_BOARD]; 1477a6afd9f3SGreg Kroah-Hartman ch->port.count++; 1478a6afd9f3SGreg Kroah-Hartman tty->driver_data = ch; 1479a6afd9f3SGreg Kroah-Hartman tty_port_tty_set(&ch->port, tty); 1480a6afd9f3SGreg Kroah-Hartman mutex_lock(&ch->port.mutex); 1481d41861caSPeter Hurley if (!tty_port_initialized(&ch->port)) { 1482a6afd9f3SGreg Kroah-Hartman ch->statusflags = 0; 1483adc8d746SAlan Cox moxa_set_tty_param(tty, &tty->termios); 14845d420399SIlpo Järvinen MoxaPortLineCtrl(ch, true, true); 1485a6afd9f3SGreg Kroah-Hartman MoxaPortEnable(ch); 1486a6afd9f3SGreg Kroah-Hartman MoxaSetFifo(ch, ch->type == PORT_16550A); 1487515be7baSIlpo Järvinen tty_port_set_initialized(&ch->port, true); 1488a6afd9f3SGreg Kroah-Hartman } 1489a6afd9f3SGreg Kroah-Hartman mutex_unlock(&ch->port.mutex); 1490a6afd9f3SGreg Kroah-Hartman mutex_unlock(&moxa_openlock); 1491a6afd9f3SGreg Kroah-Hartman 14927c31bdb6SJiri Slaby return tty_port_block_til_ready(&ch->port, tty, filp); 1493a6afd9f3SGreg Kroah-Hartman } 1494a6afd9f3SGreg Kroah-Hartman 1495a6afd9f3SGreg Kroah-Hartman static void moxa_close(struct tty_struct *tty, struct file *filp) 1496a6afd9f3SGreg Kroah-Hartman { 1497a6afd9f3SGreg Kroah-Hartman struct moxa_port *ch = tty->driver_data; 1498adc8d746SAlan Cox ch->cflag = tty->termios.c_cflag; 1499a6afd9f3SGreg Kroah-Hartman tty_port_close(&ch->port, tty, filp); 1500a6afd9f3SGreg Kroah-Hartman } 1501a6afd9f3SGreg Kroah-Hartman 1502*69851e4aSJiri Slaby (SUSE) static int moxa_write(struct tty_struct *tty, const u8 *buf, int count) 1503a6afd9f3SGreg Kroah-Hartman { 1504a6afd9f3SGreg Kroah-Hartman struct moxa_port *ch = tty->driver_data; 15050ad7c9afSJiri Slaby unsigned long flags; 1506a6afd9f3SGreg Kroah-Hartman int len; 1507a6afd9f3SGreg Kroah-Hartman 1508a6afd9f3SGreg Kroah-Hartman if (ch == NULL) 1509a6afd9f3SGreg Kroah-Hartman return 0; 1510a6afd9f3SGreg Kroah-Hartman 15110ad7c9afSJiri Slaby spin_lock_irqsave(&moxa_lock, flags); 1512a6afd9f3SGreg Kroah-Hartman len = MoxaPortWriteData(tty, buf, count); 15130ad7c9afSJiri Slaby spin_unlock_irqrestore(&moxa_lock, flags); 1514a6afd9f3SGreg Kroah-Hartman 1515a6afd9f3SGreg Kroah-Hartman set_bit(LOWWAIT, &ch->statusflags); 1516a6afd9f3SGreg Kroah-Hartman return len; 1517a6afd9f3SGreg Kroah-Hartman } 1518a6afd9f3SGreg Kroah-Hartman 151903b3b1a2SJiri Slaby static unsigned int moxa_write_room(struct tty_struct *tty) 1520a6afd9f3SGreg Kroah-Hartman { 1521a6afd9f3SGreg Kroah-Hartman struct moxa_port *ch; 1522a6afd9f3SGreg Kroah-Hartman 15236e94dbc7SJiri Slaby if (tty->flow.stopped) 1524a6afd9f3SGreg Kroah-Hartman return 0; 1525a6afd9f3SGreg Kroah-Hartman ch = tty->driver_data; 1526a6afd9f3SGreg Kroah-Hartman if (ch == NULL) 1527a6afd9f3SGreg Kroah-Hartman return 0; 1528a6afd9f3SGreg Kroah-Hartman return MoxaPortTxFree(ch); 1529a6afd9f3SGreg Kroah-Hartman } 1530a6afd9f3SGreg Kroah-Hartman 1531a6afd9f3SGreg Kroah-Hartman static void moxa_flush_buffer(struct tty_struct *tty) 1532a6afd9f3SGreg Kroah-Hartman { 1533a6afd9f3SGreg Kroah-Hartman struct moxa_port *ch = tty->driver_data; 1534a6afd9f3SGreg Kroah-Hartman 1535a6afd9f3SGreg Kroah-Hartman if (ch == NULL) 1536a6afd9f3SGreg Kroah-Hartman return; 1537a6afd9f3SGreg Kroah-Hartman MoxaPortFlushData(ch, 1); 1538a6afd9f3SGreg Kroah-Hartman tty_wakeup(tty); 1539a6afd9f3SGreg Kroah-Hartman } 1540a6afd9f3SGreg Kroah-Hartman 1541fff4ef17SJiri Slaby static unsigned int moxa_chars_in_buffer(struct tty_struct *tty) 1542a6afd9f3SGreg Kroah-Hartman { 1543a6afd9f3SGreg Kroah-Hartman struct moxa_port *ch = tty->driver_data; 1544fff4ef17SJiri Slaby unsigned int chars; 1545a6afd9f3SGreg Kroah-Hartman 1546a6afd9f3SGreg Kroah-Hartman chars = MoxaPortTxQueue(ch); 1547a6afd9f3SGreg Kroah-Hartman if (chars) 1548a6afd9f3SGreg Kroah-Hartman /* 1549a6afd9f3SGreg Kroah-Hartman * Make it possible to wakeup anything waiting for output 1550a6afd9f3SGreg Kroah-Hartman * in tty_ioctl.c, etc. 1551a6afd9f3SGreg Kroah-Hartman */ 1552a6afd9f3SGreg Kroah-Hartman set_bit(EMPTYWAIT, &ch->statusflags); 1553a6afd9f3SGreg Kroah-Hartman return chars; 1554a6afd9f3SGreg Kroah-Hartman } 1555a6afd9f3SGreg Kroah-Hartman 1556a6afd9f3SGreg Kroah-Hartman static int moxa_tiocmget(struct tty_struct *tty) 1557a6afd9f3SGreg Kroah-Hartman { 1558a6afd9f3SGreg Kroah-Hartman struct moxa_port *ch = tty->driver_data; 15592d762dabSIlpo Järvinen bool dtr_active, rts_active; 15605d420399SIlpo Järvinen int flag = 0; 15615d420399SIlpo Järvinen int status; 1562a6afd9f3SGreg Kroah-Hartman 15632d762dabSIlpo Järvinen MoxaPortGetLineOut(ch, &dtr_active, &rts_active); 15642d762dabSIlpo Järvinen if (dtr_active) 1565a6afd9f3SGreg Kroah-Hartman flag |= TIOCM_DTR; 15662d762dabSIlpo Järvinen if (rts_active) 1567a6afd9f3SGreg Kroah-Hartman flag |= TIOCM_RTS; 15685d420399SIlpo Järvinen status = MoxaPortLineStatus(ch); 15695d420399SIlpo Järvinen if (status & 1) 1570a6afd9f3SGreg Kroah-Hartman flag |= TIOCM_CTS; 15715d420399SIlpo Järvinen if (status & 2) 1572a6afd9f3SGreg Kroah-Hartman flag |= TIOCM_DSR; 15735d420399SIlpo Järvinen if (status & 4) 1574a6afd9f3SGreg Kroah-Hartman flag |= TIOCM_CD; 1575a6afd9f3SGreg Kroah-Hartman return flag; 1576a6afd9f3SGreg Kroah-Hartman } 1577a6afd9f3SGreg Kroah-Hartman 1578a6afd9f3SGreg Kroah-Hartman static int moxa_tiocmset(struct tty_struct *tty, 1579a6afd9f3SGreg Kroah-Hartman unsigned int set, unsigned int clear) 1580a6afd9f3SGreg Kroah-Hartman { 15812d762dabSIlpo Järvinen bool dtr_active, rts_active; 1582a6afd9f3SGreg Kroah-Hartman struct moxa_port *ch; 1583a6afd9f3SGreg Kroah-Hartman 1584a6afd9f3SGreg Kroah-Hartman mutex_lock(&moxa_openlock); 1585a6afd9f3SGreg Kroah-Hartman ch = tty->driver_data; 1586a6afd9f3SGreg Kroah-Hartman if (!ch) { 1587a6afd9f3SGreg Kroah-Hartman mutex_unlock(&moxa_openlock); 1588a6afd9f3SGreg Kroah-Hartman return -EINVAL; 1589a6afd9f3SGreg Kroah-Hartman } 1590a6afd9f3SGreg Kroah-Hartman 15912d762dabSIlpo Järvinen MoxaPortGetLineOut(ch, &dtr_active, &rts_active); 1592a6afd9f3SGreg Kroah-Hartman if (set & TIOCM_RTS) 15932d762dabSIlpo Järvinen rts_active = true; 1594a6afd9f3SGreg Kroah-Hartman if (set & TIOCM_DTR) 15952d762dabSIlpo Järvinen dtr_active = true; 1596a6afd9f3SGreg Kroah-Hartman if (clear & TIOCM_RTS) 15972d762dabSIlpo Järvinen rts_active = false; 1598a6afd9f3SGreg Kroah-Hartman if (clear & TIOCM_DTR) 15992d762dabSIlpo Järvinen dtr_active = false; 16002d762dabSIlpo Järvinen MoxaPortLineCtrl(ch, dtr_active, rts_active); 1601a6afd9f3SGreg Kroah-Hartman mutex_unlock(&moxa_openlock); 1602a6afd9f3SGreg Kroah-Hartman return 0; 1603a6afd9f3SGreg Kroah-Hartman } 1604a6afd9f3SGreg Kroah-Hartman 1605a6afd9f3SGreg Kroah-Hartman static void moxa_set_termios(struct tty_struct *tty, 1606a8c11c15SIlpo Järvinen const struct ktermios *old_termios) 1607a6afd9f3SGreg Kroah-Hartman { 1608a6afd9f3SGreg Kroah-Hartman struct moxa_port *ch = tty->driver_data; 1609a6afd9f3SGreg Kroah-Hartman 1610a6afd9f3SGreg Kroah-Hartman if (ch == NULL) 1611a6afd9f3SGreg Kroah-Hartman return; 1612a6afd9f3SGreg Kroah-Hartman moxa_set_tty_param(tty, old_termios); 1613a6afd9f3SGreg Kroah-Hartman if (!(old_termios->c_cflag & CLOCAL) && C_CLOCAL(tty)) 1614a6afd9f3SGreg Kroah-Hartman wake_up_interruptible(&ch->port.open_wait); 1615a6afd9f3SGreg Kroah-Hartman } 1616a6afd9f3SGreg Kroah-Hartman 1617a6afd9f3SGreg Kroah-Hartman static void moxa_stop(struct tty_struct *tty) 1618a6afd9f3SGreg Kroah-Hartman { 1619a6afd9f3SGreg Kroah-Hartman struct moxa_port *ch = tty->driver_data; 1620a6afd9f3SGreg Kroah-Hartman 1621a6afd9f3SGreg Kroah-Hartman if (ch == NULL) 1622a6afd9f3SGreg Kroah-Hartman return; 1623a6afd9f3SGreg Kroah-Hartman MoxaPortTxDisable(ch); 1624a6afd9f3SGreg Kroah-Hartman set_bit(TXSTOPPED, &ch->statusflags); 1625a6afd9f3SGreg Kroah-Hartman } 1626a6afd9f3SGreg Kroah-Hartman 1627a6afd9f3SGreg Kroah-Hartman 1628a6afd9f3SGreg Kroah-Hartman static void moxa_start(struct tty_struct *tty) 1629a6afd9f3SGreg Kroah-Hartman { 1630a6afd9f3SGreg Kroah-Hartman struct moxa_port *ch = tty->driver_data; 1631a6afd9f3SGreg Kroah-Hartman 1632a6afd9f3SGreg Kroah-Hartman if (ch == NULL) 1633a6afd9f3SGreg Kroah-Hartman return; 1634a6afd9f3SGreg Kroah-Hartman 163558112dfbSDan Carpenter if (!test_bit(TXSTOPPED, &ch->statusflags)) 1636a6afd9f3SGreg Kroah-Hartman return; 1637a6afd9f3SGreg Kroah-Hartman 1638a6afd9f3SGreg Kroah-Hartman MoxaPortTxEnable(ch); 1639a6afd9f3SGreg Kroah-Hartman clear_bit(TXSTOPPED, &ch->statusflags); 1640a6afd9f3SGreg Kroah-Hartman } 1641a6afd9f3SGreg Kroah-Hartman 1642a6afd9f3SGreg Kroah-Hartman static void moxa_hangup(struct tty_struct *tty) 1643a6afd9f3SGreg Kroah-Hartman { 1644a6afd9f3SGreg Kroah-Hartman struct moxa_port *ch = tty->driver_data; 1645a6afd9f3SGreg Kroah-Hartman tty_port_hangup(&ch->port); 1646a6afd9f3SGreg Kroah-Hartman } 1647a6afd9f3SGreg Kroah-Hartman 1648a6afd9f3SGreg Kroah-Hartman static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd) 1649a6afd9f3SGreg Kroah-Hartman { 1650a6afd9f3SGreg Kroah-Hartman unsigned long flags; 1651a6afd9f3SGreg Kroah-Hartman dcd = !!dcd; 1652a6afd9f3SGreg Kroah-Hartman 1653a6afd9f3SGreg Kroah-Hartman spin_lock_irqsave(&p->port.lock, flags); 1654a6afd9f3SGreg Kroah-Hartman if (dcd != p->DCDState) { 1655a6afd9f3SGreg Kroah-Hartman p->DCDState = dcd; 1656a6afd9f3SGreg Kroah-Hartman spin_unlock_irqrestore(&p->port.lock, flags); 1657aa27a094SJiri Slaby if (!dcd) 1658aa27a094SJiri Slaby tty_port_tty_hangup(&p->port, true); 1659a6afd9f3SGreg Kroah-Hartman } 1660a6afd9f3SGreg Kroah-Hartman else 1661a6afd9f3SGreg Kroah-Hartman spin_unlock_irqrestore(&p->port.lock, flags); 1662a6afd9f3SGreg Kroah-Hartman } 1663a6afd9f3SGreg Kroah-Hartman 1664a6afd9f3SGreg Kroah-Hartman static int moxa_poll_port(struct moxa_port *p, unsigned int handle, 1665a6afd9f3SGreg Kroah-Hartman u16 __iomem *ip) 1666a6afd9f3SGreg Kroah-Hartman { 1667a6afd9f3SGreg Kroah-Hartman struct tty_struct *tty = tty_port_tty_get(&p->port); 1668c2ac4bfaSIlpo Järvinen bool inited = tty_port_initialized(&p->port); 1669a6afd9f3SGreg Kroah-Hartman void __iomem *ofsAddr; 1670a6afd9f3SGreg Kroah-Hartman u16 intr; 1671a6afd9f3SGreg Kroah-Hartman 1672a6afd9f3SGreg Kroah-Hartman if (tty) { 1673a6afd9f3SGreg Kroah-Hartman if (test_bit(EMPTYWAIT, &p->statusflags) && 1674a6afd9f3SGreg Kroah-Hartman MoxaPortTxQueue(p) == 0) { 1675a6afd9f3SGreg Kroah-Hartman clear_bit(EMPTYWAIT, &p->statusflags); 1676a6afd9f3SGreg Kroah-Hartman tty_wakeup(tty); 1677a6afd9f3SGreg Kroah-Hartman } 16786e94dbc7SJiri Slaby if (test_bit(LOWWAIT, &p->statusflags) && !tty->flow.stopped && 1679a6afd9f3SGreg Kroah-Hartman MoxaPortTxQueue(p) <= WAKEUP_CHARS) { 1680a6afd9f3SGreg Kroah-Hartman clear_bit(LOWWAIT, &p->statusflags); 1681a6afd9f3SGreg Kroah-Hartman tty_wakeup(tty); 1682a6afd9f3SGreg Kroah-Hartman } 1683a6afd9f3SGreg Kroah-Hartman 168497ef38b8SPeter Hurley if (inited && !tty_throttled(tty) && 1685a6afd9f3SGreg Kroah-Hartman MoxaPortRxQueue(p) > 0) { /* RX */ 1686a6afd9f3SGreg Kroah-Hartman MoxaPortReadData(p); 16875f6a8515SJiri Slaby tty_flip_buffer_push(&p->port); 1688a6afd9f3SGreg Kroah-Hartman } 1689a6afd9f3SGreg Kroah-Hartman } else { 1690a6afd9f3SGreg Kroah-Hartman clear_bit(EMPTYWAIT, &p->statusflags); 1691a6afd9f3SGreg Kroah-Hartman MoxaPortFlushData(p, 0); /* flush RX */ 1692a6afd9f3SGreg Kroah-Hartman } 1693a6afd9f3SGreg Kroah-Hartman 1694a6afd9f3SGreg Kroah-Hartman if (!handle) /* nothing else to do */ 1695a6afd9f3SGreg Kroah-Hartman goto put; 1696a6afd9f3SGreg Kroah-Hartman 1697a6afd9f3SGreg Kroah-Hartman intr = readw(ip); /* port irq status */ 1698a6afd9f3SGreg Kroah-Hartman if (intr == 0) 1699a6afd9f3SGreg Kroah-Hartman goto put; 1700a6afd9f3SGreg Kroah-Hartman 1701a6afd9f3SGreg Kroah-Hartman writew(0, ip); /* ACK port */ 1702a6afd9f3SGreg Kroah-Hartman ofsAddr = p->tableAddr; 1703a6afd9f3SGreg Kroah-Hartman if (intr & IntrTx) /* disable tx intr */ 1704a6afd9f3SGreg Kroah-Hartman writew(readw(ofsAddr + HostStat) & ~WakeupTx, 1705a6afd9f3SGreg Kroah-Hartman ofsAddr + HostStat); 1706a6afd9f3SGreg Kroah-Hartman 1707a6afd9f3SGreg Kroah-Hartman if (!inited) 1708a6afd9f3SGreg Kroah-Hartman goto put; 1709a6afd9f3SGreg Kroah-Hartman 1710a6afd9f3SGreg Kroah-Hartman if (tty && (intr & IntrBreak) && !I_IGNBRK(tty)) { /* BREAK */ 171192a19f9cSJiri Slaby tty_insert_flip_char(&p->port, 0, TTY_BREAK); 17125f6a8515SJiri Slaby tty_flip_buffer_push(&p->port); 1713a6afd9f3SGreg Kroah-Hartman } 1714a6afd9f3SGreg Kroah-Hartman 1715a6afd9f3SGreg Kroah-Hartman if (intr & IntrLine) 1716a6afd9f3SGreg Kroah-Hartman moxa_new_dcdstate(p, readb(ofsAddr + FlagStat) & DCD_state); 1717a6afd9f3SGreg Kroah-Hartman put: 1718a6afd9f3SGreg Kroah-Hartman tty_kref_put(tty); 1719a6afd9f3SGreg Kroah-Hartman 1720a6afd9f3SGreg Kroah-Hartman return 0; 1721a6afd9f3SGreg Kroah-Hartman } 1722a6afd9f3SGreg Kroah-Hartman 172324ed960aSKees Cook static void moxa_poll(struct timer_list *unused) 1724a6afd9f3SGreg Kroah-Hartman { 1725a6afd9f3SGreg Kroah-Hartman struct moxa_board_conf *brd; 1726a6afd9f3SGreg Kroah-Hartman u16 __iomem *ip; 1727a6afd9f3SGreg Kroah-Hartman unsigned int card, port, served = 0; 1728a6afd9f3SGreg Kroah-Hartman 1729a6afd9f3SGreg Kroah-Hartman spin_lock(&moxa_lock); 1730a6afd9f3SGreg Kroah-Hartman for (card = 0; card < MAX_BOARDS; card++) { 1731a6afd9f3SGreg Kroah-Hartman brd = &moxa_boards[card]; 1732a6afd9f3SGreg Kroah-Hartman if (!brd->ready) 1733a6afd9f3SGreg Kroah-Hartman continue; 1734a6afd9f3SGreg Kroah-Hartman 1735a6afd9f3SGreg Kroah-Hartman served++; 1736a6afd9f3SGreg Kroah-Hartman 1737a6afd9f3SGreg Kroah-Hartman ip = NULL; 1738a6afd9f3SGreg Kroah-Hartman if (readb(brd->intPend) == 0xff) 1739a6afd9f3SGreg Kroah-Hartman ip = brd->intTable + readb(brd->intNdx); 1740a6afd9f3SGreg Kroah-Hartman 1741a6afd9f3SGreg Kroah-Hartman for (port = 0; port < brd->numPorts; port++) 1742a6afd9f3SGreg Kroah-Hartman moxa_poll_port(&brd->ports[port], !!ip, ip + port); 1743a6afd9f3SGreg Kroah-Hartman 1744a6afd9f3SGreg Kroah-Hartman if (ip) 1745a6afd9f3SGreg Kroah-Hartman writeb(0, brd->intPend); /* ACK */ 1746a6afd9f3SGreg Kroah-Hartman 1747a6afd9f3SGreg Kroah-Hartman if (moxaLowWaterChk) { 1748a6afd9f3SGreg Kroah-Hartman struct moxa_port *p = brd->ports; 1749a6afd9f3SGreg Kroah-Hartman for (port = 0; port < brd->numPorts; port++, p++) 1750a6afd9f3SGreg Kroah-Hartman if (p->lowChkFlag) { 1751a6afd9f3SGreg Kroah-Hartman p->lowChkFlag = 0; 1752a6afd9f3SGreg Kroah-Hartman moxa_low_water_check(p->tableAddr); 1753a6afd9f3SGreg Kroah-Hartman } 1754a6afd9f3SGreg Kroah-Hartman } 1755a6afd9f3SGreg Kroah-Hartman } 1756a6afd9f3SGreg Kroah-Hartman moxaLowWaterChk = 0; 1757a6afd9f3SGreg Kroah-Hartman 1758a6afd9f3SGreg Kroah-Hartman if (served) 1759a6afd9f3SGreg Kroah-Hartman mod_timer(&moxaTimer, jiffies + HZ / 50); 1760a6afd9f3SGreg Kroah-Hartman spin_unlock(&moxa_lock); 1761a6afd9f3SGreg Kroah-Hartman } 1762a6afd9f3SGreg Kroah-Hartman 1763a6afd9f3SGreg Kroah-Hartman /******************************************************************************/ 1764a6afd9f3SGreg Kroah-Hartman 1765a8c11c15SIlpo Järvinen static void moxa_set_tty_param(struct tty_struct *tty, 1766a8c11c15SIlpo Järvinen const struct ktermios *old_termios) 1767a6afd9f3SGreg Kroah-Hartman { 1768adc8d746SAlan Cox register struct ktermios *ts = &tty->termios; 1769a6afd9f3SGreg Kroah-Hartman struct moxa_port *ch = tty->driver_data; 1770a6afd9f3SGreg Kroah-Hartman int rts, cts, txflow, rxflow, xany, baud; 1771a6afd9f3SGreg Kroah-Hartman 1772a6afd9f3SGreg Kroah-Hartman rts = cts = txflow = rxflow = xany = 0; 1773a6afd9f3SGreg Kroah-Hartman if (ts->c_cflag & CRTSCTS) 1774a6afd9f3SGreg Kroah-Hartman rts = cts = 1; 1775a6afd9f3SGreg Kroah-Hartman if (ts->c_iflag & IXON) 1776a6afd9f3SGreg Kroah-Hartman txflow = 1; 1777a6afd9f3SGreg Kroah-Hartman if (ts->c_iflag & IXOFF) 1778a6afd9f3SGreg Kroah-Hartman rxflow = 1; 1779a6afd9f3SGreg Kroah-Hartman if (ts->c_iflag & IXANY) 1780a6afd9f3SGreg Kroah-Hartman xany = 1; 1781a6afd9f3SGreg Kroah-Hartman 1782a6afd9f3SGreg Kroah-Hartman MoxaPortFlowCtrl(ch, rts, cts, txflow, rxflow, xany); 1783a6afd9f3SGreg Kroah-Hartman baud = MoxaPortSetTermio(ch, ts, tty_get_baud_rate(tty)); 1784a6afd9f3SGreg Kroah-Hartman if (baud == -1) 1785a6afd9f3SGreg Kroah-Hartman baud = tty_termios_baud_rate(old_termios); 1786a6afd9f3SGreg Kroah-Hartman /* Not put the baud rate into the termios data */ 1787a6afd9f3SGreg Kroah-Hartman tty_encode_baud_rate(tty, baud, baud); 1788a6afd9f3SGreg Kroah-Hartman } 1789a6afd9f3SGreg Kroah-Hartman 1790a6afd9f3SGreg Kroah-Hartman /***************************************************************************** 1791a6afd9f3SGreg Kroah-Hartman * Driver level functions: * 1792a6afd9f3SGreg Kroah-Hartman *****************************************************************************/ 1793a6afd9f3SGreg Kroah-Hartman 1794a6afd9f3SGreg Kroah-Hartman static void MoxaPortFlushData(struct moxa_port *port, int mode) 1795a6afd9f3SGreg Kroah-Hartman { 1796a6afd9f3SGreg Kroah-Hartman void __iomem *ofsAddr; 1797a6afd9f3SGreg Kroah-Hartman if (mode < 0 || mode > 2) 1798a6afd9f3SGreg Kroah-Hartman return; 1799a6afd9f3SGreg Kroah-Hartman ofsAddr = port->tableAddr; 1800a6afd9f3SGreg Kroah-Hartman moxafunc(ofsAddr, FC_FlushQueue, mode); 1801a6afd9f3SGreg Kroah-Hartman if (mode != 1) { 1802a6afd9f3SGreg Kroah-Hartman port->lowChkFlag = 0; 1803a6afd9f3SGreg Kroah-Hartman moxa_low_water_check(ofsAddr); 1804a6afd9f3SGreg Kroah-Hartman } 1805a6afd9f3SGreg Kroah-Hartman } 1806a6afd9f3SGreg Kroah-Hartman 1807a6afd9f3SGreg Kroah-Hartman /* 1808a6afd9f3SGreg Kroah-Hartman * Moxa Port Number Description: 1809a6afd9f3SGreg Kroah-Hartman * 1810a6afd9f3SGreg Kroah-Hartman * MOXA serial driver supports up to 4 MOXA-C218/C320 boards. And, 1811a6afd9f3SGreg Kroah-Hartman * the port number using in MOXA driver functions will be 0 to 31 for 1812a6afd9f3SGreg Kroah-Hartman * first MOXA board, 32 to 63 for second, 64 to 95 for third and 96 1813a6afd9f3SGreg Kroah-Hartman * to 127 for fourth. For example, if you setup three MOXA boards, 1814a6afd9f3SGreg Kroah-Hartman * first board is C218, second board is C320-16 and third board is 1815a6afd9f3SGreg Kroah-Hartman * C320-32. The port number of first board (C218 - 8 ports) is from 1816a6afd9f3SGreg Kroah-Hartman * 0 to 7. The port number of second board (C320 - 16 ports) is form 1817a6afd9f3SGreg Kroah-Hartman * 32 to 47. The port number of third board (C320 - 32 ports) is from 1818a6afd9f3SGreg Kroah-Hartman * 64 to 95. And those port numbers form 8 to 31, 48 to 63 and 96 to 1819a6afd9f3SGreg Kroah-Hartman * 127 will be invalid. 1820a6afd9f3SGreg Kroah-Hartman * 1821a6afd9f3SGreg Kroah-Hartman * 1822a6afd9f3SGreg Kroah-Hartman * Moxa Functions Description: 1823a6afd9f3SGreg Kroah-Hartman * 1824a6afd9f3SGreg Kroah-Hartman * Function 1: Driver initialization routine, this routine must be 1825a6afd9f3SGreg Kroah-Hartman * called when initialized driver. 1826a6afd9f3SGreg Kroah-Hartman * Syntax: 1827a6afd9f3SGreg Kroah-Hartman * void MoxaDriverInit(); 1828a6afd9f3SGreg Kroah-Hartman * 1829a6afd9f3SGreg Kroah-Hartman * 1830a6afd9f3SGreg Kroah-Hartman * Function 2: Moxa driver private IOCTL command processing. 1831a6afd9f3SGreg Kroah-Hartman * Syntax: 1832a6afd9f3SGreg Kroah-Hartman * int MoxaDriverIoctl(unsigned int cmd, unsigned long arg, int port); 1833a6afd9f3SGreg Kroah-Hartman * 1834a6afd9f3SGreg Kroah-Hartman * unsigned int cmd : IOCTL command 1835a6afd9f3SGreg Kroah-Hartman * unsigned long arg : IOCTL argument 1836a6afd9f3SGreg Kroah-Hartman * int port : port number (0 - 127) 1837a6afd9f3SGreg Kroah-Hartman * 1838a6afd9f3SGreg Kroah-Hartman * return: 0 (OK) 1839a6afd9f3SGreg Kroah-Hartman * -EINVAL 1840a6afd9f3SGreg Kroah-Hartman * -ENOIOCTLCMD 1841a6afd9f3SGreg Kroah-Hartman * 1842a6afd9f3SGreg Kroah-Hartman * 1843a6afd9f3SGreg Kroah-Hartman * Function 6: Enable this port to start Tx/Rx data. 1844a6afd9f3SGreg Kroah-Hartman * Syntax: 1845a6afd9f3SGreg Kroah-Hartman * void MoxaPortEnable(int port); 1846a6afd9f3SGreg Kroah-Hartman * int port : port number (0 - 127) 1847a6afd9f3SGreg Kroah-Hartman * 1848a6afd9f3SGreg Kroah-Hartman * 1849a6afd9f3SGreg Kroah-Hartman * Function 7: Disable this port 1850a6afd9f3SGreg Kroah-Hartman * Syntax: 1851a6afd9f3SGreg Kroah-Hartman * void MoxaPortDisable(int port); 1852a6afd9f3SGreg Kroah-Hartman * int port : port number (0 - 127) 1853a6afd9f3SGreg Kroah-Hartman * 1854a6afd9f3SGreg Kroah-Hartman * 1855a6afd9f3SGreg Kroah-Hartman * Function 10: Setting baud rate of this port. 1856a6afd9f3SGreg Kroah-Hartman * Syntax: 1857a6afd9f3SGreg Kroah-Hartman * speed_t MoxaPortSetBaud(int port, speed_t baud); 1858a6afd9f3SGreg Kroah-Hartman * int port : port number (0 - 127) 1859a6afd9f3SGreg Kroah-Hartman * long baud : baud rate (50 - 115200) 1860a6afd9f3SGreg Kroah-Hartman * 1861a6afd9f3SGreg Kroah-Hartman * return: 0 : this port is invalid or baud < 50 1862a6afd9f3SGreg Kroah-Hartman * 50 - 115200 : the real baud rate set to the port, if 1863a6afd9f3SGreg Kroah-Hartman * the argument baud is large than maximun 1864a6afd9f3SGreg Kroah-Hartman * available baud rate, the real setting 1865a6afd9f3SGreg Kroah-Hartman * baud rate will be the maximun baud rate. 1866a6afd9f3SGreg Kroah-Hartman * 1867a6afd9f3SGreg Kroah-Hartman * 1868a6afd9f3SGreg Kroah-Hartman * Function 12: Configure the port. 1869a6afd9f3SGreg Kroah-Hartman * Syntax: 1870a6afd9f3SGreg Kroah-Hartman * int MoxaPortSetTermio(int port, struct ktermios *termio, speed_t baud); 1871a6afd9f3SGreg Kroah-Hartman * int port : port number (0 - 127) 1872a6afd9f3SGreg Kroah-Hartman * struct ktermios * termio : termio structure pointer 1873a6afd9f3SGreg Kroah-Hartman * speed_t baud : baud rate 1874a6afd9f3SGreg Kroah-Hartman * 1875a6afd9f3SGreg Kroah-Hartman * return: -1 : this port is invalid or termio == NULL 1876a6afd9f3SGreg Kroah-Hartman * 0 : setting O.K. 1877a6afd9f3SGreg Kroah-Hartman * 1878a6afd9f3SGreg Kroah-Hartman * 1879a6afd9f3SGreg Kroah-Hartman * Function 13: Get the DTR/RTS state of this port. 1880a6afd9f3SGreg Kroah-Hartman * Syntax: 18815d420399SIlpo Järvinen * int MoxaPortGetLineOut(int port, bool *dtrState, bool *rtsState); 1882a6afd9f3SGreg Kroah-Hartman * int port : port number (0 - 127) 18832d762dabSIlpo Järvinen * bool * dtr_active : pointer to bool to receive the current DTR 1884a6afd9f3SGreg Kroah-Hartman * state. (if NULL, this function will not 1885a6afd9f3SGreg Kroah-Hartman * write to this address) 18862d762dabSIlpo Järvinen * bool * rts_active : pointer to bool to receive the current RTS 1887a6afd9f3SGreg Kroah-Hartman * state. (if NULL, this function will not 1888a6afd9f3SGreg Kroah-Hartman * write to this address) 1889a6afd9f3SGreg Kroah-Hartman * 1890a6afd9f3SGreg Kroah-Hartman * return: -1 : this port is invalid 1891a6afd9f3SGreg Kroah-Hartman * 0 : O.K. 1892a6afd9f3SGreg Kroah-Hartman * 1893a6afd9f3SGreg Kroah-Hartman * 1894a6afd9f3SGreg Kroah-Hartman * Function 14: Setting the DTR/RTS output state of this port. 1895a6afd9f3SGreg Kroah-Hartman * Syntax: 18965d420399SIlpo Järvinen * void MoxaPortLineCtrl(int port, bool dtrState, bool rtsState); 1897a6afd9f3SGreg Kroah-Hartman * int port : port number (0 - 127) 18982d762dabSIlpo Järvinen * bool dtr_active : DTR output state 18992d762dabSIlpo Järvinen * bool rts_active : RTS output state 1900a6afd9f3SGreg Kroah-Hartman * 1901a6afd9f3SGreg Kroah-Hartman * 1902a6afd9f3SGreg Kroah-Hartman * Function 15: Setting the flow control of this port. 1903a6afd9f3SGreg Kroah-Hartman * Syntax: 1904a6afd9f3SGreg Kroah-Hartman * void MoxaPortFlowCtrl(int port, int rtsFlow, int ctsFlow, int rxFlow, 1905a6afd9f3SGreg Kroah-Hartman * int txFlow,int xany); 1906a6afd9f3SGreg Kroah-Hartman * int port : port number (0 - 127) 1907a6afd9f3SGreg Kroah-Hartman * int rtsFlow : H/W RTS flow control (0: no, 1: yes) 1908a6afd9f3SGreg Kroah-Hartman * int ctsFlow : H/W CTS flow control (0: no, 1: yes) 1909a6afd9f3SGreg Kroah-Hartman * int rxFlow : S/W Rx XON/XOFF flow control (0: no, 1: yes) 1910a6afd9f3SGreg Kroah-Hartman * int txFlow : S/W Tx XON/XOFF flow control (0: no, 1: yes) 1911a6afd9f3SGreg Kroah-Hartman * int xany : S/W XANY flow control (0: no, 1: yes) 1912a6afd9f3SGreg Kroah-Hartman * 1913a6afd9f3SGreg Kroah-Hartman * 1914a6afd9f3SGreg Kroah-Hartman * Function 16: Get ths line status of this port 1915a6afd9f3SGreg Kroah-Hartman * Syntax: 1916a6afd9f3SGreg Kroah-Hartman * int MoxaPortLineStatus(int port); 1917a6afd9f3SGreg Kroah-Hartman * int port : port number (0 - 127) 1918a6afd9f3SGreg Kroah-Hartman * 1919a6afd9f3SGreg Kroah-Hartman * return: Bit 0 - CTS state (0: off, 1: on) 1920a6afd9f3SGreg Kroah-Hartman * Bit 1 - DSR state (0: off, 1: on) 1921a6afd9f3SGreg Kroah-Hartman * Bit 2 - DCD state (0: off, 1: on) 1922a6afd9f3SGreg Kroah-Hartman * 1923a6afd9f3SGreg Kroah-Hartman * 1924a6afd9f3SGreg Kroah-Hartman * Function 19: Flush the Rx/Tx buffer data of this port. 1925a6afd9f3SGreg Kroah-Hartman * Syntax: 1926a6afd9f3SGreg Kroah-Hartman * void MoxaPortFlushData(int port, int mode); 1927a6afd9f3SGreg Kroah-Hartman * int port : port number (0 - 127) 1928a6afd9f3SGreg Kroah-Hartman * int mode 1929a6afd9f3SGreg Kroah-Hartman * 0 : flush the Rx buffer 1930a6afd9f3SGreg Kroah-Hartman * 1 : flush the Tx buffer 1931a6afd9f3SGreg Kroah-Hartman * 2 : flush the Rx and Tx buffer 1932a6afd9f3SGreg Kroah-Hartman * 1933a6afd9f3SGreg Kroah-Hartman * 1934a6afd9f3SGreg Kroah-Hartman * Function 20: Write data. 1935a6afd9f3SGreg Kroah-Hartman * Syntax: 1936a6afd9f3SGreg Kroah-Hartman * int MoxaPortWriteData(int port, unsigned char * buffer, int length); 1937a6afd9f3SGreg Kroah-Hartman * int port : port number (0 - 127) 1938a6afd9f3SGreg Kroah-Hartman * unsigned char * buffer : pointer to write data buffer. 1939a6afd9f3SGreg Kroah-Hartman * int length : write data length 1940a6afd9f3SGreg Kroah-Hartman * 1941a6afd9f3SGreg Kroah-Hartman * return: 0 - length : real write data length 1942a6afd9f3SGreg Kroah-Hartman * 1943a6afd9f3SGreg Kroah-Hartman * 1944a6afd9f3SGreg Kroah-Hartman * Function 21: Read data. 1945a6afd9f3SGreg Kroah-Hartman * Syntax: 1946a6afd9f3SGreg Kroah-Hartman * int MoxaPortReadData(int port, struct tty_struct *tty); 1947a6afd9f3SGreg Kroah-Hartman * int port : port number (0 - 127) 1948a6afd9f3SGreg Kroah-Hartman * struct tty_struct *tty : tty for data 1949a6afd9f3SGreg Kroah-Hartman * 1950a6afd9f3SGreg Kroah-Hartman * return: 0 - length : real read data length 1951a6afd9f3SGreg Kroah-Hartman * 1952a6afd9f3SGreg Kroah-Hartman * 1953a6afd9f3SGreg Kroah-Hartman * Function 24: Get the Tx buffer current queued data bytes 1954a6afd9f3SGreg Kroah-Hartman * Syntax: 1955a6afd9f3SGreg Kroah-Hartman * int MoxaPortTxQueue(int port); 1956a6afd9f3SGreg Kroah-Hartman * int port : port number (0 - 127) 1957a6afd9f3SGreg Kroah-Hartman * 1958a6afd9f3SGreg Kroah-Hartman * return: .. : Tx buffer current queued data bytes 1959a6afd9f3SGreg Kroah-Hartman * 1960a6afd9f3SGreg Kroah-Hartman * 1961a6afd9f3SGreg Kroah-Hartman * Function 25: Get the Tx buffer current free space 1962a6afd9f3SGreg Kroah-Hartman * Syntax: 1963a6afd9f3SGreg Kroah-Hartman * int MoxaPortTxFree(int port); 1964a6afd9f3SGreg Kroah-Hartman * int port : port number (0 - 127) 1965a6afd9f3SGreg Kroah-Hartman * 1966a6afd9f3SGreg Kroah-Hartman * return: .. : Tx buffer current free space 1967a6afd9f3SGreg Kroah-Hartman * 1968a6afd9f3SGreg Kroah-Hartman * 1969a6afd9f3SGreg Kroah-Hartman * Function 26: Get the Rx buffer current queued data bytes 1970a6afd9f3SGreg Kroah-Hartman * Syntax: 1971a6afd9f3SGreg Kroah-Hartman * int MoxaPortRxQueue(int port); 1972a6afd9f3SGreg Kroah-Hartman * int port : port number (0 - 127) 1973a6afd9f3SGreg Kroah-Hartman * 1974a6afd9f3SGreg Kroah-Hartman * return: .. : Rx buffer current queued data bytes 1975a6afd9f3SGreg Kroah-Hartman * 1976a6afd9f3SGreg Kroah-Hartman * 1977a6afd9f3SGreg Kroah-Hartman * Function 28: Disable port data transmission. 1978a6afd9f3SGreg Kroah-Hartman * Syntax: 1979a6afd9f3SGreg Kroah-Hartman * void MoxaPortTxDisable(int port); 1980a6afd9f3SGreg Kroah-Hartman * int port : port number (0 - 127) 1981a6afd9f3SGreg Kroah-Hartman * 1982a6afd9f3SGreg Kroah-Hartman * 1983a6afd9f3SGreg Kroah-Hartman * Function 29: Enable port data transmission. 1984a6afd9f3SGreg Kroah-Hartman * Syntax: 1985a6afd9f3SGreg Kroah-Hartman * void MoxaPortTxEnable(int port); 1986a6afd9f3SGreg Kroah-Hartman * int port : port number (0 - 127) 1987a6afd9f3SGreg Kroah-Hartman * 1988a6afd9f3SGreg Kroah-Hartman * 1989a6afd9f3SGreg Kroah-Hartman * Function 31: Get the received BREAK signal count and reset it. 1990a6afd9f3SGreg Kroah-Hartman * Syntax: 1991a6afd9f3SGreg Kroah-Hartman * int MoxaPortResetBrkCnt(int port); 1992a6afd9f3SGreg Kroah-Hartman * int port : port number (0 - 127) 1993a6afd9f3SGreg Kroah-Hartman * 1994a6afd9f3SGreg Kroah-Hartman * return: 0 - .. : BREAK signal count 1995a6afd9f3SGreg Kroah-Hartman * 1996a6afd9f3SGreg Kroah-Hartman * 1997a6afd9f3SGreg Kroah-Hartman */ 1998a6afd9f3SGreg Kroah-Hartman 1999a6afd9f3SGreg Kroah-Hartman static void MoxaPortEnable(struct moxa_port *port) 2000a6afd9f3SGreg Kroah-Hartman { 2001a6afd9f3SGreg Kroah-Hartman void __iomem *ofsAddr; 2002a6afd9f3SGreg Kroah-Hartman u16 lowwater = 512; 2003a6afd9f3SGreg Kroah-Hartman 2004a6afd9f3SGreg Kroah-Hartman ofsAddr = port->tableAddr; 2005a6afd9f3SGreg Kroah-Hartman writew(lowwater, ofsAddr + Low_water); 2006a6afd9f3SGreg Kroah-Hartman if (MOXA_IS_320(port->board)) 2007a6afd9f3SGreg Kroah-Hartman moxafunc(ofsAddr, FC_SetBreakIrq, 0); 2008a6afd9f3SGreg Kroah-Hartman else 2009a6afd9f3SGreg Kroah-Hartman writew(readw(ofsAddr + HostStat) | WakeupBreak, 2010a6afd9f3SGreg Kroah-Hartman ofsAddr + HostStat); 2011a6afd9f3SGreg Kroah-Hartman 2012a6afd9f3SGreg Kroah-Hartman moxafunc(ofsAddr, FC_SetLineIrq, Magic_code); 2013a6afd9f3SGreg Kroah-Hartman moxafunc(ofsAddr, FC_FlushQueue, 2); 2014a6afd9f3SGreg Kroah-Hartman 2015a6afd9f3SGreg Kroah-Hartman moxafunc(ofsAddr, FC_EnableCH, Magic_code); 2016a6afd9f3SGreg Kroah-Hartman MoxaPortLineStatus(port); 2017a6afd9f3SGreg Kroah-Hartman } 2018a6afd9f3SGreg Kroah-Hartman 2019a6afd9f3SGreg Kroah-Hartman static void MoxaPortDisable(struct moxa_port *port) 2020a6afd9f3SGreg Kroah-Hartman { 2021a6afd9f3SGreg Kroah-Hartman void __iomem *ofsAddr = port->tableAddr; 2022a6afd9f3SGreg Kroah-Hartman 2023a6afd9f3SGreg Kroah-Hartman moxafunc(ofsAddr, FC_SetFlowCtl, 0); /* disable flow control */ 2024a6afd9f3SGreg Kroah-Hartman moxafunc(ofsAddr, FC_ClrLineIrq, Magic_code); 2025a6afd9f3SGreg Kroah-Hartman writew(0, ofsAddr + HostStat); 2026a6afd9f3SGreg Kroah-Hartman moxafunc(ofsAddr, FC_DisableCH, Magic_code); 2027a6afd9f3SGreg Kroah-Hartman } 2028a6afd9f3SGreg Kroah-Hartman 2029a6afd9f3SGreg Kroah-Hartman static speed_t MoxaPortSetBaud(struct moxa_port *port, speed_t baud) 2030a6afd9f3SGreg Kroah-Hartman { 2031a6afd9f3SGreg Kroah-Hartman void __iomem *ofsAddr = port->tableAddr; 2032a6afd9f3SGreg Kroah-Hartman unsigned int clock, val; 2033a6afd9f3SGreg Kroah-Hartman speed_t max; 2034a6afd9f3SGreg Kroah-Hartman 2035a6afd9f3SGreg Kroah-Hartman max = MOXA_IS_320(port->board) ? 460800 : 921600; 2036a6afd9f3SGreg Kroah-Hartman if (baud < 50) 2037a6afd9f3SGreg Kroah-Hartman return 0; 2038a6afd9f3SGreg Kroah-Hartman if (baud > max) 2039a6afd9f3SGreg Kroah-Hartman baud = max; 2040a6afd9f3SGreg Kroah-Hartman clock = 921600; 2041a6afd9f3SGreg Kroah-Hartman val = clock / baud; 2042a6afd9f3SGreg Kroah-Hartman moxafunc(ofsAddr, FC_SetBaud, val); 2043a6afd9f3SGreg Kroah-Hartman baud = clock / val; 2044a6afd9f3SGreg Kroah-Hartman return baud; 2045a6afd9f3SGreg Kroah-Hartman } 2046a6afd9f3SGreg Kroah-Hartman 2047a6afd9f3SGreg Kroah-Hartman static int MoxaPortSetTermio(struct moxa_port *port, struct ktermios *termio, 2048a6afd9f3SGreg Kroah-Hartman speed_t baud) 2049a6afd9f3SGreg Kroah-Hartman { 2050a6afd9f3SGreg Kroah-Hartman void __iomem *ofsAddr; 2051a6afd9f3SGreg Kroah-Hartman tcflag_t mode = 0; 2052a6afd9f3SGreg Kroah-Hartman 2053a6afd9f3SGreg Kroah-Hartman ofsAddr = port->tableAddr; 2054a6afd9f3SGreg Kroah-Hartman 2055a6afd9f3SGreg Kroah-Hartman mode = termio->c_cflag & CSIZE; 2056a6afd9f3SGreg Kroah-Hartman if (mode == CS5) 2057a6afd9f3SGreg Kroah-Hartman mode = MX_CS5; 2058a6afd9f3SGreg Kroah-Hartman else if (mode == CS6) 2059a6afd9f3SGreg Kroah-Hartman mode = MX_CS6; 2060a6afd9f3SGreg Kroah-Hartman else if (mode == CS7) 2061a6afd9f3SGreg Kroah-Hartman mode = MX_CS7; 2062a6afd9f3SGreg Kroah-Hartman else if (mode == CS8) 2063a6afd9f3SGreg Kroah-Hartman mode = MX_CS8; 2064a6afd9f3SGreg Kroah-Hartman 2065a6afd9f3SGreg Kroah-Hartman if (termio->c_cflag & CSTOPB) { 2066a6afd9f3SGreg Kroah-Hartman if (mode == MX_CS5) 2067a6afd9f3SGreg Kroah-Hartman mode |= MX_STOP15; 2068a6afd9f3SGreg Kroah-Hartman else 2069a6afd9f3SGreg Kroah-Hartman mode |= MX_STOP2; 2070a6afd9f3SGreg Kroah-Hartman } else 2071a6afd9f3SGreg Kroah-Hartman mode |= MX_STOP1; 2072a6afd9f3SGreg Kroah-Hartman 2073a6afd9f3SGreg Kroah-Hartman if (termio->c_cflag & PARENB) { 2074d8dcbdd0SLars Kanis if (termio->c_cflag & PARODD) { 2075d8dcbdd0SLars Kanis if (termio->c_cflag & CMSPAR) 2076d8dcbdd0SLars Kanis mode |= MX_PARMARK; 2077d8dcbdd0SLars Kanis else 2078a6afd9f3SGreg Kroah-Hartman mode |= MX_PARODD; 2079d8dcbdd0SLars Kanis } else { 2080d8dcbdd0SLars Kanis if (termio->c_cflag & CMSPAR) 2081d8dcbdd0SLars Kanis mode |= MX_PARSPACE; 2082a6afd9f3SGreg Kroah-Hartman else 2083a6afd9f3SGreg Kroah-Hartman mode |= MX_PAREVEN; 2084d8dcbdd0SLars Kanis } 2085a6afd9f3SGreg Kroah-Hartman } else 2086a6afd9f3SGreg Kroah-Hartman mode |= MX_PARNONE; 2087a6afd9f3SGreg Kroah-Hartman 2088a6afd9f3SGreg Kroah-Hartman moxafunc(ofsAddr, FC_SetDataMode, (u16)mode); 2089a6afd9f3SGreg Kroah-Hartman 2090a6afd9f3SGreg Kroah-Hartman if (MOXA_IS_320(port->board) && baud >= 921600) 2091a6afd9f3SGreg Kroah-Hartman return -1; 2092a6afd9f3SGreg Kroah-Hartman 2093a6afd9f3SGreg Kroah-Hartman baud = MoxaPortSetBaud(port, baud); 2094a6afd9f3SGreg Kroah-Hartman 2095a6afd9f3SGreg Kroah-Hartman if (termio->c_iflag & (IXON | IXOFF | IXANY)) { 2096a6afd9f3SGreg Kroah-Hartman spin_lock_irq(&moxafunc_lock); 2097a6afd9f3SGreg Kroah-Hartman writeb(termio->c_cc[VSTART], ofsAddr + FuncArg); 2098a6afd9f3SGreg Kroah-Hartman writeb(termio->c_cc[VSTOP], ofsAddr + FuncArg1); 2099a6afd9f3SGreg Kroah-Hartman writeb(FC_SetXonXoff, ofsAddr + FuncCode); 2100a6afd9f3SGreg Kroah-Hartman moxa_wait_finish(ofsAddr); 2101a6afd9f3SGreg Kroah-Hartman spin_unlock_irq(&moxafunc_lock); 2102a6afd9f3SGreg Kroah-Hartman 2103a6afd9f3SGreg Kroah-Hartman } 2104a6afd9f3SGreg Kroah-Hartman return baud; 2105a6afd9f3SGreg Kroah-Hartman } 2106a6afd9f3SGreg Kroah-Hartman 21072d762dabSIlpo Järvinen static int MoxaPortGetLineOut(struct moxa_port *port, bool *dtr_active, 21082d762dabSIlpo Järvinen bool *rts_active) 2109a6afd9f3SGreg Kroah-Hartman { 21102d762dabSIlpo Järvinen if (dtr_active) 21112d762dabSIlpo Järvinen *dtr_active = port->lineCtrl & DTR_ON; 21122d762dabSIlpo Järvinen if (rts_active) 21132d762dabSIlpo Järvinen *rts_active = port->lineCtrl & RTS_ON; 2114a6afd9f3SGreg Kroah-Hartman 2115a6afd9f3SGreg Kroah-Hartman return 0; 2116a6afd9f3SGreg Kroah-Hartman } 2117a6afd9f3SGreg Kroah-Hartman 21182d762dabSIlpo Järvinen static void MoxaPortLineCtrl(struct moxa_port *port, bool dtr_active, bool rts_active) 2119a6afd9f3SGreg Kroah-Hartman { 2120a6afd9f3SGreg Kroah-Hartman u8 mode = 0; 2121a6afd9f3SGreg Kroah-Hartman 21222d762dabSIlpo Järvinen if (dtr_active) 2123a6afd9f3SGreg Kroah-Hartman mode |= DTR_ON; 21242d762dabSIlpo Järvinen if (rts_active) 2125a6afd9f3SGreg Kroah-Hartman mode |= RTS_ON; 2126a6afd9f3SGreg Kroah-Hartman port->lineCtrl = mode; 2127a6afd9f3SGreg Kroah-Hartman moxafunc(port->tableAddr, FC_LineControl, mode); 2128a6afd9f3SGreg Kroah-Hartman } 2129a6afd9f3SGreg Kroah-Hartman 2130a6afd9f3SGreg Kroah-Hartman static void MoxaPortFlowCtrl(struct moxa_port *port, int rts, int cts, 2131a6afd9f3SGreg Kroah-Hartman int txflow, int rxflow, int txany) 2132a6afd9f3SGreg Kroah-Hartman { 2133a6afd9f3SGreg Kroah-Hartman int mode = 0; 2134a6afd9f3SGreg Kroah-Hartman 2135a6afd9f3SGreg Kroah-Hartman if (rts) 2136a6afd9f3SGreg Kroah-Hartman mode |= RTS_FlowCtl; 2137a6afd9f3SGreg Kroah-Hartman if (cts) 2138a6afd9f3SGreg Kroah-Hartman mode |= CTS_FlowCtl; 2139a6afd9f3SGreg Kroah-Hartman if (txflow) 2140a6afd9f3SGreg Kroah-Hartman mode |= Tx_FlowCtl; 2141a6afd9f3SGreg Kroah-Hartman if (rxflow) 2142a6afd9f3SGreg Kroah-Hartman mode |= Rx_FlowCtl; 2143a6afd9f3SGreg Kroah-Hartman if (txany) 2144a6afd9f3SGreg Kroah-Hartman mode |= IXM_IXANY; 2145a6afd9f3SGreg Kroah-Hartman moxafunc(port->tableAddr, FC_SetFlowCtl, mode); 2146a6afd9f3SGreg Kroah-Hartman } 2147a6afd9f3SGreg Kroah-Hartman 2148a6afd9f3SGreg Kroah-Hartman static int MoxaPortLineStatus(struct moxa_port *port) 2149a6afd9f3SGreg Kroah-Hartman { 2150a6afd9f3SGreg Kroah-Hartman void __iomem *ofsAddr; 2151a6afd9f3SGreg Kroah-Hartman int val; 2152a6afd9f3SGreg Kroah-Hartman 2153a6afd9f3SGreg Kroah-Hartman ofsAddr = port->tableAddr; 2154a6afd9f3SGreg Kroah-Hartman if (MOXA_IS_320(port->board)) 2155a6afd9f3SGreg Kroah-Hartman val = moxafuncret(ofsAddr, FC_LineStatus, 0); 2156a6afd9f3SGreg Kroah-Hartman else 2157a6afd9f3SGreg Kroah-Hartman val = readw(ofsAddr + FlagStat) >> 4; 2158a6afd9f3SGreg Kroah-Hartman val &= 0x0B; 2159a6afd9f3SGreg Kroah-Hartman if (val & 8) 2160a6afd9f3SGreg Kroah-Hartman val |= 4; 2161a6afd9f3SGreg Kroah-Hartman moxa_new_dcdstate(port, val & 8); 2162a6afd9f3SGreg Kroah-Hartman val &= 7; 2163a6afd9f3SGreg Kroah-Hartman return val; 2164a6afd9f3SGreg Kroah-Hartman } 2165a6afd9f3SGreg Kroah-Hartman 2166*69851e4aSJiri Slaby (SUSE) static int MoxaPortWriteData(struct tty_struct *tty, const u8 *buffer, int len) 2167a6afd9f3SGreg Kroah-Hartman { 2168a6afd9f3SGreg Kroah-Hartman struct moxa_port *port = tty->driver_data; 2169a6afd9f3SGreg Kroah-Hartman void __iomem *baseAddr, *ofsAddr, *ofs; 2170a6afd9f3SGreg Kroah-Hartman unsigned int c, total; 2171a6afd9f3SGreg Kroah-Hartman u16 head, tail, tx_mask, spage, epage; 2172a6afd9f3SGreg Kroah-Hartman u16 pageno, pageofs, bufhead; 2173a6afd9f3SGreg Kroah-Hartman 2174a6afd9f3SGreg Kroah-Hartman ofsAddr = port->tableAddr; 2175a6afd9f3SGreg Kroah-Hartman baseAddr = port->board->basemem; 2176a6afd9f3SGreg Kroah-Hartman tx_mask = readw(ofsAddr + TX_mask); 2177a6afd9f3SGreg Kroah-Hartman spage = readw(ofsAddr + Page_txb); 2178a6afd9f3SGreg Kroah-Hartman epage = readw(ofsAddr + EndPage_txb); 2179a6afd9f3SGreg Kroah-Hartman tail = readw(ofsAddr + TXwptr); 2180a6afd9f3SGreg Kroah-Hartman head = readw(ofsAddr + TXrptr); 2181a6afd9f3SGreg Kroah-Hartman c = (head > tail) ? (head - tail - 1) : (head - tail + tx_mask); 2182a6afd9f3SGreg Kroah-Hartman if (c > len) 2183a6afd9f3SGreg Kroah-Hartman c = len; 2184a6afd9f3SGreg Kroah-Hartman moxaLog.txcnt[port->port.tty->index] += c; 2185a6afd9f3SGreg Kroah-Hartman total = c; 2186a6afd9f3SGreg Kroah-Hartman if (spage == epage) { 2187a6afd9f3SGreg Kroah-Hartman bufhead = readw(ofsAddr + Ofs_txb); 2188a6afd9f3SGreg Kroah-Hartman writew(spage, baseAddr + Control_reg); 2189a6afd9f3SGreg Kroah-Hartman while (c > 0) { 2190a6afd9f3SGreg Kroah-Hartman if (head > tail) 2191a6afd9f3SGreg Kroah-Hartman len = head - tail - 1; 2192a6afd9f3SGreg Kroah-Hartman else 2193a6afd9f3SGreg Kroah-Hartman len = tx_mask + 1 - tail; 2194a6afd9f3SGreg Kroah-Hartman len = (c > len) ? len : c; 2195a6afd9f3SGreg Kroah-Hartman ofs = baseAddr + DynPage_addr + bufhead + tail; 2196a6afd9f3SGreg Kroah-Hartman memcpy_toio(ofs, buffer, len); 2197a6afd9f3SGreg Kroah-Hartman buffer += len; 2198a6afd9f3SGreg Kroah-Hartman tail = (tail + len) & tx_mask; 2199a6afd9f3SGreg Kroah-Hartman c -= len; 2200a6afd9f3SGreg Kroah-Hartman } 2201a6afd9f3SGreg Kroah-Hartman } else { 2202a6afd9f3SGreg Kroah-Hartman pageno = spage + (tail >> 13); 2203a6afd9f3SGreg Kroah-Hartman pageofs = tail & Page_mask; 2204a6afd9f3SGreg Kroah-Hartman while (c > 0) { 2205a6afd9f3SGreg Kroah-Hartman len = Page_size - pageofs; 2206a6afd9f3SGreg Kroah-Hartman if (len > c) 2207a6afd9f3SGreg Kroah-Hartman len = c; 2208a6afd9f3SGreg Kroah-Hartman writeb(pageno, baseAddr + Control_reg); 2209a6afd9f3SGreg Kroah-Hartman ofs = baseAddr + DynPage_addr + pageofs; 2210a6afd9f3SGreg Kroah-Hartman memcpy_toio(ofs, buffer, len); 2211a6afd9f3SGreg Kroah-Hartman buffer += len; 2212a6afd9f3SGreg Kroah-Hartman if (++pageno == epage) 2213a6afd9f3SGreg Kroah-Hartman pageno = spage; 2214a6afd9f3SGreg Kroah-Hartman pageofs = 0; 2215a6afd9f3SGreg Kroah-Hartman c -= len; 2216a6afd9f3SGreg Kroah-Hartman } 2217a6afd9f3SGreg Kroah-Hartman tail = (tail + total) & tx_mask; 2218a6afd9f3SGreg Kroah-Hartman } 2219a6afd9f3SGreg Kroah-Hartman writew(tail, ofsAddr + TXwptr); 2220a6afd9f3SGreg Kroah-Hartman writeb(1, ofsAddr + CD180TXirq); /* start to send */ 2221a6afd9f3SGreg Kroah-Hartman return total; 2222a6afd9f3SGreg Kroah-Hartman } 2223a6afd9f3SGreg Kroah-Hartman 2224a6afd9f3SGreg Kroah-Hartman static int MoxaPortReadData(struct moxa_port *port) 2225a6afd9f3SGreg Kroah-Hartman { 2226a6afd9f3SGreg Kroah-Hartman struct tty_struct *tty = port->port.tty; 2227a6afd9f3SGreg Kroah-Hartman unsigned char *dst; 2228a6afd9f3SGreg Kroah-Hartman void __iomem *baseAddr, *ofsAddr, *ofs; 2229a6afd9f3SGreg Kroah-Hartman unsigned int count, len, total; 2230a6afd9f3SGreg Kroah-Hartman u16 tail, rx_mask, spage, epage; 2231a6afd9f3SGreg Kroah-Hartman u16 pageno, pageofs, bufhead, head; 2232a6afd9f3SGreg Kroah-Hartman 2233a6afd9f3SGreg Kroah-Hartman ofsAddr = port->tableAddr; 2234a6afd9f3SGreg Kroah-Hartman baseAddr = port->board->basemem; 2235a6afd9f3SGreg Kroah-Hartman head = readw(ofsAddr + RXrptr); 2236a6afd9f3SGreg Kroah-Hartman tail = readw(ofsAddr + RXwptr); 2237a6afd9f3SGreg Kroah-Hartman rx_mask = readw(ofsAddr + RX_mask); 2238a6afd9f3SGreg Kroah-Hartman spage = readw(ofsAddr + Page_rxb); 2239a6afd9f3SGreg Kroah-Hartman epage = readw(ofsAddr + EndPage_rxb); 2240a6afd9f3SGreg Kroah-Hartman count = (tail >= head) ? (tail - head) : (tail - head + rx_mask + 1); 2241a6afd9f3SGreg Kroah-Hartman if (count == 0) 2242a6afd9f3SGreg Kroah-Hartman return 0; 2243a6afd9f3SGreg Kroah-Hartman 2244a6afd9f3SGreg Kroah-Hartman total = count; 2245a6afd9f3SGreg Kroah-Hartman moxaLog.rxcnt[tty->index] += total; 2246a6afd9f3SGreg Kroah-Hartman if (spage == epage) { 2247a6afd9f3SGreg Kroah-Hartman bufhead = readw(ofsAddr + Ofs_rxb); 2248a6afd9f3SGreg Kroah-Hartman writew(spage, baseAddr + Control_reg); 2249a6afd9f3SGreg Kroah-Hartman while (count > 0) { 2250a6afd9f3SGreg Kroah-Hartman ofs = baseAddr + DynPage_addr + bufhead + head; 2251a6afd9f3SGreg Kroah-Hartman len = (tail >= head) ? (tail - head) : 2252a6afd9f3SGreg Kroah-Hartman (rx_mask + 1 - head); 22532f693357SJiri Slaby len = tty_prepare_flip_string(&port->port, &dst, 2254a6afd9f3SGreg Kroah-Hartman min(len, count)); 2255a6afd9f3SGreg Kroah-Hartman memcpy_fromio(dst, ofs, len); 2256a6afd9f3SGreg Kroah-Hartman head = (head + len) & rx_mask; 2257a6afd9f3SGreg Kroah-Hartman count -= len; 2258a6afd9f3SGreg Kroah-Hartman } 2259a6afd9f3SGreg Kroah-Hartman } else { 2260a6afd9f3SGreg Kroah-Hartman pageno = spage + (head >> 13); 2261a6afd9f3SGreg Kroah-Hartman pageofs = head & Page_mask; 2262a6afd9f3SGreg Kroah-Hartman while (count > 0) { 2263a6afd9f3SGreg Kroah-Hartman writew(pageno, baseAddr + Control_reg); 2264a6afd9f3SGreg Kroah-Hartman ofs = baseAddr + DynPage_addr + pageofs; 22652f693357SJiri Slaby len = tty_prepare_flip_string(&port->port, &dst, 2266a6afd9f3SGreg Kroah-Hartman min(Page_size - pageofs, count)); 2267a6afd9f3SGreg Kroah-Hartman memcpy_fromio(dst, ofs, len); 2268a6afd9f3SGreg Kroah-Hartman 2269a6afd9f3SGreg Kroah-Hartman count -= len; 2270a6afd9f3SGreg Kroah-Hartman pageofs = (pageofs + len) & Page_mask; 2271a6afd9f3SGreg Kroah-Hartman if (pageofs == 0 && ++pageno == epage) 2272a6afd9f3SGreg Kroah-Hartman pageno = spage; 2273a6afd9f3SGreg Kroah-Hartman } 2274a6afd9f3SGreg Kroah-Hartman head = (head + total) & rx_mask; 2275a6afd9f3SGreg Kroah-Hartman } 2276a6afd9f3SGreg Kroah-Hartman writew(head, ofsAddr + RXrptr); 2277a6afd9f3SGreg Kroah-Hartman if (readb(ofsAddr + FlagStat) & Xoff_state) { 2278a6afd9f3SGreg Kroah-Hartman moxaLowWaterChk = 1; 2279a6afd9f3SGreg Kroah-Hartman port->lowChkFlag = 1; 2280a6afd9f3SGreg Kroah-Hartman } 2281a6afd9f3SGreg Kroah-Hartman return total; 2282a6afd9f3SGreg Kroah-Hartman } 2283a6afd9f3SGreg Kroah-Hartman 2284a6afd9f3SGreg Kroah-Hartman 2285fff4ef17SJiri Slaby static unsigned int MoxaPortTxQueue(struct moxa_port *port) 2286a6afd9f3SGreg Kroah-Hartman { 2287a6afd9f3SGreg Kroah-Hartman void __iomem *ofsAddr = port->tableAddr; 2288a6afd9f3SGreg Kroah-Hartman u16 rptr, wptr, mask; 2289a6afd9f3SGreg Kroah-Hartman 2290a6afd9f3SGreg Kroah-Hartman rptr = readw(ofsAddr + TXrptr); 2291a6afd9f3SGreg Kroah-Hartman wptr = readw(ofsAddr + TXwptr); 2292a6afd9f3SGreg Kroah-Hartman mask = readw(ofsAddr + TX_mask); 2293a6afd9f3SGreg Kroah-Hartman return (wptr - rptr) & mask; 2294a6afd9f3SGreg Kroah-Hartman } 2295a6afd9f3SGreg Kroah-Hartman 229603b3b1a2SJiri Slaby static unsigned int MoxaPortTxFree(struct moxa_port *port) 2297a6afd9f3SGreg Kroah-Hartman { 2298a6afd9f3SGreg Kroah-Hartman void __iomem *ofsAddr = port->tableAddr; 2299a6afd9f3SGreg Kroah-Hartman u16 rptr, wptr, mask; 2300a6afd9f3SGreg Kroah-Hartman 2301a6afd9f3SGreg Kroah-Hartman rptr = readw(ofsAddr + TXrptr); 2302a6afd9f3SGreg Kroah-Hartman wptr = readw(ofsAddr + TXwptr); 2303a6afd9f3SGreg Kroah-Hartman mask = readw(ofsAddr + TX_mask); 2304a6afd9f3SGreg Kroah-Hartman return mask - ((wptr - rptr) & mask); 2305a6afd9f3SGreg Kroah-Hartman } 2306a6afd9f3SGreg Kroah-Hartman 2307a6afd9f3SGreg Kroah-Hartman static int MoxaPortRxQueue(struct moxa_port *port) 2308a6afd9f3SGreg Kroah-Hartman { 2309a6afd9f3SGreg Kroah-Hartman void __iomem *ofsAddr = port->tableAddr; 2310a6afd9f3SGreg Kroah-Hartman u16 rptr, wptr, mask; 2311a6afd9f3SGreg Kroah-Hartman 2312a6afd9f3SGreg Kroah-Hartman rptr = readw(ofsAddr + RXrptr); 2313a6afd9f3SGreg Kroah-Hartman wptr = readw(ofsAddr + RXwptr); 2314a6afd9f3SGreg Kroah-Hartman mask = readw(ofsAddr + RX_mask); 2315a6afd9f3SGreg Kroah-Hartman return (wptr - rptr) & mask; 2316a6afd9f3SGreg Kroah-Hartman } 2317a6afd9f3SGreg Kroah-Hartman 2318a6afd9f3SGreg Kroah-Hartman static void MoxaPortTxDisable(struct moxa_port *port) 2319a6afd9f3SGreg Kroah-Hartman { 2320a6afd9f3SGreg Kroah-Hartman moxafunc(port->tableAddr, FC_SetXoffState, Magic_code); 2321a6afd9f3SGreg Kroah-Hartman } 2322a6afd9f3SGreg Kroah-Hartman 2323a6afd9f3SGreg Kroah-Hartman static void MoxaPortTxEnable(struct moxa_port *port) 2324a6afd9f3SGreg Kroah-Hartman { 2325a6afd9f3SGreg Kroah-Hartman moxafunc(port->tableAddr, FC_SetXonState, Magic_code); 2326a6afd9f3SGreg Kroah-Hartman } 2327a6afd9f3SGreg Kroah-Hartman 23281c729ab1SAl Viro static int moxa_get_serial_info(struct tty_struct *tty, 23291c729ab1SAl Viro struct serial_struct *ss) 2330a6afd9f3SGreg Kroah-Hartman { 23311c729ab1SAl Viro struct moxa_port *info = tty->driver_data; 23321c729ab1SAl Viro 23331c729ab1SAl Viro if (tty->index == MAX_PORTS) 23341c729ab1SAl Viro return -EINVAL; 23351c729ab1SAl Viro if (!info) 23361c729ab1SAl Viro return -ENODEV; 23371c729ab1SAl Viro mutex_lock(&info->port.mutex); 2338322003b9SDan Carpenter ss->type = info->type; 2339322003b9SDan Carpenter ss->line = info->port.tty->index; 2340322003b9SDan Carpenter ss->flags = info->port.flags; 2341322003b9SDan Carpenter ss->baud_base = 921600; 23426e70b73cSJohan Hovold ss->close_delay = jiffies_to_msecs(info->port.close_delay) / 10; 23431c729ab1SAl Viro mutex_unlock(&info->port.mutex); 23441c729ab1SAl Viro return 0; 2345a6afd9f3SGreg Kroah-Hartman } 2346a6afd9f3SGreg Kroah-Hartman 2347a6afd9f3SGreg Kroah-Hartman 23481c729ab1SAl Viro static int moxa_set_serial_info(struct tty_struct *tty, 23491c729ab1SAl Viro struct serial_struct *ss) 2350a6afd9f3SGreg Kroah-Hartman { 23511c729ab1SAl Viro struct moxa_port *info = tty->driver_data; 2352dc8c8437SJohan Hovold unsigned int close_delay; 2353a6afd9f3SGreg Kroah-Hartman 23541c729ab1SAl Viro if (tty->index == MAX_PORTS) 23551c729ab1SAl Viro return -EINVAL; 23561c729ab1SAl Viro if (!info) 23571c729ab1SAl Viro return -ENODEV; 2358a6afd9f3SGreg Kroah-Hartman 2359dc8c8437SJohan Hovold close_delay = msecs_to_jiffies(ss->close_delay * 10); 2360dc8c8437SJohan Hovold 23611c729ab1SAl Viro mutex_lock(&info->port.mutex); 2362a6afd9f3SGreg Kroah-Hartman if (!capable(CAP_SYS_ADMIN)) { 2363dc8c8437SJohan Hovold if (close_delay != info->port.close_delay || 2364dc8c8437SJohan Hovold ss->type != info->type || 2365dc8c8437SJohan Hovold ((ss->flags & ~ASYNC_USR_MASK) != 23661c729ab1SAl Viro (info->port.flags & ~ASYNC_USR_MASK))) { 23671c729ab1SAl Viro mutex_unlock(&info->port.mutex); 2368a6afd9f3SGreg Kroah-Hartman return -EPERM; 23691c729ab1SAl Viro } 2370dc8c8437SJohan Hovold } else { 2371dc8c8437SJohan Hovold info->port.close_delay = close_delay; 2372a6afd9f3SGreg Kroah-Hartman 23731c729ab1SAl Viro MoxaSetFifo(info, ss->type == PORT_16550A); 2374a6afd9f3SGreg Kroah-Hartman 23751c729ab1SAl Viro info->type = ss->type; 2376dc8c8437SJohan Hovold } 23771c729ab1SAl Viro mutex_unlock(&info->port.mutex); 2378a6afd9f3SGreg Kroah-Hartman return 0; 2379a6afd9f3SGreg Kroah-Hartman } 2380a6afd9f3SGreg Kroah-Hartman 2381a6afd9f3SGreg Kroah-Hartman 2382a6afd9f3SGreg Kroah-Hartman 2383a6afd9f3SGreg Kroah-Hartman /***************************************************************************** 2384a6afd9f3SGreg Kroah-Hartman * Static local functions: * 2385a6afd9f3SGreg Kroah-Hartman *****************************************************************************/ 2386a6afd9f3SGreg Kroah-Hartman 2387a6afd9f3SGreg Kroah-Hartman static void MoxaSetFifo(struct moxa_port *port, int enable) 2388a6afd9f3SGreg Kroah-Hartman { 2389a6afd9f3SGreg Kroah-Hartman void __iomem *ofsAddr = port->tableAddr; 2390a6afd9f3SGreg Kroah-Hartman 2391a6afd9f3SGreg Kroah-Hartman if (!enable) { 2392a6afd9f3SGreg Kroah-Hartman moxafunc(ofsAddr, FC_SetRxFIFOTrig, 0); 2393a6afd9f3SGreg Kroah-Hartman moxafunc(ofsAddr, FC_SetTxFIFOCnt, 1); 2394a6afd9f3SGreg Kroah-Hartman } else { 2395a6afd9f3SGreg Kroah-Hartman moxafunc(ofsAddr, FC_SetRxFIFOTrig, 3); 2396a6afd9f3SGreg Kroah-Hartman moxafunc(ofsAddr, FC_SetTxFIFOCnt, 16); 2397a6afd9f3SGreg Kroah-Hartman } 2398a6afd9f3SGreg Kroah-Hartman } 2399