/drivers/char/synclink.c
https://bitbucket.org/evzijst/gittest · C · 8214 lines · 4490 code · 1386 blank · 2338 comment · 948 complexity · c6885025eab792ef4139b80b7ffa6901 MD5 · raw file
Large files are truncated click here to view the full file
- /*
- * linux/drivers/char/synclink.c
- *
- * $Id: synclink.c,v 4.28 2004/08/11 19:30:01 paulkf Exp $
- *
- * Device driver for Microgate SyncLink ISA and PCI
- * high speed multiprotocol serial adapters.
- *
- * written by Paul Fulghum for Microgate Corporation
- * paulkf@microgate.com
- *
- * Microgate and SyncLink are trademarks of Microgate Corporation
- *
- * Derived from serial.c written by Theodore Ts'o and Linus Torvalds
- *
- * Original release 01/11/99
- *
- * This code is released under the GNU General Public License (GPL)
- *
- * This driver is primarily intended for use in synchronous
- * HDLC mode. Asynchronous mode is also provided.
- *
- * When operating in synchronous mode, each call to mgsl_write()
- * contains exactly one complete HDLC frame. Calling mgsl_put_char
- * will start assembling an HDLC frame that will not be sent until
- * mgsl_flush_chars or mgsl_write is called.
- *
- * Synchronous receive data is reported as complete frames. To accomplish
- * this, the TTY flip buffer is bypassed (too small to hold largest
- * frame and may fragment frames) and the line discipline
- * receive entry point is called directly.
- *
- * This driver has been tested with a slightly modified ppp.c driver
- * for synchronous PPP.
- *
- * 2000/02/16
- * Added interface for syncppp.c driver (an alternate synchronous PPP
- * implementation that also supports Cisco HDLC). Each device instance
- * registers as a tty device AND a network device (if dosyncppp option
- * is set for the device). The functionality is determined by which
- * device interface is opened.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- #if defined(__i386__)
- # define BREAKPOINT() asm(" int $3");
- #else
- # define BREAKPOINT() { }
- #endif
- #define MAX_ISA_DEVICES 10
- #define MAX_PCI_DEVICES 10
- #define MAX_TOTAL_DEVICES 20
- #include <linux/config.h>
- #include <linux/module.h>
- #include <linux/errno.h>
- #include <linux/signal.h>
- #include <linux/sched.h>
- #include <linux/timer.h>
- #include <linux/interrupt.h>
- #include <linux/pci.h>
- #include <linux/tty.h>
- #include <linux/tty_flip.h>
- #include <linux/serial.h>
- #include <linux/major.h>
- #include <linux/string.h>
- #include <linux/fcntl.h>
- #include <linux/ptrace.h>
- #include <linux/ioport.h>
- #include <linux/mm.h>
- #include <linux/slab.h>
- #include <linux/delay.h>
- #include <linux/netdevice.h>
- #include <linux/vmalloc.h>
- #include <linux/init.h>
- #include <asm/serial.h>
- #include <linux/delay.h>
- #include <linux/ioctl.h>
- #include <asm/system.h>
- #include <asm/io.h>
- #include <asm/irq.h>
- #include <asm/dma.h>
- #include <linux/bitops.h>
- #include <asm/types.h>
- #include <linux/termios.h>
- #include <linux/workqueue.h>
- #include <linux/hdlc.h>
- #ifdef CONFIG_HDLC_MODULE
- #define CONFIG_HDLC 1
- #endif
- #define GET_USER(error,value,addr) error = get_user(value,addr)
- #define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0
- #define PUT_USER(error,value,addr) error = put_user(value,addr)
- #define COPY_TO_USER(error,dest,src,size) error = copy_to_user(dest,src,size) ? -EFAULT : 0
- #include <asm/uaccess.h>
- #include "linux/synclink.h"
- #define RCLRVALUE 0xffff
- static MGSL_PARAMS default_params = {
- MGSL_MODE_HDLC, /* unsigned long mode */
- 0, /* unsigned char loopback; */
- HDLC_FLAG_UNDERRUN_ABORT15, /* unsigned short flags; */
- HDLC_ENCODING_NRZI_SPACE, /* unsigned char encoding; */
- 0, /* unsigned long clock_speed; */
- 0xff, /* unsigned char addr_filter; */
- HDLC_CRC_16_CCITT, /* unsigned short crc_type; */
- HDLC_PREAMBLE_LENGTH_8BITS, /* unsigned char preamble_length; */
- HDLC_PREAMBLE_PATTERN_NONE, /* unsigned char preamble; */
- 9600, /* unsigned long data_rate; */
- 8, /* unsigned char data_bits; */
- 1, /* unsigned char stop_bits; */
- ASYNC_PARITY_NONE /* unsigned char parity; */
- };
- #define SHARED_MEM_ADDRESS_SIZE 0x40000
- #define BUFFERLISTSIZE (PAGE_SIZE)
- #define DMABUFFERSIZE (PAGE_SIZE)
- #define MAXRXFRAMES 7
- typedef struct _DMABUFFERENTRY
- {
- u32 phys_addr; /* 32-bit flat physical address of data buffer */
- u16 count; /* buffer size/data count */
- u16 status; /* Control/status field */
- u16 rcc; /* character count field */
- u16 reserved; /* padding required by 16C32 */
- u32 link; /* 32-bit flat link to next buffer entry */
- char *virt_addr; /* virtual address of data buffer */
- u32 phys_entry; /* physical address of this buffer entry */
- } DMABUFFERENTRY, *DMAPBUFFERENTRY;
- /* The queue of BH actions to be performed */
- #define BH_RECEIVE 1
- #define BH_TRANSMIT 2
- #define BH_STATUS 4
- #define IO_PIN_SHUTDOWN_LIMIT 100
- #define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
- struct _input_signal_events {
- int ri_up;
- int ri_down;
- int dsr_up;
- int dsr_down;
- int dcd_up;
- int dcd_down;
- int cts_up;
- int cts_down;
- };
- /* transmit holding buffer definitions*/
- #define MAX_TX_HOLDING_BUFFERS 5
- struct tx_holding_buffer {
- int buffer_size;
- unsigned char * buffer;
- };
- /*
- * Device instance data structure
- */
-
- struct mgsl_struct {
- int magic;
- int flags;
- int count; /* count of opens */
- int line;
- int hw_version;
- unsigned short close_delay;
- unsigned short closing_wait; /* time to wait before closing */
-
- struct mgsl_icount icount;
-
- struct tty_struct *tty;
- int timeout;
- int x_char; /* xon/xoff character */
- int blocked_open; /* # of blocked opens */
- u16 read_status_mask;
- u16 ignore_status_mask;
- unsigned char *xmit_buf;
- int xmit_head;
- int xmit_tail;
- int xmit_cnt;
-
- wait_queue_head_t open_wait;
- wait_queue_head_t close_wait;
-
- wait_queue_head_t status_event_wait_q;
- wait_queue_head_t event_wait_q;
- struct timer_list tx_timer; /* HDLC transmit timeout timer */
- struct mgsl_struct *next_device; /* device list link */
-
- spinlock_t irq_spinlock; /* spinlock for synchronizing with ISR */
- struct work_struct task; /* task structure for scheduling bh */
- u32 EventMask; /* event trigger mask */
- u32 RecordedEvents; /* pending events */
- u32 max_frame_size; /* as set by device config */
- u32 pending_bh;
- int bh_running; /* Protection from multiple */
- int isr_overflow;
- int bh_requested;
-
- int dcd_chkcount; /* check counts to prevent */
- int cts_chkcount; /* too many IRQs if a signal */
- int dsr_chkcount; /* is floating */
- int ri_chkcount;
- char *buffer_list; /* virtual address of Rx & Tx buffer lists */
- unsigned long buffer_list_phys;
- unsigned int rx_buffer_count; /* count of total allocated Rx buffers */
- DMABUFFERENTRY *rx_buffer_list; /* list of receive buffer entries */
- unsigned int current_rx_buffer;
- int num_tx_dma_buffers; /* number of tx dma frames required */
- int tx_dma_buffers_used;
- unsigned int tx_buffer_count; /* count of total allocated Tx buffers */
- DMABUFFERENTRY *tx_buffer_list; /* list of transmit buffer entries */
- int start_tx_dma_buffer; /* tx dma buffer to start tx dma operation */
- int current_tx_buffer; /* next tx dma buffer to be loaded */
-
- unsigned char *intermediate_rxbuffer;
- int num_tx_holding_buffers; /* number of tx holding buffer allocated */
- int get_tx_holding_index; /* next tx holding buffer for adapter to load */
- int put_tx_holding_index; /* next tx holding buffer to store user request */
- int tx_holding_count; /* number of tx holding buffers waiting */
- struct tx_holding_buffer tx_holding_buffers[MAX_TX_HOLDING_BUFFERS];
- int rx_enabled;
- int rx_overflow;
- int rx_rcc_underrun;
- int tx_enabled;
- int tx_active;
- u32 idle_mode;
- u16 cmr_value;
- u16 tcsr_value;
- char device_name[25]; /* device instance name */
- unsigned int bus_type; /* expansion bus type (ISA,EISA,PCI) */
- unsigned char bus; /* expansion bus number (zero based) */
- unsigned char function; /* PCI device number */
- unsigned int io_base; /* base I/O address of adapter */
- unsigned int io_addr_size; /* size of the I/O address range */
- int io_addr_requested; /* nonzero if I/O address requested */
-
- unsigned int irq_level; /* interrupt level */
- unsigned long irq_flags;
- int irq_requested; /* nonzero if IRQ requested */
-
- unsigned int dma_level; /* DMA channel */
- int dma_requested; /* nonzero if dma channel requested */
- u16 mbre_bit;
- u16 loopback_bits;
- u16 usc_idle_mode;
- MGSL_PARAMS params; /* communications parameters */
- unsigned char serial_signals; /* current serial signal states */
- int irq_occurred; /* for diagnostics use */
- unsigned int init_error; /* Initialization startup error (DIAGS) */
- int fDiagnosticsmode; /* Driver in Diagnostic mode? (DIAGS) */
- u32 last_mem_alloc;
- unsigned char* memory_base; /* shared memory address (PCI only) */
- u32 phys_memory_base;
- int shared_mem_requested;
- unsigned char* lcr_base; /* local config registers (PCI only) */
- u32 phys_lcr_base;
- u32 lcr_offset;
- int lcr_mem_requested;
- u32 misc_ctrl_value;
- char flag_buf[MAX_ASYNC_BUFFER_SIZE];
- char char_buf[MAX_ASYNC_BUFFER_SIZE];
- BOOLEAN drop_rts_on_tx_done;
- BOOLEAN loopmode_insert_requested;
- BOOLEAN loopmode_send_done_requested;
-
- struct _input_signal_events input_signal_events;
- /* generic HDLC device parts */
- int netcount;
- int dosyncppp;
- spinlock_t netlock;
- #ifdef CONFIG_HDLC
- struct net_device *netdev;
- #endif
- };
- #define MGSL_MAGIC 0x5401
- /*
- * The size of the serial xmit buffer is 1 page, or 4096 bytes
- */
- #ifndef SERIAL_XMIT_SIZE
- #define SERIAL_XMIT_SIZE 4096
- #endif
- /*
- * These macros define the offsets used in calculating the
- * I/O address of the specified USC registers.
- */
- #define DCPIN 2 /* Bit 1 of I/O address */
- #define SDPIN 4 /* Bit 2 of I/O address */
- #define DCAR 0 /* DMA command/address register */
- #define CCAR SDPIN /* channel command/address register */
- #define DATAREG DCPIN + SDPIN /* serial data register */
- #define MSBONLY 0x41
- #define LSBONLY 0x40
- /*
- * These macros define the register address (ordinal number)
- * used for writing address/value pairs to the USC.
- */
- #define CMR 0x02 /* Channel mode Register */
- #define CCSR 0x04 /* Channel Command/status Register */
- #define CCR 0x06 /* Channel Control Register */
- #define PSR 0x08 /* Port status Register */
- #define PCR 0x0a /* Port Control Register */
- #define TMDR 0x0c /* Test mode Data Register */
- #define TMCR 0x0e /* Test mode Control Register */
- #define CMCR 0x10 /* Clock mode Control Register */
- #define HCR 0x12 /* Hardware Configuration Register */
- #define IVR 0x14 /* Interrupt Vector Register */
- #define IOCR 0x16 /* Input/Output Control Register */
- #define ICR 0x18 /* Interrupt Control Register */
- #define DCCR 0x1a /* Daisy Chain Control Register */
- #define MISR 0x1c /* Misc Interrupt status Register */
- #define SICR 0x1e /* status Interrupt Control Register */
- #define RDR 0x20 /* Receive Data Register */
- #define RMR 0x22 /* Receive mode Register */
- #define RCSR 0x24 /* Receive Command/status Register */
- #define RICR 0x26 /* Receive Interrupt Control Register */
- #define RSR 0x28 /* Receive Sync Register */
- #define RCLR 0x2a /* Receive count Limit Register */
- #define RCCR 0x2c /* Receive Character count Register */
- #define TC0R 0x2e /* Time Constant 0 Register */
- #define TDR 0x30 /* Transmit Data Register */
- #define TMR 0x32 /* Transmit mode Register */
- #define TCSR 0x34 /* Transmit Command/status Register */
- #define TICR 0x36 /* Transmit Interrupt Control Register */
- #define TSR 0x38 /* Transmit Sync Register */
- #define TCLR 0x3a /* Transmit count Limit Register */
- #define TCCR 0x3c /* Transmit Character count Register */
- #define TC1R 0x3e /* Time Constant 1 Register */
- /*
- * MACRO DEFINITIONS FOR DMA REGISTERS
- */
- #define DCR 0x06 /* DMA Control Register (shared) */
- #define DACR 0x08 /* DMA Array count Register (shared) */
- #define BDCR 0x12 /* Burst/Dwell Control Register (shared) */
- #define DIVR 0x14 /* DMA Interrupt Vector Register (shared) */
- #define DICR 0x18 /* DMA Interrupt Control Register (shared) */
- #define CDIR 0x1a /* Clear DMA Interrupt Register (shared) */
- #define SDIR 0x1c /* Set DMA Interrupt Register (shared) */
- #define TDMR 0x02 /* Transmit DMA mode Register */
- #define TDIAR 0x1e /* Transmit DMA Interrupt Arm Register */
- #define TBCR 0x2a /* Transmit Byte count Register */
- #define TARL 0x2c /* Transmit Address Register (low) */
- #define TARU 0x2e /* Transmit Address Register (high) */
- #define NTBCR 0x3a /* Next Transmit Byte count Register */
- #define NTARL 0x3c /* Next Transmit Address Register (low) */
- #define NTARU 0x3e /* Next Transmit Address Register (high) */
- #define RDMR 0x82 /* Receive DMA mode Register (non-shared) */
- #define RDIAR 0x9e /* Receive DMA Interrupt Arm Register */
- #define RBCR 0xaa /* Receive Byte count Register */
- #define RARL 0xac /* Receive Address Register (low) */
- #define RARU 0xae /* Receive Address Register (high) */
- #define NRBCR 0xba /* Next Receive Byte count Register */
- #define NRARL 0xbc /* Next Receive Address Register (low) */
- #define NRARU 0xbe /* Next Receive Address Register (high) */
- /*
- * MACRO DEFINITIONS FOR MODEM STATUS BITS
- */
- #define MODEMSTATUS_DTR 0x80
- #define MODEMSTATUS_DSR 0x40
- #define MODEMSTATUS_RTS 0x20
- #define MODEMSTATUS_CTS 0x10
- #define MODEMSTATUS_RI 0x04
- #define MODEMSTATUS_DCD 0x01
- /*
- * Channel Command/Address Register (CCAR) Command Codes
- */
- #define RTCmd_Null 0x0000
- #define RTCmd_ResetHighestIus 0x1000
- #define RTCmd_TriggerChannelLoadDma 0x2000
- #define RTCmd_TriggerRxDma 0x2800
- #define RTCmd_TriggerTxDma 0x3000
- #define RTCmd_TriggerRxAndTxDma 0x3800
- #define RTCmd_PurgeRxFifo 0x4800
- #define RTCmd_PurgeTxFifo 0x5000
- #define RTCmd_PurgeRxAndTxFifo 0x5800
- #define RTCmd_LoadRcc 0x6800
- #define RTCmd_LoadTcc 0x7000
- #define RTCmd_LoadRccAndTcc 0x7800
- #define RTCmd_LoadTC0 0x8800
- #define RTCmd_LoadTC1 0x9000
- #define RTCmd_LoadTC0AndTC1 0x9800
- #define RTCmd_SerialDataLSBFirst 0xa000
- #define RTCmd_SerialDataMSBFirst 0xa800
- #define RTCmd_SelectBigEndian 0xb000
- #define RTCmd_SelectLittleEndian 0xb800
- /*
- * DMA Command/Address Register (DCAR) Command Codes
- */
- #define DmaCmd_Null 0x0000
- #define DmaCmd_ResetTxChannel 0x1000
- #define DmaCmd_ResetRxChannel 0x1200
- #define DmaCmd_StartTxChannel 0x2000
- #define DmaCmd_StartRxChannel 0x2200
- #define DmaCmd_ContinueTxChannel 0x3000
- #define DmaCmd_ContinueRxChannel 0x3200
- #define DmaCmd_PauseTxChannel 0x4000
- #define DmaCmd_PauseRxChannel 0x4200
- #define DmaCmd_AbortTxChannel 0x5000
- #define DmaCmd_AbortRxChannel 0x5200
- #define DmaCmd_InitTxChannel 0x7000
- #define DmaCmd_InitRxChannel 0x7200
- #define DmaCmd_ResetHighestDmaIus 0x8000
- #define DmaCmd_ResetAllChannels 0x9000
- #define DmaCmd_StartAllChannels 0xa000
- #define DmaCmd_ContinueAllChannels 0xb000
- #define DmaCmd_PauseAllChannels 0xc000
- #define DmaCmd_AbortAllChannels 0xd000
- #define DmaCmd_InitAllChannels 0xf000
- #define TCmd_Null 0x0000
- #define TCmd_ClearTxCRC 0x2000
- #define TCmd_SelectTicrTtsaData 0x4000
- #define TCmd_SelectTicrTxFifostatus 0x5000
- #define TCmd_SelectTicrIntLevel 0x6000
- #define TCmd_SelectTicrdma_level 0x7000
- #define TCmd_SendFrame 0x8000
- #define TCmd_SendAbort 0x9000
- #define TCmd_EnableDleInsertion 0xc000
- #define TCmd_DisableDleInsertion 0xd000
- #define TCmd_ClearEofEom 0xe000
- #define TCmd_SetEofEom 0xf000
- #define RCmd_Null 0x0000
- #define RCmd_ClearRxCRC 0x2000
- #define RCmd_EnterHuntmode 0x3000
- #define RCmd_SelectRicrRtsaData 0x4000
- #define RCmd_SelectRicrRxFifostatus 0x5000
- #define RCmd_SelectRicrIntLevel 0x6000
- #define RCmd_SelectRicrdma_level 0x7000
- /*
- * Bits for enabling and disabling IRQs in Interrupt Control Register (ICR)
- */
-
- #define RECEIVE_STATUS BIT5
- #define RECEIVE_DATA BIT4
- #define TRANSMIT_STATUS BIT3
- #define TRANSMIT_DATA BIT2
- #define IO_PIN BIT1
- #define MISC BIT0
- /*
- * Receive status Bits in Receive Command/status Register RCSR
- */
- #define RXSTATUS_SHORT_FRAME BIT8
- #define RXSTATUS_CODE_VIOLATION BIT8
- #define RXSTATUS_EXITED_HUNT BIT7
- #define RXSTATUS_IDLE_RECEIVED BIT6
- #define RXSTATUS_BREAK_RECEIVED BIT5
- #define RXSTATUS_ABORT_RECEIVED BIT5
- #define RXSTATUS_RXBOUND BIT4
- #define RXSTATUS_CRC_ERROR BIT3
- #define RXSTATUS_FRAMING_ERROR BIT3
- #define RXSTATUS_ABORT BIT2
- #define RXSTATUS_PARITY_ERROR BIT2
- #define RXSTATUS_OVERRUN BIT1
- #define RXSTATUS_DATA_AVAILABLE BIT0
- #define RXSTATUS_ALL 0x01f6
- #define usc_UnlatchRxstatusBits(a,b) usc_OutReg( (a), RCSR, (u16)((b) & RXSTATUS_ALL) )
- /*
- * Values for setting transmit idle mode in
- * Transmit Control/status Register (TCSR)
- */
- #define IDLEMODE_FLAGS 0x0000
- #define IDLEMODE_ALT_ONE_ZERO 0x0100
- #define IDLEMODE_ZERO 0x0200
- #define IDLEMODE_ONE 0x0300
- #define IDLEMODE_ALT_MARK_SPACE 0x0500
- #define IDLEMODE_SPACE 0x0600
- #define IDLEMODE_MARK 0x0700
- #define IDLEMODE_MASK 0x0700
- /*
- * IUSC revision identifiers
- */
- #define IUSC_SL1660 0x4d44
- #define IUSC_PRE_SL1660 0x4553
- /*
- * Transmit status Bits in Transmit Command/status Register (TCSR)
- */
- #define TCSR_PRESERVE 0x0F00
- #define TCSR_UNDERWAIT BIT11
- #define TXSTATUS_PREAMBLE_SENT BIT7
- #define TXSTATUS_IDLE_SENT BIT6
- #define TXSTATUS_ABORT_SENT BIT5
- #define TXSTATUS_EOF_SENT BIT4
- #define TXSTATUS_EOM_SENT BIT4
- #define TXSTATUS_CRC_SENT BIT3
- #define TXSTATUS_ALL_SENT BIT2
- #define TXSTATUS_UNDERRUN BIT1
- #define TXSTATUS_FIFO_EMPTY BIT0
- #define TXSTATUS_ALL 0x00fa
- #define usc_UnlatchTxstatusBits(a,b) usc_OutReg( (a), TCSR, (u16)((a)->tcsr_value + ((b) & 0x00FF)) )
-
- #define MISCSTATUS_RXC_LATCHED BIT15
- #define MISCSTATUS_RXC BIT14
- #define MISCSTATUS_TXC_LATCHED BIT13
- #define MISCSTATUS_TXC BIT12
- #define MISCSTATUS_RI_LATCHED BIT11
- #define MISCSTATUS_RI BIT10
- #define MISCSTATUS_DSR_LATCHED BIT9
- #define MISCSTATUS_DSR BIT8
- #define MISCSTATUS_DCD_LATCHED BIT7
- #define MISCSTATUS_DCD BIT6
- #define MISCSTATUS_CTS_LATCHED BIT5
- #define MISCSTATUS_CTS BIT4
- #define MISCSTATUS_RCC_UNDERRUN BIT3
- #define MISCSTATUS_DPLL_NO_SYNC BIT2
- #define MISCSTATUS_BRG1_ZERO BIT1
- #define MISCSTATUS_BRG0_ZERO BIT0
- #define usc_UnlatchIostatusBits(a,b) usc_OutReg((a),MISR,(u16)((b) & 0xaaa0))
- #define usc_UnlatchMiscstatusBits(a,b) usc_OutReg((a),MISR,(u16)((b) & 0x000f))
- #define SICR_RXC_ACTIVE BIT15
- #define SICR_RXC_INACTIVE BIT14
- #define SICR_RXC (BIT15+BIT14)
- #define SICR_TXC_ACTIVE BIT13
- #define SICR_TXC_INACTIVE BIT12
- #define SICR_TXC (BIT13+BIT12)
- #define SICR_RI_ACTIVE BIT11
- #define SICR_RI_INACTIVE BIT10
- #define SICR_RI (BIT11+BIT10)
- #define SICR_DSR_ACTIVE BIT9
- #define SICR_DSR_INACTIVE BIT8
- #define SICR_DSR (BIT9+BIT8)
- #define SICR_DCD_ACTIVE BIT7
- #define SICR_DCD_INACTIVE BIT6
- #define SICR_DCD (BIT7+BIT6)
- #define SICR_CTS_ACTIVE BIT5
- #define SICR_CTS_INACTIVE BIT4
- #define SICR_CTS (BIT5+BIT4)
- #define SICR_RCC_UNDERFLOW BIT3
- #define SICR_DPLL_NO_SYNC BIT2
- #define SICR_BRG1_ZERO BIT1
- #define SICR_BRG0_ZERO BIT0
- void usc_DisableMasterIrqBit( struct mgsl_struct *info );
- void usc_EnableMasterIrqBit( struct mgsl_struct *info );
- void usc_EnableInterrupts( struct mgsl_struct *info, u16 IrqMask );
- void usc_DisableInterrupts( struct mgsl_struct *info, u16 IrqMask );
- void usc_ClearIrqPendingBits( struct mgsl_struct *info, u16 IrqMask );
- #define usc_EnableInterrupts( a, b ) \
- usc_OutReg( (a), ICR, (u16)((usc_InReg((a),ICR) & 0xff00) + 0xc0 + (b)) )
- #define usc_DisableInterrupts( a, b ) \
- usc_OutReg( (a), ICR, (u16)((usc_InReg((a),ICR) & 0xff00) + 0x80 + (b)) )
- #define usc_EnableMasterIrqBit(a) \
- usc_OutReg( (a), ICR, (u16)((usc_InReg((a),ICR) & 0x0f00) + 0xb000) )
- #define usc_DisableMasterIrqBit(a) \
- usc_OutReg( (a), ICR, (u16)(usc_InReg((a),ICR) & 0x7f00) )
- #define usc_ClearIrqPendingBits( a, b ) usc_OutReg( (a), DCCR, 0x40 + (b) )
- /*
- * Transmit status Bits in Transmit Control status Register (TCSR)
- * and Transmit Interrupt Control Register (TICR) (except BIT2, BIT0)
- */
- #define TXSTATUS_PREAMBLE_SENT BIT7
- #define TXSTATUS_IDLE_SENT BIT6
- #define TXSTATUS_ABORT_SENT BIT5
- #define TXSTATUS_EOF BIT4
- #define TXSTATUS_CRC_SENT BIT3
- #define TXSTATUS_ALL_SENT BIT2
- #define TXSTATUS_UNDERRUN BIT1
- #define TXSTATUS_FIFO_EMPTY BIT0
- #define DICR_MASTER BIT15
- #define DICR_TRANSMIT BIT0
- #define DICR_RECEIVE BIT1
- #define usc_EnableDmaInterrupts(a,b) \
- usc_OutDmaReg( (a), DICR, (u16)(usc_InDmaReg((a),DICR) | (b)) )
- #define usc_DisableDmaInterrupts(a,b) \
- usc_OutDmaReg( (a), DICR, (u16)(usc_InDmaReg((a),DICR) & ~(b)) )
- #define usc_EnableStatusIrqs(a,b) \
- usc_OutReg( (a), SICR, (u16)(usc_InReg((a),SICR) | (b)) )
- #define usc_DisablestatusIrqs(a,b) \
- usc_OutReg( (a), SICR, (u16)(usc_InReg((a),SICR) & ~(b)) )
- /* Transmit status Bits in Transmit Control status Register (TCSR) */
- /* and Transmit Interrupt Control Register (TICR) (except BIT2, BIT0) */
- #define DISABLE_UNCONDITIONAL 0
- #define DISABLE_END_OF_FRAME 1
- #define ENABLE_UNCONDITIONAL 2
- #define ENABLE_AUTO_CTS 3
- #define ENABLE_AUTO_DCD 3
- #define usc_EnableTransmitter(a,b) \
- usc_OutReg( (a), TMR, (u16)((usc_InReg((a),TMR) & 0xfffc) | (b)) )
- #define usc_EnableReceiver(a,b) \
- usc_OutReg( (a), RMR, (u16)((usc_InReg((a),RMR) & 0xfffc) | (b)) )
- static u16 usc_InDmaReg( struct mgsl_struct *info, u16 Port );
- static void usc_OutDmaReg( struct mgsl_struct *info, u16 Port, u16 Value );
- static void usc_DmaCmd( struct mgsl_struct *info, u16 Cmd );
- static u16 usc_InReg( struct mgsl_struct *info, u16 Port );
- static void usc_OutReg( struct mgsl_struct *info, u16 Port, u16 Value );
- static void usc_RTCmd( struct mgsl_struct *info, u16 Cmd );
- void usc_RCmd( struct mgsl_struct *info, u16 Cmd );
- void usc_TCmd( struct mgsl_struct *info, u16 Cmd );
- #define usc_TCmd(a,b) usc_OutReg((a), TCSR, (u16)((a)->tcsr_value + (b)))
- #define usc_RCmd(a,b) usc_OutReg((a), RCSR, (b))
- #define usc_SetTransmitSyncChars(a,s0,s1) usc_OutReg((a), TSR, (u16)(((u16)s0<<8)|(u16)s1))
- static void usc_process_rxoverrun_sync( struct mgsl_struct *info );
- static void usc_start_receiver( struct mgsl_struct *info );
- static void usc_stop_receiver( struct mgsl_struct *info );
- static void usc_start_transmitter( struct mgsl_struct *info );
- static void usc_stop_transmitter( struct mgsl_struct *info );
- static void usc_set_txidle( struct mgsl_struct *info );
- static void usc_load_txfifo( struct mgsl_struct *info );
- static void usc_enable_aux_clock( struct mgsl_struct *info, u32 DataRate );
- static void usc_enable_loopback( struct mgsl_struct *info, int enable );
- static void usc_get_serial_signals( struct mgsl_struct *info );
- static void usc_set_serial_signals( struct mgsl_struct *info );
- static void usc_reset( struct mgsl_struct *info );
- static void usc_set_sync_mode( struct mgsl_struct *info );
- static void usc_set_sdlc_mode( struct mgsl_struct *info );
- static void usc_set_async_mode( struct mgsl_struct *info );
- static void usc_enable_async_clock( struct mgsl_struct *info, u32 DataRate );
- static void usc_loopback_frame( struct mgsl_struct *info );
- static void mgsl_tx_timeout(unsigned long context);
- static void usc_loopmode_cancel_transmit( struct mgsl_struct * info );
- static void usc_loopmode_insert_request( struct mgsl_struct * info );
- static int usc_loopmode_active( struct mgsl_struct * info);
- static void usc_loopmode_send_done( struct mgsl_struct * info );
- static int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigned long arg);
- #ifdef CONFIG_HDLC
- #define dev_to_port(D) (dev_to_hdlc(D)->priv)
- static void hdlcdev_tx_done(struct mgsl_struct *info);
- static void hdlcdev_rx(struct mgsl_struct *info, char *buf, int size);
- static int hdlcdev_init(struct mgsl_struct *info);
- static void hdlcdev_exit(struct mgsl_struct *info);
- #endif
- /*
- * Defines a BUS descriptor value for the PCI adapter
- * local bus address ranges.
- */
- #define BUS_DESCRIPTOR( WrHold, WrDly, RdDly, Nwdd, Nwad, Nxda, Nrdd, Nrad ) \
- (0x00400020 + \
- ((WrHold) << 30) + \
- ((WrDly) << 28) + \
- ((RdDly) << 26) + \
- ((Nwdd) << 20) + \
- ((Nwad) << 15) + \
- ((Nxda) << 13) + \
- ((Nrdd) << 11) + \
- ((Nrad) << 6) )
- static void mgsl_trace_block(struct mgsl_struct *info,const char* data, int count, int xmit);
- /*
- * Adapter diagnostic routines
- */
- static BOOLEAN mgsl_register_test( struct mgsl_struct *info );
- static BOOLEAN mgsl_irq_test( struct mgsl_struct *info );
- static BOOLEAN mgsl_dma_test( struct mgsl_struct *info );
- static BOOLEAN mgsl_memory_test( struct mgsl_struct *info );
- static int mgsl_adapter_test( struct mgsl_struct *info );
- /*
- * device and resource management routines
- */
- static int mgsl_claim_resources(struct mgsl_struct *info);
- static void mgsl_release_resources(struct mgsl_struct *info);
- static void mgsl_add_device(struct mgsl_struct *info);
- static struct mgsl_struct* mgsl_allocate_device(void);
- /*
- * DMA buffer manupulation functions.
- */
- static void mgsl_free_rx_frame_buffers( struct mgsl_struct *info, unsigned int StartIndex, unsigned int EndIndex );
- static int mgsl_get_rx_frame( struct mgsl_struct *info );
- static int mgsl_get_raw_rx_frame( struct mgsl_struct *info );
- static void mgsl_reset_rx_dma_buffers( struct mgsl_struct *info );
- static void mgsl_reset_tx_dma_buffers( struct mgsl_struct *info );
- static int num_free_tx_dma_buffers(struct mgsl_struct *info);
- static void mgsl_load_tx_dma_buffer( struct mgsl_struct *info, const char *Buffer, unsigned int BufferSize);
- static void mgsl_load_pci_memory(char* TargetPtr, const char* SourcePtr, unsigned short count);
- /*
- * DMA and Shared Memory buffer allocation and formatting
- */
- static int mgsl_allocate_dma_buffers(struct mgsl_struct *info);
- static void mgsl_free_dma_buffers(struct mgsl_struct *info);
- static int mgsl_alloc_frame_memory(struct mgsl_struct *info, DMABUFFERENTRY *BufferList,int Buffercount);
- static void mgsl_free_frame_memory(struct mgsl_struct *info, DMABUFFERENTRY *BufferList,int Buffercount);
- static int mgsl_alloc_buffer_list_memory(struct mgsl_struct *info);
- static void mgsl_free_buffer_list_memory(struct mgsl_struct *info);
- static int mgsl_alloc_intermediate_rxbuffer_memory(struct mgsl_struct *info);
- static void mgsl_free_intermediate_rxbuffer_memory(struct mgsl_struct *info);
- static int mgsl_alloc_intermediate_txbuffer_memory(struct mgsl_struct *info);
- static void mgsl_free_intermediate_txbuffer_memory(struct mgsl_struct *info);
- static int load_next_tx_holding_buffer(struct mgsl_struct *info);
- static int save_tx_buffer_request(struct mgsl_struct *info,const char *Buffer, unsigned int BufferSize);
- /*
- * Bottom half interrupt handlers
- */
- static void mgsl_bh_handler(void* Context);
- static void mgsl_bh_receive(struct mgsl_struct *info);
- static void mgsl_bh_transmit(struct mgsl_struct *info);
- static void mgsl_bh_status(struct mgsl_struct *info);
- /*
- * Interrupt handler routines and dispatch table.
- */
- static void mgsl_isr_null( struct mgsl_struct *info );
- static void mgsl_isr_transmit_data( struct mgsl_struct *info );
- static void mgsl_isr_receive_data( struct mgsl_struct *info );
- static void mgsl_isr_receive_status( struct mgsl_struct *info );
- static void mgsl_isr_transmit_status( struct mgsl_struct *info );
- static void mgsl_isr_io_pin( struct mgsl_struct *info );
- static void mgsl_isr_misc( struct mgsl_struct *info );
- static void mgsl_isr_receive_dma( struct mgsl_struct *info );
- static void mgsl_isr_transmit_dma( struct mgsl_struct *info );
- typedef void (*isr_dispatch_func)(struct mgsl_struct *);
- static isr_dispatch_func UscIsrTable[7] =
- {
- mgsl_isr_null,
- mgsl_isr_misc,
- mgsl_isr_io_pin,
- mgsl_isr_transmit_data,
- mgsl_isr_transmit_status,
- mgsl_isr_receive_data,
- mgsl_isr_receive_status
- };
- /*
- * ioctl call handlers
- */
- static int tiocmget(struct tty_struct *tty, struct file *file);
- static int tiocmset(struct tty_struct *tty, struct file *file,
- unsigned int set, unsigned int clear);
- static int mgsl_get_stats(struct mgsl_struct * info, struct mgsl_icount
- __user *user_icount);
- static int mgsl_get_params(struct mgsl_struct * info, MGSL_PARAMS __user *user_params);
- static int mgsl_set_params(struct mgsl_struct * info, MGSL_PARAMS __user *new_params);
- static int mgsl_get_txidle(struct mgsl_struct * info, int __user *idle_mode);
- static int mgsl_set_txidle(struct mgsl_struct * info, int idle_mode);
- static int mgsl_txenable(struct mgsl_struct * info, int enable);
- static int mgsl_txabort(struct mgsl_struct * info);
- static int mgsl_rxenable(struct mgsl_struct * info, int enable);
- static int mgsl_wait_event(struct mgsl_struct * info, int __user *mask);
- static int mgsl_loopmode_send_done( struct mgsl_struct * info );
- /* set non-zero on successful registration with PCI subsystem */
- static int pci_registered;
- /*
- * Global linked list of SyncLink devices
- */
- static struct mgsl_struct *mgsl_device_list;
- static int mgsl_device_count;
- /*
- * Set this param to non-zero to load eax with the
- * .text section address and breakpoint on module load.
- * This is useful for use with gdb and add-symbol-file command.
- */
- static int break_on_load;
- /*
- * Driver major number, defaults to zero to get auto
- * assigned major number. May be forced as module parameter.
- */
- static int ttymajor;
- /*
- * Array of user specified options for ISA adapters.
- */
- static int io[MAX_ISA_DEVICES];
- static int irq[MAX_ISA_DEVICES];
- static int dma[MAX_ISA_DEVICES];
- static int debug_level;
- static int maxframe[MAX_TOTAL_DEVICES];
- static int dosyncppp[MAX_TOTAL_DEVICES];
- static int txdmabufs[MAX_TOTAL_DEVICES];
- static int txholdbufs[MAX_TOTAL_DEVICES];
-
- module_param(break_on_load, bool, 0);
- module_param(ttymajor, int, 0);
- module_param_array(io, int, NULL, 0);
- module_param_array(irq, int, NULL, 0);
- module_param_array(dma, int, NULL, 0);
- module_param(debug_level, int, 0);
- module_param_array(maxframe, int, NULL, 0);
- module_param_array(dosyncppp, int, NULL, 0);
- module_param_array(txdmabufs, int, NULL, 0);
- module_param_array(txholdbufs, int, NULL, 0);
- static char *driver_name = "SyncLink serial driver";
- static char *driver_version = "$Revision: 4.28 $";
- static int synclink_init_one (struct pci_dev *dev,
- const struct pci_device_id *ent);
- static void synclink_remove_one (struct pci_dev *dev);
- static struct pci_device_id synclink_pci_tbl[] = {
- { PCI_VENDOR_ID_MICROGATE, PCI_DEVICE_ID_MICROGATE_USC, PCI_ANY_ID, PCI_ANY_ID, },
- { PCI_VENDOR_ID_MICROGATE, 0x0210, PCI_ANY_ID, PCI_ANY_ID, },
- { 0, }, /* terminate list */
- };
- MODULE_DEVICE_TABLE(pci, synclink_pci_tbl);
- MODULE_LICENSE("GPL");
- static struct pci_driver synclink_pci_driver = {
- .name = "synclink",
- .id_table = synclink_pci_tbl,
- .probe = synclink_init_one,
- .remove = __devexit_p(synclink_remove_one),
- };
- static struct tty_driver *serial_driver;
- /* number of characters left in xmit buffer before we ask for more */
- #define WAKEUP_CHARS 256
- static void mgsl_change_params(struct mgsl_struct *info);
- static void mgsl_wait_until_sent(struct tty_struct *tty, int timeout);
- /*
- * 1st function defined in .text section. Calling this function in
- * init_module() followed by a breakpoint allows a remote debugger
- * (gdb) to get the .text address for the add-symbol-file command.
- * This allows remote debugging of dynamically loadable modules.
- */
- static void* mgsl_get_text_ptr(void)
- {
- return mgsl_get_text_ptr;
- }
- /*
- * tmp_buf is used as a temporary buffer by mgsl_write. We need to
- * lock it in case the COPY_FROM_USER blocks while swapping in a page,
- * and some other program tries to do a serial write at the same time.
- * Since the lock will only come under contention when the system is
- * swapping and available memory is low, it makes sense to share one
- * buffer across all the serial ioports, since it significantly saves
- * memory if large numbers of serial ports are open.
- */
- static unsigned char *tmp_buf;
- static DECLARE_MUTEX(tmp_buf_sem);
- static inline int mgsl_paranoia_check(struct mgsl_struct *info,
- char *name, const char *routine)
- {
- #ifdef MGSL_PARANOIA_CHECK
- static const char *badmagic =
- "Warning: bad magic number for mgsl struct (%s) in %s\n";
- static const char *badinfo =
- "Warning: null mgsl_struct for (%s) in %s\n";
- if (!info) {
- printk(badinfo, name, routine);
- return 1;
- }
- if (info->magic != MGSL_MAGIC) {
- printk(badmagic, name, routine);
- return 1;
- }
- #else
- if (!info)
- return 1;
- #endif
- return 0;
- }
- /**
- * line discipline callback wrappers
- *
- * The wrappers maintain line discipline references
- * while calling into the line discipline.
- *
- * ldisc_receive_buf - pass receive data to line discipline
- */
- static void ldisc_receive_buf(struct tty_struct *tty,
- const __u8 *data, char *flags, int count)
- {
- struct tty_ldisc *ld;
- if (!tty)
- return;
- ld = tty_ldisc_ref(tty);
- if (ld) {
- if (ld->receive_buf)
- ld->receive_buf(tty, data, flags, count);
- tty_ldisc_deref(ld);
- }
- }
- /* mgsl_stop() throttle (stop) transmitter
- *
- * Arguments: tty pointer to tty info structure
- * Return Value: None
- */
- static void mgsl_stop(struct tty_struct *tty)
- {
- struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
- unsigned long flags;
-
- if (mgsl_paranoia_check(info, tty->name, "mgsl_stop"))
- return;
-
- if ( debug_level >= DEBUG_LEVEL_INFO )
- printk("mgsl_stop(%s)\n",info->device_name);
-
- spin_lock_irqsave(&info->irq_spinlock,flags);
- if (info->tx_enabled)
- usc_stop_transmitter(info);
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
-
- } /* end of mgsl_stop() */
- /* mgsl_start() release (start) transmitter
- *
- * Arguments: tty pointer to tty info structure
- * Return Value: None
- */
- static void mgsl_start(struct tty_struct *tty)
- {
- struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
- unsigned long flags;
-
- if (mgsl_paranoia_check(info, tty->name, "mgsl_start"))
- return;
-
- if ( debug_level >= DEBUG_LEVEL_INFO )
- printk("mgsl_start(%s)\n",info->device_name);
-
- spin_lock_irqsave(&info->irq_spinlock,flags);
- if (!info->tx_enabled)
- usc_start_transmitter(info);
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
-
- } /* end of mgsl_start() */
- /*
- * Bottom half work queue access functions
- */
- /* mgsl_bh_action() Return next bottom half action to perform.
- * Return Value: BH action code or 0 if nothing to do.
- */
- static int mgsl_bh_action(struct mgsl_struct *info)
- {
- unsigned long flags;
- int rc = 0;
-
- spin_lock_irqsave(&info->irq_spinlock,flags);
- if (info->pending_bh & BH_RECEIVE) {
- info->pending_bh &= ~BH_RECEIVE;
- rc = BH_RECEIVE;
- } else if (info->pending_bh & BH_TRANSMIT) {
- info->pending_bh &= ~BH_TRANSMIT;
- rc = BH_TRANSMIT;
- } else if (info->pending_bh & BH_STATUS) {
- info->pending_bh &= ~BH_STATUS;
- rc = BH_STATUS;
- }
- if (!rc) {
- /* Mark BH routine as complete */
- info->bh_running = 0;
- info->bh_requested = 0;
- }
-
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
-
- return rc;
- }
- /*
- * Perform bottom half processing of work items queued by ISR.
- */
- static void mgsl_bh_handler(void* Context)
- {
- struct mgsl_struct *info = (struct mgsl_struct*)Context;
- int action;
- if (!info)
- return;
-
- if ( debug_level >= DEBUG_LEVEL_BH )
- printk( "%s(%d):mgsl_bh_handler(%s) entry\n",
- __FILE__,__LINE__,info->device_name);
-
- info->bh_running = 1;
- while((action = mgsl_bh_action(info)) != 0) {
-
- /* Process work item */
- if ( debug_level >= DEBUG_LEVEL_BH )
- printk( "%s(%d):mgsl_bh_handler() work item action=%d\n",
- __FILE__,__LINE__,action);
- switch (action) {
-
- case BH_RECEIVE:
- mgsl_bh_receive(info);
- break;
- case BH_TRANSMIT:
- mgsl_bh_transmit(info);
- break;
- case BH_STATUS:
- mgsl_bh_status(info);
- break;
- default:
- /* unknown work item ID */
- printk("Unknown work item ID=%08X!\n", action);
- break;
- }
- }
- if ( debug_level >= DEBUG_LEVEL_BH )
- printk( "%s(%d):mgsl_bh_handler(%s) exit\n",
- __FILE__,__LINE__,info->device_name);
- }
- static void mgsl_bh_receive(struct mgsl_struct *info)
- {
- int (*get_rx_frame)(struct mgsl_struct *info) =
- (info->params.mode == MGSL_MODE_HDLC ? mgsl_get_rx_frame : mgsl_get_raw_rx_frame);
- if ( debug_level >= DEBUG_LEVEL_BH )
- printk( "%s(%d):mgsl_bh_receive(%s)\n",
- __FILE__,__LINE__,info->device_name);
-
- do
- {
- if (info->rx_rcc_underrun) {
- unsigned long flags;
- spin_lock_irqsave(&info->irq_spinlock,flags);
- usc_start_receiver(info);
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
- return;
- }
- } while(get_rx_frame(info));
- }
- static void mgsl_bh_transmit(struct mgsl_struct *info)
- {
- struct tty_struct *tty = info->tty;
- unsigned long flags;
-
- if ( debug_level >= DEBUG_LEVEL_BH )
- printk( "%s(%d):mgsl_bh_transmit() entry on %s\n",
- __FILE__,__LINE__,info->device_name);
- if (tty) {
- tty_wakeup(tty);
- wake_up_interruptible(&tty->write_wait);
- }
- /* if transmitter idle and loopmode_send_done_requested
- * then start echoing RxD to TxD
- */
- spin_lock_irqsave(&info->irq_spinlock,flags);
- if ( !info->tx_active && info->loopmode_send_done_requested )
- usc_loopmode_send_done( info );
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
- }
- static void mgsl_bh_status(struct mgsl_struct *info)
- {
- if ( debug_level >= DEBUG_LEVEL_BH )
- printk( "%s(%d):mgsl_bh_status() entry on %s\n",
- __FILE__,__LINE__,info->device_name);
- info->ri_chkcount = 0;
- info->dsr_chkcount = 0;
- info->dcd_chkcount = 0;
- info->cts_chkcount = 0;
- }
- /* mgsl_isr_receive_status()
- *
- * Service a receive status interrupt. The type of status
- * interrupt is indicated by the state of the RCSR.
- * This is only used for HDLC mode.
- *
- * Arguments: info pointer to device instance data
- * Return Value: None
- */
- static void mgsl_isr_receive_status( struct mgsl_struct *info )
- {
- u16 status = usc_InReg( info, RCSR );
- if ( debug_level >= DEBUG_LEVEL_ISR )
- printk("%s(%d):mgsl_isr_receive_status status=%04X\n",
- __FILE__,__LINE__,status);
-
- if ( (status & RXSTATUS_ABORT_RECEIVED) &&
- info->loopmode_insert_requested &&
- usc_loopmode_active(info) )
- {
- ++info->icount.rxabort;
- info->loopmode_insert_requested = FALSE;
-
- /* clear CMR:13 to start echoing RxD to TxD */
- info->cmr_value &= ~BIT13;
- usc_OutReg(info, CMR, info->cmr_value);
-
- /* disable received abort irq (no longer required) */
- usc_OutReg(info, RICR,
- (usc_InReg(info, RICR) & ~RXSTATUS_ABORT_RECEIVED));
- }
- if (status & (RXSTATUS_EXITED_HUNT + RXSTATUS_IDLE_RECEIVED)) {
- if (status & RXSTATUS_EXITED_HUNT)
- info->icount.exithunt++;
- if (status & RXSTATUS_IDLE_RECEIVED)
- info->icount.rxidle++;
- wake_up_interruptible(&info->event_wait_q);
- }
- if (status & RXSTATUS_OVERRUN){
- info->icount.rxover++;
- usc_process_rxoverrun_sync( info );
- }
- usc_ClearIrqPendingBits( info, RECEIVE_STATUS );
- usc_UnlatchRxstatusBits( info, status );
- } /* end of mgsl_isr_receive_status() */
- /* mgsl_isr_transmit_status()
- *
- * Service a transmit status interrupt
- * HDLC mode :end of transmit frame
- * Async mode:all data is sent
- * transmit status is indicated by bits in the TCSR.
- *
- * Arguments: info pointer to device instance data
- * Return Value: None
- */
- static void mgsl_isr_transmit_status( struct mgsl_struct *info )
- {
- u16 status = usc_InReg( info, TCSR );
- if ( debug_level >= DEBUG_LEVEL_ISR )
- printk("%s(%d):mgsl_isr_transmit_status status=%04X\n",
- __FILE__,__LINE__,status);
-
- usc_ClearIrqPendingBits( info, TRANSMIT_STATUS );
- usc_UnlatchTxstatusBits( info, status );
-
- if ( status & (TXSTATUS_UNDERRUN | TXSTATUS_ABORT_SENT) )
- {
- /* finished sending HDLC abort. This may leave */
- /* the TxFifo with data from the aborted frame */
- /* so purge the TxFifo. Also shutdown the DMA */
- /* channel in case there is data remaining in */
- /* the DMA buffer */
- usc_DmaCmd( info, DmaCmd_ResetTxChannel );
- usc_RTCmd( info, RTCmd_PurgeTxFifo );
- }
-
- if ( status & TXSTATUS_EOF_SENT )
- info->icount.txok++;
- else if ( status & TXSTATUS_UNDERRUN )
- info->icount.txunder++;
- else if ( status & TXSTATUS_ABORT_SENT )
- info->icount.txabort++;
- else
- info->icount.txunder++;
-
- info->tx_active = 0;
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
- del_timer(&info->tx_timer);
-
- if ( info->drop_rts_on_tx_done ) {
- usc_get_serial_signals( info );
- if ( info->serial_signals & SerialSignal_RTS ) {
- info->serial_signals &= ~SerialSignal_RTS;
- usc_set_serial_signals( info );
- }
- info->drop_rts_on_tx_done = 0;
- }
- #ifdef CONFIG_HDLC
- if (info->netcount)
- hdlcdev_tx_done(info);
- else
- #endif
- {
- if (info->tty->stopped || info->tty->hw_stopped) {
- usc_stop_transmitter(info);
- return;
- }
- info->pending_bh |= BH_TRANSMIT;
- }
- } /* end of mgsl_isr_transmit_status() */
- /* mgsl_isr_io_pin()
- *
- * Service an Input/Output pin interrupt. The type of
- * interrupt is indicated by bits in the MISR
- *
- * Arguments: info pointer to device instance data
- * Return Value: None
- */
- static void mgsl_isr_io_pin( struct mgsl_struct *info )
- {
- struct mgsl_icount *icount;
- u16 status = usc_InReg( info, MISR );
- if ( debug_level >= DEBUG_LEVEL_ISR )
- printk("%s(%d):mgsl_isr_io_pin status=%04X\n",
- __FILE__,__LINE__,status);
-
- usc_ClearIrqPendingBits( info, IO_PIN );
- usc_UnlatchIostatusBits( info, status );
- if (status & (MISCSTATUS_CTS_LATCHED | MISCSTATUS_DCD_LATCHED |
- MISCSTATUS_DSR_LATCHED | MISCSTATUS_RI_LATCHED) ) {
- icount = &info->icount;
- /* update input line counters */
- if (status & MISCSTATUS_RI_LATCHED) {
- if ((info->ri_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT)
- usc_DisablestatusIrqs(info,SICR_RI);
- icount->rng++;
- if ( status & MISCSTATUS_RI )
- info->input_signal_events.ri_up++;
- else
- info->input_signal_events.ri_down++;
- }
- if (status & MISCSTATUS_DSR_LATCHED) {
- if ((info->dsr_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT)
- usc_DisablestatusIrqs(info,SICR_DSR);
- icount->dsr++;
- if ( status & MISCSTATUS_DSR )
- info->input_signal_events.dsr_up++;
- else
- info->input_signal_events.dsr_down++;
- }
- if (status & MISCSTATUS_DCD_LATCHED) {
- if ((info->dcd_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT)
- usc_DisablestatusIrqs(info,SICR_DCD);
- icount->dcd++;
- if (status & MISCSTATUS_DCD) {
- info->input_signal_events.dcd_up++;
- } else
- info->input_signal_events.dcd_down++;
- #ifdef CONFIG_HDLC
- if (info->netcount)
- hdlc_set_carrier(status & MISCSTATUS_DCD, info->netdev);
- #endif
- }
- if (status & MISCSTATUS_CTS_LATCHED)
- {
- if ((info->cts_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT)
- usc_DisablestatusIrqs(info,SICR_CTS);
- icount->cts++;
- if ( status & MISCSTATUS_CTS )
- info->input_signal_events.cts_up++;
- else
- info->input_signal_events.cts_down++;
- }
- wake_up_interruptible(&info->status_event_wait_q);
- wake_up_interruptible(&info->event_wait_q);
- if ( (info->flags & ASYNC_CHECK_CD) &&
- (status & MISCSTATUS_DCD_LATCHED) ) {
- if ( debug_level >= DEBUG_LEVEL_ISR )
- printk("%s CD now %s...", info->device_name,
- (status & MISCSTATUS_DCD) ? "on" : "off");
- if (status & MISCSTATUS_DCD)
- wake_up_interruptible(&info->open_wait);
- else {
- if ( debug_level >= DEBUG_LEVEL_ISR )
- printk("doing serial hangup...");
- if (info->tty)
- tty_hangup(info->tty);
- }
- }
-
- if ( (info->flags & ASYNC_CTS_FLOW) &&
- (status & MISCSTATUS_CTS_LATCHED) ) {
- if (info->tty->hw_stopped) {
- if (status & MISCSTATUS_CTS) {
- if ( debug_level >= DEBUG_LEVEL_ISR )
- printk("CTS tx start...");
- if (info->tty)
- info->tty->hw_stopped = 0;
- usc_start_transmitter(info);
- info->pending_bh |= BH_TRANSMIT;
- return;
- }
- } else {
- if (!(status & MISCSTATUS_CTS)) {
- if ( debug_level >= DEBUG_LEVEL_ISR )
- printk("CTS tx stop...");
- if (info->tty)
- info->tty->hw_stopped = 1;
- usc_stop_transmitter(info);
- }
- }
- }
- }
- info->pending_bh |= BH_STATUS;
-
- /* for diagnostics set IRQ flag */
- if ( status & MISCSTATUS_TXC_LATCHED ){
- usc_OutReg( info, SICR,
- (unsigned short)(usc_InReg(info,SICR) & ~(SICR_TXC_ACTIVE+SICR_TXC_INACTIVE)) );
- usc_UnlatchIostatusBits( info, MISCSTATUS_TXC_LATCHED );
- info->irq_occurred = 1;
- }
- } /* end of mgsl_isr_io_pin() */
- /* mgsl_isr_transmit_data()
- *
- * Service a transmit data interrupt (async mode only).
- *
- * Arguments: info pointer to device instance data
- * Return Value: None
- */
- static void mgsl_isr_transmit_data( struct mgsl_struct *info )
- {
- if ( debug_level >= DEBUG_LEVEL_ISR )
- printk("%s(%d):mgsl_isr_transmit_data xmit_cnt=%d\n",
- __FILE__,__LINE__,info->xmit_cnt);
-
- usc_ClearIrqPendingBits( info, TRANSMIT_DATA );
-
- if (info->tty->stopped || info->tty->hw_stopped) {
- usc_stop_transmitter(info);
- return;
- }
-
- if ( info->xmit_cnt )
- usc_load_txfifo( info );
- else
- info->tx_active = 0;
-
- if (info->xmit_cnt < WAKEUP_CHARS)
- info->pending_bh |= BH_TRANSMIT;
- } /* end of mgsl_isr_transmit_data() */
- /* mgsl_isr_receive_data()
- *
- * Service a receive data interrupt. This occurs
- * when operating in asynchronous interrupt transfer mode.
- * The receive data FIFO is flushed to the receive data buffers.
- *
- * Arguments: info pointer to device instance data
- * Return Value: None
- */
- static void mgsl_isr_receive_data( struct mgsl_struct *info )
- {
- int Fifocount;
- u16 status;
- unsigned char DataByte;
- struct tty_struct *tty = info->tty;
- struct mgsl_icount *icount = &info->icount;
-
- if ( debug_level >= DEBUG_LEVEL_ISR )
- printk("%s(%d):mgsl_isr_receive_data\n",
- __FILE__,__LINE__);
- usc_ClearIrqPendingBits( info, RECEIVE_DATA );
-
- /* select FIFO status for RICR readback */
- usc_RCmd( info, RCmd_SelectRicrRxFifostatus );
- /* clear the Wordstatus bit so that status readback */
- /* only reflects the status of this byte */
- usc_OutReg( info, RICR+LSBONLY, (u16)(usc_InReg(info, RICR+LSBONLY) & ~BIT3 ));
- /* flush the receive FIFO */
- while( (Fifocount = (usc_InReg(info,RICR) >> 8)) ) {
- /* read one byte from RxFIFO */
- outw( (inw(info->io_base + CCAR) & 0x0780) | (RDR+LSBONLY),
- info->io_base + CCAR );
- DataByte = inb( info->io_base + CCAR );
- /* get the status of the received byte */
- status = usc_InReg(info, RCSR);
- if ( status & (RXSTATUS_FRAMING_ERROR + RXSTATUS_PARITY_ERROR +
- RXSTATUS_OVERRUN + RXSTATUS_BREAK_RECEIVED) )
- usc_UnlatchRxstatusBits(info,RXSTATUS_ALL);
-
- if (tty->flip.count >= TTY_FLIPBUF_SIZE)
- continue;
-
- *tty->flip.char_buf_ptr = DataByte;
- icount->rx++;
-
- *tty->flip.flag_buf_ptr = 0;
- if ( status & (RXSTATUS_FRAMING_ERROR + RXSTATUS_PARITY_ERROR +
- RXSTATUS_OVERRUN + RXSTATUS_BREAK_RECEIVED) ) {
- printk("rxerr=%04X\n",status);
- /* update error statistics */
- if ( status & RXSTATUS_BREAK_RECEIVED ) {
- status &= ~(RXSTATUS_FRAMING_ERROR + RXSTATUS_PARITY_ERROR);
- icount->brk++;
- } else if (status & RXSTATUS_PARITY_ERROR)
- icount->parity++;
- else if (status & RXSTATUS_FRAMING_ERROR)
- icount->frame++;
- else if (status & RXSTATUS_OVERRUN) {
- /* must issue purge fifo cmd before */
- /* 16C32 accepts more receive chars */
- usc_RTCmd(info,RTCmd_PurgeRxFifo);
- icount->overrun++;
- }
- /* discard char if tty control flags say so */
- if (status & info->ignore_status_mask)
- continue;
-
- status &= info->read_status_mask;
-
- if (status & RXSTATUS_BREAK_RECEIVED) {
- *tty->flip.flag_buf_ptr = TTY_BREAK;
- if (info->flags & ASYNC_SAK)
- do_SAK(tty);
- } else if (status & RXSTATUS_PARITY_ERROR)
- *tty->flip.flag_buf_ptr = TTY_PARITY;
- else if (status & RXSTATUS_FRAMING_ERROR)
- *tty->flip.flag_buf_ptr = TTY_FRAME;
- if (status & RXSTATUS_OVERRUN) {
- /* Overrun is special, since it's
- * reported immediately, and doesn't
- * affect the current character
- */
- if (tty->flip.count < TTY_FLIPBUF_SIZE) {
- tty->flip.count++;
- tty->flip.flag_buf_ptr++;
- tty->flip.char_buf_ptr++;
- *tty->flip.flag_buf_ptr = TTY_OVERRUN;
- }
- }
- } /* end of if (error) */
-
- tty->flip.flag_buf_ptr++;
- tty->flip.char_buf_ptr++;
- tty->flip.count++;
- }
- if ( debug_level >= DEBUG_LEVEL_ISR ) {
- printk("%s(%d):mgsl_isr_receive_data flip count=%d\n",
- __FILE__,__LINE__,tty->flip.count);
- printk("%s(%d):rx=%d brk=%d parity=%d frame=%d overrun=%d\n",
- __FILE__,__LINE__,icount->rx,icount->brk,
- icount->parity,icount->frame,icount->overrun);
- }
-
- if ( tty->flip.count )
- tty_flip_buffer_push(tty);
- }
- /* mgsl_isr_misc()
- *
- * Service a miscellaneos interrupt source.
- *
- * Arguments: info pointer to device extension (instance data)
- * Return Value: None
- */
- static void mgsl_isr_misc( struct mgsl_struct *info )
- {
- u16 status = usc_InReg( info, MISR );
- if ( debug_level >= DEBUG_LEVEL_ISR )
- printk("%s(%d):mgsl_isr_misc status=%04X\n",
- __FILE__,__LINE__,status);
-
- if ((status & MISCSTATUS_RCC_UNDERRUN) &&
- (info->params.mode == MGSL_MODE_HDLC)) {
- /* turn off receiver and rx DMA */
- usc_EnableReceiver(info,DISABLE_UNCONDITIONAL);
- usc_DmaCmd(info, DmaCmd_ResetRxChannel);
- usc_UnlatchRxstatusBits(info, RXSTATUS_ALL);
- usc_ClearIrqPendingBits(info, RECEIVE_DATA + RECEIVE_STATUS);
- usc_DisableInterrupts(info, RECEIVE_DATA + RECEIVE_STATUS);
- /* schedule BH handler to restart receiver */
- info->pending_bh |= BH_RECEIVE;
- info->rx_rcc_underrun = 1;
- }
- usc_ClearIrqPendingBits( info, MISC );
- usc_UnlatchMiscstatusBits( info, status );
- } /* end of mgsl_isr_misc() */
- /* mgsl_isr_null()
- *
- * Services undefined interrupt vectors from the
- * USC. (hence this function SHOULD never be called)
- *
- * Arguments: info pointer to device extension (instance data)
- * Return Value: None
- */
- static void mgsl_isr_null( struct mgsl_struct *info )
- {
- } /* end of mgsl_isr_null() */
- /* mgsl_isr_receive_dma()
- *
- * Service a rec…