diff options
Diffstat (limited to 'drivers/char/synclinkmp.c')
-rw-r--r-- | drivers/char/synclinkmp.c | 5601 |
1 files changed, 0 insertions, 5601 deletions
diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c deleted file mode 100644 index 2f9eb4b0dec..00000000000 --- a/drivers/char/synclinkmp.c +++ /dev/null @@ -1,5601 +0,0 @@ -/* - * $Id: synclinkmp.c,v 4.38 2005/07/15 13:29:44 paulkf Exp $ - * - * Device driver for Microgate SyncLink Multiport - * high speed multiprotocol serial adapter. - * - * 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 - * This code is released under the GNU General Public License (GPL) - * - * 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_DEVICES 12 - -#include <linux/module.h> -#include <linux/errno.h> -#include <linux/signal.h> -#include <linux/sched.h> -#include <linux/timer.h> -#include <linux/interrupt.h> -#include <linux/pci.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> -#include <linux/serial.h> -#include <linux/major.h> -#include <linux/string.h> -#include <linux/fcntl.h> -#include <linux/ptrace.h> -#include <linux/ioport.h> -#include <linux/mm.h> -#include <linux/seq_file.h> -#include <linux/slab.h> -#include <linux/netdevice.h> -#include <linux/vmalloc.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/ioctl.h> - -#include <asm/system.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/dma.h> -#include <linux/bitops.h> -#include <asm/types.h> -#include <linux/termios.h> -#include <linux/workqueue.h> -#include <linux/hdlc.h> -#include <linux/synclink.h> - -#if defined(CONFIG_HDLC) || (defined(CONFIG_HDLC_MODULE) && defined(CONFIG_SYNCLINKMP_MODULE)) -#define SYNCLINK_GENERIC_HDLC 1 -#else -#define SYNCLINK_GENERIC_HDLC 0 -#endif - -#define GET_USER(error,value,addr) error = get_user(value,addr) -#define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0 -#define PUT_USER(error,value,addr) error = put_user(value,addr) -#define COPY_TO_USER(error,dest,src,size) error = copy_to_user(dest,src,size) ? -EFAULT : 0 - -#include <asm/uaccess.h> - -static MGSL_PARAMS default_params = { - MGSL_MODE_HDLC, /* unsigned long mode */ - 0, /* unsigned char loopback; */ - HDLC_FLAG_UNDERRUN_ABORT15, /* unsigned short flags; */ - HDLC_ENCODING_NRZI_SPACE, /* unsigned char encoding; */ - 0, /* unsigned long clock_speed; */ - 0xff, /* unsigned char addr_filter; */ - HDLC_CRC_16_CCITT, /* unsigned short crc_type; */ - HDLC_PREAMBLE_LENGTH_8BITS, /* unsigned char preamble_length; */ - HDLC_PREAMBLE_PATTERN_NONE, /* unsigned char preamble; */ - 9600, /* unsigned long data_rate; */ - 8, /* unsigned char data_bits; */ - 1, /* unsigned char stop_bits; */ - ASYNC_PARITY_NONE /* unsigned char parity; */ -}; - -/* size in bytes of DMA data buffers */ -#define SCABUFSIZE 1024 -#define SCA_MEM_SIZE 0x40000 -#define SCA_BASE_SIZE 512 -#define SCA_REG_SIZE 16 -#define SCA_MAX_PORTS 4 -#define SCAMAXDESC 128 - -#define BUFFERLISTSIZE 4096 - -/* SCA-I style DMA buffer descriptor */ -typedef struct _SCADESC -{ - u16 next; /* lower l6 bits of next descriptor addr */ - u16 buf_ptr; /* lower 16 bits of buffer addr */ - u8 buf_base; /* upper 8 bits of buffer addr */ - u8 pad1; - u16 length; /* length of buffer */ - u8 status; /* status of buffer */ - u8 pad2; -} SCADESC, *PSCADESC; - -typedef struct _SCADESC_EX -{ - /* device driver bookkeeping section */ - char *virt_addr; /* virtual address of data buffer */ - u16 phys_entry; /* lower 16-bits of physical address of this descriptor */ -} SCADESC_EX, *PSCADESC_EX; - -/* The queue of BH actions to be performed */ - -#define BH_RECEIVE 1 -#define BH_TRANSMIT 2 -#define BH_STATUS 4 - -#define IO_PIN_SHUTDOWN_LIMIT 100 - -struct _input_signal_events { - int ri_up; - int ri_down; - int dsr_up; - int dsr_down; - int dcd_up; - int dcd_down; - int cts_up; - int cts_down; -}; - -/* - * Device instance data structure - */ -typedef struct _synclinkmp_info { - void *if_ptr; /* General purpose pointer (used by SPPP) */ - int magic; - struct tty_port port; - int line; - unsigned short close_delay; - unsigned short closing_wait; /* time to wait before closing */ - - struct mgsl_icount icount; - - int timeout; - int x_char; /* xon/xoff character */ - u16 read_status_mask1; /* break detection (SR1 indications) */ - u16 read_status_mask2; /* parity/framing/overun (SR2 indications) */ - unsigned char ignore_status_mask1; /* break detection (SR1 indications) */ - unsigned char ignore_status_mask2; /* parity/framing/overun (SR2 indications) */ - unsigned char *tx_buf; - int tx_put; - int tx_get; - int tx_count; - - 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 _synclinkmp_info *next_device; /* device list link */ - struct timer_list status_timer; /* input signal status check timer */ - - spinlock_t lock; /* spinlock for synchronizing with ISR */ - struct work_struct task; /* task structure for scheduling bh */ - - u32 max_frame_size; /* as set by device config */ - - u32 pending_bh; - - bool bh_running; /* Protection from multiple */ - int isr_overflow; - bool bh_requested; - - int dcd_chkcount; /* check counts to prevent */ - int cts_chkcount; /* too many IRQs if a signal */ - int dsr_chkcount; /* is floating */ - int ri_chkcount; - - char *buffer_list; /* virtual address of Rx & Tx buffer lists */ - unsigned long buffer_list_phys; - - unsigned int rx_buf_count; /* count of total allocated Rx buffers */ - SCADESC *rx_buf_list; /* list of receive buffer entries */ - SCADESC_EX rx_buf_list_ex[SCAMAXDESC]; /* list of receive buffer entries */ - unsigned int current_rx_buf; - - unsigned int tx_buf_count; /* count of total allocated Tx buffers */ - SCADESC *tx_buf_list; /* list of transmit buffer entries */ - SCADESC_EX tx_buf_list_ex[SCAMAXDESC]; /* list of transmit buffer entries */ - unsigned int last_tx_buf; - - unsigned char *tmp_rx_buf; - unsigned int tmp_rx_buf_count; - - bool rx_enabled; - bool rx_overflow; - - bool tx_enabled; - bool tx_active; - u32 idle_mode; - - unsigned char ie0_value; - unsigned char ie1_value; - unsigned char ie2_value; - unsigned char ctrlreg_value; - unsigned char old_signals; - - char device_name[25]; /* device instance name */ - - int port_count; - int adapter_num; - int port_num; - - struct _synclinkmp_info *port_array[SCA_MAX_PORTS]; - - unsigned int bus_type; /* expansion bus type (ISA,EISA,PCI) */ - - unsigned int irq_level; /* interrupt level */ - unsigned long irq_flags; - bool irq_requested; /* true if IRQ requested */ - - MGSL_PARAMS params; /* communications parameters */ - - unsigned char serial_signals; /* current serial signal states */ - - bool irq_occurred; /* for diagnostics use */ - unsigned int init_error; /* Initialization startup error */ - - u32 last_mem_alloc; - unsigned char* memory_base; /* shared memory address (PCI only) */ - u32 phys_memory_base; - int shared_mem_requested; - - unsigned char* sca_base; /* HD64570 SCA Memory address */ - u32 phys_sca_base; - u32 sca_offset; - bool sca_base_requested; - - unsigned char* lcr_base; /* local config registers (PCI only) */ - u32 phys_lcr_base; - u32 lcr_offset; - int lcr_mem_requested; - - unsigned char* statctrl_base; /* status/control register memory */ - u32 phys_statctrl_base; - u32 statctrl_offset; - bool sca_statctrl_requested; - - u32 misc_ctrl_value; - char flag_buf[MAX_ASYNC_BUFFER_SIZE]; - char char_buf[MAX_ASYNC_BUFFER_SIZE]; - bool drop_rts_on_tx_done; - - struct _input_signal_events input_signal_events; - - /* SPPP/Cisco HDLC device parts */ - int netcount; - spinlock_t netlock; - -#if SYNCLINK_GENERIC_HDLC - struct net_device *netdev; -#endif - -} SLMP_INFO; - -#define MGSL_MAGIC 0x5401 - -/* - * define serial signal status change macros - */ -#define MISCSTATUS_DCD_LATCHED (SerialSignal_DCD<<8) /* indicates change in DCD */ -#define MISCSTATUS_RI_LATCHED (SerialSignal_RI<<8) /* indicates change in RI */ -#define MISCSTATUS_CTS_LATCHED (SerialSignal_CTS<<8) /* indicates change in CTS */ -#define MISCSTATUS_DSR_LATCHED (SerialSignal_DSR<<8) /* change in DSR */ - -/* Common Register macros */ -#define LPR 0x00 -#define PABR0 0x02 -#define PABR1 0x03 -#define WCRL 0x04 -#define WCRM 0x05 -#define WCRH 0x06 -#define DPCR 0x08 -#define DMER 0x09 -#define ISR0 0x10 -#define ISR1 0x11 -#define ISR2 0x12 -#define IER0 0x14 -#define IER1 0x15 -#define IER2 0x16 -#define ITCR 0x18 -#define INTVR 0x1a -#define IMVR 0x1c - -/* MSCI Register macros */ -#define TRB 0x20 -#define TRBL 0x20 -#define TRBH 0x21 -#define SR0 0x22 -#define SR1 0x23 -#define SR2 0x24 -#define SR3 0x25 -#define FST 0x26 -#define IE0 0x28 -#define IE1 0x29 -#define IE2 0x2a -#define FIE 0x2b -#define CMD 0x2c -#define MD0 0x2e -#define MD1 0x2f -#define MD2 0x30 -#define CTL 0x31 -#define SA0 0x32 -#define SA1 0x33 -#define IDL 0x34 -#define TMC 0x35 -#define RXS 0x36 -#define TXS 0x37 -#define TRC0 0x38 -#define TRC1 0x39 -#define RRC 0x3a -#define CST0 0x3c -#define CST1 0x3d - -/* Timer Register Macros */ -#define TCNT 0x60 -#define TCNTL 0x60 -#define TCNTH 0x61 -#define TCONR 0x62 -#define TCONRL 0x62 -#define TCONRH 0x63 -#define TMCS 0x64 -#define TEPR 0x65 - -/* DMA Controller Register macros */ -#define DARL 0x80 -#define DARH 0x81 -#define DARB 0x82 -#define BAR 0x80 -#define BARL 0x80 -#define BARH 0x81 -#define BARB 0x82 -#define SAR 0x84 -#define SARL 0x84 -#define SARH 0x85 -#define SARB 0x86 -#define CPB 0x86 -#define CDA 0x88 -#define CDAL 0x88 -#define CDAH 0x89 -#define EDA 0x8a -#define EDAL 0x8a -#define EDAH 0x8b -#define BFL 0x8c -#define BFLL 0x8c -#define BFLH 0x8d -#define BCR 0x8e -#define BCRL 0x8e -#define BCRH 0x8f -#define DSR 0x90 -#define DMR 0x91 -#define FCT 0x93 -#define DIR 0x94 -#define DCMD 0x95 - -/* combine with timer or DMA register address */ -#define TIMER0 0x00 -#define TIMER1 0x08 -#define TIMER2 0x10 -#define TIMER3 0x18 -#define RXDMA 0x00 -#define TXDMA 0x20 - -/* SCA Command Codes */ -#define NOOP 0x00 -#define TXRESET 0x01 -#define TXENABLE 0x02 -#define TXDISABLE 0x03 -#define TXCRCINIT 0x04 -#define TXCRCEXCL 0x05 -#define TXEOM 0x06 -#define TXABORT 0x07 -#define MPON 0x08 -#define TXBUFCLR 0x09 -#define RXRESET 0x11 -#define RXENABLE 0x12 -#define RXDISABLE 0x13 -#define RXCRCINIT 0x14 -#define RXREJECT 0x15 -#define SEARCHMP 0x16 -#define RXCRCEXCL 0x17 -#define RXCRCCALC 0x18 -#define CHRESET 0x21 -#define HUNT 0x31 - -/* DMA command codes */ -#define SWABORT 0x01 -#define FEICLEAR 0x02 - -/* IE0 */ -#define TXINTE BIT7 -#define RXINTE BIT6 -#define TXRDYE BIT1 -#define RXRDYE BIT0 - -/* IE1 & SR1 */ -#define UDRN BIT7 -#define IDLE BIT6 -#define SYNCD BIT4 -#define FLGD BIT4 -#define CCTS BIT3 -#define CDCD BIT2 -#define BRKD BIT1 -#define ABTD BIT1 -#define GAPD BIT1 -#define BRKE BIT0 -#define IDLD BIT0 - -/* IE2 & SR2 */ -#define EOM BIT7 -#define PMP BIT6 -#define SHRT BIT6 -#define PE BIT5 -#define ABT BIT5 -#define FRME BIT4 -#define RBIT BIT4 -#define OVRN BIT3 -#define CRCE BIT2 - - -/* - * Global linked list of SyncLink devices - */ -static SLMP_INFO *synclinkmp_device_list = NULL; -static int synclinkmp_adapter_count = -1; -static int synclinkmp_device_count = 0; - -/* - * Set this param to non-zero to load eax with the - * .text section address and breakpoint on module load. - * This is useful for use with gdb and add-symbol-file command. - */ -static int break_on_load = 0; - -/* - * Driver major number, defaults to zero to get auto - * assigned major number. May be forced as module parameter. - */ -static int ttymajor = 0; - -/* - * Array of user specified options for ISA adapters. - */ -static int debug_level = 0; -static int maxframe[MAX_DEVICES] = {0,}; - -module_param(break_on_load, bool, 0); -module_param(ttymajor, int, 0); -module_param(debug_level, int, 0); -module_param_array(maxframe, int, NULL, 0); - -static char *driver_name = "SyncLink MultiPort driver"; -static char *driver_version = "$Revision: 4.38 $"; - -static int synclinkmp_init_one(struct pci_dev *dev,const struct pci_device_id *ent); -static void synclinkmp_remove_one(struct pci_dev *dev); - -static struct pci_device_id synclinkmp_pci_tbl[] = { - { PCI_VENDOR_ID_MICROGATE, PCI_DEVICE_ID_MICROGATE_SCA, PCI_ANY_ID, PCI_ANY_ID, }, - { 0, }, /* terminate list */ -}; -MODULE_DEVICE_TABLE(pci, synclinkmp_pci_tbl); - -MODULE_LICENSE("GPL"); - -static struct pci_driver synclinkmp_pci_driver = { - .name = "synclinkmp", - .id_table = synclinkmp_pci_tbl, - .probe = synclinkmp_init_one, - .remove = __devexit_p(synclinkmp_remove_one), -}; - - -static struct tty_driver *serial_driver; - -/* number of characters left in xmit buffer before we ask for more */ -#define WAKEUP_CHARS 256 - - -/* tty callbacks */ - -static int open(struct tty_struct *tty, struct file * filp); -static void close(struct tty_struct *tty, struct file * filp); -static void hangup(struct tty_struct *tty); -static void set_termios(struct tty_struct *tty, struct ktermios *old_termios); - -static int write(struct tty_struct *tty, const unsigned char *buf, int count); -static int put_char(struct tty_struct *tty, unsigned char ch); -static void send_xchar(struct tty_struct *tty, char ch); -static void wait_until_sent(struct tty_struct *tty, int timeout); -static int write_room(struct tty_struct *tty); -static void flush_chars(struct tty_struct *tty); -static void flush_buffer(struct tty_struct *tty); -static void tx_hold(struct tty_struct *tty); -static void tx_release(struct tty_struct *tty); - -static int ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg); -static int chars_in_buffer(struct tty_struct *tty); -static void throttle(struct tty_struct * tty); -static void unthrottle(struct tty_struct * tty); -static int set_break(struct tty_struct *tty, int break_state); - -#if SYNCLINK_GENERIC_HDLC -#define dev_to_port(D) (dev_to_hdlc(D)->priv) -static void hdlcdev_tx_done(SLMP_INFO *info); -static void hdlcdev_rx(SLMP_INFO *info, char *buf, int size); -static int hdlcdev_init(SLMP_INFO *info); -static void hdlcdev_exit(SLMP_INFO *info); -#endif - -/* ioctl handlers */ - -static int get_stats(SLMP_INFO *info, struct mgsl_icount __user *user_icount); -static int get_params(SLMP_INFO *info, MGSL_PARAMS __user *params); -static int set_params(SLMP_INFO *info, MGSL_PARAMS __user *params); -static int get_txidle(SLMP_INFO *info, int __user *idle_mode); -static int set_txidle(SLMP_INFO *info, int idle_mode); -static int tx_enable(SLMP_INFO *info, int enable); -static int tx_abort(SLMP_INFO *info); -static int rx_enable(SLMP_INFO *info, int enable); -static int modem_input_wait(SLMP_INFO *info,int arg); -static int wait_mgsl_event(SLMP_INFO *info, int __user *mask_ptr); -static int tiocmget(struct tty_struct *tty, struct file *file); -static int tiocmset(struct tty_struct *tty, struct file *file, - unsigned int set, unsigned int clear); -static int set_break(struct tty_struct *tty, int break_state); - -static void add_device(SLMP_INFO *info); -static void device_init(int adapter_num, struct pci_dev *pdev); -static int claim_resources(SLMP_INFO *info); -static void release_resources(SLMP_INFO *info); - -static int startup(SLMP_INFO *info); -static int block_til_ready(struct tty_struct *tty, struct file * filp,SLMP_INFO *info); -static int carrier_raised(struct tty_port *port); -static void shutdown(SLMP_INFO *info); -static void program_hw(SLMP_INFO *info); -static void change_params(SLMP_INFO *info); - -static bool init_adapter(SLMP_INFO *info); -static bool register_test(SLMP_INFO *info); -static bool irq_test(SLMP_INFO *info); -static bool loopback_test(SLMP_INFO *info); -static int adapter_test(SLMP_INFO *info); -static bool memory_test(SLMP_INFO *info); - -static void reset_adapter(SLMP_INFO *info); -static void reset_port(SLMP_INFO *info); -static void async_mode(SLMP_INFO *info); -static void hdlc_mode(SLMP_INFO *info); - -static void rx_stop(SLMP_INFO *info); -static void rx_start(SLMP_INFO *info); -static void rx_reset_buffers(SLMP_INFO *info); -static void rx_free_frame_buffers(SLMP_INFO *info, unsigned int first, unsigned int last); -static bool rx_get_frame(SLMP_INFO *info); - -static void tx_start(SLMP_INFO *info); -static void tx_stop(SLMP_INFO *info); -static void tx_load_fifo(SLMP_INFO *info); -static void tx_set_idle(SLMP_INFO *info); -static void tx_load_dma_buffer(SLMP_INFO *info, const char *buf, unsigned int count); - -static void get_signals(SLMP_INFO *info); -static void set_signals(SLMP_INFO *info); -static void enable_loopback(SLMP_INFO *info, int enable); -static void set_rate(SLMP_INFO *info, u32 data_rate); - -static int bh_action(SLMP_INFO *info); -static void bh_handler(struct work_struct *work); -static void bh_receive(SLMP_INFO *info); -static void bh_transmit(SLMP_INFO *info); -static void bh_status(SLMP_INFO *info); -static void isr_timer(SLMP_INFO *info); -static void isr_rxint(SLMP_INFO *info); -static void isr_rxrdy(SLMP_INFO *info); -static void isr_txint(SLMP_INFO *info); -static void isr_txrdy(SLMP_INFO *info); -static void isr_rxdmaok(SLMP_INFO *info); -static void isr_rxdmaerror(SLMP_INFO *info); -static void isr_txdmaok(SLMP_INFO *info); -static void isr_txdmaerror(SLMP_INFO *info); -static void isr_io_pin(SLMP_INFO *info, u16 status); - -static int alloc_dma_bufs(SLMP_INFO *info); -static void free_dma_bufs(SLMP_INFO *info); -static int alloc_buf_list(SLMP_INFO *info); -static int alloc_frame_bufs(SLMP_INFO *info, SCADESC *list, SCADESC_EX *list_ex,int count); -static int alloc_tmp_rx_buf(SLMP_INFO *info); -static void free_tmp_rx_buf(SLMP_INFO *info); - -static void load_pci_memory(SLMP_INFO *info, char* dest, const char* src, unsigned short count); -static void trace_block(SLMP_INFO *info, const char* data, int count, int xmit); -static void tx_timeout(unsigned long context); -static void status_timeout(unsigned long context); - -static unsigned char read_reg(SLMP_INFO *info, unsigned char addr); -static void write_reg(SLMP_INFO *info, unsigned char addr, unsigned char val); -static u16 read_reg16(SLMP_INFO *info, unsigned char addr); -static void write_reg16(SLMP_INFO *info, unsigned char addr, u16 val); -static unsigned char read_status_reg(SLMP_INFO * info); -static void write_control_reg(SLMP_INFO * info); - - -static unsigned char rx_active_fifo_level = 16; // rx request FIFO activation level in bytes -static unsigned char tx_active_fifo_level = 16; // tx request FIFO activation level in bytes -static unsigned char tx_negate_fifo_level = 32; // tx request FIFO negation level in bytes - -static u32 misc_ctrl_value = 0x007e4040; -static u32 lcr1_brdr_value = 0x00800028; - -static u32 read_ahead_count = 8; - -/* DPCR, DMA Priority Control - * - * 07..05 Not used, must be 0 - * 04 BRC, bus release condition: 0=all transfers complete - * 1=release after 1 xfer on all channels - * 03 CCC, channel change condition: 0=every cycle - * 1=after each channel completes all xfers - * 02..00 PR<2..0>, priority 100=round robin - * - * 00000100 = 0x00 - */ -static unsigned char dma_priority = 0x04; - -// Number of bytes that can be written to shared RAM -// in a single write operation -static u32 sca_pci_load_interval = 64; - -/* - * 1st function defined in .text section. Calling this function in - * init_module() followed by a breakpoint allows a remote debugger - * (gdb) to get the .text address for the add-symbol-file command. - * This allows remote debugging of dynamically loadable modules. - */ -static void* synclinkmp_get_text_ptr(void); -static void* synclinkmp_get_text_ptr(void) {return synclinkmp_get_text_ptr;} - -static inline int sanity_check(SLMP_INFO *info, - char *name, const char *routine) -{ -#ifdef SANITY_CHECK - static const char *badmagic = - "Warning: bad magic number for synclinkmp_struct (%s) in %s\n"; - static const char *badinfo = - "Warning: null synclinkmp_struct for (%s) in %s\n"; - - if (!info) { - printk(badinfo, name, routine); - return 1; - } - if (info->magic != MGSL_MAGIC) { - printk(badmagic, name, routine); - return 1; - } -#else - if (!info) - return 1; -#endif - return 0; -} - -/** - * line discipline callback wrappers - * - * The wrappers maintain line discipline references - * while calling into the line discipline. - * - * ldisc_receive_buf - pass receive data to line discipline - */ - -static void ldisc_receive_buf(struct tty_struct *tty, - const __u8 *data, char *flags, int count) -{ - struct tty_ldisc *ld; - if (!tty) - return; - ld = tty_ldisc_ref(tty); - if (ld) { - if (ld->ops->receive_buf) - ld->ops->receive_buf(tty, data, flags, count); - tty_ldisc_deref(ld); - } -} - -/* tty callbacks */ - -/* Called when a port is opened. Init and enable port. - */ -static int open(struct tty_struct *tty, struct file *filp) -{ - SLMP_INFO *info; - int retval, line; - unsigned long flags; - - line = tty->index; - if ((line < 0) || (line >= synclinkmp_device_count)) { - printk("%s(%d): open with invalid line #%d.\n", - __FILE__,__LINE__,line); - return -ENODEV; - } - - info = synclinkmp_device_list; - while(info && info->line != line) - info = info->next_device; - if (sanity_check(info, tty->name, "open")) - return -ENODEV; - if ( info->init_error ) { - printk("%s(%d):%s device is not allocated, init error=%d\n", - __FILE__,__LINE__,info->device_name,info->init_error); - return -ENODEV; - } - - tty->driver_data = info; - info->port.tty = tty; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s open(), old ref count = %d\n", - __FILE__,__LINE__,tty->driver->name, info->port.count); - - /* If port is closing, signal caller to try again */ - if (tty_hung_up_p(filp) || info->port.flags & ASYNC_CLOSING){ - if (info->port.flags & ASYNC_CLOSING) - interruptible_sleep_on(&info->port.close_wait); - retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ? - -EAGAIN : -ERESTARTSYS); - goto cleanup; - } - - info->port.tty->low_latency = (info->port.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->port.count++; - spin_unlock_irqrestore(&info->netlock, flags); - - if (info->port.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):%s block_til_ready() returned %d\n", - __FILE__,__LINE__, info->device_name, retval); - goto cleanup; - } - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s open() success\n", - __FILE__,__LINE__, info->device_name); - retval = 0; - -cleanup: - if (retval) { - if (tty->count == 1) - info->port.tty = NULL; /* tty layer will release tty struct */ - if(info->port.count) - info->port.count--; - } - - return retval; -} - -/* Called when port is closed. Wait for remaining data to be - * sent. Disable port and free resources. - */ -static void close(struct tty_struct *tty, struct file *filp) -{ - SLMP_INFO * info = tty->driver_data; - - if (sanity_check(info, tty->name, "close")) - return; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s close() entry, count=%d\n", - __FILE__,__LINE__, info->device_name, info->port.count); - - if (tty_port_close_start(&info->port, tty, filp) == 0) - goto cleanup; - - mutex_lock(&info->port.mutex); - if (info->port.flags & ASYNC_INITIALIZED) - wait_until_sent(tty, info->timeout); - - flush_buffer(tty); - tty_ldisc_flush(tty); - shutdown(info); - mutex_unlock(&info->port.mutex); - - tty_port_close_end(&info->port, tty); - info->port.tty = NULL; -cleanup: - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s close() exit, count=%d\n", __FILE__,__LINE__, - tty->driver->name, info->port.count); -} - -/* Called by tty_hangup() when a hangup is signaled. - * This is the same as closing all open descriptors for the port. - */ -static void hangup(struct tty_struct *tty) -{ - SLMP_INFO *info = tty->driver_data; - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s hangup()\n", - __FILE__,__LINE__, info->device_name ); - - if (sanity_check(info, tty->name, "hangup")) - return; - - mutex_lock(&info->port.mutex); - flush_buffer(tty); - shutdown(info); - - spin_lock_irqsave(&info->port.lock, flags); - info->port.count = 0; - info->port.flags &= ~ASYNC_NORMAL_ACTIVE; - info->port.tty = NULL; - spin_unlock_irqrestore(&info->port.lock, flags); - mutex_unlock(&info->port.mutex); - - wake_up_interruptible(&info->port.open_wait); -} - -/* Set new termios settings - */ -static void set_termios(struct tty_struct *tty, struct ktermios *old_termios) -{ - SLMP_INFO *info = tty->driver_data; - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s set_termios()\n", __FILE__,__LINE__, - tty->driver->name ); - - 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->lock,flags); - set_signals(info); - spin_unlock_irqrestore(&info->lock,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->lock,flags); - set_signals(info); - spin_unlock_irqrestore(&info->lock,flags); - } - - /* Handle turning off CRTSCTS */ - if (old_termios->c_cflag & CRTSCTS && - !(tty->termios->c_cflag & CRTSCTS)) { - tty->hw_stopped = 0; - tx_release(tty); - } -} - -/* Send a block of data - * - * Arguments: - * - * tty pointer to tty information structure - * buf pointer to buffer containing send data - * count size of send data in bytes - * - * Return Value: number of characters written - */ -static int write(struct tty_struct *tty, - const unsigned char *buf, int count) -{ - int c, ret = 0; - SLMP_INFO *info = tty->driver_data; - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s write() count=%d\n", - __FILE__,__LINE__,info->device_name,count); - - if (sanity_check(info, tty->name, "write")) - goto cleanup; - - if (!info->tx_buf) - goto cleanup; - - if (info->params.mode == MGSL_MODE_HDLC) { - if (count > info->max_frame_size) { - ret = -EIO; - goto cleanup; - } - if (info->tx_active) - goto cleanup; - if (info->tx_count) { - /* send accumulated data from send_char() calls */ - /* as frame and wait before accepting more data. */ - tx_load_dma_buffer(info, info->tx_buf, info->tx_count); - goto start; - } - ret = info->tx_count = count; - tx_load_dma_buffer(info, buf, count); - goto start; - } - - for (;;) { - c = min_t(int, count, - min(info->max_frame_size - info->tx_count - 1, - info->max_frame_size - info->tx_put)); - if (c <= 0) - break; - - memcpy(info->tx_buf + info->tx_put, buf, c); - - spin_lock_irqsave(&info->lock,flags); - info->tx_put += c; - if (info->tx_put >= info->max_frame_size) - info->tx_put -= info->max_frame_size; - info->tx_count += c; - spin_unlock_irqrestore(&info->lock,flags); - - buf += c; - count -= c; - ret += c; - } - - if (info->params.mode == MGSL_MODE_HDLC) { - if (count) { - ret = info->tx_count = 0; - goto cleanup; - } - tx_load_dma_buffer(info, info->tx_buf, info->tx_count); - } -start: - if (info->tx_count && !tty->stopped && !tty->hw_stopped) { - spin_lock_irqsave(&info->lock,flags); - if (!info->tx_active) - tx_start(info); - spin_unlock_irqrestore(&info->lock,flags); - } - -cleanup: - if (debug_level >= DEBUG_LEVEL_INFO) - printk( "%s(%d):%s write() returning=%d\n", - __FILE__,__LINE__,info->device_name,ret); - return ret; -} - -/* Add a character to the transmit buffer. - */ -static int put_char(struct tty_struct *tty, unsigned char ch) -{ - SLMP_INFO *info = tty->driver_data; - unsigned long flags; - int ret = 0; - - if ( debug_level >= DEBUG_LEVEL_INFO ) { - printk( "%s(%d):%s put_char(%d)\n", - __FILE__,__LINE__,info->device_name,ch); - } - - if (sanity_check(info, tty->name, "put_char")) - return 0; - - if (!info->tx_buf) - return 0; - - spin_lock_irqsave(&info->lock,flags); - - if ( (info->params.mode != MGSL_MODE_HDLC) || - !info->tx_active ) { - - if (info->tx_count < info->max_frame_size - 1) { - info->tx_buf[info->tx_put++] = ch; - if (info->tx_put >= info->max_frame_size) - info->tx_put -= info->max_frame_size; - info->tx_count++; - ret = 1; - } - } - - spin_unlock_irqrestore(&info->lock,flags); - return ret; -} - -/* Send a high-priority XON/XOFF character - */ -static void send_xchar(struct tty_struct *tty, char ch) -{ - SLMP_INFO *info = tty->driver_data; - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s send_xchar(%d)\n", - __FILE__,__LINE__, info->device_name, ch ); - - if (sanity_check(info, tty->name, "send_xchar")) - return; - - info->x_char = ch; - if (ch) { - /* Make sure transmit interrupts are on */ - spin_lock_irqsave(&info->lock,flags); - if (!info->tx_enabled) - tx_start(info); - spin_unlock_irqrestore(&info->lock,flags); - } -} - -/* Wait until the transmitter is empty. - */ -static void wait_until_sent(struct tty_struct *tty, int timeout) -{ - SLMP_INFO * info = tty->driver_data; - unsigned long orig_jiffies, char_time; - - if (!info ) - return; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s wait_until_sent() entry\n", - __FILE__,__LINE__, info->device_name ); - - if (sanity_check(info, tty->name, "wait_until_sent")) - return; - - if (!test_bit(ASYNCB_INITIALIZED, &info->port.flags)) - 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_t(unsigned long, char_time, timeout); - - if ( info->params.mode == MGSL_MODE_HDLC ) { - while (info->tx_active) { - msleep_interruptible(jiffies_to_msecs(char_time)); - if (signal_pending(current)) - break; - if (timeout && time_after(jiffies, orig_jiffies + timeout)) - break; - } - } else { - /* - * TODO: determine if there is something similar to USC16C32 - * TXSTATUS_ALL_SENT status - */ - while ( info->tx_active && info->tx_enabled) { - msleep_interruptible(jiffies_to_msecs(char_time)); - if (signal_pending(current)) - break; - if (timeout && time_after(jiffies, orig_jiffies + timeout)) - break; - } - } - -exit: - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s wait_until_sent() exit\n", - __FILE__,__LINE__, info->device_name ); -} - -/* Return the count of free bytes in transmit buffer - */ -static int write_room(struct tty_struct *tty) -{ - SLMP_INFO *info = tty->driver_data; - int ret; - - if (sanity_check(info, tty->name, "write_room")) - return 0; - - if (info->params.mode == MGSL_MODE_HDLC) { - ret = (info->tx_active) ? 0 : HDLC_MAX_FRAME_SIZE; - } else { - ret = info->max_frame_size - info->tx_count - 1; - if (ret < 0) - ret = 0; - } - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s write_room()=%d\n", - __FILE__, __LINE__, info->device_name, ret); - - return ret; -} - -/* enable transmitter and send remaining buffered characters - */ -static void flush_chars(struct tty_struct *tty) -{ - SLMP_INFO *info = tty->driver_data; - unsigned long flags; - - if ( debug_level >= DEBUG_LEVEL_INFO ) - printk( "%s(%d):%s flush_chars() entry tx_count=%d\n", - __FILE__,__LINE__,info->device_name,info->tx_count); - - if (sanity_check(info, tty->name, "flush_chars")) - return; - - if (info->tx_count <= 0 || tty->stopped || tty->hw_stopped || - !info->tx_buf) - return; - - if ( debug_level & |