synclink.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:232k
- /*
- * linux/drivers/char/synclink.c
- *
- * $Id: synclink.c,v 3.12 2001/07/18 19:14:21 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.
- */
- #define VERSION(ver,rel,seq) (((ver)<<16) | ((rel)<<8) | (seq))
- #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/version.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/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 <asm/bitops.h>
- #include <asm/types.h>
- #include <linux/termios.h>
- #include <linux/tqueue.h>
- #ifdef CONFIG_SYNCLINK_SYNCPPP_MODULE
- #define CONFIG_SYNCLINK_SYNCPPP 1
- #endif
- #ifdef CONFIG_SYNCLINK_SYNCPPP
- #if LINUX_VERSION_CODE < VERSION(2,4,3)
- #include "../net/wan/syncppp.h"
- #else
- #include <net/syncppp.h>
- #endif
- #endif
- #include <asm/segment.h>
- #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
- 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 {
- void *if_ptr; /* General purpose pointer (used by SPPP) */
- int magic;
- int flags;
- int count; /* count of opens */
- int line;
- unsigned short close_delay;
- unsigned short closing_wait; /* time to wait before closing */
-
- struct mgsl_icount icount;
-
- struct termios normal_termios;
- struct termios callout_termios;
-
- struct tty_struct *tty;
- int timeout;
- int x_char; /* xon/xoff character */
- int blocked_open; /* # of blocked opens */
- long session; /* Session of opening process */
- long pgrp; /* pgrp of opening process */
- 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 tq_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 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;
- /* SPPP/Cisco HDLC device parts */
- int netcount;
- int dosyncppp;
- spinlock_t netlock;
- #ifdef CONFIG_SYNCLINK_SYNCPPP
- struct ppp_device pppdev;
- char netname[10];
- struct net_device *netdev;
- struct net_device_stats netstats;
- struct net_device netdevice;
- #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)) )
- u16 usc_InDmaReg( struct mgsl_struct *info, u16 Port );
- void usc_OutDmaReg( struct mgsl_struct *info, u16 Port, u16 Value );
- void usc_DmaCmd( struct mgsl_struct *info, u16 Cmd );
- u16 usc_InReg( struct mgsl_struct *info, u16 Port );
- void usc_OutReg( struct mgsl_struct *info, u16 Port, u16 Value );
- 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))
- void usc_process_rxoverrun_sync( struct mgsl_struct *info );
- void usc_start_receiver( struct mgsl_struct *info );
- void usc_stop_receiver( struct mgsl_struct *info );
- void usc_start_transmitter( struct mgsl_struct *info );
- void usc_stop_transmitter( struct mgsl_struct *info );
- void usc_set_txidle( struct mgsl_struct *info );
- void usc_load_txfifo( struct mgsl_struct *info );
- void usc_enable_aux_clock( struct mgsl_struct *info, u32 DataRate );
- void usc_enable_loopback( struct mgsl_struct *info, int enable );
- void usc_get_serial_signals( struct mgsl_struct *info );
- void usc_set_serial_signals( struct mgsl_struct *info );
- void usc_reset( struct mgsl_struct *info );
- void usc_set_sync_mode( struct mgsl_struct *info );
- void usc_set_sdlc_mode( struct mgsl_struct *info );
- void usc_set_async_mode( struct mgsl_struct *info );
- void usc_enable_async_clock( struct mgsl_struct *info, u32 DataRate );
- void usc_loopback_frame( struct mgsl_struct *info );
- void mgsl_tx_timeout(unsigned long context);
- void usc_loopmode_cancel_transmit( struct mgsl_struct * info );
- void usc_loopmode_insert_request( struct mgsl_struct * info );
- int usc_loopmode_active( struct mgsl_struct * info);
- void usc_loopmode_send_done( struct mgsl_struct * info );
- int usc_loopmode_send_active( struct mgsl_struct * info );
- int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigned long arg);
- #ifdef CONFIG_SYNCLINK_SYNCPPP
- /* SPPP/HDLC stuff */
- void mgsl_sppp_init(struct mgsl_struct *info);
- void mgsl_sppp_delete(struct mgsl_struct *info);
- int mgsl_sppp_open(struct net_device *d);
- int mgsl_sppp_close(struct net_device *d);
- void mgsl_sppp_tx_timeout(struct net_device *d);
- int mgsl_sppp_tx(struct sk_buff *skb, struct net_device *d);
- void mgsl_sppp_rx_done(struct mgsl_struct *info, char *buf, int size);
- void mgsl_sppp_tx_done(struct mgsl_struct *info);
- int mgsl_sppp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
- struct net_device_stats *mgsl_net_stats(struct net_device *dev);
- #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) )
- void mgsl_trace_block(struct mgsl_struct *info,const char* data, int count, int xmit);
- /*
- * Adapter diagnostic routines
- */
- BOOLEAN mgsl_register_test( struct mgsl_struct *info );
- BOOLEAN mgsl_irq_test( struct mgsl_struct *info );
- BOOLEAN mgsl_dma_test( struct mgsl_struct *info );
- BOOLEAN mgsl_memory_test( struct mgsl_struct *info );
- int mgsl_adapter_test( struct mgsl_struct *info );
- /*
- * device and resource management routines
- */
- int mgsl_claim_resources(struct mgsl_struct *info);
- void mgsl_release_resources(struct mgsl_struct *info);
- void mgsl_add_device(struct mgsl_struct *info);
- struct mgsl_struct* mgsl_allocate_device(void);
- int mgsl_enum_isa_devices(void);
- /*
- * DMA buffer manupulation functions.
- */
- void mgsl_free_rx_frame_buffers( struct mgsl_struct *info, unsigned int StartIndex, unsigned int EndIndex );
- int mgsl_get_rx_frame( struct mgsl_struct *info );
- int mgsl_get_raw_rx_frame( struct mgsl_struct *info );
- void mgsl_reset_rx_dma_buffers( struct mgsl_struct *info );
- void mgsl_reset_tx_dma_buffers( struct mgsl_struct *info );
- int num_free_tx_dma_buffers(struct mgsl_struct *info);
- void mgsl_load_tx_dma_buffer( struct mgsl_struct *info, const char *Buffer, unsigned int BufferSize);
- void mgsl_load_pci_memory(char* TargetPtr, const char* SourcePtr, unsigned short count);
- /*
- * DMA and Shared Memory buffer allocation and formatting
- */
- int mgsl_allocate_dma_buffers(struct mgsl_struct *info);
- void mgsl_free_dma_buffers(struct mgsl_struct *info);
- int mgsl_alloc_frame_memory(struct mgsl_struct *info, DMABUFFERENTRY *BufferList,int Buffercount);
- void mgsl_free_frame_memory(struct mgsl_struct *info, DMABUFFERENTRY *BufferList,int Buffercount);
- int mgsl_alloc_buffer_list_memory(struct mgsl_struct *info);
- void mgsl_free_buffer_list_memory(struct mgsl_struct *info);
- int mgsl_alloc_intermediate_rxbuffer_memory(struct mgsl_struct *info);
- void mgsl_free_intermediate_rxbuffer_memory(struct mgsl_struct *info);
- int mgsl_alloc_intermediate_txbuffer_memory(struct mgsl_struct *info);
- void mgsl_free_intermediate_txbuffer_memory(struct mgsl_struct *info);
- int load_next_tx_holding_buffer(struct mgsl_struct *info);
- int save_tx_buffer_request(struct mgsl_struct *info,const char *Buffer, unsigned int BufferSize);
- /*
- * Bottom half interrupt handlers
- */
- void mgsl_bh_handler(void* Context);
- void mgsl_bh_receive(struct mgsl_struct *info);
- void mgsl_bh_transmit(struct mgsl_struct *info);
- void mgsl_bh_status(struct mgsl_struct *info);
- /*
- * Interrupt handler routines and dispatch table.
- */
- void mgsl_isr_null( struct mgsl_struct *info );
- void mgsl_isr_transmit_data( struct mgsl_struct *info );
- void mgsl_isr_receive_data( struct mgsl_struct *info );
- void mgsl_isr_receive_status( struct mgsl_struct *info );
- void mgsl_isr_transmit_status( struct mgsl_struct *info );
- void mgsl_isr_io_pin( struct mgsl_struct *info );
- void mgsl_isr_misc( struct mgsl_struct *info );
- void mgsl_isr_receive_dma( struct mgsl_struct *info );
- void mgsl_isr_transmit_dma( struct mgsl_struct *info );
- typedef void (*isr_dispatch_func)(struct mgsl_struct *);
- 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 set_modem_info(struct mgsl_struct * info, unsigned int cmd,
- unsigned int *value);
- static int get_modem_info(struct mgsl_struct * info, unsigned int *value);
- static int mgsl_get_stats(struct mgsl_struct * info, struct mgsl_icount
- *user_icount);
- static int mgsl_get_params(struct mgsl_struct * info, MGSL_PARAMS *user_params);
- static int mgsl_set_params(struct mgsl_struct * info, MGSL_PARAMS *new_params);
- static int mgsl_get_txidle(struct mgsl_struct * info, int*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 * mask);
- static int mgsl_loopmode_send_done( struct mgsl_struct * info );
- #define jiffies_from_ms(a) ((((a) * HZ)/1000)+1)
- /*
- * Global linked list of SyncLink devices
- */
- struct mgsl_struct *mgsl_device_list;
- 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.
- */
- int break_on_load;
- /*
- * Driver major number, defaults to zero to get auto
- * assigned major number. May be forced as module parameter.
- */
- int ttymajor;
- int cuamajor;
- /*
- * 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_PARM(break_on_load,"i");
- MODULE_PARM(ttymajor,"i");
- MODULE_PARM(cuamajor,"i");
- MODULE_PARM(io,"1-" __MODULE_STRING(MAX_ISA_DEVICES) "i");
- MODULE_PARM(irq,"1-" __MODULE_STRING(MAX_ISA_DEVICES) "i");
- MODULE_PARM(dma,"1-" __MODULE_STRING(MAX_ISA_DEVICES) "i");
- MODULE_PARM(debug_level,"i");
- MODULE_PARM(maxframe,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i");
- MODULE_PARM(dosyncppp,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i");
- MODULE_PARM(txdmabufs,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i");
- MODULE_PARM(txholdbufs,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i");
- static char *driver_name = "SyncLink serial driver";
- static char *driver_version = "$Revision: 3.12 $";
- static int __init synclink_init_one (struct pci_dev *dev,
- const struct pci_device_id *ent);
- static void __devexit synclink_remove_one (struct pci_dev *dev);
- static struct pci_device_id synclink_pci_tbl[] __devinitdata = {
- { PCI_VENDOR_ID_MICROGATE, PCI_DEVICE_ID_MICROGATE_USC, 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, callout_driver;
- static int serial_refcount;
- /* 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);
- static struct tty_struct *serial_table[MAX_TOTAL_DEVICES];
- static struct termios *serial_termios[MAX_TOTAL_DEVICES];
- static struct termios *serial_termios_locked[MAX_TOTAL_DEVICES];
- #ifndef MIN
- #define MIN(a,b) ((a) < (b) ? (a) : (b))
- #endif
- /*
- * 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.
- */
- void* mgsl_get_text_ptr(void);
- void* mgsl_get_text_ptr() {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,
- kdev_t device, const char *routine)
- {
- #ifdef MGSL_PARANOIA_CHECK
- static const char *badmagic =
- "Warning: bad magic number for mgsl struct (%s) in %sn";
- static const char *badinfo =
- "Warning: null mgsl_struct for (%s) in %sn";
- if (!info) {
- printk(badinfo, kdevname(device), routine);
- return 1;
- }
- if (info->magic != MGSL_MAGIC) {
- printk(badmagic, kdevname(device), routine);
- return 1;
- }
- #endif
- return 0;
- }
- /* 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->device, "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->device, "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.
- */
- 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.
- */
- 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) entryn",
- __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=%dn",
- __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) exitn",
- __FILE__,__LINE__,info->device_name);
- }
- 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);
-
- while( (get_rx_frame)(info) );
- }
- 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 %sn",
- __FILE__,__LINE__,info->device_name);
- if (tty) {
- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
- tty->ldisc.write_wakeup) {
- if ( debug_level >= DEBUG_LEVEL_BH )
- printk( "%s(%d):calling ldisc.write_wakeup on %sn",
- __FILE__,__LINE__,info->device_name);
- (tty->ldisc.write_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);
- }
- void mgsl_bh_status(struct mgsl_struct *info)
- {
- if ( debug_level >= DEBUG_LEVEL_BH )
- printk( "%s(%d):mgsl_bh_status() entry on %sn",
- __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
- */
- 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=%04Xn",
- __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
- */
- 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=%04Xn",
- __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_SYNCLINK_SYNCPPP
- if (info->netcount)
- mgsl_sppp_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
- */
- 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=%04Xn",
- __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++;
- #ifdef CONFIG_SYNCLINK_SYNCPPP
- if (info->netcount)
- sppp_reopen(info->netdev);
- #endif
- } else
- info->input_signal_events.dcd_down++;
- }
- 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 (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
- (info->flags & ASYNC_CALLOUT_NOHUP))) {
- 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
- */
- void mgsl_isr_transmit_data( struct mgsl_struct *info )
- {
- if ( debug_level >= DEBUG_LEVEL_ISR )
- printk("%s(%d):mgsl_isr_transmit_data xmit_cnt=%dn",
- __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
- */
- 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_datan",
- __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=%04Xn",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=%dn",
- __FILE__,__LINE__,tty->flip.count);
- printk("%s(%d):rx=%d brk=%d parity=%d frame=%d overrun=%dn",
- __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
- */
- 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=%04Xn",
- __FILE__,__LINE__,status);
-
- 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
- */
- void mgsl_isr_null( struct mgsl_struct *info )
- {
- } /* end of mgsl_isr_null() */
- /* mgsl_isr_receive_dma()
- *
- * Service a receive DMA channel interrupt.
- * For this driver there are two sources of receive DMA interrupts
- * as identified in the Receive DMA mode Register (RDMR):
- *
- * BIT3 EOA/EOL End of List, all receive buffers in receive
- * buffer list have been filled (no more free buffers
- * available). The DMA controller has shut down.
- *
- * BIT2 EOB End of Buffer. This interrupt occurs when a receive
- * DMA buffer is terminated in response to completion
- * of a good frame or a frame with errors. The status
- * of the frame is stored in the buffer entry in the
- * list of receive buffer entries.
- *
- * Arguments: info pointer to device instance data
- * Return Value: None
- */
- void mgsl_isr_receive_dma( struct mgsl_struct *info )
- {
- u16 status;
-
- /* clear interrupt pending and IUS bit for Rx DMA IRQ */
- usc_OutDmaReg( info, CDIR, BIT9+BIT1 );
- /* Read the receive DMA status to identify interrupt type. */
- /* This also clears the status bits. */
- status = usc_InDmaReg( info, RDMR );
- if ( debug_level >= DEBUG_LEVEL_ISR )
- printk("%s(%d):mgsl_isr_receive_dma(%s) status=%04Xn",
- __FILE__,__LINE__,info->device_name,status);
-
- info->pending_bh |= BH_RECEIVE;
-
- if ( status & BIT3 ) {
- info->rx_overflow = 1;
- info->icount.buf_overrun++;
- }
- } /* end of mgsl_isr_receive_dma() */
- /* mgsl_isr_transmit_dma()
- *
- * This function services a transmit DMA channel interrupt.
- *
- * For this driver there is one source of transmit DMA interrupts
- * as identified in the Transmit DMA Mode Register (TDMR):
- *
- * BIT2 EOB End of Buffer. This interrupt occurs when a
- * transmit DMA buffer has been emptied.
- *
- * The driver maintains enough transmit DMA buffers to hold at least
- * one max frame size transmit frame. When operating in a buffered
- * transmit mode, there may be enough transmit DMA buffers to hold at
- * least two or more max frame size frames. On an EOB condition,
- * determine if there are any queued transmit buffers and copy into
- * transmit DMA buffers if we have room.
- *
- * Arguments: info pointer to device instance data
- * Return Value: None
- */
- void mgsl_isr_transmit_dma( struct mgsl_struct *info )
- {
- u16 status;
- /* clear interrupt pending and IUS bit for Tx DMA IRQ */
- usc_OutDmaReg(info, CDIR, BIT8+BIT0 );
- /* Read the transmit DMA status to identify interrupt type. */
- /* This also clears the status bits. */
- status = usc_InDmaReg( info, TDMR );
- if ( debug_level >= DEBUG_LEVEL_ISR )
- printk("%s(%d):mgsl_isr_transmit_dma(%s) status=%04Xn",
- __FILE__,__LINE__,info->device_name,status);
- if ( status & BIT2 ) {
- --info->tx_dma_buffers_used;
- /* if there are transmit frames queued,
- * try to load the next one
- */
- if ( load_next_tx_holding_buffer(info) ) {
- /* if call returns non-zero value, we have
- * at least one free tx holding buffer
- */
- info->pending_bh |= BH_TRANSMIT;
- }
- }
- } /* end of mgsl_isr_transmit_dma() */
- /* mgsl_interrupt()
- *
- * Interrupt service routine entry point.
- *
- * Arguments:
- *
- * irq interrupt number that caused interrupt
- * dev_id device ID supplied during interrupt registration
- * regs interrupted processor context
- *
- * Return Value: None
- */
- static void mgsl_interrupt(int irq, void *dev_id, struct pt_regs * regs)
- {
- struct mgsl_struct * info;
- u16 UscVector;
- u16 DmaVector;
- if ( debug_level >= DEBUG_LEVEL_ISR )
- printk("%s(%d):mgsl_interrupt(%d)entry.n",
- __FILE__,__LINE__,irq);
- info = (struct mgsl_struct *)dev_id;
- if (!info)
- return;
-
- spin_lock(&info->irq_spinlock);
- for(;;) {
- /* Read the interrupt vectors from hardware. */
- UscVector = usc_InReg(info, IVR) >> 9;
- DmaVector = usc_InDmaReg(info, DIVR);
-
- if ( debug_level >= DEBUG_LEVEL_ISR )
- printk("%s(%d):%s UscVector=%08X DmaVector=%08Xn",
- __FILE__,__LINE__,info->device_name,UscVector,DmaVector);
-
- if ( !UscVector && !DmaVector )
- break;
-
- /* Dispatch interrupt vector */
- if ( UscVector )
- (*UscIsrTable[UscVector])(info);
- else if ( (DmaVector&(BIT10|BIT9)) == BIT10)
- mgsl_isr_transmit_dma(info);
- else
- mgsl_isr_receive_dma(info);
- if ( info->isr_overflow ) {
- printk(KERN_ERR"%s(%d):%s isr overflow irq=%dn",
- __FILE__,__LINE__,info->device_name, irq);
- usc_DisableMasterIrqBit(info);
- usc_DisableDmaInterrupts(info,DICR_MASTER);
- break;
- }
- }
-
- /* Request bottom half processing if there's something
- * for it to do and the bh is not already running
- */
- if ( info->pending_bh && !info->bh_running && !info->bh_requested ) {
- if ( debug_level >= DEBUG_LEVEL_ISR )
- printk("%s(%d):%s queueing bh task.n",
- __FILE__,__LINE__,info->device_name);
- queue_task(&info->task, &tq_immediate);
- mark_bh(IMMEDIATE_BH);
- info->bh_requested = 1;
- }
- spin_unlock(&info->irq_spinlock);
-
- if ( debug_level >= DEBUG_LEVEL_ISR )
- printk("%s(%d):mgsl_interrupt(%d)exit.n",
- __FILE__,__LINE__,irq);
- } /* end of mgsl_interrupt() */
- /* startup()
- *
- * Initialize and start device.
- *
- * Arguments: info pointer to device instance data
- * Return Value: 0 if success, otherwise error code
- */
- static int startup(struct mgsl_struct * info)
- {
- int retval = 0;
-
- if ( debug_level >= DEBUG_LEVEL_INFO )
- printk("%s(%d):mgsl_startup(%s)n",__FILE__,__LINE__,info->device_name);
-
- if (info->flags & ASYNC_INITIALIZED)
- return 0;
-
- if (!info->xmit_buf) {
- /* allocate a page of memory for a transmit buffer */
- info->xmit_buf = (unsigned char *)get_free_page(GFP_KERNEL);
- if (!info->xmit_buf) {
- printk(KERN_ERR"%s(%d):%s can't allocate transmit buffern",
- __FILE__,__LINE__,info->device_name);
- return -ENOMEM;
- }
- }
- info->pending_bh = 0;
-
- init_timer(&info->tx_timer);
- info->tx_timer.data = (unsigned long)info;
- info->tx_timer.function = mgsl_tx_timeout;
-
- /* Allocate and claim adapter resources */
- retval = mgsl_claim_resources(info);
-
- /* perform existance check and diagnostics */
- if ( !retval )
- retval = mgsl_adapter_test(info);
-
- if ( retval ) {
- if (capable(CAP_SYS_ADMIN) && info->tty)
- set_bit(TTY_IO_ERROR, &info->tty->flags);
- mgsl_release_resources(info);
- return retval;
- }
- /* program hardware for current parameters */
- mgsl_change_params(info);
-
- if (info->tty)
- clear_bit(TTY_IO_ERROR, &info->tty->flags);
- info->flags |= ASYNC_INITIALIZED;
-
- return 0;
-
- } /* end of startup() */
- /* shutdown()
- *
- * Called by mgsl_close() and mgsl_hangup() to shutdown hardware
- *
- * Arguments: info pointer to device instance data
- * Return Value: None
- */
- static void shutdown(struct mgsl_struct * info)
- {
- unsigned long flags;
-
- if (!(info->flags & ASYNC_INITIALIZED))
- return;
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):mgsl_shutdown(%s)n",
- __FILE__,__LINE__, info->device_name );
- /* clear status wait queue because status changes */
- /* can't happen after shutting down the hardware */
- wake_up_interruptible(&info->status_event_wait_q);
- wake_up_interruptible(&info->event_wait_q);
- del_timer(&info->tx_timer);
- if (info->xmit_buf) {
- free_page((unsigned long) info->xmit_buf);
- info->xmit_buf = 0;
- }
- spin_lock_irqsave(&info->irq_spinlock,flags);
- usc_DisableMasterIrqBit(info);
- usc_stop_receiver(info);
- usc_stop_transmitter(info);
- usc_DisableInterrupts(info,RECEIVE_DATA + RECEIVE_STATUS +
- TRANSMIT_DATA + TRANSMIT_STATUS + IO_PIN + MISC );
- usc_DisableDmaInterrupts(info,DICR_MASTER + DICR_TRANSMIT + DICR_RECEIVE);
-
- /* Disable DMAEN (Port 7, Bit 14) */
- /* This disconnects the DMA request signal from the ISA bus */
- /* on the ISA adapter. This has no effect for the PCI adapter */
- usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT15) | BIT14));
-
- /* Disable INTEN (Port 6, Bit12) */
- /* This disconnects the IRQ request signal to the ISA bus */
- /* on the ISA adapter. This has no effect for the PCI adapter */
- usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT13) | BIT12));
-
- if (!info->tty || info->tty->termios->c_cflag & HUPCL) {
- info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS);
- usc_set_serial_signals(info);
- }
-
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
- mgsl_release_resources(info);
-
- if (info->tty)
- set_bit(TTY_IO_ERROR, &info->tty->flags);
- info->flags &= ~ASYNC_INITIALIZED;
-
- } /* end of shutdown() */
- static void mgsl_program_hw(struct mgsl_struct *info)
- {
- unsigned long flags;
- spin_lock_irqsave(&info->irq_spinlock,flags);
-
- usc_stop_receiver(info);
- usc_stop_transmitter(info);
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-
- if (info->params.mode == MGSL_MODE_HDLC ||
- info->params.mode == MGSL_MODE_RAW ||
- info->netcount)
- usc_set_sync_mode(info);
- else
- usc_set_async_mode(info);
-
- usc_set_serial_signals(info);
-
- info->dcd_chkcount = 0;
- info->cts_chkcount = 0;
- info->ri_chkcount = 0;
- info->dsr_chkcount = 0;
- usc_EnableStatusIrqs(info,SICR_CTS+SICR_DSR+SICR_DCD+SICR_RI);
- usc_EnableInterrupts(info, IO_PIN);
- usc_get_serial_signals(info);
-
- if (info->netcount || info->tty->termios->c_cflag & CREAD)
- usc_start_receiver(info);
-
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
- }
- /* Reconfigure adapter based on new parameters
- */
- static void mgsl_change_params(struct mgsl_struct *info)
- {
- unsigned cflag;
- int bits_per_char;
- if (!info->tty || !info->tty->termios)
- return;
-
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):mgsl_change_params(%s)n",
- __FILE__,__LINE__, info->device_name );
-
- cflag = info->tty->termios->c_cflag;
- /* if B0 rate (hangup) specified then negate DTR and RTS */
- /* otherwise assert DTR and RTS */
- if (cflag & CBAUD)
- info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
- else
- info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
-
- /* byte size and parity */
-
- switch (cflag & CSIZE) {
- case CS5: info->params.data_bits = 5; break;
- case CS6: info->params.data_bits = 6; break;
- case CS7: info->params.data_bits = 7; break;
- case CS8: info->params.data_bits = 8; break;
- /* Never happens, but GCC is too dumb to figure it out */
- default: info->params.data_bits = 7; break;
- }
-
- if (cflag & CSTOPB)
- info->params.stop_bits = 2;
- else
- info->params.stop_bits = 1;
- info->params.parity = ASYNC_PARITY_NONE;
- if (cflag & PARENB) {
- if (cflag & PARODD)
- info->params.parity = ASYNC_PARITY_ODD;
- else
- info->params.parity = ASYNC_PARITY_EVEN;
- #ifdef CMSPAR
- if (cflag & CMSPAR)
- info->params.parity = ASYNC_PARITY_SPACE;
- #endif
- }
- /* calculate number of jiffies to transmit a full
- * FIFO (32 bytes) at specified data rate
- */
- bits_per_char = info->params.data_bits +
- info->params.stop_bits + 1;
- /* if port data rate is set to 460800 or less then
- * allow tty settings to override, otherwise keep the
- * current data rate.
- */
- if (info->params.data_rate <= 460800)
- info->params.data_rate = tty_get_baud_rate(info->tty);
-
- if ( info->params.data_rate ) {
- info->timeout = (32*HZ*bits_per_char) /
- info->params.data_rate;
- }
- info->timeout += HZ/50; /* Add .02 seconds of slop */
- if (cflag & CRTSCTS)
- info->flags |= ASYNC_CTS_FLOW;
- else
- info->flags &= ~ASYNC_CTS_FLOW;
-
- if (cflag & CLOCAL)
- info->flags &= ~ASYNC_CHECK_CD;
- else
- info->flags |= ASYNC_CHECK_CD;
- /* process tty input control flags */
-
- info->read_status_mask = RXSTATUS_OVERRUN;
- if (I_INPCK(info->tty))
- info->read_status_mask |= RXSTATUS_PARITY_ERROR | RXSTATUS_FRAMING_ERROR;
- if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
- info->read_status_mask |= RXSTATUS_BREAK_RECEIVED;
-
- if (I_IGNPAR(info->tty))
- info->ignore_status_mask |= RXSTATUS_PARITY_ERROR | RXSTATUS_FRAMING_ERROR;
- if (I_IGNBRK(info->tty)) {
- info->ignore_status_mask |= RXSTATUS_BREAK_RECEIVED;
- /* If ignoring parity and break indicators, ignore
- * overruns too. (For real raw support).
- */
- if (I_IGNPAR(info->tty))
- info->ignore_status_mask |= RXSTATUS_OVERRUN;
- }
- mgsl_program_hw(info);
- } /* end of mgsl_change_params() */
- /* mgsl_put_char()
- *
- * Add a character to the transmit buffer.
- *
- * Arguments: tty pointer to tty information structure
- * ch character to add to transmit buffer
- *
- * Return Value: None
- */
- static void mgsl_put_char(struct tty_struct *tty, unsigned char ch)
- {
- struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
- unsigned long flags;
- if ( debug_level >= DEBUG_LEVEL_INFO ) {
- printk( "%s(%d):mgsl_put_char(%d) on %sn",
- __FILE__,__LINE__,ch,info->device_name);
- }
-
- if (mgsl_paranoia_check(info, tty->device, "mgsl_put_char"))
- return;
- if (!tty || !info->xmit_buf)
- return;
- spin_lock_irqsave(&info->irq_spinlock,flags);
-
- if ( (info->params.mode == MGSL_MODE_ASYNC ) || !info->tx_active ) {
-
- if (info->xmit_cnt < SERIAL_XMIT_SIZE - 1) {
- info->xmit_buf[info->xmit_head++] = ch;
- info->xmit_head &= SERIAL_XMIT_SIZE-1;
- info->xmit_cnt++;
- }
- }
-
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
-
- } /* end of mgsl_put_char() */
- /* mgsl_flush_chars()
- *
- * Enable transmitter so remaining characters in the
- * transmit buffer are sent.
- *
- * Arguments: tty pointer to tty information structure
- * Return Value: None
- */
- static void mgsl_flush_chars(struct tty_struct *tty)
- {
- struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
- unsigned long flags;
-
- if ( debug_level >= DEBUG_LEVEL_INFO )
- printk( "%s(%d):mgsl_flush_chars() entry on %s xmit_cnt=%dn",
- __FILE__,__LINE__,info->device_name,info->xmit_cnt);
-
- if (mgsl_paranoia_check(info, tty->device, "mgsl_flush_chars"))
- return;
- if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
- !info->xmit_buf)
- return;
- if ( debug_level >= DEBUG_LEVEL_INFO )
- printk( "%s(%d):mgsl_flush_chars() entry on %s starting transmittern",
- __FILE__,__LINE__,info->device_name );
- spin_lock_irqsave(&info->irq_spinlock,flags);
-
- if (!info->tx_active) {
- if ( (info->params.mode == MGSL_MODE_HDLC ||
- info->params.mode == MGSL_MODE_RAW) && info->xmit_cnt ) {
- /* operating in synchronous (frame oriented) mode */
- /* copy data from circular xmit_buf to */
- /* transmit DMA buffer. */
- mgsl_load_tx_dma_buffer(info,
- info->xmit_buf,info->xmit_cnt);
- }
- usc_start_transmitter(info);
- }
-
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
-
- } /* end of mgsl_flush_chars() */
- /* mgsl_write()
- *
- * Send a block of data
- *
- * Arguments:
- *
- * tty pointer to tty information structure
- * from_user flag: 1 = from user process
- * buf pointer to buffer containing send data
- * count size of send data in bytes
- *
- * Return Value: number of characters written
- */
- static int mgsl_write(struct tty_struct * tty, int from_user,
- const unsigned char *buf, int count)
- {
- int c, ret = 0, err;
- struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
- unsigned long flags;
-
- if ( debug_level >= DEBUG_LEVEL_INFO )
- printk( "%s(%d):mgsl_write(%s) count=%dn",
- __FILE__,__LINE__,info->device_name,count);
-
- if (mgsl_paranoia_check(info, tty->device, "mgsl_write"))
- goto cleanup;
- if (!tty || !info->xmit_buf || !tmp_buf)
- goto cleanup;
- if ( info->params.mode == MGSL_MODE_HDLC ||
- info->params.mode == MGSL_MODE_RAW ) {
- /* operating in synchronous (frame oriented) mode */
- /* operating in synchronous (frame oriented) mode */
- if (info->tx_active) {
- if ( info->params.mode == MGSL_MODE_HDLC ) {
- ret = 0;
- goto cleanup;
- }
- /* transmitter is actively sending data -
- * if we have multiple transmit dma and
- * holding buffers, attempt to queue this
- * frame for transmission at a later time.
- */
- if (info->tx_holding_count >= info->num_tx_holding_buffers ) {
- /* no tx holding buffers available */
- ret = 0;
- goto cleanup;
- }
- /* queue transmit frame request */
- ret = count;
- if (from_user) {
- down(&tmp_buf_sem);
- COPY_FROM_USER(err,tmp_buf, buf, count);
- if (err) {
- if ( debug_level >= DEBUG_LEVEL_INFO )
- printk( "%s(%d):mgsl_write(%s) sync user buf copy failedn",
- __FILE__,__LINE__,info->device_name);
- ret = -EFAULT;
- } else
- save_tx_buffer_request(info,tmp_buf,count);
- up(&tmp_buf_sem);
- }
- else
- save_tx_buffer_request(info,buf,count);
- /* if we have sufficient tx dma buffers,
- * load the next buffered tx request
- */
- spin_lock_irqsave(&info->irq_spinlock,flags);
- load_next_tx_holding_buffer(info);
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
- goto cleanup;
- }
-
- /* if operating in HDLC LoopMode and the adapter */
- /* has yet to be inserted into the loop, we can't */
- /* transmit */
- if ( (info->params.flags & HDLC_FLAG_HDLC_LOOPMODE) &&
- !usc_loopmode_active(info) )
- {
- ret = 0;
- goto cleanup;
- }
- if ( info->xmit_cnt ) {
- /* Send accumulated from send_char() calls */
- /* as frame and wait before accepting more data. */
- ret = 0;
-
- /* copy data from circular xmit_buf to */
- /* transmit DMA buffer. */
- mgsl_load_tx_dma_buffer(info,
- info->xmit_buf,info->xmit_cnt);
- if ( debug_level >= DEBUG_LEVEL_INFO )
- printk( "%s(%d):mgsl_write(%s) sync xmit_cnt flushingn",
- __FILE__,__LINE__,info->device_name);
- } else {
- if ( debug_level >= DEBUG_LEVEL_INFO )
- printk( "%s(%d):mgsl_write(%s) sync transmit acceptedn",
- __FILE__,__LINE__,info->device_name);
- ret = count;
- info->xmit_cnt = count;
- if (from_user) {
- down(&tmp_buf_sem);
- COPY_FROM_USER(err,tmp_buf, buf, count);
- if (err) {
- if ( debug_level >= DEBUG_LEVEL_INFO )
- printk( "%s(%d):mgsl_write(%s) sync user buf copy failedn",
- __FILE__,__LINE__,info->device_name);
- ret = -EFAULT;
- } else
- mgsl_load_tx_dma_buffer(info,tmp_buf,count);
- up(&tmp_buf_sem);
- }
- else
- mgsl_load_tx_dma_buffer(info,buf,count);
- }
- } else {
- if (from_user) {
- down(&tmp_buf_sem);
- while (1) {
- c = MIN(count,
- MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
- SERIAL_XMIT_SIZE - info->xmit_head));
- if (c <= 0)
- break;
- COPY_FROM_USER(err,tmp_buf, buf, c);
- c -= err;
- if (!c) {
- if (!ret)
- ret = -EFAULT;
- break;
- }
- spin_lock_irqsave(&info->irq_spinlock,flags);
- c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
- SERIAL_XMIT_SIZE - info->xmit_head));
- memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
- info->xmit_head = ((info->xmit_head + c) &
- (SERIAL_XMIT_SIZE-1));
- info->xmit_cnt += c;
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
- buf += c;
- count -= c;
- ret += c;
- }
- up(&tmp_buf_sem);
- } else {
- while (1) {
- spin_lock_irqsave(&info->irq_spinlock,flags);
- c = MIN(count,
- MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
- SERIAL_XMIT_SIZE - info->xmit_head));
- if (c <= 0) {
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
- break;
- }
- memcpy(info->xmit_buf + info->xmit_head, buf, c);
- info->xmit_head = ((info->xmit_head + c) &
- (SERIAL_XMIT_SIZE-1));
- info->xmit_cnt += c;
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
- buf += c;
- count -= c;
- ret += c;
- }
- }
- }
-
- if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
- spin_lock_irqsave(&info->irq_spinlock,flags);
- if (!info->tx_active)
- usc_start_transmitter(info);
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
- }
- cleanup:
- if ( debug_level >= DEBUG_LEVEL_INFO )
- printk( "%s(%d):mgsl_write(%s) returning=%dn",
- __FILE__,__LINE__,info->device_name,ret);
-
- return ret;
-
- } /* end of mgsl_write() */
- /* mgsl_write_room()
- *
- * Return the count of free bytes in transmit buffer
- *
- * Arguments: tty pointer to tty info structure
- * Return Value: None
- */
- static int mgsl_write_room(struct tty_struct *tty)
- {
- struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
- int ret;
-
- if (mgsl_paranoia_check(info, tty->device, "mgsl_write_room"))
- return 0;
- ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
- if (ret < 0)
- ret = 0;
-
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):mgsl_write_room(%s)=%dn",
- __FILE__,__LINE__, info->device_name,ret );
-
- if ( info->params.mode == MGSL_MODE_HDLC ||
- info->params.mode == MGSL_MODE_RAW ) {
- /* operating in synchronous (frame oriented) mode */
- if ( info->tx_active )
- return 0;
- else
- return HDLC_MAX_FRAME_SIZE;
- }
-
- return ret;
-
- } /* end of mgsl_write_room() */
- /* mgsl_chars_in_buffer()
- *
- * Return the count of bytes in transmit buffer
- *
- * Arguments: tty pointer to tty info structure
- * Return Value: None
- */
- static int mgsl_chars_in_buffer(struct tty_struct *tty)
- {
- struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
-
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):mgsl_chars_in_buffer(%s)n",
- __FILE__,__LINE__, info->device_name );
-
- if (mgsl_paranoia_check(info, tty->device, "mgsl_chars_in_buffer"))
- return 0;
-
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):mgsl_chars_in_buffer(%s)=%dn",
- __FILE__,__LINE__, info->device_name,info->xmit_cnt );
-
- if ( info->params.mode == MGSL_MODE_HDLC ||
- info->params.mode == MGSL_MODE_RAW ) {
- /* operating in synchronous (frame oriented) mode */
- if ( info->tx_active )
- return info->max_frame_size;
- else
- return 0;
- }
-
- return info->xmit_cnt;
- } /* end of mgsl_chars_in_buffer() */
- /* mgsl_flush_buffer()
- *
- * Discard all data in the send buffer
- *
- * Arguments: tty pointer to tty info structure
- * Return Value: None
- */
- static void mgsl_flush_buffer(struct tty_struct *tty)
- {
- struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
- unsigned long flags;
-
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):mgsl_flush_buffer(%s) entryn",
- __FILE__,__LINE__, info->device_name );
-
- if (mgsl_paranoia_check(info, tty->device, "mgsl_flush_buffer"))
- return;
-
- spin_lock_irqsave(&info->irq_spinlock,flags);
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
- del_timer(&info->tx_timer);
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
-
- wake_up_interruptible(&tty->write_wait);
- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
- tty->ldisc.write_wakeup)
- (tty->ldisc.write_wakeup)(tty);
-
- } /* end of mgsl_flush_buffer() */
- /* mgsl_send_xchar()
- *
- * Send a high-priority XON/XOFF character
- *
- * Arguments: tty pointer to tty info structure
- * ch character to send
- * Return Value: None
- */
- static void mgsl_send_xchar(struct tty_struct *tty, char ch)
- {
- struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
- unsigned long flags;
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):mgsl_send_xchar(%s,%d)n",
- __FILE__,__LINE__, info->device_name, ch );
-
- if (mgsl_paranoia_check(info, tty->device, "mgsl_send_xchar"))
- return;
- info->x_char = ch;
- if (ch) {
- /* Make sure transmit interrupts are on */
- 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_send_xchar() */
- /* mgsl_throttle()
- *
- * Signal remote device to throttle send data (our receive data)
- *
- * Arguments: tty pointer to tty info structure
- * Return Value: None
- */
- static void mgsl_throttle(struct tty_struct * tty)
- {
- struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
- unsigned long flags;
-
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):mgsl_throttle(%s) entryn",
- __FILE__,__LINE__, info->device_name );
- if (mgsl_paranoia_check(info, tty->device, "mgsl_throttle"))
- return;
-
- if (I_IXOFF(tty))
- mgsl_send_xchar(tty, STOP_CHAR(tty));
-
- if (tty->termios->c_cflag & CRTSCTS) {
- spin_lock_irqsave(&info->irq_spinlock,flags);
- info->serial_signals &= ~SerialSignal_RTS;
- usc_set_serial_signals(info);
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
- }
- } /* end of mgsl_throttle() */
- /* mgsl_unthrottle()
- *
- * Signal remote device to stop throttling send data (our receive data)
- *
- * Arguments: tty pointer to tty info structure
- * Return Value: None
- */
- static void mgsl_unthrottle(struct tty_struct * tty)
- {
- struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
- unsigned long flags;
-
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):mgsl_unthrottle(%s) entryn",
- __FILE__,__LINE__, info->device_name );
- if (mgsl_paranoia_check(info, tty->device, "mgsl_unthrottle"))
- return;
-
- if (I_IXOFF(tty)) {
- if (info->x_char)
- info->x_char = 0;
- else
- mgsl_send_xchar(tty, START_CHAR(tty));
- }
-
- if (tty->termios->c_cflag & CRTSCTS) {
- spin_lock_irqsave(&info->irq_spinlock,flags);
- info->serial_signals |= SerialSignal_RTS;
- usc_set_serial_signals(info);
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
- }
-
- } /* end of mgsl_unthrottle() */
- /* mgsl_get_stats()
- *
- * get the current serial parameters information
- *
- * Arguments: info pointer to device instance data
- * user_icount pointer to buffer to hold returned stats
- *
- * Return Value: 0 if success, otherwise error code
- */
- static int mgsl_get_stats(struct mgsl_struct * info, struct mgsl_icount *user_icount)
- {
- int err;
-
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):mgsl_get_params(%s)n",
- __FILE__,__LINE__, info->device_name);
-
- COPY_TO_USER(err,user_icount, &info->icount, sizeof(struct mgsl_icount));
- if (err) {
- if ( debug_level >= DEBUG_LEVEL_INFO )
- printk( "%s(%d):mgsl_get_stats(%s) user buffer copy failedn",
- __FILE__,__LINE__,info->device_name);
- return -EFAULT;
- }
-
- return 0;
-
- } /* end of mgsl_get_stats() */
- /* mgsl_get_params()
- *
- * get the current serial parameters information
- *
- * Arguments: info pointer to device instance data
- * user_params pointer to buffer to hold returned params
- *
- * Return Value: 0 if success, otherwise error code
- */
- static int mgsl_get_params(struct mgsl_struct * info, MGSL_PARAMS *user_params)
- {
- int err;
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):mgsl_get_params(%s)n",
- __FILE__,__LINE__, info->device_name);
-
- COPY_TO_USER(err,user_params, &info->params, sizeof(MGSL_PARAMS));
- if (err) {
- if ( debug_level >= DEBUG_LEVEL_INFO )
- printk( "%s(%d):mgsl_get_params(%s) user buffer copy failedn",
- __FILE__,__LINE__,info->device_name);
- return -EFAULT;
- }
-
- return 0;
-
- } /* end of mgsl_get_params() */
- /* mgsl_set_params()
- *
- * set the serial parameters
- *
- * Arguments:
- *
- * info pointer to device instance data
- * new_params user buffer containing new serial params
- *
- * Return Value: 0 if success, otherwise error code
- */
- static int mgsl_set_params(struct mgsl_struct * info, MGSL_PARAMS *new_params)
- {
- unsigned long flags;
- MGSL_PARAMS tmp_params;
- int err;
-
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):mgsl_set_params %sn", __FILE__,__LINE__,
- info->device_name );
- COPY_FROM_USER(err,&tmp_params, new_params, sizeof(MGSL_PARAMS));
- if (err) {
- if ( debug_level >= DEBUG_LEVEL_INFO )
- printk( "%s(%d):mgsl_set_params(%s) user buffer copy failedn",
- __FILE__,__LINE__,info->device_name);
- return -EFAULT;
- }
-
- spin_lock_irqsave(&info->irq_spinlock,flags);
- memcpy(&info->params,&tmp_params,sizeof(MGSL_PARAMS));
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
-
- mgsl_change_params(info);
-
- return 0;
-
- } /* end of mgsl_set_params() */
- /* mgsl_get_txidle()
- *
- * get the current transmit idle mode
- *
- * Arguments: info pointer to device instance data
- * idle_mode pointer to buffer to hold returned idle mode
- *
- * Return Value: 0 if success, otherwise error code
- */
- static int mgsl_get_txidle(struct mgsl_struct * info, int*idle_mode)
- {
- int err;
-
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):mgsl_get_txidle(%s)=%dn",
- __FILE__,__LINE__, info->device_name, info->idle_mode);
-
- COPY_TO_USER(err,idle_mode, &info->idle_mode, sizeof(int));
- if (err) {
- if ( debug_level >= DEBUG_LEVEL_INFO )
- printk( "%s(%d):mgsl_get_txidle(%s) user buffer copy failedn",
- __FILE__,__LINE__,info->device_name);
- return -EFAULT;
- }
-
- return 0;
-
- } /* end of mgsl_get_txidle() */
- /* mgsl_set_txidle() service ioctl to set transmit idle mode
- *
- * Arguments: info pointer to device instance data
- * idle_mode new idle mode
- *
- * Return Value: 0 if success, otherwise error code
- */
- static int mgsl_set_txidle(struct mgsl_struct * info, int idle_mode)
- {
- unsigned long flags;
-
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):mgsl_set_txidle(%s,%d)n", __FILE__,__LINE__,
- info->device_name, idle_mode );
-
- spin_lock_irqsave(&info->irq_spinlock,flags);
- info->idle_mode = idle_mode;
- usc_set_txidle( info );
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
- return 0;
-
- } /* end of mgsl_set_txidle() */
- /* mgsl_txenable()
- *
- * enable or disable the transmitter
- *
- * Arguments:
- *
- * info pointer to device instance data
- * enable 1 = enable, 0 = disable
- *
- * Return Value: 0 if success, otherwise error code
- */
- static int mgsl_txenable(struct mgsl_struct * info, int enable)
- {
- unsigned long flags;
-
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):mgsl_txenable(%s,%d)n", __FILE__,__LINE__,
- info->device_name, enable);
-
- spin_lock_irqsave(&info->irq_spinlock,flags);
- if ( enable ) {
- if ( !info->tx_enabled ) {
- usc_start_transmitter(info);
- /*--------------------------------------------------
- * if HDLC/SDLC Loop mode, attempt to insert the
- * station in the 'loop' by setting CMR:13. Upon
- * receipt of the next GoAhead (RxAbort) sequence,
- * the OnLoop indicator (CCSR:7) should go active
- * to indicate that we are on the loop
- *--------------------------------------------------*/
- if ( info->params.flags & HDLC_FLAG_HDLC_LOOPMODE )
- usc_loopmode_insert_request( info );
- }
- } else {
- if ( info->tx_enabled )
- usc_stop_transmitter(info);
- }
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
- return 0;
-
- } /* end of mgsl_txenable() */
- /* mgsl_txabort() abort send HDLC frame
- *
- * Arguments: info pointer to device instance data
- * Return Value: 0 if success, otherwise error code
- */
- static int mgsl_txabort(struct mgsl_struct * info)
- {
- unsigned long flags;
-
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):mgsl_txabort(%s)n", __FILE__,__LINE__,
- info->device_name);
-
- spin_lock_irqsave(&info->irq_spinlock,flags);
- if ( info->tx_active && info->params.mode == MGSL_MODE_HDLC )
- {
- if ( info->params.flags & HDLC_FLAG_HDLC_LOOPMODE )
- usc_loopmode_cancel_transmit( info );
- else
- usc_TCmd(info,TCmd_SendAbort);
- }
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
- return 0;
-
- } /* end of mgsl_txabort() */
- /* mgsl_rxenable() enable or disable the receiver
- *
- * Arguments: info pointer to device instance data
- * enable 1 = enable, 0 = disable
- * Return Value: 0 if success, otherwise error code
- */
- static int mgsl_rxenable(struct mgsl_struct * info, int enable)
- {
- unsigned long flags;
-
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):mgsl_rxenable(%s,%d)n", __FILE__,__LINE__,
- info->device_name, enable);
-
- spin_lock_irqsave(&info->irq_spinlock,flags);
- if ( enable ) {
- if ( !info->rx_enabled )
- usc_start_receiver(info);
- } else {
- if ( info->rx_enabled )
- usc_stop_receiver(info);
- }
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
- return 0;
-
- } /* end of mgsl_rxenable() */
- /* mgsl_wait_event() wait for specified event to occur
- *
- * Arguments: info pointer to device instance data
- * mask pointer to bitmask of events to wait for
- * Return Value: 0 if successful and bit mask updated with
- * of events triggerred,
- * otherwise error code
- */
- static int mgsl_wait_event(struct mgsl_struct * info, int * mask_ptr)
- {
- unsigned long flags;
- int s;
- int rc=0;
- struct mgsl_icount cprev, cnow;
- int events;
- int mask;
- struct _input_signal_events oldsigs, newsigs;
- DECLARE_WAITQUEUE(wait, current);
- COPY_FROM_USER(rc,&mask, mask_ptr, sizeof(int));
- if (rc) {
- return -EFAULT;
- }
-
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):mgsl_wait_event(%s,%d)n", __FILE__,__LINE__,
- info->device_name, mask);
- spin_lock_irqsave(&info->irq_spinlock,flags);
- /* return immediately if state matches requested events */
- usc_get_serial_signals(info);
- s = info->serial_signals;
- events = mask &
- ( ((s & SerialSignal_DSR) ? MgslEvent_DsrActive:MgslEvent_DsrInactive) +
- ((s & SerialSignal_DCD) ? MgslEvent_DcdActive:MgslEvent_DcdInactive) +
- ((s & SerialSignal_CTS) ? MgslEvent_CtsActive:MgslEvent_CtsInactive) +
- ((s & SerialSignal_RI) ? MgslEvent_RiActive :MgslEvent_RiInactive) );
- if (events) {
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
- goto exit;
- }
- /* save current irq counts */
- cprev = info->icount;
- oldsigs = info->input_signal_events;
-
- /* enable hunt and idle irqs if needed */
- if (mask & (MgslEvent_ExitHuntMode + MgslEvent_IdleReceived)) {
- u16 oldreg = usc_InReg(info,RICR);
- u16 newreg = oldreg +
- (mask & MgslEvent_ExitHuntMode ? RXSTATUS_EXITED_HUNT:0) +
- (mask & MgslEvent_IdleReceived ? RXSTATUS_IDLE_RECEIVED:0);
- if (oldreg != newreg)
- usc_OutReg(info, RICR, newreg);
- }
-
- set_current_state(TASK_INTERRUPTIBLE);
- add_wait_queue(&info->event_wait_q, &wait);
-
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
-
- for(;;) {
- schedule();
- if (signal_pending(current)) {
- rc = -ERESTARTSYS;
- break;
- }
-
- /* get current irq counts */
- spin_lock_irqsave(&info->irq_spinlock,flags);
- cnow = info->icount;
- newsigs = info->input_signal_events;
- set_current_state(TASK_INTERRUPTIBLE);
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
- /* if no change, wait aborted for some reason */
- if (newsigs.dsr_up == oldsigs.dsr_up &&
- newsigs.dsr_down == oldsigs.dsr_down &&
- newsigs.dcd_up == oldsigs.dcd_up &&
- newsigs.dcd_down == oldsigs.dcd_down &&
- newsigs.cts_up == oldsigs.cts_up &&
- newsigs.cts_down == oldsigs.cts_down &&
- newsigs.ri_up == oldsigs.ri_up &&
- newsigs.ri_down == oldsigs.ri_down &&
- cnow.exithunt == cprev.exithunt &&
- cnow.rxidle == cprev.rxidle) {
- rc = -EIO;
- break;
- }
- events = mask &
- ( (newsigs.dsr_up != oldsigs.dsr_up ? MgslEvent_DsrActive:0) +
- (newsigs.dsr_down != oldsigs.dsr_down ? MgslEvent_DsrInactive:0) +
- (newsigs.dcd_up != oldsigs.dcd_up ? MgslEvent_DcdActive:0) +
- (newsigs.dcd_down != oldsigs.dcd_down ? MgslEvent_DcdInactive:0) +
- (newsigs.cts_up != oldsigs.cts_up ? MgslEvent_CtsActive:0) +
- (newsigs.cts_down != oldsigs.cts_down ? MgslEvent_CtsInactive:0) +
- (newsigs.ri_up != oldsigs.ri_up ? MgslEvent_RiActive:0) +
- (newsigs.ri_down != oldsigs.ri_down ? MgslEvent_RiInactive:0) +
- (cnow.exithunt != cprev.exithunt ? MgslEvent_ExitHuntMode:0) +
- (cnow.rxidle != cprev.rxidle ? MgslEvent_IdleReceived:0) );
- if (events)
- break;
-
- cprev = cnow;
- oldsigs = newsigs;
- }
-
- remove_wait_queue(&info->event_wait_q, &wait);
- set_current_state(TASK_RUNNING);
- if (mask & (MgslEvent_ExitHuntMode + MgslEvent_IdleReceived)) {
- spin_lock_irqsave(&info->irq_spinlock,flags);
- if (!waitqueue_active(&info->event_wait_q)) {
- /* disable enable exit hunt mode/idle rcvd IRQs */
- usc_OutReg(info, RICR, usc_InReg(info,RICR) &
- ~(RXSTATUS_EXITED_HUNT + RXSTATUS_IDLE_RECEIVED));
- }
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
- }
- exit:
- if ( rc == 0 )
- PUT_USER(rc, events, mask_ptr);
-
- return rc;
-
- } /* end of mgsl_wait_event() */
- static int modem_input_wait(struct mgsl_struct *info,int arg)
- {
- unsigned long flags;
- int rc;
- struct mgsl_icount cprev, cnow;
- DECLARE_WAITQUEUE(wait, current);
- /* save current irq counts */
- spin_lock_irqsave(&info->irq_spinlock,flags);
- cprev = info->icount;
- add_wait_queue(&info->status_event_wait_q, &wait);
- set_current_state(TASK_INTERRUPTIBLE);
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
- for(;;) {
- schedule();
- if (signal_pending(current)) {
- rc = -ERESTARTSYS;
- break;
- }
- /* get new irq counts */
- spin_lock_irqsave(&info->irq_spinlock,flags);
- cnow = info->icount;
- set_current_state(TASK_INTERRUPTIBLE);
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
- /* if no change, wait aborted for some reason */
- if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
- cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) {
- rc = -EIO;
- break;
- }
- /* check for change in caller specified modem input */
- if ((arg & TIOCM_RNG && cnow.rng != cprev.rng) ||
- (arg & TIOCM_DSR && cnow.dsr != cprev.dsr) ||
- (arg & TIOCM_CD && cnow.dcd != cprev.dcd) ||
- (arg & TIOCM_CTS && cnow.cts != cprev.cts)) {
- rc = 0;
- break;
- }
- cprev = cnow;
- }
- remove_wait_queue(&info->status_event_wait_q, &wait);
- set_current_state(TASK_RUNNING);
- return rc;
- }
- /* get_modem_info()
- *
- * Read the state of the serial control and
- * status signals and return to caller.
- *
- * Arguments: info pointer to device instance data
- * value pointer to int to hold returned info
- *
- * Return Value: 0 if success, otherwise error code
- */
- static int get_modem_info(struct mgsl_struct * info, unsigned int *value)
- {
- unsigned int result = 0;
- unsigned long flags;
- int err;
-
- spin_lock_irqsave(&info->irq_spinlock,flags);
- usc_get_serial_signals(info);
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
- if (info->serial_signals & SerialSignal_RTS)
- result |= TIOCM_RTS;
- if (info->serial_signals & SerialSignal_DTR)
- result |= TIOCM_DTR;
- if (info->serial_signals & SerialSignal_DCD)
- result |= TIOCM_CAR;
- if (info->serial_signals & SerialSignal_RI)
- result |= TIOCM_RNG;
- if (info->serial_signals & SerialSignal_DSR)
- result |= TIOCM_DSR;
- if (info->serial_signals & SerialSignal_CTS)
- result |= TIOCM_CTS;
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):mgsl_get_modem_info %s value=%08Xn",
- __FILE__,__LINE__, info->device_name, result );
-
- PUT_USER(err,result,value);
- return err;
- } /* end of get_modem_info() */
- /* set_modem_info()
- *
- * Set the state of the modem control signals (DTR/RTS)
- *
- * Arguments:
- *
- * info pointer to device instance data
- * cmd signal command: TIOCMBIS = set bit TIOCMBIC = clear bit
- * TIOCMSET = set/clear signal values
- * value bit mask for command
- *
- * Return Value: 0 if success, otherwise error code
- */
- static int set_modem_info(struct mgsl_struct * info, unsigned int cmd,
- unsigned int *value)
- {
- int error;
- unsigned int arg;
- unsigned long flags;
-
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):mgsl_set_modem_info %sn", __FILE__,__LINE__,
- info->device_name );
-
- GET_USER(error,arg,value);
- if (error)
- return error;
-
- switch (cmd) {
- case TIOCMBIS:
- if (arg & TIOCM_RTS)
- info->serial_signals |= SerialSignal_RTS;
- if (arg & TIOCM_DTR)
- info->serial_signals |= SerialSignal_DTR;
- break;
- case TIOCMBIC:
- if (arg & TIOCM_RTS)
- info->serial_signals &= ~SerialSignal_RTS;
- if (arg & TIOCM_DTR)
- info->serial_signals &= ~SerialSignal_DTR;
- break;
- case TIOCMSET:
- if (arg & TIOCM_RTS)
- info->serial_signals |= SerialSignal_RTS;
- else
- info->serial_signals &= ~SerialSignal_RTS;
-
- if (arg & TIOCM_DTR)
- info->serial_signals |= SerialSignal_DTR;
- else
- info->serial_signals &= ~SerialSignal_DTR;
- break;
- default:
- return -EINVAL;
- }
-
- spin_lock_irqsave(&info->irq_spinlock,flags);
- usc_set_serial_signals(info);
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
-
- return 0;
-
- } /* end of set_modem_info() */
- /* mgsl_break() Set or clear transmit break condition
- *
- * Arguments: tty pointer to tty instance data
- * break_state -1=set break condition, 0=clear
- * Return Value: None
- */
- static void mgsl_break(struct tty_struct *tty, int break_state)
- {
- struct mgsl_struct * info = (struct mgsl_struct *)tty->driver_data;
- unsigned long flags;
-
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):mgsl_break(%s,%d)n",
- __FILE__,__LINE__, info->device_name, break_state);
-
- if (mgsl_paranoia_check(info, tty->device, "mgsl_break"))
- return;
- spin_lock_irqsave(&info->irq_spinlock,flags);
- if (break_state == -1)
- usc_OutReg(info,IOCR,(u16)(usc_InReg(info,IOCR) | BIT7));
- else
- usc_OutReg(info,IOCR,(u16)(usc_InReg(info,IOCR) & ~BIT7));
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
-
- } /* end of mgsl_break() */
- /* mgsl_ioctl() Service an IOCTL request
- *
- * Arguments:
- *
- * tty pointer to tty instance data
- * file pointer to associated file object for device
- * cmd IOCTL command code
- * arg command argument/context
- *
- * Return Value: 0 if success, otherwise error code
- */
- static int mgsl_ioctl(struct tty_struct *tty, struct file * file,
- unsigned int cmd, unsigned long arg)
- {
- struct mgsl_struct * info = (struct mgsl_struct *)tty->driver_data;
-
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):mgsl_ioctl %s cmd=%08Xn", __FILE__,__LINE__,
- info->device_name, cmd );
-
- if (mgsl_paranoia_check(info, tty->device, "mgsl_ioctl"))
- return -ENODEV;
- if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
- (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
- if (tty->flags & (1 << TTY_IO_ERROR))
- return -EIO;
- }
- return mgsl_ioctl_common(info, cmd, arg);
- }
- int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigned long arg)
- {
- int error;
- struct mgsl_icount cnow; /* kernel counter temps */
- struct serial_icounter_struct *p_cuser; /* user space */
- unsigned long flags;
-
- switch (cmd) {
- case TIOCMGET:
- return get_modem_info(info, (unsigned int *) arg);
- case TIOCMBIS:
- case TIOCMBIC:
- case TIOCMSET:
- return set_modem_info(info, cmd, (unsigned int *) arg);
- case MGSL_IOCGPARAMS:
- return mgsl_get_params(info,(MGSL_PARAMS *)arg);
- case MGSL_IOCSPARAMS:
- return mgsl_set_params(info,(MGSL_PARAMS *)arg);
- case MGSL_IOCGTXIDLE:
- return mgsl_get_txidle(info,(int*)arg);
- case MGSL_IOCSTXIDLE:
- return mgsl_set_txidle(info,(int)arg);
- case MGSL_IOCTXENABLE:
- return mgsl_txenable(info,(int)arg);
- case MGSL_IOCRXENABLE:
- return mgsl_rxenable(info,(int)arg);
- case MGSL_IOCTXABORT:
- return mgsl_txabort(info);
- case MGSL_IOCGSTATS:
- return mgsl_get_stats(info,(struct mgsl_icount*)arg);
- case MGSL_IOCWAITEVENT:
- return mgsl_wait_event(info,(int*)arg);
- case MGSL_IOCLOOPTXDONE:
- return mgsl_loopmode_send_done(info);
- case MGSL_IOCCLRMODCOUNT:
- while(MOD_IN_USE)
- MOD_DEC_USE_COUNT;
- return 0;
- /* Wait for modem input (DCD,RI,DSR,CTS) change
- * as specified by mask in arg (TIOCM_RNG/DSR/CD/CTS)
- */
- case TIOCMIWAIT:
- return modem_input_wait(info,(int)arg);
- /*
- * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
- * Return: write counters to the user passed counter struct
- * NB: both 1->0 and 0->1 transitions are counted except for
- * RI where only 0->1 is counted.
- */
- case TIOCGICOUNT:
- spin_lock_irqsave(&info->irq_spinlock,flags);
- cnow = info->icount;
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
- p_cuser = (struct serial_icounter_struct *) arg;
- PUT_USER(error,cnow.cts, &p_cuser->cts);
- if (error) return error;
- PUT_USER(error,cnow.dsr, &p_cuser->dsr);
- if (error) return error;
- PUT_USER(error,cnow.rng, &p_cuser->rng);
- if (error) return error;
- PUT_USER(error,cnow.dcd, &p_cuser->dcd);
- if (error) return error;
- PUT_USER(error,cnow.rx, &p_cuser->rx);
- if (error) return error;
- PUT_USER(error,cnow.tx, &p_cuser->tx);
- if (error) return error;
- PUT_USER(error,cnow.frame, &p_cuser->frame);
- if (error) return error;
- PUT_USER(error,cnow.overrun, &p_cuser->overrun);
- if (error) return error;
- PUT_USER(error,cnow.parity, &p_cuser->parity);
- if (error) return error;
- PUT_USER(error,cnow.brk, &p_cuser->brk);
- if (error) return error;
- PUT_USER(error,cnow.buf_overrun, &p_cuser->buf_overrun);
- if (error) return error;
- return 0;
- default:
- return -ENOIOCTLCMD;
- }
- return 0;
- }
- /* mgsl_set_termios()
- *
- * Set new termios settings
- *
- * Arguments:
- *
- * tty pointer to tty structure
- * termios pointer to buffer to hold returned old termios
- *
- * Return Value: None
- */
- static void mgsl_set_termios(struct tty_struct *tty, struct termios *old_termios)
- {
- struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
- unsigned long flags;
-
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):mgsl_set_termios %sn", __FILE__,__LINE__,
- tty->driver.name );
-
- /* just return if nothing has changed */
- if ((tty->termios->c_cflag == old_termios->c_cflag)
- && (RELEVANT_IFLAG(tty->termios->c_iflag)
- == RELEVANT_IFLAG(old_termios->c_iflag)))
- return;
- mgsl_change_params(info);
- /* Handle transition to B0 status */
- if (old_termios->c_cflag & CBAUD &&
- !(tty->termios->c_cflag & CBAUD)) {
- info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
- spin_lock_irqsave(&info->irq_spinlock,flags);
- usc_set_serial_signals(info);
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
- }
-
- /* Handle transition away from B0 status */
- if (!(old_termios->c_cflag & CBAUD) &&
- tty->termios->c_cflag & CBAUD) {
- info->serial_signals |= SerialSignal_DTR;
- if (!(tty->termios->c_cflag & CRTSCTS) ||
- !test_bit(TTY_THROTTLED, &tty->flags)) {
- info->serial_signals |= SerialSignal_RTS;
- }
- spin_lock_irqsave(&info->irq_spinlock,flags);
- usc_set_serial_signals(info);
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
- }
-
- /* Handle turning off CRTSCTS */
- if (old_termios->c_cflag & CRTSCTS &&
- !(tty->termios->c_cflag & CRTSCTS)) {
- tty->hw_stopped = 0;
- mgsl_start(tty);
- }
- } /* end of mgsl_set_termios() */
- /* mgsl_close()
- *
- * Called when port is closed. Wait for remaining data to be
- * sent. Disable port and free resources.
- *
- * Arguments:
- *
- * tty pointer to open tty structure
- * filp pointer to open file object
- *
- * Return Value: None
- */
- static void mgsl_close(struct tty_struct *tty, struct file * filp)
- {
- struct mgsl_struct * info = (struct mgsl_struct *)tty->driver_data;
- if (!info || mgsl_paranoia_check(info, tty->device, "mgsl_close"))
- return;
-
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):mgsl_close(%s) entry, count=%dn",
- __FILE__,__LINE__, info->device_name, info->count);
-
- if (!info->count || tty_hung_up_p(filp))
- goto cleanup;
-
- if ((tty->count == 1) && (info->count != 1)) {
- /*
- * tty->count is 1 and the tty structure will be freed.
- * info->count should be one in this case.
- * if it's not, correct it so that the port is shutdown.
- */
- printk("mgsl_close: bad refcount; tty->count is 1, "
- "info->count is %dn", info->count);
- info->count = 1;
- }
-
- info->count--;
-
- /* if at least one open remaining, leave hardware active */
- if (info->count)
- goto cleanup;
-
- info->flags |= ASYNC_CLOSING;
-
- /* Save the termios structure, since this port may have
- * separate termios for callout and dialin.
- */
- if (info->flags & ASYNC_NORMAL_ACTIVE)
- info->normal_termios = *tty->termios;
- if (info->flags & ASYNC_CALLOUT_ACTIVE)
- info->callout_termios = *tty->termios;
-
- /* set tty->closing to notify line discipline to
- * only process XON/XOFF characters. Only the N_TTY
- * discipline appears to use this (ppp does not).
- */
- tty->closing = 1;
-
- /* wait for transmit data to clear all layers */
-
- if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) {
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):mgsl_close(%s) calling tty_wait_until_sentn",
- __FILE__,__LINE__, info->device_name );
- tty_wait_until_sent(tty, info->closing_wait);
- }
-
- if (info->flags & ASYNC_INITIALIZED)
- mgsl_wait_until_sent(tty, info->timeout);
- if (tty->driver.flush_buffer)
- tty->driver.flush_buffer(tty);
-
- if (tty->ldisc.flush_buffer)
- tty->ldisc.flush_buffer(tty);
-
- shutdown(info);
-
- tty->closing = 0;
- info->tty = 0;
-
- if (info->blocked_open) {
- if (info->close_delay) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(info->close_delay);
- }
- wake_up_interruptible(&info->open_wait);
- }
-
- info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
- ASYNC_CLOSING);
-
- wake_up_interruptible(&info->close_wait);
-
- cleanup:
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):mgsl_close(%s) exit, count=%dn", __FILE__,__LINE__,
- tty->driver.name, info->count);
- if(MOD_IN_USE)
- MOD_DEC_USE_COUNT;
-
- } /* end of mgsl_close() */
- /* mgsl_wait_until_sent()
- *
- * Wait until the transmitter is empty.
- *
- * Arguments:
- *
- * tty pointer to tty info structure
- * timeout time to wait for send completion
- *
- * Return Value: None
- */
- static void mgsl_wait_until_sent(struct tty_struct *tty, int timeout)
- {
- struct mgsl_struct * info = (struct mgsl_struct *)tty->driver_data;
- unsigned long orig_jiffies, char_time;
- if (!info )
- return;
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):mgsl_wait_until_sent(%s) entryn",
- __FILE__,__LINE__, info->device_name );
-
- if (mgsl_paranoia_check(info, tty->device, "mgsl_wait_until_sent"))
- return;
- if (!(info->flags & ASYNC_INITIALIZED))
- goto exit;
-
- orig_jiffies = jiffies;
-
- /* Set check interval to 1/5 of estimated time to
- * send a character, and make it at least 1. The check
- * interval should also be less than the timeout.
- * Note: use tight timings here to satisfy the NIST-PCTS.
- */
-
- if ( info->params.data_rate ) {
- char_time = info->timeout/(32 * 5);
- if (!char_time)
- char_time++;
- } else
- char_time = 1;
-
- if (timeout)
- char_time = MIN(char_time, timeout);
-
- if ( info->params.mode == MGSL_MODE_HDLC ||
- info->params.mode == MGSL_MODE_RAW ) {
- while (info->tx_active) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(char_time);
- if (signal_pending(current))
- break;
- if (timeout && ((orig_jiffies + timeout) < jiffies))
- break;
- }
- } else {
- while (!(usc_InReg(info,TCSR) & TXSTATUS_ALL_SENT) &&
- info->tx_enabled) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(char_time);
- if (signal_pending(current))
- break;
- if (timeout && ((orig_jiffies + timeout) < jiffies))
- break;
- }
- }
-
- exit:
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):mgsl_wait_until_sent(%s) exitn",
- __FILE__,__LINE__, info->device_name );
-
- } /* end of mgsl_wait_until_sent() */
- /* mgsl_hangup()
- *
- * Called by tty_hangup() when a hangup is signaled.
- * This is the same as to closing all open files for the port.
- *
- * Arguments: tty pointer to associated tty object
- * Return Value: None
- */
- static void mgsl_hangup(struct tty_struct *tty)
- {
- struct mgsl_struct * info = (struct mgsl_struct *)tty->driver_data;
-
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):mgsl_hangup(%s)n",
- __FILE__,__LINE__, info->device_name );
-
- if (mgsl_paranoia_check(info, tty->device, "mgsl_hangup"))
- return;
- mgsl_flush_buffer(tty);
- shutdown(info);
-
- info->count = 0;
- info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
- info->tty = 0;
- wake_up_interruptible(&info->open_wait);
-
- } /* end of mgsl_hangup() */
- /* block_til_ready()
- *
- * Block the current process until the specified port
- * is ready to be opened.
- *
- * Arguments:
- *
- * tty pointer to tty info structure
- * filp pointer to open file object
- * info pointer to device instance data
- *
- * Return Value: 0 if success, otherwise error code
- */
- static int block_til_ready(struct tty_struct *tty, struct file * filp,
- struct mgsl_struct *info)
- {
- DECLARE_WAITQUEUE(wait, current);
- int retval;
- int do_clocal = 0, extra_count = 0;
- unsigned long flags;
-
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):block_til_ready on %sn",
- __FILE__,__LINE__, tty->driver.name );
- if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
- /* this is a callout device */
- /* just verify that normal device is not in use */
- if (info->flags & ASYNC_NORMAL_ACTIVE)
- return -EBUSY;
- if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
- (info->flags & ASYNC_SESSION_LOCKOUT) &&
- (info->session != current->session))
- return -EBUSY;
- if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
- (info->flags & ASYNC_PGRP_LOCKOUT) &&
- (info->pgrp != current->pgrp))
- return -EBUSY;
- info->flags |= ASYNC_CALLOUT_ACTIVE;
- return 0;
- }
-
- if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){
- /* nonblock mode is set or port is not enabled */
- /* just verify that callout device is not active */
- if (info->flags & ASYNC_CALLOUT_ACTIVE)
- return -EBUSY;
- info->flags |= ASYNC_NORMAL_ACTIVE;
- return 0;
- }
- if (info->flags & ASYNC_CALLOUT_ACTIVE) {
- if (info->normal_termios.c_cflag & CLOCAL)
- do_clocal = 1;
- } else {
- if (tty->termios->c_cflag & CLOCAL)
- do_clocal = 1;
- }
-
- /* Wait for carrier detect and the line to become
- * free (i.e., not in use by the callout). While we are in
- * this loop, info->count is dropped by one, so that
- * mgsl_close() knows when to free things. We restore it upon
- * exit, either normal or abnormal.
- */
-
- retval = 0;
- add_wait_queue(&info->open_wait, &wait);
-
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):block_til_ready before block on %s count=%dn",
- __FILE__,__LINE__, tty->driver.name, info->count );
- save_flags(flags); cli();
- if (!tty_hung_up_p(filp)) {
- extra_count = 1;
- info->count--;
- }
- restore_flags(flags);
- info->blocked_open++;
-
- while (1) {
- if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
- (tty->termios->c_cflag & CBAUD)) {
- spin_lock_irqsave(&info->irq_spinlock,flags);
- info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
- usc_set_serial_signals(info);
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
- }
-
- set_current_state(TASK_INTERRUPTIBLE);
-
- if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)){
- retval = (info->flags & ASYNC_HUP_NOTIFY) ?
- -EAGAIN : -ERESTARTSYS;
- break;
- }
-
- spin_lock_irqsave(&info->irq_spinlock,flags);
- usc_get_serial_signals(info);
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
-
- if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
- !(info->flags & ASYNC_CLOSING) &&
- (do_clocal || (info->serial_signals & SerialSignal_DCD)) ) {
- break;
- }
-
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
-
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):block_til_ready blocking on %s count=%dn",
- __FILE__,__LINE__, tty->driver.name, info->count );
-
- schedule();
- }
-
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&info->open_wait, &wait);
-
- if (extra_count)
- info->count++;
- info->blocked_open--;
-
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):block_til_ready after blocking on %s count=%dn",
- __FILE__,__LINE__, tty->driver.name, info->count );
-
- if (!retval)
- info->flags |= ASYNC_NORMAL_ACTIVE;
-
- return retval;
-
- } /* end of block_til_ready() */
- /* mgsl_open()
- *
- * Called when a port is opened. Init and enable port.
- * Perform serial-specific initialization for the tty structure.
- *
- * Arguments: tty pointer to tty info structure
- * filp associated file pointer
- *
- * Return Value: 0 if success, otherwise error code
- */
- static int mgsl_open(struct tty_struct *tty, struct file * filp)
- {
- struct mgsl_struct *info;
- int retval, line;
- unsigned long page;
- unsigned long flags;
- /* verify range of specified line number */
- line = MINOR(tty->device) - tty->driver.minor_start;
- if ((line < 0) || (line >= mgsl_device_count)) {
- printk("%s(%d):mgsl_open with illegal line #%d.n",
- __FILE__,__LINE__,line);
- return -ENODEV;
- }
- /* find the info structure for the specified line */
- info = mgsl_device_list;
- while(info && info->line != line)
- info = info->next_device;
- if ( !info ){
- printk("%s(%d):Can't find specified device on open (line=%d)n",
- __FILE__,__LINE__,line);
- return -ENODEV;
- }
-
- tty->driver_data = info;
- info->tty = tty;
- if (mgsl_paranoia_check(info, tty->device, "mgsl_open"))
- return -ENODEV;
-
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):mgsl_open(%s), old ref count = %dn",
- __FILE__,__LINE__,tty->driver.name, info->count);
- MOD_INC_USE_COUNT;
-
- /* If port is closing, signal caller to try again */
- if (tty_hung_up_p(filp) || info->flags & ASYNC_CLOSING){
- if (info->flags & ASYNC_CLOSING)
- interruptible_sleep_on(&info->close_wait);
- retval = ((info->flags & ASYNC_HUP_NOTIFY) ?
- -EAGAIN : -ERESTARTSYS);
- goto cleanup;
- }
-
- if (!tmp_buf) {
- page = get_free_page(GFP_KERNEL);
- if (!page) {
- retval = -ENOMEM;
- goto cleanup;
- }
- if (tmp_buf)
- free_page(page);
- else
- tmp_buf = (unsigned char *) page;
- }
-
- info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
- spin_lock_irqsave(&info->netlock, flags);
- if (info->netcount) {
- retval = -EBUSY;
- spin_unlock_irqrestore(&info->netlock, flags);
- goto cleanup;
- }
- info->count++;
- spin_unlock_irqrestore(&info->netlock, flags);
- if (info->count == 1) {
- /* 1st open on this device, init hardware */
- retval = startup(info);
- if (retval < 0)
- goto cleanup;
- }
- retval = block_til_ready(tty, filp, info);
- if (retval) {
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):block_til_ready(%s) returned %dn",
- __FILE__,__LINE__, info->device_name, retval);
- goto cleanup;
- }
- if ((info->count == 1) &&
- info->flags & ASYNC_SPLIT_TERMIOS) {
- if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
- *tty->termios = info->normal_termios;
- else
- *tty->termios = info->callout_termios;
- mgsl_change_params(info);
- }
-
- info->session = current->session;
- info->pgrp = current->pgrp;
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):mgsl_open(%s) successn",
- __FILE__,__LINE__, info->device_name);
- retval = 0;
-
- cleanup:
- if (retval) {
- if(MOD_IN_USE)
- MOD_DEC_USE_COUNT;
- if(info->count)
- info->count--;
- }
-
- return retval;
-
- } /* end of mgsl_open() */
- /*
- * /proc fs routines....
- */
- static inline int line_info(char *buf, struct mgsl_struct *info)
- {
- char stat_buf[30];
- int ret;
- unsigned long flags;
- if (info->bus_type == MGSL_BUS_TYPE_PCI) {
- ret = sprintf(buf, "%s:PCI io:%04X irq:%d mem:%08X lcr:%08X",
- info->device_name, info->io_base, info->irq_level,
- info->phys_memory_base, info->phys_lcr_base);
- } else {
- ret = sprintf(buf, "%s:(E)ISA io:%04X irq:%d dma:%d",
- info->device_name, info->io_base,
- info->irq_level, info->dma_level);
- }
- /* output current serial signal states */
- spin_lock_irqsave(&info->irq_spinlock,flags);
- usc_get_serial_signals(info);
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
-
- stat_buf[0] = 0;
- stat_buf[1] = 0;
- if (info->serial_signals & SerialSignal_RTS)
- strcat(stat_buf, "|RTS");
- if (info->serial_signals & SerialSignal_CTS)
- strcat(stat_buf, "|CTS");
- if (info->serial_signals & SerialSignal_DTR)
- strcat(stat_buf, "|DTR");
- if (info->serial_signals & SerialSignal_DSR)
- strcat(stat_buf, "|DSR");
- if (info->serial_signals & SerialSignal_DCD)
- strcat(stat_buf, "|CD");
- if (info->serial_signals & SerialSignal_RI)
- strcat(stat_buf, "|RI");
- if (info->params.mode == MGSL_MODE_HDLC ||
- info->params.mode == MGSL_MODE_RAW ) {
- ret += sprintf(buf+ret, " HDLC txok:%d rxok:%d",
- info->icount.txok, info->icount.rxok);
- if (info->icount.txunder)
- ret += sprintf(buf+ret, " txunder:%d", info->icount.txunder);
- if (info->icount.txabort)
- ret += sprintf(buf+ret, " txabort:%d", info->icount.txabort);
- if (info->icount.rxshort)
- ret += sprintf(buf+ret, " rxshort:%d", info->icount.rxshort);
- if (info->icount.rxlong)
- ret += sprintf(buf+ret, " rxlong:%d", info->icount.rxlong);
- if (info->icount.rxover)
- ret += sprintf(buf+ret, " rxover:%d", info->icount.rxover);
- if (info->icount.rxcrc)
- ret += sprintf(buf+ret, " rxlong:%d", info->icount.rxcrc);
- } else {
- ret += sprintf(buf+ret, " ASYNC tx:%d rx:%d",
- info->icount.tx, info->icount.rx);
- if (info->icount.frame)
- ret += sprintf(buf+ret, " fe:%d", info->icount.frame);
- if (info->icount.parity)
- ret += sprintf(buf+ret, " pe:%d", info->icount.parity);
- if (info->icount.brk)
- ret += sprintf(buf+ret, " brk:%d", info->icount.brk);
- if (info->icount.overrun)
- ret += sprintf(buf+ret, " oe:%d", info->icount.overrun);
- }
-
- /* Append serial signal status to end */
- ret += sprintf(buf+ret, " %sn", stat_buf+1);
-
- ret += sprintf(buf+ret, "txactive=%d bh_req=%d bh_run=%d pending_bh=%xn",
- info->tx_active,info->bh_requested,info->bh_running,
- info->pending_bh);
-
- spin_lock_irqsave(&info->irq_spinlock,flags);
- {
- u16 Tcsr = usc_InReg( info, TCSR );
- u16 Tdmr = usc_InDmaReg( info, TDMR );
- u16 Ticr = usc_InReg( info, TICR );
- u16 Rscr = usc_InReg( info, RCSR );
- u16 Rdmr = usc_InDmaReg( info, RDMR );
- u16 Ricr = usc_InReg( info, RICR );
- u16 Icr = usc_InReg( info, ICR );
- u16 Dccr = usc_InReg( info, DCCR );
- u16 Tmr = usc_InReg( info, TMR );
- u16 Tccr = usc_InReg( info, TCCR );
- u16 Ccar = inw( info->io_base + CCAR );
- ret += sprintf(buf+ret, "tcsr=%04X tdmr=%04X ticr=%04X rcsr=%04X rdmr=%04Xn"
- "ricr=%04X icr =%04X dccr=%04X tmr=%04X tccr=%04X ccar=%04Xn",
- Tcsr,Tdmr,Ticr,Rscr,Rdmr,Ricr,Icr,Dccr,Tmr,Tccr,Ccar );
- }
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
-
- return ret;
-
- } /* end of line_info() */
- /* mgsl_read_proc()
- *
- * Called to print information about devices
- *
- * Arguments:
- * page page of memory to hold returned info
- * start
- * off
- * count
- * eof
- * data
- *
- * Return Value:
- */
- int mgsl_read_proc(char *page, char **start, off_t off, int count,
- int *eof, void *data)
- {
- int len = 0, l;
- off_t begin = 0;
- struct mgsl_struct *info;
-
- len += sprintf(page, "synclink driver:%sn", driver_version);
-
- info = mgsl_device_list;
- while( info ) {
- l = line_info(page + len, info);
- len += l;
- if (len+begin > off+count)
- goto done;
- if (len+begin < off) {
- begin += len;
- len = 0;
- }
- info = info->next_device;
- }
- *eof = 1;
- done:
- if (off >= len+begin)
- return 0;
- *start = page + (off-begin);
- return ((count < begin+len-off) ? count : begin+len-off);
-
- } /* end of mgsl_read_proc() */
- /* mgsl_allocate_dma_buffers()
- *
- * Allocate and format DMA buffers (ISA adapter)
- * or format shared memory buffers (PCI adapter).
- *
- * Arguments: info pointer to device instance data
- * Return Value: 0 if success, otherwise error
- */
- int mgsl_allocate_dma_buffers(struct mgsl_struct *info)
- {
- unsigned short BuffersPerFrame;
- info->last_mem_alloc = 0;
- /* Calculate the number of DMA buffers necessary to hold the */
- /* largest allowable frame size. Note: If the max frame size is */
- /* not an even multiple of the DMA buffer size then we need to */
- /* round the buffer count per frame up one. */
- BuffersPerFrame = (unsigned short)(info->max_frame_size/DMABUFFERSIZE);
- if ( info->max_frame_size % DMABUFFERSIZE )
- BuffersPerFrame++;
- if ( info->bus_type == MGSL_BUS_TYPE_PCI ) {
- /*
- * The PCI adapter has 256KBytes of shared memory to use.
- * This is 64 PAGE_SIZE buffers.
- *
- * The first page is used for padding at this time so the
- * buffer list does not begin at offset 0 of the PCI
- * adapter's shared memory.
- *
- * The 2nd page is used for the buffer list. A 4K buffer
- * list can hold 128 DMA_BUFFER structures at 32 bytes
- * each.
- *
- * This leaves 62 4K pages.
- *
- * The next N pages are used for transmit frame(s). We
- * reserve enough 4K page blocks to hold the required
- * number of transmit dma buffers (num_tx_dma_buffers),
- * each of MaxFrameSize size.
- *
- * Of the remaining pages (62-N), determine how many can
- * be used to receive full MaxFrameSize inbound frames
- */
- info->tx_buffer_count = info->num_tx_dma_buffers * BuffersPerFrame;
- info->rx_buffer_count = 62 - info->tx_buffer_count;
- } else {
- /* Calculate the number of PAGE_SIZE buffers needed for */
- /* receive and transmit DMA buffers. */
- /* Calculate the number of DMA buffers necessary to */
- /* hold 7 max size receive frames and one max size transmit frame. */
- /* The receive buffer count is bumped by one so we avoid an */
- /* End of List condition if all receive buffers are used when */
- /* using linked list DMA buffers. */
- info->tx_buffer_count = info->num_tx_dma_buffers * BuffersPerFrame;
- info->rx_buffer_count = (BuffersPerFrame * MAXRXFRAMES) + 6;
-
- /*
- * limit total TxBuffers & RxBuffers to 62 4K total
- * (ala PCI Allocation)
- */
-
- if ( (info->tx_buffer_count + info->rx_buffer_count) > 62 )
- info->rx_buffer_count = 62 - info->tx_buffer_count;
- }
- if ( debug_level >= DEBUG_LEVEL_INFO )
- printk("%s(%d):Allocating %d TX and %d RX DMA buffers.n",
- __FILE__,__LINE__, info->tx_buffer_count,info->rx_buffer_count);
-
- if ( mgsl_alloc_buffer_list_memory( info ) < 0 ||
- mgsl_alloc_frame_memory(info, info->rx_buffer_list, info->rx_buffer_count) < 0 ||
- mgsl_alloc_frame_memory(info, info->tx_buffer_list, info->tx_buffer_count) < 0 ||
- mgsl_alloc_intermediate_rxbuffer_memory(info) < 0 ||
- mgsl_alloc_intermediate_txbuffer_memory(info) < 0 ) {
- printk("%s(%d):Can't allocate DMA buffer memoryn",__FILE__,__LINE__);
- return -ENOMEM;
- }
-
- mgsl_reset_rx_dma_buffers( info );
- mgsl_reset_tx_dma_buffers( info );
- return 0;
- } /* end of mgsl_allocate_dma_buffers() */
- /*
- * mgsl_alloc_buffer_list_memory()
- *
- * Allocate a common DMA buffer for use as the
- * receive and transmit buffer lists.
- *
- * A buffer list is a set of buffer entries where each entry contains
- * a pointer to an actual buffer and a pointer to the next buffer entry
- * (plus some other info about the buffer).
- *
- * The buffer entries for a list are built to form a circular list so
- * that when the entire list has been traversed you start back at the
- * beginning.
- *
- * This function allocates memory for just the buffer entries.
- * The links (pointer to next entry) are filled in with the physical
- * address of the next entry so the adapter can navigate the list
- * using bus master DMA. The pointers to the actual buffers are filled
- * out later when the actual buffers are allocated.
- *
- * Arguments: info pointer to device instance data
- * Return Value: 0 if success, otherwise error
- */
- int mgsl_alloc_buffer_list_memory( struct mgsl_struct *info )
- {
- unsigned int i;
- if ( info->bus_type == MGSL_BUS_TYPE_PCI ) {
- /* PCI adapter uses shared memory. */
- info->buffer_list = info->memory_base + info->last_mem_alloc;
- info->buffer_list_phys = info->last_mem_alloc;
- info->last_mem_alloc += BUFFERLISTSIZE;
- } else {
- /* ISA adapter uses system memory. */
- /* The buffer lists are allocated as a common buffer that both */
- /* the processor and adapter can access. This allows the driver to */
- /* inspect portions of the buffer while other portions are being */
- /* updated by the adapter using Bus Master DMA. */
- info->buffer_list = kmalloc(BUFFERLISTSIZE, GFP_KERNEL | GFP_DMA);
- if ( info->buffer_list == NULL )
- return -ENOMEM;
-
- info->buffer_list_phys = virt_to_bus(info->buffer_list);
- }
- /* We got the memory for the buffer entry lists. */
- /* Initialize the memory block to all zeros. */
- memset( info->buffer_list, 0, BUFFERLISTSIZE );
- /* Save virtual address pointers to the receive and */
- /* transmit buffer lists. (Receive 1st). These pointers will */
- /* be used by the processor to access the lists. */
- info->rx_buffer_list = (DMABUFFERENTRY *)info->buffer_list;
- info->tx_buffer_list = (DMABUFFERENTRY *)info->buffer_list;
- info->tx_buffer_list += info->rx_buffer_count;
- /*
- * Build the links for the buffer entry lists such that
- * two circular lists are built. (Transmit and Receive).
- *
- * Note: the links are physical addresses
- * which are read by the adapter to determine the next
- * buffer entry to use.
- */
- for ( i = 0; i < info->rx_buffer_count; i++ ) {
- /* calculate and store physical address of this buffer entry */
- info->rx_buffer_list[i].phys_entry =
- info->buffer_list_phys + (i * sizeof(DMABUFFERENTRY));
- /* calculate and store physical address of */
- /* next entry in cirular list of entries */
- info->rx_buffer_list[i].link = info->buffer_list_phys;
- if ( i < info->rx_buffer_count - 1 )
- info->rx_buffer_list[i].link += (i + 1) * sizeof(DMABUFFERENTRY);
- }
- for ( i = 0; i < info->tx_buffer_count; i++ ) {
- /* calculate and store physical address of this buffer entry */
- info->tx_buffer_list[i].phys_entry = info->buffer_list_phys +
- ((info->rx_buffer_count + i) * sizeof(DMABUFFERENTRY));
- /* calculate and store physical address of */
- /* next entry in cirular list of entries */
- info->tx_buffer_list[i].link = info->buffer_list_phys +
- info->rx_buffer_count * sizeof(DMABUFFERENTRY);
- if ( i < info->tx_buffer_count - 1 )
- info->tx_buffer_list[i].link += (i + 1) * sizeof(DMABUFFERENTRY);
- }
- return 0;
- } /* end of mgsl_alloc_buffer_list_memory() */
- /* Free DMA buffers allocated for use as the
- * receive and transmit buffer lists.
- * Warning:
- *
- * The data transfer buffers associated with the buffer list
- * MUST be freed before freeing the buffer list itself because
- * the buffer list contains the information necessary to free
- * the individual buffers!
- */
- void mgsl_free_buffer_list_memory( struct mgsl_struct *info )
- {
- if ( info->buffer_list && info->bus_type != MGSL_BUS_TYPE_PCI )
- kfree(info->buffer_list);
-
- info->buffer_list = NULL;
- info->rx_buffer_list = NULL;
- info->tx_buffer_list = NULL;
- } /* end of mgsl_free_buffer_list_memory() */
- /*
- * mgsl_alloc_frame_memory()
- *
- * Allocate the frame DMA buffers used by the specified buffer list.
- * Each DMA buffer will be one memory page in size. This is necessary
- * because memory can fragment enough that it may be impossible
- * contiguous pages.
- *
- * Arguments:
- *
- * info pointer to device instance data
- * BufferList pointer to list of buffer entries
- * Buffercount count of buffer entries in buffer list
- *
- * Return Value: 0 if success, otherwise -ENOMEM
- */
- int mgsl_alloc_frame_memory(struct mgsl_struct *info,DMABUFFERENTRY *BufferList,int Buffercount)
- {
- int i;
- unsigned long phys_addr;
- /* Allocate page sized buffers for the receive buffer list */
- for ( i = 0; i < Buffercount; i++ ) {
- if ( info->bus_type == MGSL_BUS_TYPE_PCI ) {
- /* PCI adapter uses shared memory buffers. */
- BufferList[i].virt_addr = info->memory_base + info->last_mem_alloc;
- phys_addr = info->last_mem_alloc;
- info->last_mem_alloc += DMABUFFERSIZE;
- } else {
- /* ISA adapter uses system memory. */
- BufferList[i].virt_addr =
- kmalloc(DMABUFFERSIZE, GFP_KERNEL | GFP_DMA);
- if ( BufferList[i].virt_addr == NULL )
- return -ENOMEM;
- phys_addr = virt_to_bus(BufferList[i].virt_addr);
- }
- BufferList[i].phys_addr = phys_addr;
- }
- return 0;
- } /* end of mgsl_alloc_frame_memory() */
- /*
- * mgsl_free_frame_memory()
- *
- * Free the buffers associated with
- * each buffer entry of a buffer list.
- *
- * Arguments: