/*
* linux/drivers/char/synclink.c
*
* $Id: synclink.c,v 4.38 2005/11/07 16:30:34 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/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/seq_file.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/vmalloc.h>
#include <linux/init.h>
#include <linux/ioctl.h>
#include <linux/synclink.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>
#include <linux/dma-mapping.h>
#if defined(CONFIG_HDLC) || (defined(CONFIG_HDLC_MODULE) && defined(CONFIG_SYNCLINK_MODULE))
#define SYNCLINK_GENERIC_HDLC 1
#else
#define SYNCLINK_GENERIC_HDLC 0
#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>
#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 4096
#define DMABUFFERSIZE 4096
#define MAXRXFRAMES 7
typedef struct _DMABUFFERENTRY
{
u32 phys_addr; /* 32-bit flat physical address of data buffer */
volatile u16 count; /* buffer size/data count */
volatile u16 status; /* Control/status field */
volatile 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 */
dma_addr_t dma_addr;
} 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
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;
struct tty_port port;
int line;
int hw_version;
struct mgsl_icount icount;
int timeout;
int x_char; /* xon/xoff character */
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 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;
bool bh_running; /* Protection from multiple */
int isr_overflow;
bool 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 */
u32 buffer_list_phys;
dma_addr_t buffer_list_dma_addr;
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];
bool rx_enabled;
bool rx_overflow;
bool rx_rcc_underrun;
bool tx_enabled;
bool 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 */
bool io_addr_requested; /* true if I/O address requested */
unsigned int irq_level; /* interrupt level */
unsigned long irq_flags;
bool irq_requested; /* true if IRQ requested */
unsigned int dma_level; /* DMA channel */
bool dma_requested; /* true 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 */
bool 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;
bool shared_mem_requested;
unsigned char* lcr_base; /* local config registers (PCI only) */
u32 phys_lcr_base;
u32 lcr_offset;
bool lcr_mem_requested;
u32 misc_ctrl_value;
char flag_buf[MAX_ASYNC_BUFFER_SIZE];
char char_buf[MAX_ASYNC_BUFFER_SIZE];
bool drop_rts_on_tx_done;
bool loopmode_insert_requested;
bool loopmode_send_done_requested;
struct _input_signal_events input_signal_events;
/* generic HDLC device parts */
int netcount;
spinlock_t netlock;
#if SYNCLINK_GENERIC_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);
#if SYNCLINK_GENERIC_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 bool mgsl_register_test( struct mgsl_struct *info );
static bool mgsl_irq_test( struct mgsl_struct *info );
static bool mgsl_dma_test( struct mgsl_struct *info );
static bool 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 bool mgsl_get_rx_frame( struct mgsl_struct *info );
static bool 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 bool 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(struct work_struct *work);
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 bool 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 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(txdmabufs, int, NULL, 0);
module_param_array(txholdbufs, int, NULL, 0);
static char *driver_name = "SyncLink serial driver";
static char *driver_version = "$Revision: 4.38 $";
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;
}
static inline int mgsl_paranoia_check(struct mgsl_struct *info,
|