11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * linux/drivers/char/pcmcia/synclink_cs.c 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4a7482a2e7775d163aecd8c95af7bb1b8c83890ccPaul Fulghum * $Id: synclink_cs.c,v 4.34 2005/09/08 13:20:54 paulkf Exp $ 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Device driver for Microgate SyncLink PC Card 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * multiprotocol serial adapter. 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * written by Paul Fulghum for Microgate Corporation 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * paulkf@microgate.com 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Microgate and SyncLink are trademarks of Microgate Corporation 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This code is released under the GNU General Public License (GPL) 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * OF THE POSSIBILITY OF SUCH DAMAGE. 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VERSION(ver,rel,seq) (((ver)<<16) | ((rel)<<8) | (seq)) 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if defined(__i386__) 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds# define BREAKPOINT() asm(" int $3"); 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds# define BREAKPOINT() { } 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MAX_DEVICE_COUNT 4 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/signal.h> 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sched.h> 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/timer.h> 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/time.h> 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h> 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty.h> 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_flip.h> 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/serial.h> 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/major.h> 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h> 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fcntl.h> 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ptrace.h> 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h> 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h> 5487687144b4fce2ad083e689eec8b219054c292aeAlexey Dobriyan#include <linux/seq_file.h> 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h> 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/vmalloc.h> 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioctl.h> 613dd1247f4dee214a92b42e17818703ea71233288Robert P. J. Day#include <linux/synclink.h> 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/irq.h> 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/dma.h> 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/bitops.h> 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/types.h> 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/termios.h> 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/workqueue.h> 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/hdlc.h> 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <pcmcia/cistpl.h> 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <pcmcia/cisreg.h> 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <pcmcia/ds.h> 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 76af69c7f924b272927f9aea378f34f4548d3888d9Paul Fulghum#if defined(CONFIG_HDLC) || (defined(CONFIG_HDLC_MODULE) && defined(CONFIG_SYNCLINK_CS_MODULE)) 77af69c7f924b272927f9aea378f34f4548d3888d9Paul Fulghum#define SYNCLINK_GENERIC_HDLC 1 78af69c7f924b272927f9aea378f34f4548d3888d9Paul Fulghum#else 79af69c7f924b272927f9aea378f34f4548d3888d9Paul Fulghum#define SYNCLINK_GENERIC_HDLC 0 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GET_USER(error,value,addr) error = get_user(value,addr) 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PUT_USER(error,value,addr) error = put_user(value,addr) 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define COPY_TO_USER(error,dest,src,size) error = copy_to_user(dest,src,size) ? -EFAULT : 0 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h> 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic MGSL_PARAMS default_params = { 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSL_MODE_HDLC, /* unsigned long mode */ 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0, /* unsigned char loopback; */ 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HDLC_FLAG_UNDERRUN_ABORT15, /* unsigned short flags; */ 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HDLC_ENCODING_NRZI_SPACE, /* unsigned char encoding; */ 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0, /* unsigned long clock_speed; */ 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0xff, /* unsigned char addr_filter; */ 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HDLC_CRC_16_CCITT, /* unsigned short crc_type; */ 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HDLC_PREAMBLE_LENGTH_8BITS, /* unsigned char preamble_length; */ 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HDLC_PREAMBLE_PATTERN_NONE, /* unsigned char preamble; */ 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9600, /* unsigned long data_rate; */ 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8, /* unsigned char data_bits; */ 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1, /* unsigned char stop_bits; */ 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ASYNC_PARITY_NONE /* unsigned char parity; */ 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1053d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilovtypedef struct { 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int count; 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char status; 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char data[1]; 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} RXBUF; 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The queue of BH actions to be performed */ 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BH_RECEIVE 1 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BH_TRANSMIT 2 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BH_STATUS 4 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IO_PIN_SHUTDOWN_LIMIT 100 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct _input_signal_events { 122d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik int ri_up; 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ri_down; 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int dsr_up; 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int dsr_down; 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int dcd_up; 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int dcd_down; 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cts_up; 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cts_down; 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Device instance data structure 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 136d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstypedef struct _mgslpc_info { 138eeb4613436f0f19a38f667ea3078821040559c68Alan Cox struct tty_port port; 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void *if_ptr; /* General purpose pointer (used by SPPP) */ 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int magic; 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int line; 142d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mgsl_icount icount; 144d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int timeout; 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int x_char; /* xon/xoff character */ 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char read_status_mask; 148d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik unsigned char ignore_status_mask; 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *tx_buf; 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int tx_put; 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int tx_get; 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int tx_count; 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* circular list of fixed length rx buffers */ 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *rx_buf; /* memory allocated for all rx buffers */ 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rx_buf_total_size; /* size of memory allocated for rx buffers */ 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rx_put; /* index of next empty rx buffer */ 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rx_get; /* index of next full rx buffer */ 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rx_buf_size; /* size in bytes of single rx buffer */ 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rx_buf_count; /* total number of rx buffers */ 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rx_frame_count; /* number of full rx buffers */ 164d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wait_queue_head_t status_event_wait_q; 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wait_queue_head_t event_wait_q; 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct timer_list tx_timer; /* HDLC transmit timeout timer */ 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct _mgslpc_info *next_device; /* device list link */ 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short imra_value; 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short imrb_value; 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char pim_value; 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spinlock_t lock; 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct work_struct task; /* task structure for scheduling bh */ 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 max_frame_size; 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 pending_bh; 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1810fab6de09c71a976e5d765e1ff548b14be385153Joe Perches bool bh_running; 1820fab6de09c71a976e5d765e1ff548b14be385153Joe Perches bool bh_requested; 183d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int dcd_chkcount; /* check counts to prevent */ 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cts_chkcount; /* too many IRQs if a signal */ 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int dsr_chkcount; /* is floating */ 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ri_chkcount; 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1890fab6de09c71a976e5d765e1ff548b14be385153Joe Perches bool rx_enabled; 1900fab6de09c71a976e5d765e1ff548b14be385153Joe Perches bool rx_overflow; 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1920fab6de09c71a976e5d765e1ff548b14be385153Joe Perches bool tx_enabled; 1930fab6de09c71a976e5d765e1ff548b14be385153Joe Perches bool tx_active; 1940fab6de09c71a976e5d765e1ff548b14be385153Joe Perches bool tx_aborting; 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 idle_mode; 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int if_mode; /* serial interface selection (RS-232, v.35 etc) */ 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char device_name[25]; /* device instance name */ 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int io_base; /* base I/O address of adapter */ 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int irq_level; 203d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSL_PARAMS params; /* communications parameters */ 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char serial_signals; /* current serial signal states */ 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2080fab6de09c71a976e5d765e1ff548b14be385153Joe Perches bool irq_occurred; /* for diagnostics use */ 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char testing_irq; 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int init_error; /* startup error (DIAGS) */ 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 212a6b68a69fa89daeddc6ca6bb90b6f19a86ed7a9fPaul Fulghum char *flag_buf; 2130fab6de09c71a976e5d765e1ff548b14be385153Joe Perches bool drop_rts_on_tx_done; 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct _input_signal_events input_signal_events; 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* PCMCIA support */ 218fd238232cd0ff4840ae6946bb338502154096d88Dominik Brodowski struct pcmcia_device *p_dev; 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int stop; 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* SPPP/Cisco HDLC device parts */ 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int netcount; 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spinlock_t netlock; 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 225af69c7f924b272927f9aea378f34f4548d3888d9Paul Fulghum#if SYNCLINK_GENERIC_HDLC 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *netdev; 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} MGSLPC_INFO; 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MGSLPC_MAGIC 0x5402 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The size of the serial xmit buffer is 1 page, or 4096 bytes 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TXBUFSIZE 4096 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 238d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CHA 0x00 /* channel A offset */ 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CHB 0x40 /* channel B offset */ 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * FIXME: PPC has PVR defined in asm/reg.h. For now we just undef it. 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef PVR 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RXFIFO 0 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TXFIFO 0 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define STAR 0x20 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CMDR 0x20 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RSTA 0x21 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PRE 0x21 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MODE 0x22 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TIMR 0x23 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define XAD1 0x24 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define XAD2 0x25 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RAH1 0x26 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RAH2 0x27 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DAFO 0x27 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RAL1 0x28 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RFC 0x28 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RHCR 0x29 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RAL2 0x29 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RBCL 0x2a 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define XBCL 0x2a 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RBCH 0x2b 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define XBCH 0x2b 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CCR0 0x2c 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CCR1 0x2d 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CCR2 0x2e 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CCR3 0x2f 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VSTR 0x34 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BGR 0x34 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RLCR 0x35 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define AML 0x36 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define AMH 0x37 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GIS 0x38 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IVA 0x38 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IPC 0x39 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ISR 0x3a 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IMR 0x3a 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PVR 0x3c 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PIS 0x3d 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PIM 0x3d 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PCR 0x3e 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CCR4 0x3f 287d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// IMR/ISR 289d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IRQ_BREAK_ON BIT15 // rx break detected 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IRQ_DATAOVERRUN BIT14 // receive data overflow 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IRQ_ALLSENT BIT13 // all sent 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IRQ_UNDERRUN BIT12 // transmit data underrun 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IRQ_TIMER BIT11 // timer interrupt 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IRQ_CTS BIT10 // CTS status change 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IRQ_TXREPEAT BIT9 // tx message repeat 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IRQ_TXFIFO BIT8 // transmit pool ready 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IRQ_RXEOM BIT7 // receive message end 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IRQ_EXITHUNT BIT6 // receive frame start 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IRQ_RXTIME BIT6 // rx char timeout 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IRQ_DCD BIT2 // carrier detect status change 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IRQ_OVERRUN BIT1 // receive frame overflow 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IRQ_RXFIFO BIT0 // receive pool full 304d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// STAR 306d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define XFW BIT6 // transmit FIFO write enable 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CEC BIT2 // command executing 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CTS BIT1 // CTS state 310d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PVR_DTR BIT0 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PVR_DSR BIT1 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PVR_RI BIT2 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PVR_AUTOCTS BIT3 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PVR_RS232 0x20 /* 0010b */ 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PVR_V35 0xe0 /* 1110b */ 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PVR_RS422 0x40 /* 0100b */ 318d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 319d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik/* Register access functions */ 320d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define write_reg(info, reg, val) outb((val),(info)->io_base + (reg)) 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define read_reg(info, reg) inb((info)->io_base + (reg)) 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 324d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik#define read_reg16(info, reg) inw((info)->io_base + (reg)) 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define write_reg16(info, reg, val) outw((val), (info)->io_base + (reg)) 326d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define set_reg_bits(info, reg, mask) \ 3283d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov write_reg(info, (reg), \ 329d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik (unsigned char) (read_reg(info, (reg)) | (mask))) 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define clear_reg_bits(info, reg, mask) \ 3313d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov write_reg(info, (reg), \ 332d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik (unsigned char) (read_reg(info, (reg)) & ~(mask))) 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * interrupt enable/disable routines 335d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik */ 336d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzikstatic void irq_disable(MGSLPC_INFO *info, unsigned char channel, unsigned short mask) 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (channel == CHA) { 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->imra_value |= mask; 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg16(info, CHA + IMR, info->imra_value); 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->imrb_value |= mask; 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg16(info, CHB + IMR, info->imrb_value); 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 346d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzikstatic void irq_enable(MGSLPC_INFO *info, unsigned char channel, unsigned short mask) 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (channel == CHA) { 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->imra_value &= ~mask; 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg16(info, CHA + IMR, info->imra_value); 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->imrb_value &= ~mask; 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg16(info, CHB + IMR, info->imrb_value); 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define port_irq_disable(info, mask) \ 3583d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov { info->pim_value |= (mask); write_reg(info, PIM, info->pim_value); } 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define port_irq_enable(info, mask) \ 3613d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov { info->pim_value &= ~(mask); write_reg(info, PIM, info->pim_value); } 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rx_start(MGSLPC_INFO *info); 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rx_stop(MGSLPC_INFO *info); 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 366eeb4613436f0f19a38f667ea3078821040559c68Alan Coxstatic void tx_start(MGSLPC_INFO *info, struct tty_struct *tty); 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void tx_stop(MGSLPC_INFO *info); 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void tx_set_idle(MGSLPC_INFO *info); 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void get_signals(MGSLPC_INFO *info); 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void set_signals(MGSLPC_INFO *info); 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void reset_device(MGSLPC_INFO *info); 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void hdlc_mode(MGSLPC_INFO *info); 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void async_mode(MGSLPC_INFO *info); 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void tx_timeout(unsigned long context); 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 380eeb4613436f0f19a38f667ea3078821040559c68Alan Coxstatic int carrier_raised(struct tty_port *port); 381fcc8ac1825d3d0fb81f73bc1a80ebc863168bb56Alan Coxstatic void dtr_rts(struct tty_port *port, int onoff); 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 383af69c7f924b272927f9aea378f34f4548d3888d9Paul Fulghum#if SYNCLINK_GENERIC_HDLC 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define dev_to_port(D) (dev_to_hdlc(D)->priv) 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void hdlcdev_tx_done(MGSLPC_INFO *info); 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void hdlcdev_rx(MGSLPC_INFO *info, char *buf, int size); 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int hdlcdev_init(MGSLPC_INFO *info); 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void hdlcdev_exit(MGSLPC_INFO *info); 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void trace_block(MGSLPC_INFO *info,const char* data, int count, int xmit); 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3930fab6de09c71a976e5d765e1ff548b14be385153Joe Perchesstatic bool register_test(MGSLPC_INFO *info); 3940fab6de09c71a976e5d765e1ff548b14be385153Joe Perchesstatic bool irq_test(MGSLPC_INFO *info); 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int adapter_test(MGSLPC_INFO *info); 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int claim_resources(MGSLPC_INFO *info); 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void release_resources(MGSLPC_INFO *info); 399d34138d057628211b1c835e13a64d0cc2423c969Alexey Khoroshilovstatic int mgslpc_add_device(MGSLPC_INFO *info); 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mgslpc_remove_device(MGSLPC_INFO *info); 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 402eeb4613436f0f19a38f667ea3078821040559c68Alan Coxstatic bool rx_get_frame(MGSLPC_INFO *info, struct tty_struct *tty); 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rx_reset_buffers(MGSLPC_INFO *info); 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rx_alloc_buffers(MGSLPC_INFO *info); 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rx_free_buffers(MGSLPC_INFO *info); 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4077d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t mgslpc_isr(int irq, void *dev_id); 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Bottom half interrupt handlers 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 412c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howellsstatic void bh_handler(struct work_struct *work); 413eeb4613436f0f19a38f667ea3078821040559c68Alan Coxstatic void bh_transmit(MGSLPC_INFO *info, struct tty_struct *tty); 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void bh_status(MGSLPC_INFO *info); 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ioctl handlers 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 41960b33c133ca0b7c0b6072c87234b63fee6e80558Alan Coxstatic int tiocmget(struct tty_struct *tty); 42020b9d17715017ae4dd4ec87fabc36d33b9de708eAlan Coxstatic int tiocmset(struct tty_struct *tty, 42120b9d17715017ae4dd4ec87fabc36d33b9de708eAlan Cox unsigned int set, unsigned int clear); 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int get_stats(MGSLPC_INFO *info, struct mgsl_icount __user *user_icount); 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int get_params(MGSLPC_INFO *info, MGSL_PARAMS __user *user_params); 424eeb4613436f0f19a38f667ea3078821040559c68Alan Coxstatic int set_params(MGSLPC_INFO *info, MGSL_PARAMS __user *new_params, struct tty_struct *tty); 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int get_txidle(MGSLPC_INFO *info, int __user *idle_mode); 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int set_txidle(MGSLPC_INFO *info, int idle_mode); 427eeb4613436f0f19a38f667ea3078821040559c68Alan Coxstatic int set_txenable(MGSLPC_INFO *info, int enable, struct tty_struct *tty); 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tx_abort(MGSLPC_INFO *info); 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int set_rxenable(MGSLPC_INFO *info, int enable); 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int wait_events(MGSLPC_INFO *info, int __user *mask); 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic MGSLPC_INFO *mgslpc_device_list = NULL; 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mgslpc_device_count = 0; 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set this param to non-zero to load eax with the 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * .text section address and breakpoint on module load. 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is useful for use with gdb and add-symbol-file command. 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 44090ab5ee94171b3e28de6bb42ee30b527014e0be7Rusty Russellstatic bool break_on_load=0; 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Driver major number, defaults to zero to get auto 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * assigned major number. May be forced as module parameter. 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ttymajor=0; 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int debug_level = 0; 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int maxframe[MAX_DEVICE_COUNT] = {0,}; 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(break_on_load, bool, 0); 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(ttymajor, int, 0); 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(debug_level, int, 0); 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_array(maxframe, int, NULL, 0); 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char *driver_name = "SyncLink PC Card driver"; 459a7482a2e7775d163aecd8c95af7bb1b8c83890ccPaul Fulghumstatic char *driver_version = "$Revision: 4.34 $"; 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct tty_driver *serial_driver; 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* number of characters left in xmit buffer before we ask for more */ 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define WAKEUP_CHARS 256 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 466eeb4613436f0f19a38f667ea3078821040559c68Alan Coxstatic void mgslpc_change_params(MGSLPC_INFO *info, struct tty_struct *tty); 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mgslpc_wait_until_sent(struct tty_struct *tty, int timeout); 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* PCMCIA prototypes */ 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 47115b99ac1729503db9e6dc642a50b9b6cb3bf51f9Dominik Brodowskistatic int mgslpc_config(struct pcmcia_device *link); 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mgslpc_release(u_long arg); 473cc3b4866bee996c922e875b8c8efe9f0d8803aaeDominik Brodowskistatic void mgslpc_detach(struct pcmcia_device *p_dev); 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1st function defined in .text section. Calling this function in 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * init_module() followed by a breakpoint allows a remote debugger 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (gdb) to get the .text address for the add-symbol-file command. 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This allows remote debugging of dynamically loadable modules. 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void* mgslpc_get_text_ptr(void) 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return mgslpc_get_text_ptr; 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * line discipline callback wrappers 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The wrappers maintain line discipline references 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * while calling into the line discipline. 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ldisc_receive_buf - pass receive data to line discipline 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ldisc_receive_buf(struct tty_struct *tty, 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const __u8 *data, char *flags, int count) 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tty_ldisc *ld; 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!tty) 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ld = tty_ldisc_ref(tty); 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ld) { 503a352def21a642133758b868c71bee12ab34ad5c5Alan Cox if (ld->ops->receive_buf) 504a352def21a642133758b868c71bee12ab34ad5c5Alan Cox ld->ops->receive_buf(tty, data, flags, count); 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_ldisc_deref(ld); 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 509eeb4613436f0f19a38f667ea3078821040559c68Alan Coxstatic const struct tty_port_operations mgslpc_port_ops = { 510eeb4613436f0f19a38f667ea3078821040559c68Alan Cox .carrier_raised = carrier_raised, 511fcc8ac1825d3d0fb81f73bc1a80ebc863168bb56Alan Cox .dtr_rts = dtr_rts 512eeb4613436f0f19a38f667ea3078821040559c68Alan Cox}; 513eeb4613436f0f19a38f667ea3078821040559c68Alan Cox 51415b99ac1729503db9e6dc642a50b9b6cb3bf51f9Dominik Brodowskistatic int mgslpc_probe(struct pcmcia_device *link) 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5163d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov MGSLPC_INFO *info; 5173d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov int ret; 5183d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov 5193d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov if (debug_level >= DEBUG_LEVEL_INFO) 5203d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov printk("mgslpc_attach\n"); 5213d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov 5223d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov info = kzalloc(sizeof(MGSLPC_INFO), GFP_KERNEL); 5233d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov if (!info) { 5243d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov printk("Error can't allocate device instance data\n"); 5253d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov return -ENOMEM; 5263d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov } 5273d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov 5283d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov info->magic = MGSLPC_MAGIC; 5293d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov tty_port_init(&info->port); 5303d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov info->port.ops = &mgslpc_port_ops; 5313d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov INIT_WORK(&info->task, bh_handler); 5323d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov info->max_frame_size = 4096; 5333d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov info->port.close_delay = 5*HZ/10; 5343d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov info->port.closing_wait = 30*HZ; 5353d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov init_waitqueue_head(&info->status_event_wait_q); 5363d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov init_waitqueue_head(&info->event_wait_q); 5373d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_lock_init(&info->lock); 5383d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_lock_init(&info->netlock); 5393d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov memcpy(&info->params,&default_params,sizeof(MGSL_PARAMS)); 5403d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov info->idle_mode = HDLC_TXIDLE_FLAGS; 5413d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov info->imra_value = 0xffff; 5423d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov info->imrb_value = 0xffff; 5433d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov info->pim_value = 0xff; 5443d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov 5453d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov info->p_dev = link; 5463d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov link->priv = info; 5473d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov 5483d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov /* Initialize the struct pcmcia_device structure */ 5493d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov 5503d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov ret = mgslpc_config(link); 5513d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov if (ret != 0) 5523d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov goto failed; 5533d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov 5543d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov ret = mgslpc_add_device(info); 5553d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov if (ret != 0) 5563d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov goto failed_release; 5573d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov 5583d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov return 0; 559d34138d057628211b1c835e13a64d0cc2423c969Alexey Khoroshilov 560d34138d057628211b1c835e13a64d0cc2423c969Alexey Khoroshilovfailed_release: 5613d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov mgslpc_release((u_long)link); 562d34138d057628211b1c835e13a64d0cc2423c969Alexey Khoroshilovfailed: 5633d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov tty_port_destroy(&info->port); 5643d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov kfree(info); 5653d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov return ret; 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Card has been inserted. 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 57100990e7ce0b0e596fe41d9c64d6933ea70084003Dominik Brodowskistatic int mgslpc_ioprobe(struct pcmcia_device *p_dev, void *priv_data) 572aaa8cfdada648a6bae32f62df76cc60137a2b323Dominik Brodowski{ 57390abdc3b973229bae98dd96649d9f7106cc177a4Dominik Brodowski return pcmcia_request_io(p_dev); 574aaa8cfdada648a6bae32f62df76cc60137a2b323Dominik Brodowski} 575aaa8cfdada648a6bae32f62df76cc60137a2b323Dominik Brodowski 57615b99ac1729503db9e6dc642a50b9b6cb3bf51f9Dominik Brodowskistatic int mgslpc_config(struct pcmcia_device *link) 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5783d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov MGSLPC_INFO *info = link->priv; 5793d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov int ret; 580d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 5813d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov if (debug_level >= DEBUG_LEVEL_INFO) 5823d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov printk("mgslpc_config(0x%p)\n", link); 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5843d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; 58500990e7ce0b0e596fe41d9c64d6933ea70084003Dominik Brodowski 5863d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov ret = pcmcia_loop_config(link, mgslpc_ioprobe, NULL); 5873d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov if (ret != 0) 5883d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov goto failed; 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5903d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov link->config_index = 8; 5913d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov link->config_regs = PRESENT_OPTION; 592d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 5933d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov ret = pcmcia_request_irq(link, mgslpc_isr); 5943d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov if (ret) 5953d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov goto failed; 5963d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov ret = pcmcia_enable_device(link); 5973d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov if (ret) 5983d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov goto failed; 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6003d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov info->io_base = link->resource[0]->start; 6013d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov info->irq_level = link->irq; 6023d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov return 0; 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 604cbf624f0e18c4a05219855663a3e5f9fe8f2d876Dominik Brodowskifailed: 6053d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov mgslpc_release((u_long)link); 6063d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov return -ENODEV; 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Card has been removed. 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Unregister device and release PCMCIA configuration. 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If device is open, postpone until it is closed. 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mgslpc_release(u_long arg) 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 615e2d4096365e06b9a3799afbadc28b4519c0b3526Dominik Brodowski struct pcmcia_device *link = (struct pcmcia_device *)arg; 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 617e2d4096365e06b9a3799afbadc28b4519c0b3526Dominik Brodowski if (debug_level >= DEBUG_LEVEL_INFO) 618e2d4096365e06b9a3799afbadc28b4519c0b3526Dominik Brodowski printk("mgslpc_release(0x%p)\n", link); 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 620e2d4096365e06b9a3799afbadc28b4519c0b3526Dominik Brodowski pcmcia_disable_device(link); 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 623fba395eee7d3f342ca739c20f5b3ee635d0420a0Dominik Brodowskistatic void mgslpc_detach(struct pcmcia_device *link) 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 625e2d4096365e06b9a3799afbadc28b4519c0b3526Dominik Brodowski if (debug_level >= DEBUG_LEVEL_INFO) 626e2d4096365e06b9a3799afbadc28b4519c0b3526Dominik Brodowski printk("mgslpc_detach(0x%p)\n", link); 627cc3b4866bee996c922e875b8c8efe9f0d8803aaeDominik Brodowski 628e2d4096365e06b9a3799afbadc28b4519c0b3526Dominik Brodowski ((MGSLPC_INFO *)link->priv)->stop = 1; 629e2d4096365e06b9a3799afbadc28b4519c0b3526Dominik Brodowski mgslpc_release((u_long)link); 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 631e2d4096365e06b9a3799afbadc28b4519c0b3526Dominik Brodowski mgslpc_remove_device((MGSLPC_INFO *)link->priv); 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 634fba395eee7d3f342ca739c20f5b3ee635d0420a0Dominik Brodowskistatic int mgslpc_suspend(struct pcmcia_device *link) 63598e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski{ 63698e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski MGSLPC_INFO *info = link->priv; 63798e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski 63898e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski info->stop = 1; 63998e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski 64098e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski return 0; 64198e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski} 64298e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski 643fba395eee7d3f342ca739c20f5b3ee635d0420a0Dominik Brodowskistatic int mgslpc_resume(struct pcmcia_device *link) 64498e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski{ 64598e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski MGSLPC_INFO *info = link->priv; 64698e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski 64798e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski info->stop = 0; 64898e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski 64998e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski return 0; 65098e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski} 65198e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski 65298e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski 6530fab6de09c71a976e5d765e1ff548b14be385153Joe Perchesstatic inline bool mgslpc_paranoia_check(MGSLPC_INFO *info, 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *name, const char *routine) 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef MGSLPC_PARANOIA_CHECK 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds static const char *badmagic = 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Warning: bad magic number for mgsl struct (%s) in %s\n"; 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds static const char *badinfo = 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Warning: null mgslpc_info for (%s) in %s\n"; 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info) { 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(badinfo, name, routine); 6640fab6de09c71a976e5d765e1ff548b14be385153Joe Perches return true; 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->magic != MGSLPC_MAGIC) { 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(badmagic, name, routine); 6680fab6de09c71a976e5d765e1ff548b14be385153Joe Perches return true; 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info) 6720fab6de09c71a976e5d765e1ff548b14be385153Joe Perches return true; 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 6740fab6de09c71a976e5d765e1ff548b14be385153Joe Perches return false; 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CMD_RXFIFO BIT7 // release current rx FIFO 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CMD_RXRESET BIT6 // receiver reset 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CMD_RXFIFO_READ BIT5 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CMD_START_TIMER BIT4 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CMD_TXFIFO BIT3 // release current tx FIFO 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CMD_TXEOM BIT1 // transmit end message 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CMD_TXRESET BIT0 // transmit reset 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6860fab6de09c71a976e5d765e1ff548b14be385153Joe Perchesstatic bool wait_command_complete(MGSLPC_INFO *info, unsigned char channel) 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i = 0; 689d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik /* wait for command completion */ 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (read_reg(info, (unsigned char)(channel+STAR)) & BIT2) { 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(1); 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i++ == 1000) 6930fab6de09c71a976e5d765e1ff548b14be385153Joe Perches return false; 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6950fab6de09c71a976e5d765e1ff548b14be385153Joe Perches return true; 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 698d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzikstatic void issue_command(MGSLPC_INFO *info, unsigned char channel, unsigned char cmd) 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wait_command_complete(info, channel); 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, (unsigned char) (channel + CMDR), cmd); 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void tx_pause(struct tty_struct *tty) 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 708d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mgslpc_paranoia_check(info, tty->name, "tx_pause")) 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 7123d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov printk("tx_pause(%s)\n", info->device_name); 713d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 7143d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_lock_irqsave(&info->lock, flags); 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->tx_enabled) 7163d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov tx_stop(info); 7173d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_unlock_irqrestore(&info->lock, flags); 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void tx_release(struct tty_struct *tty) 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 724d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mgslpc_paranoia_check(info, tty->name, "tx_release")) 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 7283d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov printk("tx_release(%s)\n", info->device_name); 729d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 7303d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_lock_irqsave(&info->lock, flags); 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info->tx_enabled) 7323d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov tx_start(info, tty); 7333d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_unlock_irqrestore(&info->lock, flags); 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Return next bottom half action to perform. 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * or 0 if nothing to do. 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int bh_action(MGSLPC_INFO *info) 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc = 0; 743d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 7443d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_lock_irqsave(&info->lock, flags); 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->pending_bh & BH_RECEIVE) { 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->pending_bh &= ~BH_RECEIVE; 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = BH_RECEIVE; 7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (info->pending_bh & BH_TRANSMIT) { 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->pending_bh &= ~BH_TRANSMIT; 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = BH_TRANSMIT; 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (info->pending_bh & BH_STATUS) { 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->pending_bh &= ~BH_STATUS; 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = BH_STATUS; 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!rc) { 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Mark BH routine as complete */ 7590fab6de09c71a976e5d765e1ff548b14be385153Joe Perches info->bh_running = false; 7600fab6de09c71a976e5d765e1ff548b14be385153Joe Perches info->bh_requested = false; 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 762d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 7633d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_unlock_irqrestore(&info->lock, flags); 764d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 768c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howellsstatic void bh_handler(struct work_struct *work) 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 770c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells MGSLPC_INFO *info = container_of(work, MGSLPC_INFO, task); 771eeb4613436f0f19a38f667ea3078821040559c68Alan Cox struct tty_struct *tty; 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int action; 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_BH) 7753d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov printk("%s(%d):bh_handler(%s) entry\n", 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__,info->device_name); 777d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 7780fab6de09c71a976e5d765e1ff548b14be385153Joe Perches info->bh_running = true; 779eeb4613436f0f19a38f667ea3078821040559c68Alan Cox tty = tty_port_tty_get(&info->port); 7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while((action = bh_action(info)) != 0) { 782d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Process work item */ 7843d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov if (debug_level >= DEBUG_LEVEL_BH) 7853d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov printk("%s(%d):bh_handler() work item action=%d\n", 7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__,action); 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (action) { 789d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case BH_RECEIVE: 791eeb4613436f0f19a38f667ea3078821040559c68Alan Cox while(rx_get_frame(info, tty)); 7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case BH_TRANSMIT: 794eeb4613436f0f19a38f667ea3078821040559c68Alan Cox bh_transmit(info, tty); 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case BH_STATUS: 7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh_status(info); 7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* unknown work item ID */ 8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("Unknown work item ID=%08X!\n", action); 8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 806eeb4613436f0f19a38f667ea3078821040559c68Alan Cox tty_kref_put(tty); 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_BH) 8083d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov printk("%s(%d):bh_handler(%s) exit\n", 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__,info->device_name); 8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 812eeb4613436f0f19a38f667ea3078821040559c68Alan Coxstatic void bh_transmit(MGSLPC_INFO *info, struct tty_struct *tty) 8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_BH) 8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("bh_transmit() entry on %s\n", info->device_name); 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 817b963a8441cb95999c97bea379607071a869c65f0Jiri Slaby if (tty) 8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_wakeup(tty); 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 821cdaad343b561cdeb38b0578bb038eb5e87ed5551Peter Hagervallstatic void bh_status(MGSLPC_INFO *info) 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->ri_chkcount = 0; 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->dsr_chkcount = 0; 8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->dcd_chkcount = 0; 8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->cts_chkcount = 0; 8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 829d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik/* eom: non-zero = end of frame */ 8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rx_ready_hdlc(MGSLPC_INFO *info, int eom) 8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char data[2]; 8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char fifo_count, read_count, i; 8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds RXBUF *buf = (RXBUF*)(info->rx_buf + (info->rx_put * info->rx_buf_size)); 8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_ISR) 8373d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov printk("%s(%d):rx_ready_hdlc(eom=%d)\n", __FILE__, __LINE__, eom); 838d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info->rx_enabled) 8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->rx_frame_count >= info->rx_buf_count) { 8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* no more free buffers */ 8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds issue_command(info, CHA, CMD_RXRESET); 8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->pending_bh |= BH_RECEIVE; 8460fab6de09c71a976e5d765e1ff548b14be385153Joe Perches info->rx_overflow = true; 8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->icount.buf_overrun++; 8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (eom) { 852d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik /* end of frame, get FIFO count from RBCL register */ 8533d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov fifo_count = (unsigned char)(read_reg(info, CHA+RBCL) & 0x1f); 8543d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov if (fifo_count == 0) 8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fifo_count = 32; 8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fifo_count = 32; 858d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fifo_count == 1) { 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read_count = 1; 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data[0] = read_reg(info, CHA + RXFIFO); 8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read_count = 2; 8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *((unsigned short *) data) = read_reg16(info, CHA + RXFIFO); 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fifo_count -= read_count; 8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!fifo_count && eom) 8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf->status = data[--read_count]; 8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < read_count; i++) { 8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (buf->count >= info->max_frame_size) { 8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* frame too large, reset receiver and reset current buffer */ 8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds issue_command(info, CHA, CMD_RXRESET); 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf->count = 0; 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *(buf->data + buf->count) = data[i]; 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf->count++; 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (fifo_count); 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (eom) { 8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->pending_bh |= BH_RECEIVE; 8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->rx_frame_count++; 8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->rx_put++; 8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->rx_put >= info->rx_buf_count) 8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->rx_put = 0; 8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds issue_command(info, CHA, CMD_RXFIFO); 8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8932e124b4a390ca85325fae75764bef92f0547fa25Jiri Slabystatic void rx_ready_async(MGSLPC_INFO *info, int tcd) 8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 895227434f8986c3827a1faedd1feb437acd6285315Jiri Slaby struct tty_port *port = &info->port; 89633f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox unsigned char data, status, flag; 8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int fifo_count; 89833f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox int work = 0; 8993d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov struct mgsl_icount *icount = &info->icount; 9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tcd) { 902d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik /* early termination, get FIFO count from RBCL register */ 9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fifo_count = (unsigned char)(read_reg(info, CHA+RBCL) & 0x1f); 9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Zero fifo count could mean 0 or 32 bytes available. 9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If BIT5 of STAR is set then at least 1 byte is available. 9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!fifo_count && (read_reg(info,CHA+STAR) & BIT5)) 9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fifo_count = 32; 9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fifo_count = 32; 91233f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox 913227434f8986c3827a1faedd1feb437acd6285315Jiri Slaby tty_buffer_request_room(port, fifo_count); 914d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik /* Flush received async data to receive data buffer. */ 9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (fifo_count) { 9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data = read_reg(info, CHA + RXFIFO); 9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = read_reg(info, CHA + RXFIFO); 9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fifo_count -= 2; 9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds icount->rx++; 92133f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox flag = TTY_NORMAL; 9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // if no frameing/crc error then save data 9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // BIT7:parity error 9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // BIT6:framing error 9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & (BIT7 + BIT6)) { 928d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik if (status & BIT7) 9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds icount->parity++; 9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds icount->frame++; 9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* discard char if tty control flags say so */ 9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & info->ignore_status_mask) 9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 936d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status &= info->read_status_mask; 9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & BIT7) 94033f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox flag = TTY_PARITY; 9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (status & BIT6) 94233f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox flag = TTY_FRAME; 9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 94492a19f9cec9a80ad93c06e115822deb729e2c6adJiri Slaby work += tty_insert_flip_char(port, data, flag); 9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds issue_command(info, CHA, CMD_RXFIFO); 9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_ISR) { 94933f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox printk("%s(%d):rx_ready_async", 95033f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox __FILE__,__LINE__); 9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):rx=%d brk=%d parity=%d frame=%d overrun=%d\n", 9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__,icount->rx,icount->brk, 9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds icount->parity,icount->frame,icount->overrun); 9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 955d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 95633f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox if (work) 9572e124b4a390ca85325fae75764bef92f0547fa25Jiri Slaby tty_flip_buffer_push(port); 9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 961eeb4613436f0f19a38f667ea3078821040559c68Alan Coxstatic void tx_done(MGSLPC_INFO *info, struct tty_struct *tty) 9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info->tx_active) 9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 965d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 9660fab6de09c71a976e5d765e1ff548b14be385153Joe Perches info->tx_active = false; 9670fab6de09c71a976e5d765e1ff548b14be385153Joe Perches info->tx_aborting = false; 9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.mode == MGSL_MODE_ASYNC) 9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_count = info->tx_put = info->tx_get = 0; 973d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik del_timer(&info->tx_timer); 974d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->drop_rts_on_tx_done) { 9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds get_signals(info); 9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->serial_signals & SerialSignal_RTS) { 9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->serial_signals &= ~SerialSignal_RTS; 9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_signals(info); 9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9810fab6de09c71a976e5d765e1ff548b14be385153Joe Perches info->drop_rts_on_tx_done = false; 9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 984af69c7f924b272927f9aea378f34f4548d3888d9Paul Fulghum#if SYNCLINK_GENERIC_HDLC 9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->netcount) 9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdlcdev_tx_done(info); 987d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik else 9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 990221b7b5796b520b51c34c40239d77921ba39225bAlexey Khoroshilov if (tty && (tty->stopped || tty->hw_stopped)) { 9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_stop(info); 9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->pending_bh |= BH_TRANSMIT; 9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 998eeb4613436f0f19a38f667ea3078821040559c68Alan Coxstatic void tx_ready(MGSLPC_INFO *info, struct tty_struct *tty) 9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char fifo_count = 32; 10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int c; 10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_ISR) 10043d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov printk("%s(%d):tx_ready(%s)\n", __FILE__, __LINE__, info->device_name); 10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.mode == MGSL_MODE_HDLC) { 10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info->tx_active) 10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1010221b7b5796b520b51c34c40239d77921ba39225bAlexey Khoroshilov if (tty && (tty->stopped || tty->hw_stopped)) { 10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_stop(info); 10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info->tx_count) 10150fab6de09c71a976e5d765e1ff548b14be385153Joe Perches info->tx_active = false; 10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info->tx_count) 10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (info->tx_count && fifo_count) { 10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds c = min(2, min_t(int, fifo_count, min(info->tx_count, TXBUFSIZE - info->tx_get))); 1023d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (c == 1) { 10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + TXFIFO, *(info->tx_buf + info->tx_get)); 10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg16(info, CHA + TXFIFO, 10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *((unsigned short*)(info->tx_buf + info->tx_get))); 10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_count -= c; 10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_get = (info->tx_get + c) & (TXBUFSIZE - 1); 10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fifo_count -= c; 10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.mode == MGSL_MODE_ASYNC) { 10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->tx_count < WAKEUP_CHARS) 10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->pending_bh |= BH_TRANSMIT; 10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds issue_command(info, CHA, CMD_TXFIFO); 10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->tx_count) 10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds issue_command(info, CHA, CMD_TXFIFO); 10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds issue_command(info, CHA, CMD_TXFIFO + CMD_TXEOM); 10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1047eeb4613436f0f19a38f667ea3078821040559c68Alan Coxstatic void cts_change(MGSLPC_INFO *info, struct tty_struct *tty) 10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds get_signals(info); 10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((info->cts_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) 10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq_disable(info, CHB, IRQ_CTS); 10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->icount.cts++; 10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->serial_signals & SerialSignal_CTS) 10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->input_signal_events.cts_up++; 10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->input_signal_events.cts_down++; 10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up_interruptible(&info->status_event_wait_q); 10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up_interruptible(&info->event_wait_q); 10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10603498d13b8090c0b0ef911409fbc503a7c4cca6efLinus Torvalds if (tty && tty_port_cts_enabled(&info->port)) { 1061eeb4613436f0f19a38f667ea3078821040559c68Alan Cox if (tty->hw_stopped) { 10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->serial_signals & SerialSignal_CTS) { 10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_ISR) 10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("CTS tx start..."); 1065221b7b5796b520b51c34c40239d77921ba39225bAlexey Khoroshilov tty->hw_stopped = 0; 1066eeb4613436f0f19a38f667ea3078821040559c68Alan Cox tx_start(info, tty); 10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->pending_bh |= BH_TRANSMIT; 10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(info->serial_signals & SerialSignal_CTS)) { 10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_ISR) 10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("CTS tx stop..."); 1074221b7b5796b520b51c34c40239d77921ba39225bAlexey Khoroshilov tty->hw_stopped = 1; 10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_stop(info); 10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->pending_bh |= BH_STATUS; 10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1082eeb4613436f0f19a38f667ea3078821040559c68Alan Coxstatic void dcd_change(MGSLPC_INFO *info, struct tty_struct *tty) 10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds get_signals(info); 10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((info->dcd_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) 10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq_disable(info, CHB, IRQ_DCD); 10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->icount.dcd++; 10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->serial_signals & SerialSignal_DCD) { 10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->input_signal_events.dcd_up++; 10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->input_signal_events.dcd_down++; 1093af69c7f924b272927f9aea378f34f4548d3888d9Paul Fulghum#if SYNCLINK_GENERIC_HDLC 1094fbeff3c1d35d07b1f967e47fcfb00cd16b7ecd02Krzysztof Halasa if (info->netcount) { 1095fbeff3c1d35d07b1f967e47fcfb00cd16b7ecd02Krzysztof Halasa if (info->serial_signals & SerialSignal_DCD) 1096fbeff3c1d35d07b1f967e47fcfb00cd16b7ecd02Krzysztof Halasa netif_carrier_on(info->netdev); 1097fbeff3c1d35d07b1f967e47fcfb00cd16b7ecd02Krzysztof Halasa else 1098fbeff3c1d35d07b1f967e47fcfb00cd16b7ecd02Krzysztof Halasa netif_carrier_off(info->netdev); 1099fbeff3c1d35d07b1f967e47fcfb00cd16b7ecd02Krzysztof Halasa } 11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up_interruptible(&info->status_event_wait_q); 11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up_interruptible(&info->event_wait_q); 11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1104eeb4613436f0f19a38f667ea3078821040559c68Alan Cox if (info->port.flags & ASYNC_CHECK_CD) { 11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_ISR) 11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s CD now %s...", info->device_name, 11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (info->serial_signals & SerialSignal_DCD) ? "on" : "off"); 11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->serial_signals & SerialSignal_DCD) 1109eeb4613436f0f19a38f667ea3078821040559c68Alan Cox wake_up_interruptible(&info->port.open_wait); 11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_ISR) 11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("doing serial hangup..."); 1113eeb4613436f0f19a38f667ea3078821040559c68Alan Cox if (tty) 1114eeb4613436f0f19a38f667ea3078821040559c68Alan Cox tty_hangup(tty); 11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->pending_bh |= BH_STATUS; 11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void dsr_change(MGSLPC_INFO *info) 11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds get_signals(info); 11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((info->dsr_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) 11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port_irq_disable(info, PVR_DSR); 11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->icount.dsr++; 11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->serial_signals & SerialSignal_DSR) 11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->input_signal_events.dsr_up++; 11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->input_signal_events.dsr_down++; 11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up_interruptible(&info->status_event_wait_q); 11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up_interruptible(&info->event_wait_q); 11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->pending_bh |= BH_STATUS; 11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ri_change(MGSLPC_INFO *info) 11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds get_signals(info); 11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((info->ri_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) 11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port_irq_disable(info, PVR_RI); 11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->icount.rng++; 11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->serial_signals & SerialSignal_RI) 11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->input_signal_events.ri_up++; 11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->input_signal_events.ri_down++; 11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up_interruptible(&info->status_event_wait_q); 11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up_interruptible(&info->event_wait_q); 11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->pending_bh |= BH_STATUS; 11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Interrupt service routine entry point. 1151d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik * 11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Arguments: 1153d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik * 11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * irq interrupt number that caused interrupt 11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dev_id device ID supplied during interrupt registration 11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1157a6f97b293b08877d945ea3f28926aa446dd7ca2eJeff Garzikstatic irqreturn_t mgslpc_isr(int dummy, void *dev_id) 11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1159a6f97b293b08877d945ea3f28926aa446dd7ca2eJeff Garzik MGSLPC_INFO *info = dev_id; 1160eeb4613436f0f19a38f667ea3078821040559c68Alan Cox struct tty_struct *tty; 11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short isr; 11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char gis, pis; 11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int count=0; 11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1165d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik if (debug_level >= DEBUG_LEVEL_ISR) 1166a6f97b293b08877d945ea3f28926aa446dd7ca2eJeff Garzik printk("mgslpc_isr(%d) entry.\n", info->irq_level); 1167d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 1168e2d4096365e06b9a3799afbadc28b4519c0b3526Dominik Brodowski if (!(info->p_dev->_locked)) 11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_HANDLED; 11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1171eeb4613436f0f19a38f667ea3078821040559c68Alan Cox tty = tty_port_tty_get(&info->port); 1172eeb4613436f0f19a38f667ea3078821040559c68Alan Cox 11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&info->lock); 11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while ((gis = read_reg(info, CHA + GIS))) { 1176d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik if (debug_level >= DEBUG_LEVEL_ISR) 11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("mgslpc_isr %s gis=%04X\n", info->device_name,gis); 11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((gis & 0x70) || count > 1000) { 11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("synclink_cs:hardware failed or ejected\n"); 11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count++; 11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1185ecda040ff3724f021a96491ecee88d48e968c153Alexandru Juncu if (gis & (BIT1 | BIT0)) { 11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds isr = read_reg16(info, CHB + ISR); 11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (isr & IRQ_DCD) 1188eeb4613436f0f19a38f667ea3078821040559c68Alan Cox dcd_change(info, tty); 11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (isr & IRQ_CTS) 1190eeb4613436f0f19a38f667ea3078821040559c68Alan Cox cts_change(info, tty); 11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1192ecda040ff3724f021a96491ecee88d48e968c153Alexandru Juncu if (gis & (BIT3 | BIT2)) 11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds isr = read_reg16(info, CHA + ISR); 11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (isr & IRQ_TIMER) { 11960fab6de09c71a976e5d765e1ff548b14be385153Joe Perches info->irq_occurred = true; 11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq_disable(info, CHA, IRQ_TIMER); 11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1200d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik /* receive IRQs */ 12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (isr & IRQ_EXITHUNT) { 12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->icount.exithunt++; 12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up_interruptible(&info->event_wait_q); 12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (isr & IRQ_BREAK_ON) { 12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->icount.brk++; 1207eeb4613436f0f19a38f667ea3078821040559c68Alan Cox if (info->port.flags & ASYNC_SAK) 1208eeb4613436f0f19a38f667ea3078821040559c68Alan Cox do_SAK(tty); 12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (isr & IRQ_RXTIME) { 12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds issue_command(info, CHA, CMD_RXFIFO_READ); 12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1213ecda040ff3724f021a96491ecee88d48e968c153Alexandru Juncu if (isr & (IRQ_RXEOM | IRQ_RXFIFO)) { 12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.mode == MGSL_MODE_HDLC) 1215d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik rx_ready_hdlc(info, isr & IRQ_RXEOM); 12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 12172e124b4a390ca85325fae75764bef92f0547fa25Jiri Slaby rx_ready_async(info, isr & IRQ_RXEOM); 12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1220d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik /* transmit IRQs */ 12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (isr & IRQ_UNDERRUN) { 12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->tx_aborting) 12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->icount.txabort++; 12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->icount.txunder++; 1226eeb4613436f0f19a38f667ea3078821040559c68Alan Cox tx_done(info, tty); 12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (isr & IRQ_ALLSENT) { 12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->icount.txok++; 1230eeb4613436f0f19a38f667ea3078821040559c68Alan Cox tx_done(info, tty); 12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (isr & IRQ_TXFIFO) 1233eeb4613436f0f19a38f667ea3078821040559c68Alan Cox tx_ready(info, tty); 12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (gis & BIT7) { 12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pis = read_reg(info, CHA + PIS); 12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pis & BIT1) 12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dsr_change(info); 12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pis & BIT2) 12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ri_change(info); 12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1243d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 1244d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik /* Request bottom half processing if there's something 12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for it to do and the bh is not already running 12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->pending_bh && !info->bh_running && !info->bh_requested) { 12493d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov if (debug_level >= DEBUG_LEVEL_ISR) 12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):%s queueing bh task.\n", 12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__,info->device_name); 12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds schedule_work(&info->task); 12530fab6de09c71a976e5d765e1ff548b14be385153Joe Perches info->bh_requested = true; 12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&info->lock); 1257eeb4613436f0f19a38f667ea3078821040559c68Alan Cox tty_kref_put(tty); 1258d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 1259d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik if (debug_level >= DEBUG_LEVEL_ISR) 12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):mgslpc_isr(%d)exit.\n", 1261a6f97b293b08877d945ea3f28926aa446dd7ca2eJeff Garzik __FILE__, __LINE__, info->irq_level); 12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_HANDLED; 12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Initialize and start device. 12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1268eeb4613436f0f19a38f667ea3078821040559c68Alan Coxstatic int startup(MGSLPC_INFO * info, struct tty_struct *tty) 12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval = 0; 1271d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 12733d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov printk("%s(%d):startup(%s)\n", __FILE__, __LINE__, info->device_name); 1274d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 1275eeb4613436f0f19a38f667ea3078821040559c68Alan Cox if (info->port.flags & ASYNC_INITIALIZED) 12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1277d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info->tx_buf) { 12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* allocate a page of memory for a transmit buffer */ 12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL); 12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info->tx_buf) { 12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR"%s(%d):%s can't allocate transmit buffer\n", 12833d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov __FILE__, __LINE__, info->device_name); 12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->pending_bh = 0; 1289d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 1290a7482a2e7775d163aecd8c95af7bb1b8c83890ccPaul Fulghum memset(&info->icount, 0, sizeof(info->icount)); 1291a7482a2e7775d163aecd8c95af7bb1b8c83890ccPaul Fulghum 129240565f1962c5be9b9e285e05af01ab7771534868Jiri Slaby setup_timer(&info->tx_timer, tx_timeout, (unsigned long)info); 12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Allocate and claim adapter resources */ 12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = claim_resources(info); 1296d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 129725985edcedea6396277003854657b5f3cb31a628Lucas De Marchi /* perform existence check and diagnostics */ 12983d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov if (!retval) 12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = adapter_test(info); 1300d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 13013d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov if (retval) { 13023d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov if (capable(CAP_SYS_ADMIN) && tty) 1303eeb4613436f0f19a38f667ea3078821040559c68Alan Cox set_bit(TTY_IO_ERROR, &tty->flags); 13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_resources(info); 13053d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov return retval; 13063d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov } 13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* program hardware for current parameters */ 1309eeb4613436f0f19a38f667ea3078821040559c68Alan Cox mgslpc_change_params(info, tty); 1310d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 1311eeb4613436f0f19a38f667ea3078821040559c68Alan Cox if (tty) 1312eeb4613436f0f19a38f667ea3078821040559c68Alan Cox clear_bit(TTY_IO_ERROR, &tty->flags); 13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1314eeb4613436f0f19a38f667ea3078821040559c68Alan Cox info->port.flags |= ASYNC_INITIALIZED; 1315d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Called by mgslpc_close() and mgslpc_hangup() to shutdown hardware 13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1321eeb4613436f0f19a38f667ea3078821040559c68Alan Coxstatic void shutdown(MGSLPC_INFO * info, struct tty_struct *tty) 13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1324d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 1325eeb4613436f0f19a38f667ea3078821040559c68Alan Cox if (!(info->port.flags & ASYNC_INITIALIZED)) 13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):mgslpc_shutdown(%s)\n", 13303d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov __FILE__, __LINE__, info->device_name); 13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* clear status wait queue because status changes */ 13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* can't happen after shutting down the hardware */ 13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up_interruptible(&info->status_event_wait_q); 13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up_interruptible(&info->event_wait_q); 13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 133740565f1962c5be9b9e285e05af01ab7771534868Jiri Slaby del_timer_sync(&info->tx_timer); 13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->tx_buf) { 13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_page((unsigned long) info->tx_buf); 13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_buf = NULL; 13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13443d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_lock_irqsave(&info->lock, flags); 13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_stop(info); 13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_stop(info); 13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* TODO:disable interrupts instead of reset to preserve signal states */ 13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reset_device(info); 1351d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 13523d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov if (!tty || tty->termios.c_cflag & HUPCL) { 13539fe8074b82ed14358be50c62ab9d081bcb911607Joe Perches info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR); 13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_signals(info); 13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1356d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 13573d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_unlock_irqrestore(&info->lock, flags); 13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1359d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik release_resources(info); 1360d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 1361eeb4613436f0f19a38f667ea3078821040559c68Alan Cox if (tty) 1362eeb4613436f0f19a38f667ea3078821040559c68Alan Cox set_bit(TTY_IO_ERROR, &tty->flags); 13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1364eeb4613436f0f19a38f667ea3078821040559c68Alan Cox info->port.flags &= ~ASYNC_INITIALIZED; 13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1367eeb4613436f0f19a38f667ea3078821040559c68Alan Coxstatic void mgslpc_program_hw(MGSLPC_INFO *info, struct tty_struct *tty) 13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13713d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_lock_irqsave(&info->lock, flags); 1372d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_stop(info); 13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_stop(info); 13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_count = info->tx_put = info->tx_get = 0; 1376d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.mode == MGSL_MODE_HDLC || info->netcount) 13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdlc_mode(info); 13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds async_mode(info); 1381d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_signals(info); 1383d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->dcd_chkcount = 0; 13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->cts_chkcount = 0; 13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->ri_chkcount = 0; 13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->dsr_chkcount = 0; 13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq_enable(info, CHB, IRQ_DCD | IRQ_CTS); 13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port_irq_enable(info, (unsigned char) PVR_DSR | PVR_RI); 13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds get_signals(info); 1392d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 1393373f5aedbc6fb73d30f00eeb0dc7313ecfede908Alan Cox if (info->netcount || (tty && (tty->termios.c_cflag & CREAD))) 13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_start(info); 1395d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 13963d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_unlock_irqrestore(&info->lock, flags); 13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Reconfigure adapter based on new parameters 14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1401eeb4613436f0f19a38f667ea3078821040559c68Alan Coxstatic void mgslpc_change_params(MGSLPC_INFO *info, struct tty_struct *tty) 14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned cflag; 14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int bits_per_char; 14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1406373f5aedbc6fb73d30f00eeb0dc7313ecfede908Alan Cox if (!tty) 14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 1408d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):mgslpc_change_params(%s)\n", 14113d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov __FILE__, __LINE__, info->device_name); 1412d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 1413373f5aedbc6fb73d30f00eeb0dc7313ecfede908Alan Cox cflag = tty->termios.c_cflag; 14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14159fe8074b82ed14358be50c62ab9d081bcb911607Joe Perches /* if B0 rate (hangup) specified then negate RTS and DTR */ 14169fe8074b82ed14358be50c62ab9d081bcb911607Joe Perches /* otherwise assert RTS and DTR */ 14173d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov if (cflag & CBAUD) 14189fe8074b82ed14358be50c62ab9d081bcb911607Joe Perches info->serial_signals |= SerialSignal_RTS | SerialSignal_DTR; 14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 14209fe8074b82ed14358be50c62ab9d081bcb911607Joe Perches info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR); 1421d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* byte size and parity */ 1423d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cflag & CSIZE) { 14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CS5: info->params.data_bits = 5; break; 14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CS6: info->params.data_bits = 6; break; 14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CS7: info->params.data_bits = 7; break; 14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CS8: info->params.data_bits = 8; break; 14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: info->params.data_bits = 7; break; 14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1431d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cflag & CSTOPB) 14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->params.stop_bits = 2; 14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->params.stop_bits = 1; 14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->params.parity = ASYNC_PARITY_NONE; 14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cflag & PARENB) { 14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cflag & PARODD) 14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->params.parity = ASYNC_PARITY_ODD; 14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->params.parity = ASYNC_PARITY_EVEN; 14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CMSPAR 14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cflag & CMSPAR) 14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->params.parity = ASYNC_PARITY_SPACE; 14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* calculate number of jiffies to transmit a full 14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * FIFO (32 bytes) at specified data rate 14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1452d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik bits_per_char = info->params.data_bits + 14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->params.stop_bits + 1; 14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if port data rate is set to 460800 or less then 14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * allow tty settings to override, otherwise keep the 14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * current data rate. 14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.data_rate <= 460800) { 1460eeb4613436f0f19a38f667ea3078821040559c68Alan Cox info->params.data_rate = tty_get_baud_rate(tty); 14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1462d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 14633d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov if (info->params.data_rate) { 1464d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik info->timeout = (32*HZ*bits_per_char) / 14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->params.data_rate; 14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->timeout += HZ/50; /* Add .02 seconds of slop */ 14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cflag & CRTSCTS) 1470eeb4613436f0f19a38f667ea3078821040559c68Alan Cox info->port.flags |= ASYNC_CTS_FLOW; 14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 1472eeb4613436f0f19a38f667ea3078821040559c68Alan Cox info->port.flags &= ~ASYNC_CTS_FLOW; 1473d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cflag & CLOCAL) 1475eeb4613436f0f19a38f667ea3078821040559c68Alan Cox info->port.flags &= ~ASYNC_CHECK_CD; 14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 1477eeb4613436f0f19a38f667ea3078821040559c68Alan Cox info->port.flags |= ASYNC_CHECK_CD; 14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* process tty input control flags */ 1480d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->read_status_mask = 0; 1482eeb4613436f0f19a38f667ea3078821040559c68Alan Cox if (I_INPCK(tty)) 14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->read_status_mask |= BIT7 | BIT6; 1484eeb4613436f0f19a38f667ea3078821040559c68Alan Cox if (I_IGNPAR(tty)) 14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->ignore_status_mask |= BIT7 | BIT6; 14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1487eeb4613436f0f19a38f667ea3078821040559c68Alan Cox mgslpc_program_hw(info, tty); 14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Add a character to the transmit buffer 14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1492d7e752e2757fba49178f4b1af4778ca64d305cbbAlan Coxstatic int mgslpc_put_char(struct tty_struct *tty, unsigned char ch) 14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; 14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) { 14983d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov printk("%s(%d):mgslpc_put_char(%d) on %s\n", 14993d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov __FILE__, __LINE__, ch, info->device_name); 15001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mgslpc_paranoia_check(info, tty->name, "mgslpc_put_char")) 1503d7e752e2757fba49178f4b1af4778ca64d305cbbAlan Cox return 0; 15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1505326f28e9ec4b2619c2fd410593fc95fcb0ba6b41Eric Sesterhenn if (!info->tx_buf) 1506d7e752e2757fba49178f4b1af4778ca64d305cbbAlan Cox return 0; 15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15083d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_lock_irqsave(&info->lock, flags); 1509d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.mode == MGSL_MODE_ASYNC || !info->tx_active) { 15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->tx_count < TXBUFSIZE - 1) { 15121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_buf[info->tx_put++] = ch; 15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_put &= TXBUFSIZE-1; 15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_count++; 15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1517d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 15183d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_unlock_irqrestore(&info->lock, flags); 1519d7e752e2757fba49178f4b1af4778ca64d305cbbAlan Cox return 1; 15201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Enable transmitter so remaining characters in the 15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * transmit buffer are sent. 15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mgslpc_flush_chars(struct tty_struct *tty) 15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; 15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1529d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 15313d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov printk("%s(%d):mgslpc_flush_chars() entry on %s tx_count=%d\n", 15323d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov __FILE__, __LINE__, info->device_name, info->tx_count); 1533d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mgslpc_paranoia_check(info, tty->name, "mgslpc_flush_chars")) 15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->tx_count <= 0 || tty->stopped || 15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty->hw_stopped || !info->tx_buf) 15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 15423d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov printk("%s(%d):mgslpc_flush_chars() entry on %s starting transmitter\n", 15433d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov __FILE__, __LINE__, info->device_name); 15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15453d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_lock_irqsave(&info->lock, flags); 15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info->tx_active) 15473d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov tx_start(info, tty); 15483d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_unlock_irqrestore(&info->lock, flags); 15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Send a block of data 1552d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik * 15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Arguments: 1554d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik * 15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * tty pointer to tty information structure 15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * buf pointer to buffer containing send data 15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * count size of send data in bytes 1558d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik * 15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns: number of characters written 15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mgslpc_write(struct tty_struct * tty, 15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const unsigned char *buf, int count) 15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int c, ret = 0; 15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; 15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1567d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 15693d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov printk("%s(%d):mgslpc_write(%s) count=%d\n", 15703d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov __FILE__, __LINE__, info->device_name, count); 1571d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 15721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mgslpc_paranoia_check(info, tty->name, "mgslpc_write") || 1573326f28e9ec4b2619c2fd410593fc95fcb0ba6b41Eric Sesterhenn !info->tx_buf) 15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.mode == MGSL_MODE_HDLC) { 15771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (count > TXBUFSIZE) { 15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EIO; 15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->tx_active) 15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (info->tx_count) 15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto start; 15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (;;) { 15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds c = min(count, 15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds min(TXBUFSIZE - info->tx_count - 1, 15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds TXBUFSIZE - info->tx_put)); 15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (c <= 0) 15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1593d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 15941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(info->tx_buf + info->tx_put, buf, c); 15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15963d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_lock_irqsave(&info->lock, flags); 15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_put = (info->tx_put + c) & (TXBUFSIZE-1); 15981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_count += c; 15993d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_unlock_irqrestore(&info->lock, flags); 16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf += c; 16021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count -= c; 16031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret += c; 16041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstart: 16063d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov if (info->tx_count && !tty->stopped && !tty->hw_stopped) { 16073d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_lock_irqsave(&info->lock, flags); 16081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info->tx_active) 16093d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov tx_start(info, tty); 16103d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_unlock_irqrestore(&info->lock, flags); 16113d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov } 1612d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzikcleanup: 16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 16143d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov printk("%s(%d):mgslpc_write(%s) returning=%d\n", 16153d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov __FILE__, __LINE__, info->device_name, ret); 16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Return the count of free bytes in transmit buffer 16201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mgslpc_write_room(struct tty_struct *tty) 16221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; 16241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 1625d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mgslpc_paranoia_check(info, tty->name, "mgslpc_write_room")) 16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 16281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.mode == MGSL_MODE_HDLC) { 16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* HDLC (frame oriented) mode */ 16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->tx_active) 16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return HDLC_MAX_FRAME_SIZE; 16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = TXBUFSIZE - info->tx_count - 1; 16371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret < 0) 16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = 0; 16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1640d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):mgslpc_write_room(%s)=%d\n", 16433d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov __FILE__, __LINE__, info->device_name, ret); 16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Return the count of bytes in transmit buffer 16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mgslpc_chars_in_buffer(struct tty_struct *tty) 16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; 16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 1653d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 16551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):mgslpc_chars_in_buffer(%s)\n", 16563d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov __FILE__, __LINE__, info->device_name); 1657d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 16581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mgslpc_paranoia_check(info, tty->name, "mgslpc_chars_in_buffer")) 16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1660d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.mode == MGSL_MODE_HDLC) 16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = info->tx_active ? info->max_frame_size : 0; 16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = info->tx_count; 16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):mgslpc_chars_in_buffer(%s)=%d\n", 16683d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov __FILE__, __LINE__, info->device_name, rc); 1669d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Discard all data in the send buffer 16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mgslpc_flush_buffer(struct tty_struct *tty) 16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; 16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1679d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 16801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):mgslpc_flush_buffer(%s) entry\n", 16823d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov __FILE__, __LINE__, info->device_name); 1683d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mgslpc_paranoia_check(info, tty->name, "mgslpc_flush_buffer")) 16851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 1686d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 16873d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_lock_irqsave(&info->lock, flags); 16881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_count = info->tx_put = info->tx_get = 0; 1689d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik del_timer(&info->tx_timer); 16903d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_unlock_irqrestore(&info->lock, flags); 16911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up_interruptible(&tty->write_wait); 16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_wakeup(tty); 16941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Send a high-priority XON/XOFF character 16971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mgslpc_send_xchar(struct tty_struct *tty, char ch) 16991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; 17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):mgslpc_send_xchar(%s,%d)\n", 17053d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov __FILE__, __LINE__, info->device_name, ch); 1706d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 17071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mgslpc_paranoia_check(info, tty->name, "mgslpc_send_xchar")) 17081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->x_char = ch; 17111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ch) { 17123d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_lock_irqsave(&info->lock, flags); 17131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info->tx_enabled) 17143d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov tx_start(info, tty); 17153d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_unlock_irqrestore(&info->lock, flags); 17161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Signal remote device to throttle send data (our receive data) 17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 17211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mgslpc_throttle(struct tty_struct * tty) 17221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; 17241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1725d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 17261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 17271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):mgslpc_throttle(%s) entry\n", 17283d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov __FILE__, __LINE__, info->device_name); 17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mgslpc_paranoia_check(info, tty->name, "mgslpc_throttle")) 17311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 1732d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 17331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (I_IXOFF(tty)) 17341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_send_xchar(tty, STOP_CHAR(tty)); 1735d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 17363d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov if (tty->termios.c_cflag & CRTSCTS) { 17373d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_lock_irqsave(&info->lock, flags); 17381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->serial_signals &= ~SerialSignal_RTS; 17393d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov set_signals(info); 17403d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_unlock_irqrestore(&info->lock, flags); 17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Signal remote device to stop throttling send data (our receive data) 17451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 17461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mgslpc_unthrottle(struct tty_struct * tty) 17471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; 17491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1750d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 17511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 17521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):mgslpc_unthrottle(%s) entry\n", 17533d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov __FILE__, __LINE__, info->device_name); 17541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mgslpc_paranoia_check(info, tty->name, "mgslpc_unthrottle")) 17561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 1757d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 17581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (I_IXOFF(tty)) { 17591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->x_char) 17601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->x_char = 0; 17611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 17621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_send_xchar(tty, START_CHAR(tty)); 17631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1764d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 17653d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov if (tty->termios.c_cflag & CRTSCTS) { 17663d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_lock_irqsave(&info->lock, flags); 17671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->serial_signals |= SerialSignal_RTS; 17683d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov set_signals(info); 17693d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_unlock_irqrestore(&info->lock, flags); 17701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* get the current serial statistics 17741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 17751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int get_stats(MGSLPC_INFO * info, struct mgsl_icount __user *user_icount) 17761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 17781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 17791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("get_params(%s)\n", info->device_name); 1780a7482a2e7775d163aecd8c95af7bb1b8c83890ccPaul Fulghum if (!user_icount) { 1781a7482a2e7775d163aecd8c95af7bb1b8c83890ccPaul Fulghum memset(&info->icount, 0, sizeof(info->icount)); 1782a7482a2e7775d163aecd8c95af7bb1b8c83890ccPaul Fulghum } else { 1783a7482a2e7775d163aecd8c95af7bb1b8c83890ccPaul Fulghum COPY_TO_USER(err, user_icount, &info->icount, sizeof(struct mgsl_icount)); 1784a7482a2e7775d163aecd8c95af7bb1b8c83890ccPaul Fulghum if (err) 1785a7482a2e7775d163aecd8c95af7bb1b8c83890ccPaul Fulghum return -EFAULT; 1786a7482a2e7775d163aecd8c95af7bb1b8c83890ccPaul Fulghum } 17871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* get the current serial parameters 17911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 17921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int get_params(MGSLPC_INFO * info, MGSL_PARAMS __user *user_params) 17931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 17951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 17961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("get_params(%s)\n", info->device_name); 17971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds COPY_TO_USER(err,user_params, &info->params, sizeof(MGSL_PARAMS)); 17981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 17991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 18001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 18011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* set the serial parameters 1804d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik * 18051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Arguments: 1806d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik * 18073d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov * info pointer to device instance data 18083d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov * new_params user buffer containing new serial params 18091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 18101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns: 0 if success, otherwise error code 18111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1812eeb4613436f0f19a38f667ea3078821040559c68Alan Coxstatic int set_params(MGSLPC_INFO * info, MGSL_PARAMS __user *new_params, struct tty_struct *tty) 18131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 18143d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov unsigned long flags; 18151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSL_PARAMS tmp_params; 18161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 1817d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 18181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 18191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):set_params %s\n", __FILE__,__LINE__, 18203d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov info->device_name); 18211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds COPY_FROM_USER(err,&tmp_params, new_params, sizeof(MGSL_PARAMS)); 18221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) { 18233d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov if (debug_level >= DEBUG_LEVEL_INFO) 18243d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov printk("%s(%d):set_params(%s) user buffer copy failed\n", 18253d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov __FILE__, __LINE__, info->device_name); 18261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 18271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1828d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 18293d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_lock_irqsave(&info->lock, flags); 18301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(&info->params,&tmp_params,sizeof(MGSL_PARAMS)); 18313d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_unlock_irqrestore(&info->lock, flags); 1832d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 18333d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov mgslpc_change_params(info, tty); 1834d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 18351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 18361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int get_txidle(MGSLPC_INFO * info, int __user *idle_mode) 18391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 18401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 18411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 18421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("get_txidle(%s)=%d\n", info->device_name, info->idle_mode); 18431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds COPY_TO_USER(err,idle_mode, &info->idle_mode, sizeof(int)); 18441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 18451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 18461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 18471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int set_txidle(MGSLPC_INFO * info, int idle_mode) 18501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 18513d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov unsigned long flags; 18521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 18531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("set_txidle(%s,%d)\n", info->device_name, idle_mode); 18543d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_lock_irqsave(&info->lock, flags); 18551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->idle_mode = idle_mode; 18561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_set_idle(info); 18573d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_unlock_irqrestore(&info->lock, flags); 18581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 18591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int get_interface(MGSLPC_INFO * info, int __user *if_mode) 18621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 18631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 18641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 18651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("get_interface(%s)=%d\n", info->device_name, info->if_mode); 18661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds COPY_TO_USER(err,if_mode, &info->if_mode, sizeof(int)); 18671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 18681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 18691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 18701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int set_interface(MGSLPC_INFO * info, int if_mode) 18731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 18743d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov unsigned long flags; 18751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char val; 18761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 18771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("set_interface(%s,%d)\n", info->device_name, if_mode); 18783d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_lock_irqsave(&info->lock, flags); 18791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->if_mode = if_mode; 18801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = read_reg(info, PVR) & 0x0f; 18821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (info->if_mode) 18831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 18841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MGSL_INTERFACE_RS232: val |= PVR_RS232; break; 18851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MGSL_INTERFACE_V35: val |= PVR_V35; break; 18861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MGSL_INTERFACE_RS422: val |= PVR_RS422; break; 18871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, PVR, val); 18891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18903d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_unlock_irqrestore(&info->lock, flags); 18911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 18921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1894eeb4613436f0f19a38f667ea3078821040559c68Alan Coxstatic int set_txenable(MGSLPC_INFO * info, int enable, struct tty_struct *tty) 18951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 18963d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov unsigned long flags; 1897d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 18981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 18991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("set_txenable(%s,%d)\n", info->device_name, enable); 1900d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 19013d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_lock_irqsave(&info->lock, flags); 19021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (enable) { 19031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info->tx_enabled) 1904eeb4613436f0f19a38f667ea3078821040559c68Alan Cox tx_start(info, tty); 19051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 19061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->tx_enabled) 19071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_stop(info); 19081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19093d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_unlock_irqrestore(&info->lock, flags); 19101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 19111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 19121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tx_abort(MGSLPC_INFO * info) 19141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 19153d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov unsigned long flags; 1916d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 19171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 19181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("tx_abort(%s)\n", info->device_name); 1919d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 19203d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_lock_irqsave(&info->lock, flags); 19211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->tx_active && info->tx_count && 19221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->params.mode == MGSL_MODE_HDLC) { 19231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* clear data count so FIFO is not filled on next IRQ. 19241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This results in underrun and abort transmission. 19251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 19261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_count = info->tx_put = info->tx_get = 0; 19270fab6de09c71a976e5d765e1ff548b14be385153Joe Perches info->tx_aborting = true; 19281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19293d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_unlock_irqrestore(&info->lock, flags); 19301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 19311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 19321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int set_rxenable(MGSLPC_INFO * info, int enable) 19341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 19353d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov unsigned long flags; 1936d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 19371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 19381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("set_rxenable(%s,%d)\n", info->device_name, enable); 1939d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 19403d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_lock_irqsave(&info->lock, flags); 19411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (enable) { 19421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info->rx_enabled) 19431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_start(info); 19441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 19451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->rx_enabled) 19461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_stop(info); 19471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19483d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_unlock_irqrestore(&info->lock, flags); 19491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 19501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 19511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* wait for specified event to occur 1953d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik * 19543d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov * Arguments: info pointer to device instance data 19553d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov * mask pointer to bitmask of events to wait for 19563d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov * Return Value: 0 if successful and bit mask updated with 19571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of events triggerred, 19583d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov * otherwise error code 19591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 19601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int wait_events(MGSLPC_INFO * info, int __user *mask_ptr) 19611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 19623d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov unsigned long flags; 19631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int s; 19641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc=0; 19651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mgsl_icount cprev, cnow; 19661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int events; 19671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int mask; 19681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct _input_signal_events oldsigs, newsigs; 19691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DECLARE_WAITQUEUE(wait, current); 19701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds COPY_FROM_USER(rc,&mask, mask_ptr, sizeof(int)); 19721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc) 19731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 1974d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 19751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 19761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("wait_events(%s,%d)\n", info->device_name, mask); 19771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19783d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_lock_irqsave(&info->lock, flags); 19791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* return immediately if state matches requested events */ 19811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds get_signals(info); 19821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s = info->serial_signals; 19831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds events = mask & 19841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ( ((s & SerialSignal_DSR) ? MgslEvent_DsrActive:MgslEvent_DsrInactive) + 19853d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov ((s & SerialSignal_DCD) ? MgslEvent_DcdActive:MgslEvent_DcdInactive) + 19861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((s & SerialSignal_CTS) ? MgslEvent_CtsActive:MgslEvent_CtsInactive) + 19871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((s & SerialSignal_RI) ? MgslEvent_RiActive :MgslEvent_RiInactive) ); 19881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (events) { 19893d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_unlock_irqrestore(&info->lock, flags); 19901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 19911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* save current irq counts */ 19941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cprev = info->icount; 19951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds oldsigs = info->input_signal_events; 1996d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 19971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((info->params.mode == MGSL_MODE_HDLC) && 19981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (mask & MgslEvent_ExitHuntMode)) 19991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq_enable(info, CHA, IRQ_EXITHUNT); 2000d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 20011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_current_state(TASK_INTERRUPTIBLE); 20021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds add_wait_queue(&info->event_wait_q, &wait); 2003d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 20043d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_unlock_irqrestore(&info->lock, flags); 2005d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 2006d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 20071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for(;;) { 20081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds schedule(); 20091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (signal_pending(current)) { 20101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -ERESTARTSYS; 20111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 20121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2013d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 20141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* get current irq counts */ 20153d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_lock_irqsave(&info->lock, flags); 20161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cnow = info->icount; 20171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newsigs = info->input_signal_events; 20181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_current_state(TASK_INTERRUPTIBLE); 20193d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_unlock_irqrestore(&info->lock, flags); 20201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if no change, wait aborted for some reason */ 20221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (newsigs.dsr_up == oldsigs.dsr_up && 20231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newsigs.dsr_down == oldsigs.dsr_down && 20241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newsigs.dcd_up == oldsigs.dcd_up && 20251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newsigs.dcd_down == oldsigs.dcd_down && 20261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newsigs.cts_up == oldsigs.cts_up && 20271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newsigs.cts_down == oldsigs.cts_down && 20281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newsigs.ri_up == oldsigs.ri_up && 20291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newsigs.ri_down == oldsigs.ri_down && 20301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cnow.exithunt == cprev.exithunt && 20311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cnow.rxidle == cprev.rxidle) { 20321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EIO; 20331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 20341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds events = mask & 20371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ( (newsigs.dsr_up != oldsigs.dsr_up ? MgslEvent_DsrActive:0) + 20381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (newsigs.dsr_down != oldsigs.dsr_down ? MgslEvent_DsrInactive:0) + 20391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (newsigs.dcd_up != oldsigs.dcd_up ? MgslEvent_DcdActive:0) + 20401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (newsigs.dcd_down != oldsigs.dcd_down ? MgslEvent_DcdInactive:0) + 20411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (newsigs.cts_up != oldsigs.cts_up ? MgslEvent_CtsActive:0) + 20421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (newsigs.cts_down != oldsigs.cts_down ? MgslEvent_CtsInactive:0) + 20431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (newsigs.ri_up != oldsigs.ri_up ? MgslEvent_RiActive:0) + 20441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (newsigs.ri_down != oldsigs.ri_down ? MgslEvent_RiInactive:0) + 20451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (cnow.exithunt != cprev.exithunt ? MgslEvent_ExitHuntMode:0) + 20461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (cnow.rxidle != cprev.rxidle ? MgslEvent_IdleReceived:0) ); 20471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (events) 20481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2049d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 20501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cprev = cnow; 20511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds oldsigs = newsigs; 20521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2053d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 20541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds remove_wait_queue(&info->event_wait_q, &wait); 20551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_current_state(TASK_RUNNING); 20561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mask & MgslEvent_ExitHuntMode) { 20583d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_lock_irqsave(&info->lock, flags); 20591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!waitqueue_active(&info->event_wait_q)) 20601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq_disable(info, CHA, IRQ_EXITHUNT); 20613d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_unlock_irqrestore(&info->lock, flags); 20621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit: 20641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc == 0) 20651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PUT_USER(rc, events, mask_ptr); 20661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 20671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 20681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int modem_input_wait(MGSLPC_INFO *info,int arg) 20701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 20713d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov unsigned long flags; 20721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 20731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mgsl_icount cprev, cnow; 20741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DECLARE_WAITQUEUE(wait, current); 20751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* save current irq counts */ 20773d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_lock_irqsave(&info->lock, flags); 20781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cprev = info->icount; 20791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds add_wait_queue(&info->status_event_wait_q, &wait); 20801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_current_state(TASK_INTERRUPTIBLE); 20813d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_unlock_irqrestore(&info->lock, flags); 20821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for(;;) { 20841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds schedule(); 20851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (signal_pending(current)) { 20861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -ERESTARTSYS; 20871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 20881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* get new irq counts */ 20913d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_lock_irqsave(&info->lock, flags); 20921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cnow = info->icount; 20931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_current_state(TASK_INTERRUPTIBLE); 20943d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_unlock_irqrestore(&info->lock, flags); 20951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if no change, wait aborted for some reason */ 20971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && 20981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) { 20991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EIO; 21001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 21011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* check for change in caller specified modem input */ 21041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((arg & TIOCM_RNG && cnow.rng != cprev.rng) || 21051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (arg & TIOCM_DSR && cnow.dsr != cprev.dsr) || 21061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (arg & TIOCM_CD && cnow.dcd != cprev.dcd) || 21071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (arg & TIOCM_CTS && cnow.cts != cprev.cts)) { 21081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = 0; 21091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 21101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cprev = cnow; 21131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds remove_wait_queue(&info->status_event_wait_q, &wait); 21151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_current_state(TASK_RUNNING); 21161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 21171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 21181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* return the state of the serial control and status signals 21201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 212160b33c133ca0b7c0b6072c87234b63fee6e80558Alan Coxstatic int tiocmget(struct tty_struct *tty) 21221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 21231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; 21241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int result; 21253d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov unsigned long flags; 21261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21273d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_lock_irqsave(&info->lock, flags); 21283d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov get_signals(info); 21293d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_unlock_irqrestore(&info->lock, flags); 21301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = ((info->serial_signals & SerialSignal_RTS) ? TIOCM_RTS:0) + 21321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((info->serial_signals & SerialSignal_DTR) ? TIOCM_DTR:0) + 21331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((info->serial_signals & SerialSignal_DCD) ? TIOCM_CAR:0) + 21341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((info->serial_signals & SerialSignal_RI) ? TIOCM_RNG:0) + 21351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((info->serial_signals & SerialSignal_DSR) ? TIOCM_DSR:0) + 21361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((info->serial_signals & SerialSignal_CTS) ? TIOCM_CTS:0); 21371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 21391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):%s tiocmget() value=%08X\n", 21403d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov __FILE__, __LINE__, info->device_name, result); 21411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return result; 21421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 21431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* set modem control signals (DTR/RTS) 21451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 214620b9d17715017ae4dd4ec87fabc36d33b9de708eAlan Coxstatic int tiocmset(struct tty_struct *tty, 21471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int set, unsigned int clear) 21481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 21491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; 21503d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov unsigned long flags; 21511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 21531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):%s tiocmset(%x,%x)\n", 21543d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov __FILE__, __LINE__, info->device_name, set, clear); 21551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (set & TIOCM_RTS) 21571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->serial_signals |= SerialSignal_RTS; 21581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (set & TIOCM_DTR) 21591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->serial_signals |= SerialSignal_DTR; 21601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clear & TIOCM_RTS) 21611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->serial_signals &= ~SerialSignal_RTS; 21621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clear & TIOCM_DTR) 21631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->serial_signals &= ~SerialSignal_DTR; 21641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21653d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_lock_irqsave(&info->lock, flags); 21663d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov set_signals(info); 21673d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_unlock_irqrestore(&info->lock, flags); 21681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 21701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 21711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Set or clear transmit break condition 21731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 21741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Arguments: tty pointer to tty instance data 21751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * break_state -1=set break condition, 0=clear 21761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 21779e98966c7bb94355689478bc84cc3e0c190f977eAlan Coxstatic int mgslpc_break(struct tty_struct *tty, int break_state) 21781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 21791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data; 21801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 2181d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 21821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 21831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):mgslpc_break(%s,%d)\n", 21843d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov __FILE__, __LINE__, info->device_name, break_state); 2185d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 21861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mgslpc_paranoia_check(info, tty->name, "mgslpc_break")) 21879e98966c7bb94355689478bc84cc3e0c190f977eAlan Cox return -EINVAL; 21881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21893d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_lock_irqsave(&info->lock, flags); 21903d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov if (break_state == -1) 21911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_reg_bits(info, CHA+DAFO, BIT6); 2192d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik else 21931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_reg_bits(info, CHA+DAFO, BIT6); 21943d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_unlock_irqrestore(&info->lock, flags); 21959e98966c7bb94355689478bc84cc3e0c190f977eAlan Cox return 0; 21961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 21971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21980587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Coxstatic int mgslpc_get_icount(struct tty_struct *tty, 21990587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox struct serial_icounter_struct *icount) 22000587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox{ 22010587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data; 22020587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox struct mgsl_icount cnow; /* kernel counter temps */ 22030587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox unsigned long flags; 22040587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox 22053d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_lock_irqsave(&info->lock, flags); 22060587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox cnow = info->icount; 22073d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_unlock_irqrestore(&info->lock, flags); 22080587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox 22090587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->cts = cnow.cts; 22100587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->dsr = cnow.dsr; 22110587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->rng = cnow.rng; 22120587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->dcd = cnow.dcd; 22130587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->rx = cnow.rx; 22140587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->tx = cnow.tx; 22150587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->frame = cnow.frame; 22160587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->overrun = cnow.overrun; 22170587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->parity = cnow.parity; 22180587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->brk = cnow.brk; 22190587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox icount->buf_overrun = cnow.buf_overrun; 22200587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox 22210587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox return 0; 22220587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox} 22230587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox 22241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Service an IOCTL request 2225d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik * 22261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Arguments: 2227d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik * 22283d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov * tty pointer to tty instance data 22293d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov * cmd IOCTL command code 22303d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov * arg command argument/context 2231d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik * 22321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Return Value: 0 if success, otherwise error code 22331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2234751b3840d216f1ecd3b91ff5251bf7703b690cd8Axel Linstatic int mgslpc_ioctl(struct tty_struct *tty, 22351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int cmd, unsigned long arg) 22361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 22371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data; 2238eeb4613436f0f19a38f667ea3078821040559c68Alan Cox void __user *argp = (void __user *)arg; 2239d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 22401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 22413d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov printk("%s(%d):mgslpc_ioctl %s cmd=%08X\n", __FILE__, __LINE__, 22423d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov info->device_name, cmd); 2243d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 22441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mgslpc_paranoia_check(info, tty->name, "mgslpc_ioctl")) 22451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 22461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && 22480587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox (cmd != TIOCMIWAIT)) { 22491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tty->flags & (1 << TTY_IO_ERROR)) 22501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 22511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) { 22541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MGSL_IOCGPARAMS: 22551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return get_params(info, argp); 22561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MGSL_IOCSPARAMS: 2257eeb4613436f0f19a38f667ea3078821040559c68Alan Cox return set_params(info, argp, tty); 22581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MGSL_IOCGTXIDLE: 22591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return get_txidle(info, argp); 22601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MGSL_IOCSTXIDLE: 22611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return set_txidle(info, (int)arg); 22621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MGSL_IOCGIF: 22631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return get_interface(info, argp); 22641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MGSL_IOCSIF: 22651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return set_interface(info,(int)arg); 22661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MGSL_IOCTXENABLE: 2267eeb4613436f0f19a38f667ea3078821040559c68Alan Cox return set_txenable(info,(int)arg, tty); 22681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MGSL_IOCRXENABLE: 22691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return set_rxenable(info,(int)arg); 22701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MGSL_IOCTXABORT: 22711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return tx_abort(info); 22721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MGSL_IOCGSTATS: 22731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return get_stats(info, argp); 22741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MGSL_IOCWAITEVENT: 22751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return wait_events(info, argp); 22761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case TIOCMIWAIT: 22771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return modem_input_wait(info,(int)arg); 22781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 22791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOIOCTLCMD; 22801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 22821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 22831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Set new termios settings 2285d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik * 22861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Arguments: 2287d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik * 22883d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov * tty pointer to tty structure 22893d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov * termios pointer to buffer to hold returned old termios 22901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2291606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Coxstatic void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_termios) 22921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 22931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; 22941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 2295d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 22961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 22973d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov printk("%s(%d):mgslpc_set_termios %s\n", __FILE__, __LINE__, 22983d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov tty->driver->name); 2299d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 23001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* just return if nothing has changed */ 2301373f5aedbc6fb73d30f00eeb0dc7313ecfede908Alan Cox if ((tty->termios.c_cflag == old_termios->c_cflag) 2302373f5aedbc6fb73d30f00eeb0dc7313ecfede908Alan Cox && (RELEVANT_IFLAG(tty->termios.c_iflag) 23031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds == RELEVANT_IFLAG(old_termios->c_iflag))) 23041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 23051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2306eeb4613436f0f19a38f667ea3078821040559c68Alan Cox mgslpc_change_params(info, tty); 23071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Handle transition to B0 status */ 23091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (old_termios->c_cflag & CBAUD && 2310373f5aedbc6fb73d30f00eeb0dc7313ecfede908Alan Cox !(tty->termios.c_cflag & CBAUD)) { 23119fe8074b82ed14358be50c62ab9d081bcb911607Joe Perches info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR); 23123d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_lock_irqsave(&info->lock, flags); 23133d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov set_signals(info); 23143d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_unlock_irqrestore(&info->lock, flags); 23151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2316d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 23171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Handle transition away from B0 status */ 23181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(old_termios->c_cflag & CBAUD) && 2319373f5aedbc6fb73d30f00eeb0dc7313ecfede908Alan Cox tty->termios.c_cflag & CBAUD) { 23201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->serial_signals |= SerialSignal_DTR; 23213d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov if (!(tty->termios.c_cflag & CRTSCTS) || 23223d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov !test_bit(TTY_THROTTLED, &tty->flags)) { 23231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->serial_signals |= SerialSignal_RTS; 23243d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov } 23253d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_lock_irqsave(&info->lock, flags); 23263d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov set_signals(info); 23273d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_unlock_irqrestore(&info->lock, flags); 23281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2329d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 23301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Handle turning off CRTSCTS */ 23311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (old_termios->c_cflag & CRTSCTS && 2332373f5aedbc6fb73d30f00eeb0dc7313ecfede908Alan Cox !(tty->termios.c_cflag & CRTSCTS)) { 23331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty->hw_stopped = 0; 23341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_release(tty); 23351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 23371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mgslpc_close(struct tty_struct *tty, struct file * filp) 23391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 23401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data; 2341eeb4613436f0f19a38f667ea3078821040559c68Alan Cox struct tty_port *port = &info->port; 23421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mgslpc_paranoia_check(info, tty->name, "mgslpc_close")) 23441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 2345d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 23461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 23471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):mgslpc_close(%s) entry, count=%d\n", 23483d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov __FILE__, __LINE__, info->device_name, port->count); 23491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2350eeb4613436f0f19a38f667ea3078821040559c68Alan Cox if (tty_port_close_start(port, tty, filp) == 0) 23511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 2352d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 23533d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov if (port->flags & ASYNC_INITIALIZED) 23543d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov mgslpc_wait_until_sent(tty, info->timeout); 23551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2356978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox mgslpc_flush_buffer(tty); 23571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2358978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox tty_ldisc_flush(tty); 2359eeb4613436f0f19a38f667ea3078821040559c68Alan Cox shutdown(info, tty); 2360eeb4613436f0f19a38f667ea3078821040559c68Alan Cox 2361eeb4613436f0f19a38f667ea3078821040559c68Alan Cox tty_port_close_end(port, tty); 2362eeb4613436f0f19a38f667ea3078821040559c68Alan Cox tty_port_tty_set(port, NULL); 2363d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzikcleanup: 23641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 23653d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov printk("%s(%d):mgslpc_close(%s) exit, count=%d\n", __FILE__, __LINE__, 2366eeb4613436f0f19a38f667ea3078821040559c68Alan Cox tty->driver->name, port->count); 23671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 23681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Wait until the transmitter is empty. 23701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 23711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mgslpc_wait_until_sent(struct tty_struct *tty, int timeout) 23721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 23731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data; 23741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long orig_jiffies, char_time; 23751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23763d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov if (!info) 23771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 23781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 23801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):mgslpc_wait_until_sent(%s) entry\n", 23813d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov __FILE__, __LINE__, info->device_name); 2382d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 23831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mgslpc_paranoia_check(info, tty->name, "mgslpc_wait_until_sent")) 23841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 23851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2386eeb4613436f0f19a38f667ea3078821040559c68Alan Cox if (!(info->port.flags & ASYNC_INITIALIZED)) 23871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 2388d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 23891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds orig_jiffies = jiffies; 2390d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 23911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Set check interval to 1/5 of estimated time to 23921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * send a character, and make it at least 1. The check 23931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * interval should also be less than the timeout. 23941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note: use tight timings here to satisfy the NIST-PCTS. 2395d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik */ 2396d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 23973d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov if (info->params.data_rate) { 23983d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov char_time = info->timeout/(32 * 5); 23991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!char_time) 24001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char_time++; 24011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 24021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char_time = 1; 2403d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 24041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (timeout) 24051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char_time = min_t(unsigned long, char_time, timeout); 2406d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 24071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.mode == MGSL_MODE_HDLC) { 24081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (info->tx_active) { 24091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msleep_interruptible(jiffies_to_msecs(char_time)); 24101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (signal_pending(current)) 24111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 24121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (timeout && time_after(jiffies, orig_jiffies + timeout)) 24131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 24141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 24161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while ((info->tx_count || info->tx_active) && 24171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_enabled) { 24181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msleep_interruptible(jiffies_to_msecs(char_time)); 24191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (signal_pending(current)) 24201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 24211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (timeout && time_after(jiffies, orig_jiffies + timeout)) 24221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 24231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2425d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 24261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit: 24271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 24281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):mgslpc_wait_until_sent(%s) exit\n", 24293d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov __FILE__, __LINE__, info->device_name); 24301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 24311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Called by tty_hangup() when a hangup is signaled. 24331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is the same as closing all open files for the port. 24341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 24351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mgslpc_hangup(struct tty_struct *tty) 24361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 24371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data; 2438d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 24391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 24401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):mgslpc_hangup(%s)\n", 24413d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov __FILE__, __LINE__, info->device_name); 2442d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 24431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mgslpc_paranoia_check(info, tty->name, "mgslpc_hangup")) 24441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 24451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_flush_buffer(tty); 2447eeb4613436f0f19a38f667ea3078821040559c68Alan Cox shutdown(info, tty); 2448eeb4613436f0f19a38f667ea3078821040559c68Alan Cox tty_port_hangup(&info->port); 24491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 24501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2451eeb4613436f0f19a38f667ea3078821040559c68Alan Coxstatic int carrier_raised(struct tty_port *port) 24521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2453eeb4613436f0f19a38f667ea3078821040559c68Alan Cox MGSLPC_INFO *info = container_of(port, MGSLPC_INFO, port); 2454eeb4613436f0f19a38f667ea3078821040559c68Alan Cox unsigned long flags; 2455d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 24563d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_lock_irqsave(&info->lock, flags); 24573d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov get_signals(info); 24583d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_unlock_irqrestore(&info->lock, flags); 2459d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 2460eeb4613436f0f19a38f667ea3078821040559c68Alan Cox if (info->serial_signals & SerialSignal_DCD) 2461eeb4613436f0f19a38f667ea3078821040559c68Alan Cox return 1; 2462eeb4613436f0f19a38f667ea3078821040559c68Alan Cox return 0; 2463eeb4613436f0f19a38f667ea3078821040559c68Alan Cox} 2464d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 2465fcc8ac1825d3d0fb81f73bc1a80ebc863168bb56Alan Coxstatic void dtr_rts(struct tty_port *port, int onoff) 2466eeb4613436f0f19a38f667ea3078821040559c68Alan Cox{ 2467eeb4613436f0f19a38f667ea3078821040559c68Alan Cox MGSLPC_INFO *info = container_of(port, MGSLPC_INFO, port); 2468eeb4613436f0f19a38f667ea3078821040559c68Alan Cox unsigned long flags; 2469d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 24703d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_lock_irqsave(&info->lock, flags); 2471fcc8ac1825d3d0fb81f73bc1a80ebc863168bb56Alan Cox if (onoff) 24729fe8074b82ed14358be50c62ab9d081bcb911607Joe Perches info->serial_signals |= SerialSignal_RTS | SerialSignal_DTR; 2473fcc8ac1825d3d0fb81f73bc1a80ebc863168bb56Alan Cox else 24749fe8074b82ed14358be50c62ab9d081bcb911607Joe Perches info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR); 2475eeb4613436f0f19a38f667ea3078821040559c68Alan Cox set_signals(info); 24763d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_unlock_irqrestore(&info->lock, flags); 24771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 24781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2479eeb4613436f0f19a38f667ea3078821040559c68Alan Cox 24801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mgslpc_open(struct tty_struct *tty, struct file * filp) 24811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 24821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info; 2483eeb4613436f0f19a38f667ea3078821040559c68Alan Cox struct tty_port *port; 24843d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov int retval, line; 24853d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov unsigned long flags; 24861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2487d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik /* verify range of specified line number */ 24881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds line = tty->index; 2489410235fd4d20b8feaf8930a0575d23acc088aa87Jiri Slaby if (line >= mgslpc_device_count) { 24901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):mgslpc_open with invalid line #%d.\n", 24913d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov __FILE__, __LINE__, line); 24921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 24931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* find the info structure for the specified line */ 24961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info = mgslpc_device_list; 24971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while(info && info->line != line) 24981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info = info->next_device; 24991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mgslpc_paranoia_check(info, tty->name, "mgslpc_open")) 25001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 2501d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 2502eeb4613436f0f19a38f667ea3078821040559c68Alan Cox port = &info->port; 25031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty->driver_data = info; 2504eeb4613436f0f19a38f667ea3078821040559c68Alan Cox tty_port_tty_set(port, tty); 2505d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 25061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 25071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):mgslpc_open(%s), old ref count = %d\n", 25083d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov __FILE__, __LINE__, tty->driver->name, port->count); 25091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If port is closing, signal caller to try again */ 2511e359a4e38d229d53e28905863a1fabf41debd591Peter Hurley if (port->flags & ASYNC_CLOSING){ 2512b8c98ae49e8d53344b1d62417eea05ebc3cdbd78Arnd Bergmann wait_event_interruptible_tty(tty, port->close_wait, 2513b8c98ae49e8d53344b1d62417eea05ebc3cdbd78Arnd Bergmann !(port->flags & ASYNC_CLOSING)); 2514eeb4613436f0f19a38f667ea3078821040559c68Alan Cox retval = ((port->flags & ASYNC_HUP_NOTIFY) ? 25151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds -EAGAIN : -ERESTARTSYS); 25161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 25171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2518d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 2519d6c53c0e9bd0a83f9f9ddbc9fd80141a54d83896Jiri Slaby port->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0; 25201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->netlock, flags); 25221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->netcount) { 25231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -EBUSY; 25241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->netlock, flags); 25251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 25261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2527eeb4613436f0f19a38f667ea3078821040559c68Alan Cox spin_lock(&port->lock); 2528eeb4613436f0f19a38f667ea3078821040559c68Alan Cox port->count++; 2529eeb4613436f0f19a38f667ea3078821040559c68Alan Cox spin_unlock(&port->lock); 25301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->netlock, flags); 25311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2532eeb4613436f0f19a38f667ea3078821040559c68Alan Cox if (port->count == 1) { 25331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1st open on this device, init hardware */ 2534eeb4613436f0f19a38f667ea3078821040559c68Alan Cox retval = startup(info, tty); 25351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval < 0) 25361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 25371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2539eeb4613436f0f19a38f667ea3078821040559c68Alan Cox retval = tty_port_block_til_ready(&info->port, tty, filp); 25401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) { 25411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 25421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):block_til_ready(%s) returned %d\n", 25433d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov __FILE__, __LINE__, info->device_name, retval); 25441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 25451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 25481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):mgslpc_open(%s) success\n", 25493d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov __FILE__, __LINE__, info->device_name); 25501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = 0; 2551d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 2552d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzikcleanup: 25531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 25541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 25551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 25571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * /proc fs routines.... 25581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 25591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 256087687144b4fce2ad083e689eec8b219054c292aeAlexey Dobriyanstatic inline void line_info(struct seq_file *m, MGSLPC_INFO *info) 25611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 25621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char stat_buf[30]; 25631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 25641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 256587687144b4fce2ad083e689eec8b219054c292aeAlexey Dobriyan seq_printf(m, "%s:io:%04X irq:%d", 25661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->device_name, info->io_base, info->irq_level); 25671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* output current serial signal states */ 25693d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_lock_irqsave(&info->lock, flags); 25703d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov get_signals(info); 25713d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_unlock_irqrestore(&info->lock, flags); 2572d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 25731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stat_buf[0] = 0; 25741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stat_buf[1] = 0; 25751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->serial_signals & SerialSignal_RTS) 25761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcat(stat_buf, "|RTS"); 25771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->serial_signals & SerialSignal_CTS) 25781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcat(stat_buf, "|CTS"); 25791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->serial_signals & SerialSignal_DTR) 25801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcat(stat_buf, "|DTR"); 25811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->serial_signals & SerialSignal_DSR) 25821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcat(stat_buf, "|DSR"); 25831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->serial_signals & SerialSignal_DCD) 25841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcat(stat_buf, "|CD"); 25851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->serial_signals & SerialSignal_RI) 25861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcat(stat_buf, "|RI"); 25871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.mode == MGSL_MODE_HDLC) { 258987687144b4fce2ad083e689eec8b219054c292aeAlexey Dobriyan seq_printf(m, " HDLC txok:%d rxok:%d", 25901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->icount.txok, info->icount.rxok); 25911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->icount.txunder) 259287687144b4fce2ad083e689eec8b219054c292aeAlexey Dobriyan seq_printf(m, " txunder:%d", info->icount.txunder); 25931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->icount.txabort) 259487687144b4fce2ad083e689eec8b219054c292aeAlexey Dobriyan seq_printf(m, " txabort:%d", info->icount.txabort); 25951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->icount.rxshort) 259687687144b4fce2ad083e689eec8b219054c292aeAlexey Dobriyan seq_printf(m, " rxshort:%d", info->icount.rxshort); 25971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->icount.rxlong) 259887687144b4fce2ad083e689eec8b219054c292aeAlexey Dobriyan seq_printf(m, " rxlong:%d", info->icount.rxlong); 25991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->icount.rxover) 260087687144b4fce2ad083e689eec8b219054c292aeAlexey Dobriyan seq_printf(m, " rxover:%d", info->icount.rxover); 26011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->icount.rxcrc) 260287687144b4fce2ad083e689eec8b219054c292aeAlexey Dobriyan seq_printf(m, " rxcrc:%d", info->icount.rxcrc); 26031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 260487687144b4fce2ad083e689eec8b219054c292aeAlexey Dobriyan seq_printf(m, " ASYNC tx:%d rx:%d", 26051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->icount.tx, info->icount.rx); 26061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->icount.frame) 260787687144b4fce2ad083e689eec8b219054c292aeAlexey Dobriyan seq_printf(m, " fe:%d", info->icount.frame); 26081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->icount.parity) 260987687144b4fce2ad083e689eec8b219054c292aeAlexey Dobriyan seq_printf(m, " pe:%d", info->icount.parity); 26101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->icount.brk) 261187687144b4fce2ad083e689eec8b219054c292aeAlexey Dobriyan seq_printf(m, " brk:%d", info->icount.brk); 26121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->icount.overrun) 261387687144b4fce2ad083e689eec8b219054c292aeAlexey Dobriyan seq_printf(m, " oe:%d", info->icount.overrun); 26141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2615d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 26161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Append serial signal status to end */ 261787687144b4fce2ad083e689eec8b219054c292aeAlexey Dobriyan seq_printf(m, " %s\n", stat_buf+1); 2618d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 261987687144b4fce2ad083e689eec8b219054c292aeAlexey Dobriyan seq_printf(m, "txactive=%d bh_req=%d bh_run=%d pending_bh=%x\n", 26201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_active,info->bh_requested,info->bh_running, 26211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->pending_bh); 26221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 26231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Called to print information about devices 26251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 262687687144b4fce2ad083e689eec8b219054c292aeAlexey Dobriyanstatic int mgslpc_proc_show(struct seq_file *m, void *v) 26271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 26281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info; 2629d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 263087687144b4fce2ad083e689eec8b219054c292aeAlexey Dobriyan seq_printf(m, "synclink driver:%s\n", driver_version); 2631d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 26321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info = mgslpc_device_list; 26333d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov while (info) { 263487687144b4fce2ad083e689eec8b219054c292aeAlexey Dobriyan line_info(m, info); 26351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info = info->next_device; 26361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 263787687144b4fce2ad083e689eec8b219054c292aeAlexey Dobriyan return 0; 263887687144b4fce2ad083e689eec8b219054c292aeAlexey Dobriyan} 26391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 264087687144b4fce2ad083e689eec8b219054c292aeAlexey Dobriyanstatic int mgslpc_proc_open(struct inode *inode, struct file *file) 264187687144b4fce2ad083e689eec8b219054c292aeAlexey Dobriyan{ 264287687144b4fce2ad083e689eec8b219054c292aeAlexey Dobriyan return single_open(file, mgslpc_proc_show, NULL); 26431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 26441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 264587687144b4fce2ad083e689eec8b219054c292aeAlexey Dobriyanstatic const struct file_operations mgslpc_proc_fops = { 264687687144b4fce2ad083e689eec8b219054c292aeAlexey Dobriyan .owner = THIS_MODULE, 264787687144b4fce2ad083e689eec8b219054c292aeAlexey Dobriyan .open = mgslpc_proc_open, 264887687144b4fce2ad083e689eec8b219054c292aeAlexey Dobriyan .read = seq_read, 264987687144b4fce2ad083e689eec8b219054c292aeAlexey Dobriyan .llseek = seq_lseek, 265087687144b4fce2ad083e689eec8b219054c292aeAlexey Dobriyan .release = single_release, 265187687144b4fce2ad083e689eec8b219054c292aeAlexey Dobriyan}; 265287687144b4fce2ad083e689eec8b219054c292aeAlexey Dobriyan 2653cdaad343b561cdeb38b0578bb038eb5e87ed5551Peter Hagervallstatic int rx_alloc_buffers(MGSLPC_INFO *info) 26541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 26551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* each buffer has header and data */ 26561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->rx_buf_size = sizeof(RXBUF) + info->max_frame_size; 26571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* calculate total allocation size for 8 buffers */ 26591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->rx_buf_total_size = info->rx_buf_size * 8; 26601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* limit total allocated memory */ 26621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->rx_buf_total_size > 0x10000) 26631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->rx_buf_total_size = 0x10000; 26641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* calculate number of buffers */ 26661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->rx_buf_count = info->rx_buf_total_size / info->rx_buf_size; 26671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->rx_buf = kmalloc(info->rx_buf_total_size, GFP_KERNEL); 26691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->rx_buf == NULL) 26701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 26711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2672a6b68a69fa89daeddc6ca6bb90b6f19a86ed7a9fPaul Fulghum /* unused flag buffer to satisfy receive_buf calling interface */ 2673a6b68a69fa89daeddc6ca6bb90b6f19a86ed7a9fPaul Fulghum info->flag_buf = kzalloc(info->max_frame_size, GFP_KERNEL); 2674a6b68a69fa89daeddc6ca6bb90b6f19a86ed7a9fPaul Fulghum if (!info->flag_buf) { 2675a6b68a69fa89daeddc6ca6bb90b6f19a86ed7a9fPaul Fulghum kfree(info->rx_buf); 2676a6b68a69fa89daeddc6ca6bb90b6f19a86ed7a9fPaul Fulghum info->rx_buf = NULL; 2677a6b68a69fa89daeddc6ca6bb90b6f19a86ed7a9fPaul Fulghum return -ENOMEM; 2678a6b68a69fa89daeddc6ca6bb90b6f19a86ed7a9fPaul Fulghum } 2679a6b68a69fa89daeddc6ca6bb90b6f19a86ed7a9fPaul Fulghum 26801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_reset_buffers(info); 26811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 26821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 26831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2684cdaad343b561cdeb38b0578bb038eb5e87ed5551Peter Hagervallstatic void rx_free_buffers(MGSLPC_INFO *info) 26851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2686735d5661d5c5f023a78fbe68e771e261040ff1b7Jesper Juhl kfree(info->rx_buf); 26871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->rx_buf = NULL; 2688a6b68a69fa89daeddc6ca6bb90b6f19a86ed7a9fPaul Fulghum kfree(info->flag_buf); 2689a6b68a69fa89daeddc6ca6bb90b6f19a86ed7a9fPaul Fulghum info->flag_buf = NULL; 26901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 26911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2692cdaad343b561cdeb38b0578bb038eb5e87ed5551Peter Hagervallstatic int claim_resources(MGSLPC_INFO *info) 26931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 26943d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov if (rx_alloc_buffers(info) < 0) { 26953d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov printk("Can't allocate rx buffer %s\n", info->device_name); 26961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_resources(info); 26971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 2698d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik } 26991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 27001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 27011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2702cdaad343b561cdeb38b0578bb038eb5e87ed5551Peter Hagervallstatic void release_resources(MGSLPC_INFO *info) 27031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 27041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 27051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("release_resources(%s)\n", info->device_name); 27061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_free_buffers(info); 27071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 27081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Add the specified device instance data structure to the 27101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * global linked list of devices and increment the device count. 2711d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik * 27121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Arguments: info pointer to device instance data 27131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2714d34138d057628211b1c835e13a64d0cc2423c969Alexey Khoroshilovstatic int mgslpc_add_device(MGSLPC_INFO *info) 27151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2716d34138d057628211b1c835e13a64d0cc2423c969Alexey Khoroshilov MGSLPC_INFO *current_dev = NULL; 2717d34138d057628211b1c835e13a64d0cc2423c969Alexey Khoroshilov struct device *tty_dev; 2718d34138d057628211b1c835e13a64d0cc2423c969Alexey Khoroshilov int ret; 2719d34138d057628211b1c835e13a64d0cc2423c969Alexey Khoroshilov 27201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->next_device = NULL; 27211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->line = mgslpc_device_count; 27221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sprintf(info->device_name,"ttySLP%d",info->line); 2723d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 27241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->line < MAX_DEVICE_COUNT) { 27251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (maxframe[info->line]) 27261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->max_frame_size = maxframe[info->line]; 27271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 27281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_device_count++; 2730d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 27311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!mgslpc_device_list) 27321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_device_list = info; 2733d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik else { 2734d34138d057628211b1c835e13a64d0cc2423c969Alexey Khoroshilov current_dev = mgslpc_device_list; 27353d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov while (current_dev->next_device) 27361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds current_dev = current_dev->next_device; 27371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds current_dev->next_device = info; 27381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2739d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 27401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->max_frame_size < 4096) 27411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->max_frame_size = 4096; 27421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (info->max_frame_size > 65535) 27431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->max_frame_size = 65535; 2744d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 27453d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov printk("SyncLink PC Card %s:IO=%04X IRQ=%d\n", 27461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->device_name, info->io_base, info->irq_level); 27471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2748af69c7f924b272927f9aea378f34f4548d3888d9Paul Fulghum#if SYNCLINK_GENERIC_HDLC 2749d34138d057628211b1c835e13a64d0cc2423c969Alexey Khoroshilov ret = hdlcdev_init(info); 2750d34138d057628211b1c835e13a64d0cc2423c969Alexey Khoroshilov if (ret != 0) 2751d34138d057628211b1c835e13a64d0cc2423c969Alexey Khoroshilov goto failed; 27521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 2753d34138d057628211b1c835e13a64d0cc2423c969Alexey Khoroshilov 2754d34138d057628211b1c835e13a64d0cc2423c969Alexey Khoroshilov tty_dev = tty_port_register_device(&info->port, serial_driver, info->line, 2755a33ba827460cdab644e907fc0c740dc7fde56c17Jiri Slaby &info->p_dev->dev); 2756d34138d057628211b1c835e13a64d0cc2423c969Alexey Khoroshilov if (IS_ERR(tty_dev)) { 2757d34138d057628211b1c835e13a64d0cc2423c969Alexey Khoroshilov ret = PTR_ERR(tty_dev); 2758d34138d057628211b1c835e13a64d0cc2423c969Alexey Khoroshilov#if SYNCLINK_GENERIC_HDLC 2759d34138d057628211b1c835e13a64d0cc2423c969Alexey Khoroshilov hdlcdev_exit(info); 2760d34138d057628211b1c835e13a64d0cc2423c969Alexey Khoroshilov#endif 2761d34138d057628211b1c835e13a64d0cc2423c969Alexey Khoroshilov goto failed; 2762d34138d057628211b1c835e13a64d0cc2423c969Alexey Khoroshilov } 2763d34138d057628211b1c835e13a64d0cc2423c969Alexey Khoroshilov 2764d34138d057628211b1c835e13a64d0cc2423c969Alexey Khoroshilov return 0; 2765d34138d057628211b1c835e13a64d0cc2423c969Alexey Khoroshilov 2766d34138d057628211b1c835e13a64d0cc2423c969Alexey Khoroshilovfailed: 2767d34138d057628211b1c835e13a64d0cc2423c969Alexey Khoroshilov if (current_dev) 2768d34138d057628211b1c835e13a64d0cc2423c969Alexey Khoroshilov current_dev->next_device = NULL; 2769d34138d057628211b1c835e13a64d0cc2423c969Alexey Khoroshilov else 2770d34138d057628211b1c835e13a64d0cc2423c969Alexey Khoroshilov mgslpc_device_list = NULL; 2771d34138d057628211b1c835e13a64d0cc2423c969Alexey Khoroshilov mgslpc_device_count--; 2772d34138d057628211b1c835e13a64d0cc2423c969Alexey Khoroshilov return ret; 27731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 27741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2775cdaad343b561cdeb38b0578bb038eb5e87ed5551Peter Hagervallstatic void mgslpc_remove_device(MGSLPC_INFO *remove_info) 27761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 27771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = mgslpc_device_list; 27781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *last = NULL; 27791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while(info) { 27811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info == remove_info) { 27821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (last) 27831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds last->next_device = info->next_device; 27841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 27851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_device_list = info->next_device; 278616a1065f2113b2c068ea108a681fb6b1f3a02ce0Jiri Slaby tty_unregister_device(serial_driver, info->line); 2787af69c7f924b272927f9aea378f34f4548d3888d9Paul Fulghum#if SYNCLINK_GENERIC_HDLC 27881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdlcdev_exit(info); 27891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 27901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_resources(info); 2791191c5f10275cfbb36802edadbdb10c73537327b4Jiri Slaby tty_port_destroy(&info->port); 27921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(info); 27931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_device_count--; 27941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 27951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 27961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds last = info; 27971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info = info->next_device; 27981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 27991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 28001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 280125f8f54f6e178acfd503a95441b0ea05c525f751Joe Perchesstatic const struct pcmcia_device_id mgslpc_ids[] = { 28024af48c8c16dfc37400f63633373dd180b5540eadDominik Brodowski PCMCIA_DEVICE_MANF_CARD(0x02c5, 0x0050), 28034af48c8c16dfc37400f63633373dd180b5540eadDominik Brodowski PCMCIA_DEVICE_NULL 28044af48c8c16dfc37400f63633373dd180b5540eadDominik Brodowski}; 28054af48c8c16dfc37400f63633373dd180b5540eadDominik BrodowskiMODULE_DEVICE_TABLE(pcmcia, mgslpc_ids); 28064af48c8c16dfc37400f63633373dd180b5540eadDominik Brodowski 28071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pcmcia_driver mgslpc_driver = { 28081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .owner = THIS_MODULE, 28092e9b981a7c63ee8278df6823f8389d69dad1a499Dominik Brodowski .name = "synclink_cs", 281015b99ac1729503db9e6dc642a50b9b6cb3bf51f9Dominik Brodowski .probe = mgslpc_probe, 2811cc3b4866bee996c922e875b8c8efe9f0d8803aaeDominik Brodowski .remove = mgslpc_detach, 28124af48c8c16dfc37400f63633373dd180b5540eadDominik Brodowski .id_table = mgslpc_ids, 281398e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski .suspend = mgslpc_suspend, 281498e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski .resume = mgslpc_resume, 28151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 28161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2817b68e31d0ebbcc909d1941f9f230c9d062a3a13d3Jeff Dikestatic const struct tty_operations mgslpc_ops = { 28181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .open = mgslpc_open, 28191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .close = mgslpc_close, 28201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write = mgslpc_write, 28211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .put_char = mgslpc_put_char, 28221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .flush_chars = mgslpc_flush_chars, 28231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write_room = mgslpc_write_room, 28241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .chars_in_buffer = mgslpc_chars_in_buffer, 28251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .flush_buffer = mgslpc_flush_buffer, 28261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .ioctl = mgslpc_ioctl, 28271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .throttle = mgslpc_throttle, 28281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .unthrottle = mgslpc_unthrottle, 28291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .send_xchar = mgslpc_send_xchar, 28301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .break_ctl = mgslpc_break, 28311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .wait_until_sent = mgslpc_wait_until_sent, 28321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .set_termios = mgslpc_set_termios, 28331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .stop = tx_pause, 28341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .start = tx_release, 28351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .hangup = mgslpc_hangup, 28361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .tiocmget = tiocmget, 28371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .tiocmset = tiocmset, 2838dc98d9650891661a20842a8eef9e76536046d897Andres Salomon .get_icount = mgslpc_get_icount, 283987687144b4fce2ad083e689eec8b219054c292aeAlexey Dobriyan .proc_fops = &mgslpc_proc_fops, 28401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 28411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init synclink_cs_init(void) 28431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 28441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 28451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2846cc93441eed0d39af9d99ba1642b9f733b195435cJiri Slaby if (break_on_load) { 2847cc93441eed0d39af9d99ba1642b9f733b195435cJiri Slaby mgslpc_get_text_ptr(); 2848cc93441eed0d39af9d99ba1642b9f733b195435cJiri Slaby BREAKPOINT(); 28491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 28501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2851cc93441eed0d39af9d99ba1642b9f733b195435cJiri Slaby serial_driver = tty_alloc_driver(MAX_DEVICE_COUNT, 2852cc93441eed0d39af9d99ba1642b9f733b195435cJiri Slaby TTY_DRIVER_REAL_RAW | 2853cc93441eed0d39af9d99ba1642b9f733b195435cJiri Slaby TTY_DRIVER_DYNAMIC_DEV); 2854c3a6344ae475763b6fb0fb2ec3639004f500d0f1Dan Carpenter if (IS_ERR(serial_driver)) { 2855c3a6344ae475763b6fb0fb2ec3639004f500d0f1Dan Carpenter rc = PTR_ERR(serial_driver); 2856cc93441eed0d39af9d99ba1642b9f733b195435cJiri Slaby goto err; 2857cc93441eed0d39af9d99ba1642b9f733b195435cJiri Slaby } 28581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2859cc93441eed0d39af9d99ba1642b9f733b195435cJiri Slaby /* Initialize the tty_driver structure */ 2860cc93441eed0d39af9d99ba1642b9f733b195435cJiri Slaby serial_driver->driver_name = "synclink_cs"; 2861cc93441eed0d39af9d99ba1642b9f733b195435cJiri Slaby serial_driver->name = "ttySLP"; 2862cc93441eed0d39af9d99ba1642b9f733b195435cJiri Slaby serial_driver->major = ttymajor; 2863cc93441eed0d39af9d99ba1642b9f733b195435cJiri Slaby serial_driver->minor_start = 64; 2864cc93441eed0d39af9d99ba1642b9f733b195435cJiri Slaby serial_driver->type = TTY_DRIVER_TYPE_SERIAL; 2865cc93441eed0d39af9d99ba1642b9f733b195435cJiri Slaby serial_driver->subtype = SERIAL_TYPE_NORMAL; 2866cc93441eed0d39af9d99ba1642b9f733b195435cJiri Slaby serial_driver->init_termios = tty_std_termios; 2867cc93441eed0d39af9d99ba1642b9f733b195435cJiri Slaby serial_driver->init_termios.c_cflag = 2868cc93441eed0d39af9d99ba1642b9f733b195435cJiri Slaby B9600 | CS8 | CREAD | HUPCL | CLOCAL; 2869cc93441eed0d39af9d99ba1642b9f733b195435cJiri Slaby tty_set_operations(serial_driver, &mgslpc_ops); 28701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2871cc93441eed0d39af9d99ba1642b9f733b195435cJiri Slaby rc = tty_register_driver(serial_driver); 2872cc93441eed0d39af9d99ba1642b9f733b195435cJiri Slaby if (rc < 0) { 2873cc93441eed0d39af9d99ba1642b9f733b195435cJiri Slaby printk(KERN_ERR "%s(%d):Couldn't register serial driver\n", 2874cc93441eed0d39af9d99ba1642b9f733b195435cJiri Slaby __FILE__, __LINE__); 2875cc93441eed0d39af9d99ba1642b9f733b195435cJiri Slaby goto err_put_tty; 2876cc93441eed0d39af9d99ba1642b9f733b195435cJiri Slaby } 28771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 287816a1065f2113b2c068ea108a681fb6b1f3a02ce0Jiri Slaby rc = pcmcia_register_driver(&mgslpc_driver); 287916a1065f2113b2c068ea108a681fb6b1f3a02ce0Jiri Slaby if (rc < 0) 288016a1065f2113b2c068ea108a681fb6b1f3a02ce0Jiri Slaby goto err_unreg_tty; 2881d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 2882cc93441eed0d39af9d99ba1642b9f733b195435cJiri Slaby printk(KERN_INFO "%s %s, tty major#%d\n", driver_name, driver_version, 2883cc93441eed0d39af9d99ba1642b9f733b195435cJiri Slaby serial_driver->major); 2884d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 2885737586fe51e6d0031f83d781c0cb2f3abf8caadaJiri Slaby return 0; 288616a1065f2113b2c068ea108a681fb6b1f3a02ce0Jiri Slabyerr_unreg_tty: 288716a1065f2113b2c068ea108a681fb6b1f3a02ce0Jiri Slaby tty_unregister_driver(serial_driver); 2888737586fe51e6d0031f83d781c0cb2f3abf8caadaJiri Slabyerr_put_tty: 2889737586fe51e6d0031f83d781c0cb2f3abf8caadaJiri Slaby put_tty_driver(serial_driver); 289016a1065f2113b2c068ea108a681fb6b1f3a02ce0Jiri Slabyerr: 2891737586fe51e6d0031f83d781c0cb2f3abf8caadaJiri Slaby return rc; 28921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 28931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2894d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzikstatic void __exit synclink_cs_exit(void) 28951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 289616a1065f2113b2c068ea108a681fb6b1f3a02ce0Jiri Slaby pcmcia_unregister_driver(&mgslpc_driver); 2897737586fe51e6d0031f83d781c0cb2f3abf8caadaJiri Slaby tty_unregister_driver(serial_driver); 2898737586fe51e6d0031f83d781c0cb2f3abf8caadaJiri Slaby put_tty_driver(serial_driver); 28991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 29001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(synclink_cs_init); 29021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(synclink_cs_exit); 29031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mgslpc_set_rate(MGSLPC_INFO *info, unsigned char channel, unsigned int rate) 29051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 29061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int M, N; 29071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char val; 29081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2909d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik /* note:standard BRG mode is broken in V3.2 chip 2910d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik * so enhanced mode is always used 29111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 29121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rate) { 29141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds N = 3686400 / rate; 29151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!N) 29161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds N = 1; 29171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds N >>= 1; 29181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (M = 1; N > 64 && M < 16; M++) 29191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds N >>= 1; 29201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds N--; 29211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* BGR[5..0] = N 29231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * BGR[9..6] = M 29241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * BGR[7..0] contained in BGR register 29251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * BGR[9..8] contained in CCR2[7..6] 29261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * divisor = (N+1)*2^M 29271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 29281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note: M *must* not be zero (causes asymetric duty cycle) 2929d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik */ 29301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, (unsigned char) (channel + BGR), 29311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned char) ((M << 6) + N)); 29321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = read_reg(info, (unsigned char) (channel + CCR2)) & 0x3f; 29331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= ((M << 4) & 0xc0); 29341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, (unsigned char) (channel + CCR2), val); 29351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 29361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 29371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Enabled the AUX clock output at the specified frequency. 29391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 29401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void enable_auxclk(MGSLPC_INFO *info) 29411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 29421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char val; 2943d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 29441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* MODE 29451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 29461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07..06 MDS[1..0] 10 = transparent HDLC mode 29471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 05 ADM Address Mode, 0 = no addr recognition 29481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04 TMD Timer Mode, 0 = external 29491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 03 RAC Receiver Active, 0 = inactive 29501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 02 RTS 0=RTS active during xmit, 1=RTS always active 29511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 01 TRS Timer Resolution, 1=512 29521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 00 TLP Test Loop, 0 = no loop 29531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 29541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1000 0010 2955d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik */ 29561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = 0x82; 2957d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 2958d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik /* channel B RTS is used to enable AUXCLK driver on SP505 */ 29591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.mode == MGSL_MODE_HDLC && info->params.clock_speed) 29601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT2; 29611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHB + MODE, val); 2962d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 29631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* CCR0 29641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 29651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07 PU Power Up, 1=active, 0=power down 29661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 06 MCE Master Clock Enable, 1=enabled 29671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 05 Reserved, 0 29681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04..02 SC[2..0] Encoding 29691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 01..00 SM[1..0] Serial Mode, 00=HDLC 29701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 29711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 11000000 2972d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik */ 29731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHB + CCR0, 0xc0); 2974d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 29751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* CCR1 29761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 29771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07 SFLG Shared Flag, 0 = disable shared flags 29781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 06 GALP Go Active On Loop, 0 = not used 29791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 05 GLP Go On Loop, 0 = not used 29801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04 ODS Output Driver Select, 1=TxD is push-pull output 29811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 03 ITF Interframe Time Fill, 0=mark, 1=flag 29821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 02..00 CM[2..0] Clock Mode 29831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 29841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0001 0111 2985d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik */ 29861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHB + CCR1, 0x17); 2987d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 29881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* CCR2 (Channel B) 29891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 29901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07..06 BGR[9..8] Baud rate bits 9..8 29911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 05 BDF Baud rate divisor factor, 0=1, 1=BGR value 29921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04 SSEL Clock source select, 1=submode b 29931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 03 TOE 0=TxCLK is input, 1=TxCLK is output 29941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 02 RWX Read/Write Exchange 0=disabled 29951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 01 C32, CRC select, 0=CRC-16, 1=CRC-32 29961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 00 DIV, data inversion 0=disabled, 1=enabled 29971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 29981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0011 1000 2999d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik */ 30001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.mode == MGSL_MODE_HDLC && info->params.clock_speed) 30011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHB + CCR2, 0x38); 30021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 30031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHB + CCR2, 0x30); 3004d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 30051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* CCR4 30061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 30071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07 MCK4 Master Clock Divide by 4, 1=enabled 30081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 06 EBRG Enhanced Baud Rate Generator Mode, 1=enabled 30091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 05 TST1 Test Pin, 0=normal operation 30101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04 ICD Ivert Carrier Detect, 1=enabled (active low) 30111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 03..02 Reserved, must be 0 30121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 01..00 RFT[1..0] RxFIFO Threshold 00=32 bytes 30131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 30141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0101 0000 3015d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik */ 30161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHB + CCR4, 0x50); 3017d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 30181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if auxclk not enabled, set internal BRG so 30191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * CTS transitions can be detected (requires TxC) 3020d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik */ 30211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.mode == MGSL_MODE_HDLC && info->params.clock_speed) 30221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_set_rate(info, CHB, info->params.clock_speed); 30231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 30241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_set_rate(info, CHB, 921600); 30251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 30261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3027d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzikstatic void loopback_enable(MGSLPC_INFO *info) 30281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 30291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char val; 3030d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 3031d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik /* CCR1:02..00 CM[2..0] Clock Mode = 111 (clock mode 7) */ 3032ecda040ff3724f021a96491ecee88d48e968c153Alexandru Juncu val = read_reg(info, CHA + CCR1) | (BIT2 | BIT1 | BIT0); 30331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + CCR1, val); 3034d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 3035d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik /* CCR2:04 SSEL Clock source select, 1=submode b */ 3036ecda040ff3724f021a96491ecee88d48e968c153Alexandru Juncu val = read_reg(info, CHA + CCR2) | (BIT4 | BIT5); 30371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + CCR2, val); 3038d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 3039d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik /* set LinkSpeed if available, otherwise default to 2Mbps */ 30401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.clock_speed) 30411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_set_rate(info, CHA, info->params.clock_speed); 30421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 30431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_set_rate(info, CHA, 1843200); 3044d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 3045d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik /* MODE:00 TLP Test Loop, 1=loopback enabled */ 30461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = read_reg(info, CHA + MODE) | BIT0; 30471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + MODE, val); 30481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 30491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3050cdaad343b561cdeb38b0578bb038eb5e87ed5551Peter Hagervallstatic void hdlc_mode(MGSLPC_INFO *info) 30511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 30521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char val; 30531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char clkmode, clksubmode; 30541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3055d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik /* disable all interrupts */ 30561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq_disable(info, CHA, 0xffff); 30571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq_disable(info, CHB, 0xffff); 30581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port_irq_disable(info, 0xff); 3059d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 3060d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik /* assume clock mode 0a, rcv=RxC xmt=TxC */ 30611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clkmode = clksubmode = 0; 30621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.flags & HDLC_FLAG_RXC_DPLL 30631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && info->params.flags & HDLC_FLAG_TXC_DPLL) { 3064d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik /* clock mode 7a, rcv = DPLL, xmt = DPLL */ 30651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clkmode = 7; 30661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (info->params.flags & HDLC_FLAG_RXC_BRG 30671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && info->params.flags & HDLC_FLAG_TXC_BRG) { 3068d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik /* clock mode 7b, rcv = BRG, xmt = BRG */ 30691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clkmode = 7; 30701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clksubmode = 1; 30711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (info->params.flags & HDLC_FLAG_RXC_DPLL) { 30721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.flags & HDLC_FLAG_TXC_BRG) { 3073d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik /* clock mode 6b, rcv = DPLL, xmt = BRG/16 */ 30741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clkmode = 6; 30751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clksubmode = 1; 30761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 3077d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik /* clock mode 6a, rcv = DPLL, xmt = TxC */ 30781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clkmode = 6; 30791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 30801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (info->params.flags & HDLC_FLAG_TXC_BRG) { 3081d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik /* clock mode 0b, rcv = RxC, xmt = BRG */ 30821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clksubmode = 1; 30831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3084d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 30851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* MODE 30861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 30871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07..06 MDS[1..0] 10 = transparent HDLC mode 30881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 05 ADM Address Mode, 0 = no addr recognition 30891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04 TMD Timer Mode, 0 = external 30901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 03 RAC Receiver Active, 0 = inactive 30911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 02 RTS 0=RTS active during xmit, 1=RTS always active 30921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 01 TRS Timer Resolution, 1=512 30931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 00 TLP Test Loop, 0 = no loop 30941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 30951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1000 0010 3096d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik */ 30971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = 0x82; 30981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.loopback) 30991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT0; 3100d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 3101d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik /* preserve RTS state */ 31021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->serial_signals & SerialSignal_RTS) 31031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT2; 31041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + MODE, val); 3105d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 31061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* CCR0 31071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 31081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07 PU Power Up, 1=active, 0=power down 31091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 06 MCE Master Clock Enable, 1=enabled 31101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 05 Reserved, 0 31111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04..02 SC[2..0] Encoding 31121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 01..00 SM[1..0] Serial Mode, 00=HDLC 31131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 31141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 11000000 3115d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik */ 31161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = 0xc0; 31171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (info->params.encoding) 31181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 31191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HDLC_ENCODING_NRZI: 31201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT3; 31211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 31221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HDLC_ENCODING_BIPHASE_SPACE: 31231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT4; 31241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; // FM0 31251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HDLC_ENCODING_BIPHASE_MARK: 3126ecda040ff3724f021a96491ecee88d48e968c153Alexandru Juncu val |= BIT4 | BIT2; 31271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; // FM1 31281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HDLC_ENCODING_BIPHASE_LEVEL: 3129ecda040ff3724f021a96491ecee88d48e968c153Alexandru Juncu val |= BIT4 | BIT3; 31301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; // Manchester 31311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 31321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + CCR0, val); 3133d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 31341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* CCR1 31351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 31361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07 SFLG Shared Flag, 0 = disable shared flags 31371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 06 GALP Go Active On Loop, 0 = not used 31381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 05 GLP Go On Loop, 0 = not used 31391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04 ODS Output Driver Select, 1=TxD is push-pull output 31401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 03 ITF Interframe Time Fill, 0=mark, 1=flag 31411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 02..00 CM[2..0] Clock Mode 31421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 31431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0001 0000 3144d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik */ 31451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = 0x10 + clkmode; 31461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + CCR1, val); 3147d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 31481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* CCR2 31491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 31501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07..06 BGR[9..8] Baud rate bits 9..8 31511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 05 BDF Baud rate divisor factor, 0=1, 1=BGR value 31521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04 SSEL Clock source select, 1=submode b 31531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 03 TOE 0=TxCLK is input, 0=TxCLK is input 31541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 02 RWX Read/Write Exchange 0=disabled 31551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 01 C32, CRC select, 0=CRC-16, 1=CRC-32 31561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 00 DIV, data inversion 0=disabled, 1=enabled 31571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 31581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0000 0000 3159d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik */ 31601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = 0x00; 31611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clkmode == 2 || clkmode == 3 || clkmode == 6 31621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || clkmode == 7 || (clkmode == 0 && clksubmode == 1)) 31631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT5; 31641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clksubmode) 31651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT4; 31661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.crc_type == HDLC_CRC_32_CCITT) 31671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT1; 31681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.encoding == HDLC_ENCODING_NRZB) 31691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT0; 31701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + CCR2, val); 3171d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 31721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* CCR3 31731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 31741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07..06 PRE[1..0] Preamble count 00=1, 01=2, 10=4, 11=8 31751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 05 EPT Enable preamble transmission, 1=enabled 31761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04 RADD Receive address pushed to FIFO, 0=disabled 31771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 03 CRL CRC Reset Level, 0=FFFF 31781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 02 RCRC Rx CRC 0=On 1=Off 31791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 01 TCRC Tx CRC 0=On 1=Off 31801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 00 PSD DPLL Phase Shift Disable 31811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 31821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0000 0000 3183d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik */ 31841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = 0x00; 31851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.crc_type == HDLC_CRC_NONE) 3186ecda040ff3724f021a96491ecee88d48e968c153Alexandru Juncu val |= BIT2 | BIT1; 31871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.preamble != HDLC_PREAMBLE_PATTERN_NONE) 31881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT5; 31891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (info->params.preamble_length) 31901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 31911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HDLC_PREAMBLE_LENGTH_16BITS: 31921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT6; 31931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 31941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HDLC_PREAMBLE_LENGTH_32BITS: 31951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT6; 31961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 31971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HDLC_PREAMBLE_LENGTH_64BITS: 3198ecda040ff3724f021a96491ecee88d48e968c153Alexandru Juncu val |= BIT7 | BIT6; 31991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 32001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 32011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + CCR3, val); 3202d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 3203d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik /* PRE - Preamble pattern */ 32041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = 0; 32051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (info->params.preamble) 32061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 32071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HDLC_PREAMBLE_PATTERN_FLAGS: val = 0x7e; break; 32081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HDLC_PREAMBLE_PATTERN_10: val = 0xaa; break; 32091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HDLC_PREAMBLE_PATTERN_01: val = 0x55; break; 32101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HDLC_PREAMBLE_PATTERN_ONES: val = 0xff; break; 32111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 32121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + PRE, val); 3213d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 32141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* CCR4 32151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 32161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07 MCK4 Master Clock Divide by 4, 1=enabled 32171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 06 EBRG Enhanced Baud Rate Generator Mode, 1=enabled 32181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 05 TST1 Test Pin, 0=normal operation 32191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04 ICD Ivert Carrier Detect, 1=enabled (active low) 32201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 03..02 Reserved, must be 0 32211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 01..00 RFT[1..0] RxFIFO Threshold 00=32 bytes 32221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 32231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0101 0000 3224d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik */ 32251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = 0x50; 32261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + CCR4, val); 32271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.flags & HDLC_FLAG_RXC_DPLL) 32281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_set_rate(info, CHA, info->params.clock_speed * 16); 32291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 32301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_set_rate(info, CHA, info->params.clock_speed); 3231d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 32321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* RLCR Receive length check register 32331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 32341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 7 1=enable receive length check 32351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 6..0 Max frame length = (RL + 1) * 32 3236d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik */ 32371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + RLCR, 0); 3238d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 32391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* XBCH Transmit Byte Count High 32401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 32411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07 DMA mode, 0 = interrupt driven 32421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 06 NRM, 0=ABM (ignored) 32431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 05 CAS Carrier Auto Start 32441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04 XC Transmit Continuously (ignored) 32451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 03..00 XBC[10..8] Transmit byte count bits 10..8 32461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 32471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0000 0000 3248d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik */ 32491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = 0x00; 32501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.flags & HDLC_FLAG_AUTO_DCD) 32511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT5; 32521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + XBCH, val); 32531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enable_auxclk(info); 32541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.loopback || info->testing_irq) 32551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds loopback_enable(info); 32561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.flags & HDLC_FLAG_AUTO_CTS) 32571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 32581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq_enable(info, CHB, IRQ_CTS); 3259d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik /* PVR[3] 1=AUTO CTS active */ 32601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_reg_bits(info, CHA + PVR, BIT3); 32611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 32621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_reg_bits(info, CHA + PVR, BIT3); 32631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq_enable(info, CHA, 3265ecda040ff3724f021a96491ecee88d48e968c153Alexandru Juncu IRQ_RXEOM | IRQ_RXFIFO | IRQ_ALLSENT | 3266ecda040ff3724f021a96491ecee88d48e968c153Alexandru Juncu IRQ_UNDERRUN | IRQ_TXFIFO); 32671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds issue_command(info, CHA, CMD_TXRESET + CMD_RXRESET); 32681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wait_command_complete(info, CHA); 32691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read_reg16(info, CHA + ISR); /* clear pending IRQs */ 3270d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 32711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Master clock mode enabled above to allow reset commands 32721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to complete even if no data clocks are present. 32731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 32741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Disable master clock mode for normal communications because 32751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * V3.2 of the ESCC2 has a bug that prevents the transmit all sent 32761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * IRQ when in master clock mode. 32771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 32781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Leave master clock mode enabled for IRQ test because the 32791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * timer IRQ used by the test can only happen in master clock mode. 3280d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik */ 32811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info->testing_irq) 32821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_reg_bits(info, CHA + CCR0, BIT6); 32831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_set_idle(info); 32851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_stop(info); 32871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_stop(info); 32881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 32891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3290cdaad343b561cdeb38b0578bb038eb5e87ed5551Peter Hagervallstatic void rx_stop(MGSLPC_INFO *info) 32911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 32921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_ISR) 32931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):rx_stop(%s)\n", 32943d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov __FILE__, __LINE__, info->device_name); 3295d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 3296d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik /* MODE:03 RAC Receiver Active, 0=inactive */ 32971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_reg_bits(info, CHA + MODE, BIT3); 32981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32990fab6de09c71a976e5d765e1ff548b14be385153Joe Perches info->rx_enabled = false; 33000fab6de09c71a976e5d765e1ff548b14be385153Joe Perches info->rx_overflow = false; 33011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 33021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3303cdaad343b561cdeb38b0578bb038eb5e87ed5551Peter Hagervallstatic void rx_start(MGSLPC_INFO *info) 33041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 33051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_ISR) 33061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):rx_start(%s)\n", 33073d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov __FILE__, __LINE__, info->device_name); 33081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_reset_buffers(info); 33100fab6de09c71a976e5d765e1ff548b14be385153Joe Perches info->rx_enabled = false; 33110fab6de09c71a976e5d765e1ff548b14be385153Joe Perches info->rx_overflow = false; 33121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3313d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik /* MODE:03 RAC Receiver Active, 1=active */ 33141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_reg_bits(info, CHA + MODE, BIT3); 33151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33160fab6de09c71a976e5d765e1ff548b14be385153Joe Perches info->rx_enabled = true; 33171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 33181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3319eeb4613436f0f19a38f667ea3078821040559c68Alan Coxstatic void tx_start(MGSLPC_INFO *info, struct tty_struct *tty) 33201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 33211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_ISR) 33221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):tx_start(%s)\n", 33233d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov __FILE__, __LINE__, info->device_name); 3324d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 33251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->tx_count) { 33261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If auto RTS enabled and RTS is inactive, then assert */ 33271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* RTS and set a flag indicating that the driver should */ 33281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* negate RTS when the transmission completes. */ 33290fab6de09c71a976e5d765e1ff548b14be385153Joe Perches info->drop_rts_on_tx_done = false; 33301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.flags & HDLC_FLAG_AUTO_RTS) { 33321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds get_signals(info); 33331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(info->serial_signals & SerialSignal_RTS)) { 33341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->serial_signals |= SerialSignal_RTS; 33351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_signals(info); 33360fab6de09c71a976e5d765e1ff548b14be385153Joe Perches info->drop_rts_on_tx_done = true; 33371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 33381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 33391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.mode == MGSL_MODE_ASYNC) { 33411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info->tx_active) { 33420fab6de09c71a976e5d765e1ff548b14be385153Joe Perches info->tx_active = true; 3343eeb4613436f0f19a38f667ea3078821040559c68Alan Cox tx_ready(info, tty); 33441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 33451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 33460fab6de09c71a976e5d765e1ff548b14be385153Joe Perches info->tx_active = true; 3347eeb4613436f0f19a38f667ea3078821040559c68Alan Cox tx_ready(info, tty); 334840565f1962c5be9b9e285e05af01ab7771534868Jiri Slaby mod_timer(&info->tx_timer, jiffies + 334940565f1962c5be9b9e285e05af01ab7771534868Jiri Slaby msecs_to_jiffies(5000)); 33501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 33511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 33521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info->tx_enabled) 33540fab6de09c71a976e5d765e1ff548b14be385153Joe Perches info->tx_enabled = true; 33551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 33561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3357cdaad343b561cdeb38b0578bb038eb5e87ed5551Peter Hagervallstatic void tx_stop(MGSLPC_INFO *info) 33581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 33591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_ISR) 33601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):tx_stop(%s)\n", 33613d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov __FILE__, __LINE__, info->device_name); 3362d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 3363d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik del_timer(&info->tx_timer); 33641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33650fab6de09c71a976e5d765e1ff548b14be385153Joe Perches info->tx_enabled = false; 33660fab6de09c71a976e5d765e1ff548b14be385153Joe Perches info->tx_active = false; 33671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 33681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Reset the adapter to a known state and prepare it for further use. 33701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3371cdaad343b561cdeb38b0578bb038eb5e87ed5551Peter Hagervallstatic void reset_device(MGSLPC_INFO *info) 33721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3373d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik /* power up both channels (set BIT7) */ 33741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + CCR0, 0x80); 33751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHB + CCR0, 0x80); 33761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + MODE, 0); 33771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHB + MODE, 0); 3378d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 3379d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik /* disable all interrupts */ 33801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq_disable(info, CHA, 0xffff); 33811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq_disable(info, CHB, 0xffff); 33821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port_irq_disable(info, 0xff); 3383d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 33841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* PCR Port Configuration Register 33851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 33861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07..04 DEC[3..0] Serial I/F select outputs 33871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 03 output, 1=AUTO CTS control enabled 33881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 02 RI Ring Indicator input 0=active 33891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 01 DSR input 0=active 33901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 00 DTR output 0=active 33911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 33921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0000 0110 3393d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik */ 33941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, PCR, 0x06); 3395d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 33961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* PVR Port Value Register 33971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 33981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07..04 DEC[3..0] Serial I/F select (0000=disabled) 33991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 03 AUTO CTS output 1=enabled 34001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 02 RI Ring Indicator input 34011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 01 DSR input 34021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 00 DTR output (1=inactive) 34031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 34041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0000 0001 34051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 34061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// write_reg(info, PVR, PVR_DTR); 3407d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 34081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* IPC Interrupt Port Configuration 34091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 34101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07 VIS 1=Masked interrupts visible 34111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 06..05 Reserved, 0 34121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04..03 SLA Slave address, 00 ignored 34131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 02 CASM Cascading Mode, 1=daisy chain 34141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 01..00 IC[1..0] Interrupt Config, 01=push-pull output, active low 34151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 34161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0000 0101 3417d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik */ 34181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, IPC, 0x05); 34191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 34201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3421cdaad343b561cdeb38b0578bb038eb5e87ed5551Peter Hagervallstatic void async_mode(MGSLPC_INFO *info) 34221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 34231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char val; 34241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3425d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik /* disable all interrupts */ 34261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq_disable(info, CHA, 0xffff); 34271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq_disable(info, CHB, 0xffff); 34281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port_irq_disable(info, 0xff); 3429d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 34301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* MODE 34311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 34321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07 Reserved, 0 34331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 06 FRTS RTS State, 0=active 34341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 05 FCTS Flow Control on CTS 34351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04 FLON Flow Control Enable 34361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 03 RAC Receiver Active, 0 = inactive 34371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 02 RTS 0=Auto RTS, 1=manual RTS 34381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 01 TRS Timer Resolution, 1=512 34391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 00 TLP Test Loop, 0 = no loop 34401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 34411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0000 0110 3442d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik */ 34431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = 0x06; 34441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.loopback) 34451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT0; 3446d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 3447d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik /* preserve RTS state */ 34481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(info->serial_signals & SerialSignal_RTS)) 34491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT6; 34501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + MODE, val); 3451d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 34521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* CCR0 34531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 34541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07 PU Power Up, 1=active, 0=power down 34551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 06 MCE Master Clock Enable, 1=enabled 34561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 05 Reserved, 0 34571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04..02 SC[2..0] Encoding, 000=NRZ 34581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 01..00 SM[1..0] Serial Mode, 11=Async 34591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 34601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1000 0011 3461d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik */ 34621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + CCR0, 0x83); 3463d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 34641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* CCR1 34651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 34661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07..05 Reserved, 0 34671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04 ODS Output Driver Select, 1=TxD is push-pull output 34681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 03 BCR Bit Clock Rate, 1=16x 34691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 02..00 CM[2..0] Clock Mode, 111=BRG 34701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 34711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0001 1111 3472d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik */ 34731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + CCR1, 0x1f); 3474d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 34751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* CCR2 (channel A) 34761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 34771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07..06 BGR[9..8] Baud rate bits 9..8 34781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 05 BDF Baud rate divisor factor, 0=1, 1=BGR value 34791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04 SSEL Clock source select, 1=submode b 34801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 03 TOE 0=TxCLK is input, 0=TxCLK is input 34811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 02 RWX Read/Write Exchange 0=disabled 34821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 01 Reserved, 0 34831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 00 DIV, data inversion 0=disabled, 1=enabled 34841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 34851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0001 0000 3486d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik */ 34871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + CCR2, 0x10); 3488d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 34891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* CCR3 34901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 34911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07..01 Reserved, 0 34921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 00 PSD DPLL Phase Shift Disable 34931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 34941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0000 0000 3495d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik */ 34961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + CCR3, 0); 3497d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 34981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* CCR4 34991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 35001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07 MCK4 Master Clock Divide by 4, 1=enabled 35011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 06 EBRG Enhanced Baud Rate Generator Mode, 1=enabled 35021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 05 TST1 Test Pin, 0=normal operation 35031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04 ICD Ivert Carrier Detect, 1=enabled (active low) 35041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 03..00 Reserved, must be 0 35051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 35061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0101 0000 3507d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik */ 35081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + CCR4, 0x50); 35091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_set_rate(info, CHA, info->params.data_rate * 16); 3510d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 35111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* DAFO Data Format 35121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 35131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07 Reserved, 0 35141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 06 XBRK transmit break, 0=normal operation 35151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 05 Stop bits (0=1, 1=2) 35161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04..03 PAR[1..0] Parity (01=odd, 10=even) 35171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 02 PAREN Parity Enable 35181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 01..00 CHL[1..0] Character Length (00=8, 01=7) 35191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3520d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik */ 35211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = 0x00; 35221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.data_bits != 8) 35231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT0; /* 7 bits */ 35241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.stop_bits != 1) 35251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT5; 35261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.parity != ASYNC_PARITY_NONE) 35271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 35281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT2; /* Parity enable */ 35291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.parity == ASYNC_PARITY_ODD) 35301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT3; 35311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 35321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT4; 35331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 35341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + DAFO, val); 3535d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 35361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* RFC Rx FIFO Control 35371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 35381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07 Reserved, 0 35391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 06 DPS, 1=parity bit not stored in data byte 35401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 05 DXS, 0=all data stored in FIFO (including XON/XOFF) 35411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04 RFDF Rx FIFO Data Format, 1=status byte stored in FIFO 35421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 03..02 RFTH[1..0], rx threshold, 11=16 status + 16 data byte 35431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 01 Reserved, 0 35441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 00 TCDE Terminate Char Detect Enable, 0=disabled 35451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 35461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0101 1100 3547d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik */ 35481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + RFC, 0x5c); 3549d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 35501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* RLCR Receive length check register 35511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 35521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Max frame length = (RL + 1) * 32 3553d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik */ 35541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + RLCR, 0); 3555d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 35561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* XBCH Transmit Byte Count High 35571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 35581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07 DMA mode, 0 = interrupt driven 35591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 06 NRM, 0=ABM (ignored) 35601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 05 CAS Carrier Auto Start 35611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04 XC Transmit Continuously (ignored) 35621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 03..00 XBC[10..8] Transmit byte count bits 10..8 35631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 35641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0000 0000 3565d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik */ 35661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = 0x00; 35671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.flags & HDLC_FLAG_AUTO_DCD) 35681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT5; 35691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + XBCH, val); 35701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.flags & HDLC_FLAG_AUTO_CTS) 35711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq_enable(info, CHA, IRQ_CTS); 3572d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 3573d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik /* MODE:03 RAC Receiver Active, 1=active */ 35741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_reg_bits(info, CHA + MODE, BIT3); 35751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enable_auxclk(info); 35761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.flags & HDLC_FLAG_AUTO_CTS) { 35771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq_enable(info, CHB, IRQ_CTS); 3578d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik /* PVR[3] 1=AUTO CTS active */ 35791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_reg_bits(info, CHA + PVR, BIT3); 35801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 35811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_reg_bits(info, CHA + PVR, BIT3); 35821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq_enable(info, CHA, 3583ecda040ff3724f021a96491ecee88d48e968c153Alexandru Juncu IRQ_RXEOM | IRQ_RXFIFO | IRQ_BREAK_ON | IRQ_RXTIME | 3584ecda040ff3724f021a96491ecee88d48e968c153Alexandru Juncu IRQ_ALLSENT | IRQ_TXFIFO); 35851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds issue_command(info, CHA, CMD_TXRESET + CMD_RXRESET); 35861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wait_command_complete(info, CHA); 35871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read_reg16(info, CHA + ISR); /* clear pending IRQs */ 35881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 35891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Set the HDLC idle mode for the transmitter. 35911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3592cdaad343b561cdeb38b0578bb038eb5e87ed5551Peter Hagervallstatic void tx_set_idle(MGSLPC_INFO *info) 35931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3594d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik /* Note: ESCC2 only supports flags and one idle modes */ 35951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->idle_mode == HDLC_TXIDLE_FLAGS) 35961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_reg_bits(info, CHA + CCR1, BIT3); 35971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 35981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_reg_bits(info, CHA + CCR1, BIT3); 35991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 36001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* get state of the V24 status (input) signals. 36021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3603cdaad343b561cdeb38b0578bb038eb5e87ed5551Peter Hagervallstatic void get_signals(MGSLPC_INFO *info) 36041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 36051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char status = 0; 3606d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 36079fe8074b82ed14358be50c62ab9d081bcb911607Joe Perches /* preserve RTS and DTR */ 36089fe8074b82ed14358be50c62ab9d081bcb911607Joe Perches info->serial_signals &= SerialSignal_RTS | SerialSignal_DTR; 36091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (read_reg(info, CHB + VSTR) & BIT7) 36111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->serial_signals |= SerialSignal_DCD; 36121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (read_reg(info, CHB + STAR) & BIT1) 36131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->serial_signals |= SerialSignal_CTS; 36141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = read_reg(info, CHA + PVR); 36161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(status & PVR_RI)) 36171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->serial_signals |= SerialSignal_RI; 36181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(status & PVR_DSR)) 36191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->serial_signals |= SerialSignal_DSR; 36201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 36211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36229fe8074b82ed14358be50c62ab9d081bcb911607Joe Perches/* Set the state of RTS and DTR based on contents of 36231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * serial_signals member of device extension. 36241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3625cdaad343b561cdeb38b0578bb038eb5e87ed5551Peter Hagervallstatic void set_signals(MGSLPC_INFO *info) 36261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 36271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char val; 36281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = read_reg(info, CHA + MODE); 36301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.mode == MGSL_MODE_ASYNC) { 36311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->serial_signals & SerialSignal_RTS) 36321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val &= ~BIT6; 36331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 36341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT6; 36351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 36361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->serial_signals & SerialSignal_RTS) 36371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT2; 36381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 36391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val &= ~BIT2; 36401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 36411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + MODE, val); 36421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->serial_signals & SerialSignal_DTR) 36441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_reg_bits(info, CHA + PVR, PVR_DTR); 36451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 36461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_reg_bits(info, CHA + PVR, PVR_DTR); 36471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 36481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3649cdaad343b561cdeb38b0578bb038eb5e87ed5551Peter Hagervallstatic void rx_reset_buffers(MGSLPC_INFO *info) 36501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 36511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds RXBUF *buf; 36521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 36531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->rx_put = 0; 36551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->rx_get = 0; 36561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->rx_frame_count = 0; 36571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i=0 ; i < info->rx_buf_count ; i++) { 36581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf = (RXBUF*)(info->rx_buf + (i * info->rx_buf_size)); 36591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf->status = buf->count = 0; 36601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 36611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 36621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Attempt to return a received HDLC frame 36641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Only frames received without errors are returned. 36651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 36660fab6de09c71a976e5d765e1ff548b14be385153Joe Perches * Returns true if frame returned, otherwise false 36671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3668eeb4613436f0f19a38f667ea3078821040559c68Alan Coxstatic bool rx_get_frame(MGSLPC_INFO *info, struct tty_struct *tty) 36691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 36701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short status; 36711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds RXBUF *buf; 36721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int framesize = 0; 36731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 36740fab6de09c71a976e5d765e1ff548b14be385153Joe Perches bool return_frame = false; 3675d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 36761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->rx_frame_count == 0) 36770fab6de09c71a976e5d765e1ff548b14be385153Joe Perches return false; 36781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf = (RXBUF*)(info->rx_buf + (info->rx_get * info->rx_buf_size)); 36801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = buf->status; 36821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 07 VFR 1=valid frame 36841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 06 RDO 1=data overrun 36851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 05 CRC 1=OK, 0=error 36861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04 RAB 1=frame aborted 36871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 36881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((status & 0xf0) != 0xA0) { 36891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(status & BIT7) || (status & BIT4)) 36901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->icount.rxabort++; 36911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (status & BIT6) 36921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->icount.rxover++; 36931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (!(status & BIT5)) { 36941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->icount.rxcrc++; 36951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.crc_type & HDLC_CRC_RETURN_EX) 36960fab6de09c71a976e5d765e1ff548b14be385153Joe Perches return_frame = true; 36971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 36981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds framesize = 0; 3699af69c7f924b272927f9aea378f34f4548d3888d9Paul Fulghum#if SYNCLINK_GENERIC_HDLC 37001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 3701198191c4a7ce4daba379608fb38b9bc5a4eedc61Krzysztof Halasa info->netdev->stats.rx_errors++; 3702198191c4a7ce4daba379608fb38b9bc5a4eedc61Krzysztof Halasa info->netdev->stats.rx_frame_errors++; 37031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 37041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 37051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 37060fab6de09c71a976e5d765e1ff548b14be385153Joe Perches return_frame = true; 37071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (return_frame) 37091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds framesize = buf->count; 37101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_BH) 37121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):rx_get_frame(%s) status=%04X size=%d\n", 37133d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov __FILE__, __LINE__, info->device_name, status, framesize); 3714d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 37151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_DATA) 3716d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik trace_block(info, buf->data, framesize, 0); 3717d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 37181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (framesize) { 37191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((info->params.crc_type & HDLC_CRC_RETURN_EX && 37201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds framesize+1 > info->max_frame_size) || 37211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds framesize > info->max_frame_size) 37221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->icount.rxlong++; 37231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 37241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & BIT5) 37251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->icount.rxok++; 37261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.crc_type & HDLC_CRC_RETURN_EX) { 37281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *(buf->data + framesize) = status & BIT5 ? RX_OK:RX_CRC_ERROR; 37291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ++framesize; 37301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 37311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3732af69c7f924b272927f9aea378f34f4548d3888d9Paul Fulghum#if SYNCLINK_GENERIC_HDLC 37331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->netcount) 37341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdlcdev_rx(info, buf->data, framesize); 37351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 37361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 37371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ldisc_receive_buf(tty, buf->data, info->flag_buf, framesize); 37381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 37391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 37401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37413d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_lock_irqsave(&info->lock, flags); 37421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf->status = buf->count = 0; 37431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->rx_frame_count--; 37441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->rx_get++; 37451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->rx_get >= info->rx_buf_count) 37461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->rx_get = 0; 37473d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_unlock_irqrestore(&info->lock, flags); 37481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37490fab6de09c71a976e5d765e1ff548b14be385153Joe Perches return true; 37501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 37511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37520fab6de09c71a976e5d765e1ff548b14be385153Joe Perchesstatic bool register_test(MGSLPC_INFO *info) 37531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3754d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik static unsigned char patterns[] = 37551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 0x00, 0xff, 0xaa, 0x55, 0x69, 0x96, 0x0f }; 3756fe971071a89c5c5184fc9f3482c7a8e997cf0520Tobias Klauser static unsigned int count = ARRAY_SIZE(patterns); 37571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int i; 37580fab6de09c71a976e5d765e1ff548b14be385153Joe Perches bool rc = true; 37591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 37601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37613d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_lock_irqsave(&info->lock, flags); 37621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reset_device(info); 37631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < count; i++) { 37651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, XAD1, patterns[i]); 37661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, XAD2, patterns[(i + 1) % count]); 3767fe971071a89c5c5184fc9f3482c7a8e997cf0520Tobias Klauser if ((read_reg(info, XAD1) != patterns[i]) || 37681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (read_reg(info, XAD2) != patterns[(i + 1) % count])) { 37690fab6de09c71a976e5d765e1ff548b14be385153Joe Perches rc = false; 37701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 37711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 37721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 37731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37743d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_unlock_irqrestore(&info->lock, flags); 37751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 37761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 37771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37780fab6de09c71a976e5d765e1ff548b14be385153Joe Perchesstatic bool irq_test(MGSLPC_INFO *info) 37791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 37801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long end_time; 37811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 37821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37833d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_lock_irqsave(&info->lock, flags); 37841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reset_device(info); 37851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37860fab6de09c71a976e5d765e1ff548b14be385153Joe Perches info->testing_irq = true; 37871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdlc_mode(info); 37881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37890fab6de09c71a976e5d765e1ff548b14be385153Joe Perches info->irq_occurred = false; 37901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* init hdlc mode */ 37921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq_enable(info, CHA, IRQ_TIMER); 37941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + TIMR, 0); /* 512 cycles */ 37951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds issue_command(info, CHA, CMD_START_TIMER); 37961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37973d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_unlock_irqrestore(&info->lock, flags); 37981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds end_time=100; 38001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while(end_time-- && !info->irq_occurred) { 38011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msleep_interruptible(10); 38021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3803d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 38040fab6de09c71a976e5d765e1ff548b14be385153Joe Perches info->testing_irq = false; 38051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38063d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_lock_irqsave(&info->lock, flags); 38071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reset_device(info); 38083d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_unlock_irqrestore(&info->lock, flags); 3809d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 38100fab6de09c71a976e5d765e1ff548b14be385153Joe Perches return info->irq_occurred; 38111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 38121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3813cdaad343b561cdeb38b0578bb038eb5e87ed5551Peter Hagervallstatic int adapter_test(MGSLPC_INFO *info) 38141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 38151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!register_test(info)) { 38161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->init_error = DiagStatus_AddressFailure; 38173d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov printk("%s(%d):Register test failure for device %s Addr=%04X\n", 38183d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov __FILE__, __LINE__, info->device_name, (unsigned short)(info->io_base)); 38191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 38201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 38211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!irq_test(info)) { 38231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->init_error = DiagStatus_IrqFailure; 38243d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov printk("%s(%d):Interrupt test failure for device %s IRQ=%d\n", 38253d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov __FILE__, __LINE__, info->device_name, (unsigned short)(info->irq_level)); 38261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 38271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 38281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 38301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):device %s passed diagnostics\n", 38313d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov __FILE__, __LINE__, info->device_name); 38321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 38331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 38341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3835cdaad343b561cdeb38b0578bb038eb5e87ed5551Peter Hagervallstatic void trace_block(MGSLPC_INFO *info,const char* data, int count, int xmit) 38361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 38371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 38381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int linecount; 38391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (xmit) 38403d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov printk("%s tx data:\n", info->device_name); 38411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 38423d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov printk("%s rx data:\n", info->device_name); 3843d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 38441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while(count) { 38451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (count > 16) 38461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds linecount = 16; 38471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 38481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds linecount = count; 3849d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 38501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for(i=0;i<linecount;i++) 38513d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov printk("%02X ", (unsigned char)data[i]); 38521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for(;i<17;i++) 38531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(" "); 38541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for(i=0;i<linecount;i++) { 38551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data[i]>=040 && data[i]<=0176) 38563d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov printk("%c", data[i]); 38571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 38581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("."); 38591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 38601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("\n"); 3861d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 38621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data += linecount; 38631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count -= linecount; 38641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 38651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 38661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* HDLC frame time out 38681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * update stats and do tx completion processing 38691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3870cdaad343b561cdeb38b0578bb038eb5e87ed5551Peter Hagervallstatic void tx_timeout(unsigned long context) 38711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 38721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = (MGSLPC_INFO*)context; 38731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 3874d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 38753d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov if (debug_level >= DEBUG_LEVEL_INFO) 38763d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov printk("%s(%d):tx_timeout(%s)\n", 38773d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov __FILE__, __LINE__, info->device_name); 38783d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov if (info->tx_active && 38793d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov info->params.mode == MGSL_MODE_HDLC) { 38801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->icount.txtimeout++; 38811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 38823d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_lock_irqsave(&info->lock, flags); 38830fab6de09c71a976e5d765e1ff548b14be385153Joe Perches info->tx_active = false; 38841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_count = info->tx_put = info->tx_get = 0; 38851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38863d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_unlock_irqrestore(&info->lock, flags); 3887d12341f9f2b7cc38c699c2af3a9f17eb39b64b17Jeff Garzik 3888af69c7f924b272927f9aea378f34f4548d3888d9Paul Fulghum#if SYNCLINK_GENERIC_HDLC 38891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->netcount) 38901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdlcdev_tx_done(info); 38911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 38921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 3893eeb4613436f0f19a38f667ea3078821040559c68Alan Cox { 3894eeb4613436f0f19a38f667ea3078821040559c68Alan Cox struct tty_struct *tty = tty_port_tty_get(&info->port); 3895eeb4613436f0f19a38f667ea3078821040559c68Alan Cox bh_transmit(info, tty); 3896eeb4613436f0f19a38f667ea3078821040559c68Alan Cox tty_kref_put(tty); 3897eeb4613436f0f19a38f667ea3078821040559c68Alan Cox } 38981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 38991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3900af69c7f924b272927f9aea378f34f4548d3888d9Paul Fulghum#if SYNCLINK_GENERIC_HDLC 39011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 39031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * called by generic HDLC layer when protocol selected (PPP, frame relay, etc.) 39041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * set encoding and frame check sequence (FCS) options 39051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 39061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dev pointer to network device structure 39071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * encoding serial encoding setting 39081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * parity FCS setting 39091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 39101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns 0 if success, otherwise error code 39111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 39121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int hdlcdev_attach(struct net_device *dev, unsigned short encoding, 39131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short parity) 39141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 39151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = dev_to_port(dev); 3916eeb4613436f0f19a38f667ea3078821040559c68Alan Cox struct tty_struct *tty; 39171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char new_encoding; 39181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short new_crctype; 39191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* return error if TTY interface open */ 3921eeb4613436f0f19a38f667ea3078821040559c68Alan Cox if (info->port.count) 39221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 39231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (encoding) 39251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 39261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ENCODING_NRZ: new_encoding = HDLC_ENCODING_NRZ; break; 39271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ENCODING_NRZI: new_encoding = HDLC_ENCODING_NRZI_SPACE; break; 39281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ENCODING_FM_MARK: new_encoding = HDLC_ENCODING_BIPHASE_MARK; break; 39291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ENCODING_FM_SPACE: new_encoding = HDLC_ENCODING_BIPHASE_SPACE; break; 39301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ENCODING_MANCHESTER: new_encoding = HDLC_ENCODING_BIPHASE_LEVEL; break; 39311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: return -EINVAL; 39321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 39331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (parity) 39351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 39361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PARITY_NONE: new_crctype = HDLC_CRC_NONE; break; 39371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PARITY_CRC16_PR1_CCITT: new_crctype = HDLC_CRC_16_CCITT; break; 39381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PARITY_CRC32_PR1_CCITT: new_crctype = HDLC_CRC_32_CCITT; break; 39391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: return -EINVAL; 39401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 39411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->params.encoding = new_encoding; 394353b3531bbbf70ac7551b32d1acc229d94de52658Alexey Dobriyan info->params.crc_type = new_crctype; 39441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if network interface up, reprogram hardware */ 3946eeb4613436f0f19a38f667ea3078821040559c68Alan Cox if (info->netcount) { 3947eeb4613436f0f19a38f667ea3078821040559c68Alan Cox tty = tty_port_tty_get(&info->port); 3948eeb4613436f0f19a38f667ea3078821040559c68Alan Cox mgslpc_program_hw(info, tty); 3949eeb4613436f0f19a38f667ea3078821040559c68Alan Cox tty_kref_put(tty); 3950eeb4613436f0f19a38f667ea3078821040559c68Alan Cox } 39511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 39531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 39541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 39561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * called by generic HDLC layer to send frame 39571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 39581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * skb socket buffer containing HDLC frame 39591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dev pointer to network device structure 39601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 39614c5d502d8b2db8947c44dc44bdc67dbe55cce2b9Stephen Hemmingerstatic netdev_tx_t hdlcdev_xmit(struct sk_buff *skb, 39624c5d502d8b2db8947c44dc44bdc67dbe55cce2b9Stephen Hemminger struct net_device *dev) 39631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 39641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = dev_to_port(dev); 39651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 39661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 39683d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov printk(KERN_INFO "%s:hdlc_xmit(%s)\n", __FILE__, dev->name); 39691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* stop sending until this frame completes */ 39711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_stop_queue(dev); 39721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* copy data to device buffers */ 3974d626f62b11e00c16e81e4308ab93d3f13551812aArnaldo Carvalho de Melo skb_copy_from_linear_data(skb, info->tx_buf, skb->len); 39751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_get = 0; 39761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_put = info->tx_count = skb->len; 39771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* update network statistics */ 3979198191c4a7ce4daba379608fb38b9bc5a4eedc61Krzysztof Halasa dev->stats.tx_packets++; 3980198191c4a7ce4daba379608fb38b9bc5a4eedc61Krzysztof Halasa dev->stats.tx_bytes += skb->len; 39811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* done with socket buffer, so free it */ 39831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_kfree_skb(skb); 39841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* save start time for transmit timeout detection */ 39861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->trans_start = jiffies; 39871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* start hardware transmitter if necessary */ 39893d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_lock_irqsave(&info->lock, flags); 3990eeb4613436f0f19a38f667ea3078821040559c68Alan Cox if (!info->tx_active) { 3991eeb4613436f0f19a38f667ea3078821040559c68Alan Cox struct tty_struct *tty = tty_port_tty_get(&info->port); 39923d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov tx_start(info, tty); 39933d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov tty_kref_put(tty); 3994eeb4613436f0f19a38f667ea3078821040559c68Alan Cox } 39953d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_unlock_irqrestore(&info->lock, flags); 39961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39974c5d502d8b2db8947c44dc44bdc67dbe55cce2b9Stephen Hemminger return NETDEV_TX_OK; 39981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 39991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 40011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * called by network layer when interface enabled 40021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * claim resources and initialize hardware 40031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 40041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dev pointer to network device structure 40051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 40061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns 0 if success, otherwise error code 40071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 40081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int hdlcdev_open(struct net_device *dev) 40091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 40101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = dev_to_port(dev); 4011eeb4613436f0f19a38f667ea3078821040559c68Alan Cox struct tty_struct *tty; 40121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 40131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 40141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 40163d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov printk("%s:hdlcdev_open(%s)\n", __FILE__, dev->name); 40171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* generic HDLC layer open processing */ 40193d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov rc = hdlc_open(dev); 40203d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov if (rc != 0) 40211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 40221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* arbitrate between network and tty opens */ 40241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->netlock, flags); 4025eeb4613436f0f19a38f667ea3078821040559c68Alan Cox if (info->port.count != 0 || info->netcount != 0) { 40261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING "%s: hdlc_open returning busy\n", dev->name); 40271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->netlock, flags); 40281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 40291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 40301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->netcount=1; 40311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->netlock, flags); 40321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4033eeb4613436f0f19a38f667ea3078821040559c68Alan Cox tty = tty_port_tty_get(&info->port); 40341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* claim resources and init adapter */ 40353d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov rc = startup(info, tty); 40363d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov if (rc != 0) { 4037eeb4613436f0f19a38f667ea3078821040559c68Alan Cox tty_kref_put(tty); 40381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->netlock, flags); 40391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->netcount=0; 40401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->netlock, flags); 40411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 40421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 40439fe8074b82ed14358be50c62ab9d081bcb911607Joe Perches /* assert RTS and DTR, apply hardware settings */ 40449fe8074b82ed14358be50c62ab9d081bcb911607Joe Perches info->serial_signals |= SerialSignal_RTS | SerialSignal_DTR; 4045eeb4613436f0f19a38f667ea3078821040559c68Alan Cox mgslpc_program_hw(info, tty); 4046eeb4613436f0f19a38f667ea3078821040559c68Alan Cox tty_kref_put(tty); 40471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* enable network layer transmit */ 40491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->trans_start = jiffies; 40501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_start_queue(dev); 40511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* inform generic HDLC layer of current DCD status */ 40531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->lock, flags); 40541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds get_signals(info); 40551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock, flags); 4056fbeff3c1d35d07b1f967e47fcfb00cd16b7ecd02Krzysztof Halasa if (info->serial_signals & SerialSignal_DCD) 4057fbeff3c1d35d07b1f967e47fcfb00cd16b7ecd02Krzysztof Halasa netif_carrier_on(dev); 4058fbeff3c1d35d07b1f967e47fcfb00cd16b7ecd02Krzysztof Halasa else 4059fbeff3c1d35d07b1f967e47fcfb00cd16b7ecd02Krzysztof Halasa netif_carrier_off(dev); 40601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 40611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 40621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 40641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * called by network layer when interface is disabled 40651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * shutdown hardware and release resources 40661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 40671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dev pointer to network device structure 40681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 40691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns 0 if success, otherwise error code 40701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 40711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int hdlcdev_close(struct net_device *dev) 40721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 40731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = dev_to_port(dev); 4074eeb4613436f0f19a38f667ea3078821040559c68Alan Cox struct tty_struct *tty = tty_port_tty_get(&info->port); 40751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 40761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 40783d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov printk("%s:hdlcdev_close(%s)\n", __FILE__, dev->name); 40791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_stop_queue(dev); 40811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* shutdown adapter and release resources */ 4083eeb4613436f0f19a38f667ea3078821040559c68Alan Cox shutdown(info, tty); 4084eeb4613436f0f19a38f667ea3078821040559c68Alan Cox tty_kref_put(tty); 40851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdlc_close(dev); 40861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->netlock, flags); 40881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->netcount=0; 40891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->netlock, flags); 40901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 40921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 40931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 40951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * called by network layer to process IOCTL call to network device 40961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 40971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dev pointer to network device structure 40981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ifr pointer to network interface request structure 40991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cmd IOCTL command code 41001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns 0 if success, otherwise error code 41021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 41031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) 41041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 41051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const size_t size = sizeof(sync_serial_settings); 41061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sync_serial_settings new_line; 41071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sync_serial_settings __user *line = ifr->ifr_settings.ifs_ifsu.sync; 41081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = dev_to_port(dev); 41091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int flags; 41101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 41123d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov printk("%s:hdlcdev_ioctl(%s)\n", __FILE__, dev->name); 41131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* return error if TTY interface open */ 4115eeb4613436f0f19a38f667ea3078821040559c68Alan Cox if (info->port.count) 41161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 41171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cmd != SIOCWANDEV) 41191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return hdlc_ioctl(dev, ifr, cmd); 41201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41215b917a1420d3d1a9c8da49fb0090692dc9aaee86Vasiliy Kulikov memset(&new_line, 0, size); 41225b917a1420d3d1a9c8da49fb0090692dc9aaee86Vasiliy Kulikov 41231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch(ifr->ifr_settings.type) { 41241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case IF_GET_IFACE: /* return current sync_serial_settings */ 41251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ifr->ifr_settings.type = IF_IFACE_SYNC_SERIAL; 41271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ifr->ifr_settings.size < size) { 41281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ifr->ifr_settings.size = size; /* data size wanted */ 41291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOBUFS; 41301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 41311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flags = info->params.flags & (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | 41331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | 41341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | 41351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); 41361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (flags){ 41381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN): new_line.clock_type = CLOCK_EXT; break; 41391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_INT; break; 41401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_TXINT; break; 41411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN): new_line.clock_type = CLOCK_TXFROMRX; break; 41421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: new_line.clock_type = CLOCK_DEFAULT; 41431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 41441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_line.clock_rate = info->params.clock_speed; 41461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_line.loopback = info->params.loopback ? 1:0; 41471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_to_user(line, &new_line, size)) 41491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 41501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 41511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case IF_IFACE_SYNC_SERIAL: /* set sync_serial_settings */ 41531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(!capable(CAP_NET_ADMIN)) 41551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EPERM; 41561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(&new_line, line, size)) 41571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 41581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (new_line.clock_type) 41601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 41611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CLOCK_EXT: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN; break; 41621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CLOCK_TXFROMRX: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN; break; 41631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CLOCK_INT: flags = HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG; break; 41641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CLOCK_TXINT: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG; break; 41651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CLOCK_DEFAULT: flags = info->params.flags & 41661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | 41671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | 41681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | 41691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); break; 41701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: return -EINVAL; 41711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 41721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (new_line.loopback != 0 && new_line.loopback != 1) 41741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 41751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->params.flags &= ~(HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | 41771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | 41781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | 41791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); 41801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->params.flags |= flags; 41811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->params.loopback = new_line.loopback; 41831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (flags & (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG)) 41851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->params.clock_speed = new_line.clock_rate; 41861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 41871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->params.clock_speed = 0; 41881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if network interface up, reprogram hardware */ 4190eeb4613436f0f19a38f667ea3078821040559c68Alan Cox if (info->netcount) { 4191eeb4613436f0f19a38f667ea3078821040559c68Alan Cox struct tty_struct *tty = tty_port_tty_get(&info->port); 4192eeb4613436f0f19a38f667ea3078821040559c68Alan Cox mgslpc_program_hw(info, tty); 4193eeb4613436f0f19a38f667ea3078821040559c68Alan Cox tty_kref_put(tty); 4194eeb4613436f0f19a38f667ea3078821040559c68Alan Cox } 41951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 41961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 41981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return hdlc_ioctl(dev, ifr, cmd); 41991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 42001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 42011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 42031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * called by network layer when transmit timeout is detected 42041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 42051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dev pointer to network device structure 42061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 42071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void hdlcdev_tx_timeout(struct net_device *dev) 42081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 42091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = dev_to_port(dev); 42101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 42111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 42133d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov printk("hdlcdev_tx_timeout(%s)\n", dev->name); 42141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4215198191c4a7ce4daba379608fb38b9bc5a4eedc61Krzysztof Halasa dev->stats.tx_errors++; 4216198191c4a7ce4daba379608fb38b9bc5a4eedc61Krzysztof Halasa dev->stats.tx_aborted_errors++; 42171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42183d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_lock_irqsave(&info->lock, flags); 42191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_stop(info); 42203d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov spin_unlock_irqrestore(&info->lock, flags); 42211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_wake_queue(dev); 42231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 42241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 42261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * called by device driver when transmit completes 42271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * reenable network layer transmit if stopped 42281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 42291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * info pointer to device instance information 42301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 42311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void hdlcdev_tx_done(MGSLPC_INFO *info) 42321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 42331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (netif_queue_stopped(info->netdev)) 42341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_wake_queue(info->netdev); 42351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 42361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 42381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * called by device driver when frame received 42391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pass frame to network layer 42401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 42411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * info pointer to device instance information 42421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * buf pointer to buffer contianing frame data 42431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * size count of data bytes in buf 42441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 42451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void hdlcdev_rx(MGSLPC_INFO *info, char *buf, int size) 42461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 42471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb = dev_alloc_skb(size); 42481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev = info->netdev; 42491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 42513d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov printk("hdlcdev_rx(%s)\n", dev->name); 42521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (skb == NULL) { 42541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_NOTICE "%s: can't alloc skb, dropping packet\n", dev->name); 4255198191c4a7ce4daba379608fb38b9bc5a4eedc61Krzysztof Halasa dev->stats.rx_dropped++; 42561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 42571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 42581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4259198191c4a7ce4daba379608fb38b9bc5a4eedc61Krzysztof Halasa memcpy(skb_put(skb, size), buf, size); 42601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4261198191c4a7ce4daba379608fb38b9bc5a4eedc61Krzysztof Halasa skb->protocol = hdlc_type_trans(skb, dev); 42621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4263198191c4a7ce4daba379608fb38b9bc5a4eedc61Krzysztof Halasa dev->stats.rx_packets++; 4264198191c4a7ce4daba379608fb38b9bc5a4eedc61Krzysztof Halasa dev->stats.rx_bytes += size; 42651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_rx(skb); 42671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 42681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4269991990a12de42281f81b4e3a6471586d2d0caf6aKrzysztof Hałasastatic const struct net_device_ops hdlcdev_ops = { 4270991990a12de42281f81b4e3a6471586d2d0caf6aKrzysztof Hałasa .ndo_open = hdlcdev_open, 4271991990a12de42281f81b4e3a6471586d2d0caf6aKrzysztof Hałasa .ndo_stop = hdlcdev_close, 4272991990a12de42281f81b4e3a6471586d2d0caf6aKrzysztof Hałasa .ndo_change_mtu = hdlc_change_mtu, 4273991990a12de42281f81b4e3a6471586d2d0caf6aKrzysztof Hałasa .ndo_start_xmit = hdlc_start_xmit, 4274991990a12de42281f81b4e3a6471586d2d0caf6aKrzysztof Hałasa .ndo_do_ioctl = hdlcdev_ioctl, 4275991990a12de42281f81b4e3a6471586d2d0caf6aKrzysztof Hałasa .ndo_tx_timeout = hdlcdev_tx_timeout, 4276991990a12de42281f81b4e3a6471586d2d0caf6aKrzysztof Hałasa}; 4277991990a12de42281f81b4e3a6471586d2d0caf6aKrzysztof Hałasa 42781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 42791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * called by device driver when adding device instance 42801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * do generic HDLC initialization 42811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 42821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * info pointer to device instance information 42831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 42841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns 0 if success, otherwise error code 42851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 42861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int hdlcdev_init(MGSLPC_INFO *info) 42871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 42881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 42891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev; 42901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdlc_device *hdlc; 42911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* allocate and initialize network and HDLC layer objects */ 42931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42943d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov dev = alloc_hdlcdev(info); 42953d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov if (dev == NULL) { 42963d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov printk(KERN_ERR "%s:hdlc device allocation failure\n", __FILE__); 42971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 42981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 42991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* for network layer reporting purposes only */ 43011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->base_addr = info->io_base; 43021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->irq = info->irq_level; 43031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* network layer callbacks and settings */ 4305991990a12de42281f81b4e3a6471586d2d0caf6aKrzysztof Hałasa dev->netdev_ops = &hdlcdev_ops; 4306991990a12de42281f81b4e3a6471586d2d0caf6aKrzysztof Hałasa dev->watchdog_timeo = 10 * HZ; 43071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->tx_queue_len = 50; 43081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* generic HDLC layer callbacks and settings */ 43101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdlc = dev_to_hdlc(dev); 43111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdlc->attach = hdlcdev_attach; 43121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdlc->xmit = hdlcdev_xmit; 43131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* register objects with HDLC layer */ 43153d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov rc = register_hdlc_device(dev); 43163d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov if (rc) { 43173d55399391c8ecb5bb3d1c426bafa2580a889c4eAlexey Khoroshilov printk(KERN_WARNING "%s:unable to register hdlc device\n", __FILE__); 43181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_netdev(dev); 43191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 43201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 43211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->netdev = dev; 43231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 43241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 43251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 43271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * called by device driver when removing device instance 43281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * do generic HDLC cleanup 43291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 43301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * info pointer to device instance information 43311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 43321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void hdlcdev_exit(MGSLPC_INFO *info) 43331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 43341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unregister_hdlc_device(info->netdev); 43351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_netdev(info->netdev); 43361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->netdev = NULL; 43371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 43381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_HDLC */ 43401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4341