synclink_cs.c revision 4af48c8c16dfc37400f63633373dd180b5540ead
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * linux/drivers/char/pcmcia/synclink_cs.c 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * $Id: synclink_cs.c,v 4.26 2004/08/11 19:30:02 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/config.h> 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/signal.h> 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sched.h> 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/timer.h> 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/time.h> 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h> 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h> 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty.h> 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_flip.h> 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/serial.h> 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/major.h> 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h> 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fcntl.h> 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ptrace.h> 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h> 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h> 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h> 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/vmalloc.h> 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/serial.h> 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioctl.h> 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/system.h> 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/irq.h> 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/dma.h> 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/bitops.h> 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/types.h> 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/termios.h> 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/workqueue.h> 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/hdlc.h> 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <pcmcia/version.h> 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <pcmcia/cs_types.h> 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <pcmcia/cs.h> 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <pcmcia/cistpl.h> 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <pcmcia/cisreg.h> 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <pcmcia/ds.h> 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_HDLC_MODULE 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONFIG_HDLC 1 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GET_USER(error,value,addr) error = get_user(value,addr) 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PUT_USER(error,value,addr) error = put_user(value,addr) 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define COPY_TO_USER(error,dest,src,size) error = copy_to_user(dest,src,size) ? -EFAULT : 0 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h> 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "linux/synclink.h" 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic MGSL_PARAMS default_params = { 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSL_MODE_HDLC, /* unsigned long mode */ 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0, /* unsigned char loopback; */ 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HDLC_FLAG_UNDERRUN_ABORT15, /* unsigned short flags; */ 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HDLC_ENCODING_NRZI_SPACE, /* unsigned char encoding; */ 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0, /* unsigned long clock_speed; */ 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0xff, /* unsigned char addr_filter; */ 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HDLC_CRC_16_CCITT, /* unsigned short crc_type; */ 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HDLC_PREAMBLE_LENGTH_8BITS, /* unsigned char preamble_length; */ 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HDLC_PREAMBLE_PATTERN_NONE, /* unsigned char preamble; */ 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9600, /* unsigned long data_rate; */ 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8, /* unsigned char data_bits; */ 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1, /* unsigned char stop_bits; */ 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ASYNC_PARITY_NONE /* unsigned char parity; */ 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstypedef struct 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int count; 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char status; 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char data[1]; 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} RXBUF; 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The queue of BH actions to be performed */ 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BH_RECEIVE 1 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BH_TRANSMIT 2 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BH_STATUS 4 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IO_PIN_SHUTDOWN_LIMIT 100 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct _input_signal_events { 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ri_up; 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ri_down; 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int dsr_up; 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int dsr_down; 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int dcd_up; 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int dcd_down; 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cts_up; 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cts_down; 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Device instance data structure 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstypedef struct _mgslpc_info { 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void *if_ptr; /* General purpose pointer (used by SPPP) */ 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int magic; 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int flags; 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int count; /* count of opens */ 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int line; 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short close_delay; 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short closing_wait; /* time to wait before closing */ 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mgsl_icount icount; 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tty_struct *tty; 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int timeout; 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int x_char; /* xon/xoff character */ 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int blocked_open; /* # of blocked opens */ 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char read_status_mask; 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char ignore_status_mask; 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *tx_buf; 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int tx_put; 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int tx_get; 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int tx_count; 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* circular list of fixed length rx buffers */ 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *rx_buf; /* memory allocated for all rx buffers */ 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rx_buf_total_size; /* size of memory allocated for rx buffers */ 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rx_put; /* index of next empty rx buffer */ 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rx_get; /* index of next full rx buffer */ 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rx_buf_size; /* size in bytes of single rx buffer */ 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rx_buf_count; /* total number of rx buffers */ 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rx_frame_count; /* number of full rx buffers */ 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wait_queue_head_t open_wait; 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wait_queue_head_t close_wait; 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wait_queue_head_t status_event_wait_q; 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wait_queue_head_t event_wait_q; 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct timer_list tx_timer; /* HDLC transmit timeout timer */ 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct _mgslpc_info *next_device; /* device list link */ 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short imra_value; 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short imrb_value; 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char pim_value; 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spinlock_t lock; 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct work_struct task; /* task structure for scheduling bh */ 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 max_frame_size; 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 pending_bh; 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int bh_running; 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int bh_requested; 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int dcd_chkcount; /* check counts to prevent */ 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cts_chkcount; /* too many IRQs if a signal */ 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int dsr_chkcount; /* is floating */ 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ri_chkcount; 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rx_enabled; 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rx_overflow; 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int tx_enabled; 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int tx_active; 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int tx_aborting; 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 idle_mode; 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int if_mode; /* serial interface selection (RS-232, v.35 etc) */ 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char device_name[25]; /* device instance name */ 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int io_base; /* base I/O address of adapter */ 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int irq_level; 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSL_PARAMS params; /* communications parameters */ 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char serial_signals; /* current serial signal states */ 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char irq_occurred; /* for diagnostics use */ 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char testing_irq; 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int init_error; /* startup error (DIAGS) */ 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char flag_buf[MAX_ASYNC_BUFFER_SIZE]; 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BOOLEAN drop_rts_on_tx_done; 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct _input_signal_events input_signal_events; 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* PCMCIA support */ 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_link_t link; 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_node_t node; 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int stop; 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* SPPP/Cisco HDLC device parts */ 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int netcount; 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int dosyncppp; 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spinlock_t netlock; 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_HDLC 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *netdev; 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} MGSLPC_INFO; 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MGSLPC_MAGIC 0x5402 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The size of the serial xmit buffer is 1 page, or 4096 bytes 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TXBUFSIZE 4096 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CHA 0x00 /* channel A offset */ 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CHB 0x40 /* channel B offset */ 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * FIXME: PPC has PVR defined in asm/reg.h. For now we just undef it. 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef PVR 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RXFIFO 0 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TXFIFO 0 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define STAR 0x20 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CMDR 0x20 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RSTA 0x21 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PRE 0x21 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MODE 0x22 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TIMR 0x23 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define XAD1 0x24 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define XAD2 0x25 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RAH1 0x26 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RAH2 0x27 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DAFO 0x27 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RAL1 0x28 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RFC 0x28 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RHCR 0x29 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RAL2 0x29 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RBCL 0x2a 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define XBCL 0x2a 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RBCH 0x2b 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define XBCH 0x2b 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CCR0 0x2c 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CCR1 0x2d 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CCR2 0x2e 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CCR3 0x2f 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VSTR 0x34 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BGR 0x34 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RLCR 0x35 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define AML 0x36 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define AMH 0x37 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GIS 0x38 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IVA 0x38 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IPC 0x39 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ISR 0x3a 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IMR 0x3a 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PVR 0x3c 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PIS 0x3d 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PIM 0x3d 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PCR 0x3e 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CCR4 0x3f 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// IMR/ISR 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IRQ_BREAK_ON BIT15 // rx break detected 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IRQ_DATAOVERRUN BIT14 // receive data overflow 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IRQ_ALLSENT BIT13 // all sent 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IRQ_UNDERRUN BIT12 // transmit data underrun 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IRQ_TIMER BIT11 // timer interrupt 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IRQ_CTS BIT10 // CTS status change 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IRQ_TXREPEAT BIT9 // tx message repeat 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IRQ_TXFIFO BIT8 // transmit pool ready 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IRQ_RXEOM BIT7 // receive message end 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IRQ_EXITHUNT BIT6 // receive frame start 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IRQ_RXTIME BIT6 // rx char timeout 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IRQ_DCD BIT2 // carrier detect status change 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IRQ_OVERRUN BIT1 // receive frame overflow 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IRQ_RXFIFO BIT0 // receive pool full 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// STAR 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define XFW BIT6 // transmit FIFO write enable 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CEC BIT2 // command executing 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CTS BIT1 // CTS state 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PVR_DTR BIT0 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PVR_DSR BIT1 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PVR_RI BIT2 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PVR_AUTOCTS BIT3 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PVR_RS232 0x20 /* 0010b */ 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PVR_V35 0xe0 /* 1110b */ 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PVR_RS422 0x40 /* 0100b */ 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Register access functions */ 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define write_reg(info, reg, val) outb((val),(info)->io_base + (reg)) 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define read_reg(info, reg) inb((info)->io_base + (reg)) 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define read_reg16(info, reg) inw((info)->io_base + (reg)) 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define write_reg16(info, reg, val) outw((val), (info)->io_base + (reg)) 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define set_reg_bits(info, reg, mask) \ 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, (reg), \ 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned char) (read_reg(info, (reg)) | (mask))) 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define clear_reg_bits(info, reg, mask) \ 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, (reg), \ 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned char) (read_reg(info, (reg)) & ~(mask))) 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * interrupt enable/disable routines 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void irq_disable(MGSLPC_INFO *info, unsigned char channel, unsigned short mask) 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (channel == CHA) { 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->imra_value |= mask; 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg16(info, CHA + IMR, info->imra_value); 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->imrb_value |= mask; 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg16(info, CHB + IMR, info->imrb_value); 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void irq_enable(MGSLPC_INFO *info, unsigned char channel, unsigned short mask) 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (channel == CHA) { 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->imra_value &= ~mask; 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg16(info, CHA + IMR, info->imra_value); 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->imrb_value &= ~mask; 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg16(info, CHB + IMR, info->imrb_value); 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define port_irq_disable(info, mask) \ 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { info->pim_value |= (mask); write_reg(info, PIM, info->pim_value); } 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define port_irq_enable(info, mask) \ 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { info->pim_value &= ~(mask); write_reg(info, PIM, info->pim_value); } 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rx_start(MGSLPC_INFO *info); 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rx_stop(MGSLPC_INFO *info); 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void tx_start(MGSLPC_INFO *info); 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void tx_stop(MGSLPC_INFO *info); 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void tx_set_idle(MGSLPC_INFO *info); 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void get_signals(MGSLPC_INFO *info); 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void set_signals(MGSLPC_INFO *info); 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void reset_device(MGSLPC_INFO *info); 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void hdlc_mode(MGSLPC_INFO *info); 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void async_mode(MGSLPC_INFO *info); 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void tx_timeout(unsigned long context); 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ioctl_common(MGSLPC_INFO *info, unsigned int cmd, unsigned long arg); 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_HDLC 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define dev_to_port(D) (dev_to_hdlc(D)->priv) 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void hdlcdev_tx_done(MGSLPC_INFO *info); 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void hdlcdev_rx(MGSLPC_INFO *info, char *buf, int size); 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int hdlcdev_init(MGSLPC_INFO *info); 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void hdlcdev_exit(MGSLPC_INFO *info); 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void trace_block(MGSLPC_INFO *info,const char* data, int count, int xmit); 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic BOOLEAN register_test(MGSLPC_INFO *info); 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic BOOLEAN irq_test(MGSLPC_INFO *info); 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int adapter_test(MGSLPC_INFO *info); 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int claim_resources(MGSLPC_INFO *info); 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void release_resources(MGSLPC_INFO *info); 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mgslpc_add_device(MGSLPC_INFO *info); 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mgslpc_remove_device(MGSLPC_INFO *info); 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rx_get_frame(MGSLPC_INFO *info); 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rx_reset_buffers(MGSLPC_INFO *info); 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rx_alloc_buffers(MGSLPC_INFO *info); 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rx_free_buffers(MGSLPC_INFO *info); 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic irqreturn_t mgslpc_isr(int irq, void *dev_id, struct pt_regs * regs); 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Bottom half interrupt handlers 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void bh_handler(void* Context); 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void bh_transmit(MGSLPC_INFO *info); 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void bh_status(MGSLPC_INFO *info); 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ioctl handlers 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tiocmget(struct tty_struct *tty, struct file *file); 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tiocmset(struct tty_struct *tty, struct file *file, 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int set, unsigned int clear); 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int get_stats(MGSLPC_INFO *info, struct mgsl_icount __user *user_icount); 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int get_params(MGSLPC_INFO *info, MGSL_PARAMS __user *user_params); 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int set_params(MGSLPC_INFO *info, MGSL_PARAMS __user *new_params); 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int get_txidle(MGSLPC_INFO *info, int __user *idle_mode); 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int set_txidle(MGSLPC_INFO *info, int idle_mode); 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int set_txenable(MGSLPC_INFO *info, int enable); 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tx_abort(MGSLPC_INFO *info); 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int set_rxenable(MGSLPC_INFO *info, int enable); 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int wait_events(MGSLPC_INFO *info, int __user *mask); 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic MGSLPC_INFO *mgslpc_device_list = NULL; 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mgslpc_device_count = 0; 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set this param to non-zero to load eax with the 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * .text section address and breakpoint on module load. 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is useful for use with gdb and add-symbol-file command. 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int break_on_load=0; 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Driver major number, defaults to zero to get auto 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * assigned major number. May be forced as module parameter. 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ttymajor=0; 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int debug_level = 0; 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int maxframe[MAX_DEVICE_COUNT] = {0,}; 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dosyncppp[MAX_DEVICE_COUNT] = {1,1,1,1}; 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(break_on_load, bool, 0); 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(ttymajor, int, 0); 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(debug_level, int, 0); 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_array(maxframe, int, NULL, 0); 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_array(dosyncppp, int, NULL, 0); 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char *driver_name = "SyncLink PC Card driver"; 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char *driver_version = "$Revision: 4.26 $"; 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct tty_driver *serial_driver; 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* number of characters left in xmit buffer before we ask for more */ 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define WAKEUP_CHARS 256 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mgslpc_change_params(MGSLPC_INFO *info); 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mgslpc_wait_until_sent(struct tty_struct *tty, int timeout); 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* PCMCIA prototypes */ 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mgslpc_config(dev_link_t *link); 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mgslpc_release(u_long arg); 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mgslpc_event(event_t event, int priority, 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds event_callback_args_t *args); 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic dev_link_t *mgslpc_attach(void); 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mgslpc_detach(dev_link_t *); 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic dev_info_t dev_info = "synclink_cs"; 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic dev_link_t *dev_list = NULL; 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1st function defined in .text section. Calling this function in 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * init_module() followed by a breakpoint allows a remote debugger 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (gdb) to get the .text address for the add-symbol-file command. 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This allows remote debugging of dynamically loadable modules. 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void* mgslpc_get_text_ptr(void) 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return mgslpc_get_text_ptr; 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * line discipline callback wrappers 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The wrappers maintain line discipline references 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * while calling into the line discipline. 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ldisc_flush_buffer - flush line discipline receive buffers 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ldisc_receive_buf - pass receive data to line discipline 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ldisc_flush_buffer(struct tty_struct *tty) 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tty_ldisc *ld = tty_ldisc_ref(tty); 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ld) { 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ld->flush_buffer) 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ld->flush_buffer(tty); 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_ldisc_deref(ld); 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ldisc_receive_buf(struct tty_struct *tty, 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const __u8 *data, char *flags, int count) 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tty_ldisc *ld; 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!tty) 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ld = tty_ldisc_ref(tty); 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ld) { 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ld->receive_buf) 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ld->receive_buf(tty, data, flags, count); 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_ldisc_deref(ld); 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic dev_link_t *mgslpc_attach(void) 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info; 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_link_t *link; 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds client_reg_t client_reg; 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("mgslpc_attach\n"); 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info = (MGSLPC_INFO *)kmalloc(sizeof(MGSLPC_INFO), GFP_KERNEL); 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info) { 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("Error can't allocate device instance data\n"); 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(info, 0, sizeof(MGSLPC_INFO)); 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->magic = MGSLPC_MAGIC; 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INIT_WORK(&info->task, bh_handler, info); 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->max_frame_size = 4096; 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->close_delay = 5*HZ/10; 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->closing_wait = 30*HZ; 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_waitqueue_head(&info->open_wait); 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_waitqueue_head(&info->close_wait); 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_waitqueue_head(&info->status_event_wait_q); 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_waitqueue_head(&info->event_wait_q); 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&info->lock); 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&info->netlock); 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(&info->params,&default_params,sizeof(MGSL_PARAMS)); 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->idle_mode = HDLC_TXIDLE_FLAGS; 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->imra_value = 0xffff; 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->imrb_value = 0xffff; 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->pim_value = 0xff; 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link = &info->link; 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->priv = info; 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Initialize the dev_link_t structure */ 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Interrupt setup */ 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->irq.Handler = NULL; 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->conf.Attributes = 0; 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->conf.Vcc = 50; 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->conf.IntType = INT_MEMORY_AND_IO; 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Register with Card Services */ 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->next = dev_list; 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_list = link; 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds client_reg.dev_info = &dev_info; 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds client_reg.EventMask = 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds client_reg.event_handler = &mgslpc_event; 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds client_reg.Version = 0x0210; 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds client_reg.event_callback_args.client_data = link; 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = pcmcia_register_client(&link->handle, &client_reg); 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret != CS_SUCCESS) { 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cs_error(link->handle, RegisterClient, ret); 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_detach(link); 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_add_device(info); 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return link; 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Card has been inserted. 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CS_CHECK(fn, ret) \ 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdo { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mgslpc_config(dev_link_t *link) 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds client_handle_t handle = link->handle; 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = link->priv; 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tuple_t tuple; 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cisparse_t parse; 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int last_fn, last_ret; 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char buf[64]; 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds config_info_t conf; 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cistpl_cftable_entry_t dflt = { 0 }; 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cistpl_cftable_entry_t *cfg; 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("mgslpc_config(0x%p)\n", link); 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* read CONFIG tuple to find its configuration registers */ 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tuple.DesiredTuple = CISTPL_CONFIG; 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tuple.Attributes = 0; 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tuple.TupleData = buf; 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tuple.TupleDataMax = sizeof(buf); 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tuple.TupleOffset = 0; 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->conf.ConfigBase = parse.config.base; 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->conf.Present = parse.config.rmask[0]; 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Configure card */ 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->state |= DEV_CONFIG; 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Look up the current Vcc */ 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf)); 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->conf.Vcc = conf.Vcc; 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* get CIS configuration entry */ 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfg = &(parse.cftable_entry); 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cfg->index == 0) 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cs_failed; 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->conf.ConfigIndex = cfg->index; 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->conf.Attributes |= CONF_ENABLE_IRQ; 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* IO window settings */ 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->io.NumPorts1 = 0; 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(io->flags & CISTPL_IO_8BIT)) 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(io->flags & CISTPL_IO_16BIT)) 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->io.BasePort1 = io->win[0].base; 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->io.NumPorts1 = io->win[0].len; 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CS_CHECK(RequestIO, pcmcia_request_io(link->handle, &link->io)); 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->conf.Attributes = CONF_ENABLE_IRQ; 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->conf.Vcc = 50; 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->conf.IntType = INT_MEMORY_AND_IO; 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->conf.ConfigIndex = 8; 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->conf.Present = PRESENT_OPTION; 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->irq.Attributes |= IRQ_HANDLE_PRESENT; 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->irq.Handler = mgslpc_isr; 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->irq.Instance = info; 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->io_base = link->io.BasePort1; 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->irq_level = link->irq.AssignedIRQ; 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* add to linked list of devices */ 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sprintf(info->node.dev_name, "mgslpc0"); 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->node.major = info->node.minor = 0; 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->dev = &info->node; 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "%s: index 0x%02x:", 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->node.dev_name, link->conf.ConfigIndex); 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (link->conf.Attributes & CONF_ENABLE_IRQ) 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(", irq %d", link->irq.AssignedIRQ); 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (link->io.NumPorts1) 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(", io 0x%04x-0x%04x", link->io.BasePort1, 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->io.BasePort1+link->io.NumPorts1-1); 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("\n"); 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->state &= ~DEV_CONFIG_PENDING; 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscs_failed: 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cs_error(link->handle, last_fn, last_ret); 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_release((u_long)link); 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Card has been removed. 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Unregister device and release PCMCIA configuration. 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If device is open, postpone until it is closed. 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mgslpc_release(u_long arg) 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_link_t *link = (dev_link_t *)arg; 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("mgslpc_release(0x%p)\n", link); 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Unlink the device chain */ 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->dev = NULL; 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->state &= ~DEV_CONFIG; 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcmcia_release_configuration(link->handle); 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (link->io.NumPorts1) 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcmcia_release_io(link->handle, &link->io); 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (link->irq.AssignedIRQ) 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcmcia_release_irq(link->handle, &link->irq); 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (link->state & DEV_STALE_LINK) 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_detach(link); 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mgslpc_detach(dev_link_t *link) 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_link_t **linkp; 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("mgslpc_detach(0x%p)\n", link); 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* find device */ 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (*linkp == link) break; 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (*linkp == NULL) 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (link->state & DEV_CONFIG) { 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* device is configured/active, mark it so when 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * release() is called a proper detach() occurs. 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG "synclinkpc: detach postponed, '%s' " 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "still locked\n", link->dev->dev_name); 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->state |= DEV_STALE_LINK; 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Break the link with Card Services */ 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (link->handle) 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcmcia_deregister_client(link->handle); 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Unlink device structure, and free it */ 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *linkp = link->next; 7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_remove_device((MGSLPC_INFO *)link->priv); 7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mgslpc_event(event_t event, int priority, 7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds event_callback_args_t *args) 7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_link_t *link = args->client_data; 7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = link->priv; 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("mgslpc_event(0x%06x)\n", event); 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (event) { 7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CS_EVENT_CARD_REMOVAL: 7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->state &= ~DEV_PRESENT; 7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (link->state & DEV_CONFIG) { 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((MGSLPC_INFO *)link->priv)->stop = 1; 7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_release((u_long)link); 7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CS_EVENT_CARD_INSERTION: 8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; 8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_config(link); 8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CS_EVENT_PM_SUSPEND: 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->state |= DEV_SUSPEND; 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Fall through... */ 8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CS_EVENT_RESET_PHYSICAL: 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Mark the device as stopped, to block IO until later */ 8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->stop = 1; 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (link->state & DEV_CONFIG) 8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcmcia_release_configuration(link->handle); 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CS_EVENT_PM_RESUME: 8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->state &= ~DEV_SUSPEND; 8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Fall through... */ 8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CS_EVENT_CARD_RESET: 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (link->state & DEV_CONFIG) 8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcmcia_request_configuration(link->handle, &link->conf); 8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->stop = 0; 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int mgslpc_paranoia_check(MGSLPC_INFO *info, 8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *name, const char *routine) 8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef MGSLPC_PARANOIA_CHECK 8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds static const char *badmagic = 8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Warning: bad magic number for mgsl struct (%s) in %s\n"; 8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds static const char *badinfo = 8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Warning: null mgslpc_info for (%s) in %s\n"; 8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info) { 8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(badinfo, name, routine); 8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->magic != MGSLPC_MAGIC) { 8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(badmagic, name, routine); 8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info) 8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CMD_RXFIFO BIT7 // release current rx FIFO 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CMD_RXRESET BIT6 // receiver reset 8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CMD_RXFIFO_READ BIT5 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CMD_START_TIMER BIT4 8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CMD_TXFIFO BIT3 // release current tx FIFO 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CMD_TXEOM BIT1 // transmit end message 8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CMD_TXRESET BIT0 // transmit reset 8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic BOOLEAN wait_command_complete(MGSLPC_INFO *info, unsigned char channel) 8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i = 0; 8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* wait for command completion */ 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (read_reg(info, (unsigned char)(channel+STAR)) & BIT2) { 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(1); 8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i++ == 1000) 8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return FALSE; 8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return TRUE; 8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void issue_command(MGSLPC_INFO *info, unsigned char channel, unsigned char cmd) 8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wait_command_complete(info, channel); 8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, (unsigned char) (channel + CMDR), cmd); 8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void tx_pause(struct tty_struct *tty) 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mgslpc_paranoia_check(info, tty->name, "tx_pause")) 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("tx_pause(%s)\n",info->device_name); 8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->lock,flags); 8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->tx_enabled) 8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_stop(info); 8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock,flags); 8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void tx_release(struct tty_struct *tty) 8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; 8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mgslpc_paranoia_check(info, tty->name, "tx_release")) 8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("tx_release(%s)\n",info->device_name); 9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->lock,flags); 9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info->tx_enabled) 9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_start(info); 9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock,flags); 9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Return next bottom half action to perform. 9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * or 0 if nothing to do. 9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int bh_action(MGSLPC_INFO *info) 9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc = 0; 9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->lock,flags); 9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->pending_bh & BH_RECEIVE) { 9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->pending_bh &= ~BH_RECEIVE; 9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = BH_RECEIVE; 9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (info->pending_bh & BH_TRANSMIT) { 9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->pending_bh &= ~BH_TRANSMIT; 9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = BH_TRANSMIT; 9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (info->pending_bh & BH_STATUS) { 9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->pending_bh &= ~BH_STATUS; 9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = BH_STATUS; 9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!rc) { 9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Mark BH routine as complete */ 9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->bh_running = 0; 9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->bh_requested = 0; 9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock,flags); 9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid bh_handler(void* Context) 9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = (MGSLPC_INFO*)Context; 9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int action; 9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info) 9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_BH) 9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk( "%s(%d):bh_handler(%s) entry\n", 9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__,info->device_name); 9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->bh_running = 1; 9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while((action = bh_action(info)) != 0) { 9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Process work item */ 9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ( debug_level >= DEBUG_LEVEL_BH ) 9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk( "%s(%d):bh_handler() work item action=%d\n", 9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__,action); 9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (action) { 9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case BH_RECEIVE: 9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while(rx_get_frame(info)); 9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case BH_TRANSMIT: 9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh_transmit(info); 9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case BH_STATUS: 9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh_status(info); 9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* unknown work item ID */ 9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("Unknown work item ID=%08X!\n", action); 9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_BH) 9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk( "%s(%d):bh_handler(%s) exit\n", 9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__,info->device_name); 9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid bh_transmit(MGSLPC_INFO *info) 9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tty_struct *tty = info->tty; 9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_BH) 9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("bh_transmit() entry on %s\n", info->device_name); 9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tty) { 9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_wakeup(tty); 9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up_interruptible(&tty->write_wait); 9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid bh_status(MGSLPC_INFO *info) 9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->ri_chkcount = 0; 9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->dsr_chkcount = 0; 9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->dcd_chkcount = 0; 10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->cts_chkcount = 0; 10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* eom: non-zero = end of frame */ 10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rx_ready_hdlc(MGSLPC_INFO *info, int eom) 10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char data[2]; 10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char fifo_count, read_count, i; 10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds RXBUF *buf = (RXBUF*)(info->rx_buf + (info->rx_put * info->rx_buf_size)); 10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_ISR) 10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):rx_ready_hdlc(eom=%d)\n",__FILE__,__LINE__,eom); 10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info->rx_enabled) 10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->rx_frame_count >= info->rx_buf_count) { 10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* no more free buffers */ 10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds issue_command(info, CHA, CMD_RXRESET); 10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->pending_bh |= BH_RECEIVE; 10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->rx_overflow = 1; 10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->icount.buf_overrun++; 10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (eom) { 10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* end of frame, get FIFO count from RBCL register */ 10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(fifo_count = (unsigned char)(read_reg(info, CHA+RBCL) & 0x1f))) 10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fifo_count = 32; 10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fifo_count = 32; 10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fifo_count == 1) { 10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read_count = 1; 10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data[0] = read_reg(info, CHA + RXFIFO); 10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read_count = 2; 10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *((unsigned short *) data) = read_reg16(info, CHA + RXFIFO); 10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fifo_count -= read_count; 10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!fifo_count && eom) 10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf->status = data[--read_count]; 10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < read_count; i++) { 10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (buf->count >= info->max_frame_size) { 10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* frame too large, reset receiver and reset current buffer */ 10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds issue_command(info, CHA, CMD_RXRESET); 10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf->count = 0; 10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *(buf->data + buf->count) = data[i]; 10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf->count++; 10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (fifo_count); 10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (eom) { 10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->pending_bh |= BH_RECEIVE; 10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->rx_frame_count++; 10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->rx_put++; 10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->rx_put >= info->rx_buf_count) 10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->rx_put = 0; 10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds issue_command(info, CHA, CMD_RXFIFO); 10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rx_ready_async(MGSLPC_INFO *info, int tcd) 10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char data, status; 10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int fifo_count; 10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tty_struct *tty = info->tty; 10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mgsl_icount *icount = &info->icount; 10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tcd) { 10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* early termination, get FIFO count from RBCL register */ 10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fifo_count = (unsigned char)(read_reg(info, CHA+RBCL) & 0x1f); 10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Zero fifo count could mean 0 or 32 bytes available. 10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If BIT5 of STAR is set then at least 1 byte is available. 10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!fifo_count && (read_reg(info,CHA+STAR) & BIT5)) 10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fifo_count = 32; 10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fifo_count = 32; 10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Flush received async data to receive data buffer. */ 10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (fifo_count) { 10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data = read_reg(info, CHA + RXFIFO); 10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = read_reg(info, CHA + RXFIFO); 10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fifo_count -= 2; 10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tty->flip.count >= TTY_FLIPBUF_SIZE) 10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *tty->flip.char_buf_ptr = data; 10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds icount->rx++; 10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *tty->flip.flag_buf_ptr = 0; 10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // if no frameing/crc error then save data 11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // BIT7:parity error 11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // BIT6:framing error 11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & (BIT7 + BIT6)) { 11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & BIT7) 11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds icount->parity++; 11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds icount->frame++; 11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* discard char if tty control flags say so */ 11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & info->ignore_status_mask) 11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status &= info->read_status_mask; 11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & BIT7) 11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *tty->flip.flag_buf_ptr = TTY_PARITY; 11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (status & BIT6) 11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *tty->flip.flag_buf_ptr = TTY_FRAME; 11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty->flip.flag_buf_ptr++; 11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty->flip.char_buf_ptr++; 11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty->flip.count++; 11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds issue_command(info, CHA, CMD_RXFIFO); 11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_ISR) { 11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):rx_ready_async count=%d\n", 11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__,tty->flip.count); 11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):rx=%d brk=%d parity=%d frame=%d overrun=%d\n", 11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__,icount->rx,icount->brk, 11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds icount->parity,icount->frame,icount->overrun); 11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tty->flip.count) 11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_flip_buffer_push(tty); 11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void tx_done(MGSLPC_INFO *info) 11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info->tx_active) 11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_active = 0; 11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_aborting = 0; 11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.mode == MGSL_MODE_ASYNC) 11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_count = info->tx_put = info->tx_get = 0; 11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds del_timer(&info->tx_timer); 11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->drop_rts_on_tx_done) { 11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds get_signals(info); 11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->serial_signals & SerialSignal_RTS) { 11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->serial_signals &= ~SerialSignal_RTS; 11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_signals(info); 11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->drop_rts_on_tx_done = 0; 11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_HDLC 11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->netcount) 11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdlcdev_tx_done(info); 11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->tty->stopped || info->tty->hw_stopped) { 11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_stop(info); 11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->pending_bh |= BH_TRANSMIT; 11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void tx_ready(MGSLPC_INFO *info) 11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char fifo_count = 32; 11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int c; 11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_ISR) 11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):tx_ready(%s)\n", __FILE__,__LINE__,info->device_name); 11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.mode == MGSL_MODE_HDLC) { 11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info->tx_active) 11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->tty->stopped || info->tty->hw_stopped) { 11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_stop(info); 11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info->tx_count) 11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_active = 0; 11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info->tx_count) 11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (info->tx_count && fifo_count) { 12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds c = min(2, min_t(int, fifo_count, min(info->tx_count, TXBUFSIZE - info->tx_get))); 12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (c == 1) { 12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + TXFIFO, *(info->tx_buf + info->tx_get)); 12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg16(info, CHA + TXFIFO, 12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *((unsigned short*)(info->tx_buf + info->tx_get))); 12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_count -= c; 12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_get = (info->tx_get + c) & (TXBUFSIZE - 1); 12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fifo_count -= c; 12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.mode == MGSL_MODE_ASYNC) { 12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->tx_count < WAKEUP_CHARS) 12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->pending_bh |= BH_TRANSMIT; 12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds issue_command(info, CHA, CMD_TXFIFO); 12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->tx_count) 12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds issue_command(info, CHA, CMD_TXFIFO); 12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds issue_command(info, CHA, CMD_TXFIFO + CMD_TXEOM); 12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void cts_change(MGSLPC_INFO *info) 12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds get_signals(info); 12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((info->cts_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) 12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq_disable(info, CHB, IRQ_CTS); 12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->icount.cts++; 12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->serial_signals & SerialSignal_CTS) 12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->input_signal_events.cts_up++; 12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->input_signal_events.cts_down++; 12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up_interruptible(&info->status_event_wait_q); 12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up_interruptible(&info->event_wait_q); 12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->flags & ASYNC_CTS_FLOW) { 12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->tty->hw_stopped) { 12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->serial_signals & SerialSignal_CTS) { 12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_ISR) 12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("CTS tx start..."); 12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->tty) 12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tty->hw_stopped = 0; 12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_start(info); 12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->pending_bh |= BH_TRANSMIT; 12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(info->serial_signals & SerialSignal_CTS)) { 12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_ISR) 12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("CTS tx stop..."); 12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->tty) 12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tty->hw_stopped = 1; 12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_stop(info); 12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->pending_bh |= BH_STATUS; 12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void dcd_change(MGSLPC_INFO *info) 12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds get_signals(info); 12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((info->dcd_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) 12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq_disable(info, CHB, IRQ_DCD); 12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->icount.dcd++; 12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->serial_signals & SerialSignal_DCD) { 12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->input_signal_events.dcd_up++; 12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->input_signal_events.dcd_down++; 12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_HDLC 12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->netcount) 12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdlc_set_carrier(info->serial_signals & SerialSignal_DCD, info->netdev); 12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up_interruptible(&info->status_event_wait_q); 12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up_interruptible(&info->event_wait_q); 12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->flags & ASYNC_CHECK_CD) { 12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_ISR) 12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s CD now %s...", info->device_name, 12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (info->serial_signals & SerialSignal_DCD) ? "on" : "off"); 12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->serial_signals & SerialSignal_DCD) 12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up_interruptible(&info->open_wait); 12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_ISR) 12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("doing serial hangup..."); 12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->tty) 12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_hangup(info->tty); 12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->pending_bh |= BH_STATUS; 12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void dsr_change(MGSLPC_INFO *info) 12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds get_signals(info); 13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((info->dsr_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) 13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port_irq_disable(info, PVR_DSR); 13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->icount.dsr++; 13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->serial_signals & SerialSignal_DSR) 13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->input_signal_events.dsr_up++; 13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->input_signal_events.dsr_down++; 13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up_interruptible(&info->status_event_wait_q); 13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up_interruptible(&info->event_wait_q); 13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->pending_bh |= BH_STATUS; 13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ri_change(MGSLPC_INFO *info) 13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds get_signals(info); 13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((info->ri_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) 13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port_irq_disable(info, PVR_RI); 13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->icount.rng++; 13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->serial_signals & SerialSignal_RI) 13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->input_signal_events.ri_up++; 13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->input_signal_events.ri_down++; 13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up_interruptible(&info->status_event_wait_q); 13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up_interruptible(&info->event_wait_q); 13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->pending_bh |= BH_STATUS; 13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Interrupt service routine entry point. 13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Arguments: 13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * irq interrupt number that caused interrupt 13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dev_id device ID supplied during interrupt registration 13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * regs interrupted processor context 13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic irqreturn_t mgslpc_isr(int irq, void *dev_id, struct pt_regs * regs) 13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO * info = (MGSLPC_INFO *)dev_id; 13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short isr; 13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char gis, pis; 13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int count=0; 13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_ISR) 13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("mgslpc_isr(%d) entry.\n", irq); 13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info) 13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_NONE; 13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(info->link.state & DEV_CONFIG)) 13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_HANDLED; 13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&info->lock); 13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while ((gis = read_reg(info, CHA + GIS))) { 13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_ISR) 13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("mgslpc_isr %s gis=%04X\n", info->device_name,gis); 13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((gis & 0x70) || count > 1000) { 13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("synclink_cs:hardware failed or ejected\n"); 13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count++; 13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (gis & (BIT1 + BIT0)) { 13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds isr = read_reg16(info, CHB + ISR); 13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (isr & IRQ_DCD) 13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dcd_change(info); 13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (isr & IRQ_CTS) 13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cts_change(info); 13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (gis & (BIT3 + BIT2)) 13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds isr = read_reg16(info, CHA + ISR); 13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (isr & IRQ_TIMER) { 13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->irq_occurred = 1; 13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq_disable(info, CHA, IRQ_TIMER); 13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* receive IRQs */ 13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (isr & IRQ_EXITHUNT) { 13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->icount.exithunt++; 13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up_interruptible(&info->event_wait_q); 13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (isr & IRQ_BREAK_ON) { 13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->icount.brk++; 13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->flags & ASYNC_SAK) 13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do_SAK(info->tty); 13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (isr & IRQ_RXTIME) { 13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds issue_command(info, CHA, CMD_RXFIFO_READ); 13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (isr & (IRQ_RXEOM + IRQ_RXFIFO)) { 13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.mode == MGSL_MODE_HDLC) 13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_ready_hdlc(info, isr & IRQ_RXEOM); 13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_ready_async(info, isr & IRQ_RXEOM); 13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* transmit IRQs */ 13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (isr & IRQ_UNDERRUN) { 13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->tx_aborting) 14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->icount.txabort++; 14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->icount.txunder++; 14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_done(info); 14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (isr & IRQ_ALLSENT) { 14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->icount.txok++; 14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_done(info); 14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (isr & IRQ_TXFIFO) 14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_ready(info); 14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (gis & BIT7) { 14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pis = read_reg(info, CHA + PIS); 14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pis & BIT1) 14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dsr_change(info); 14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pis & BIT2) 14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ri_change(info); 14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Request bottom half processing if there's something 14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for it to do and the bh is not already running 14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->pending_bh && !info->bh_running && !info->bh_requested) { 14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ( debug_level >= DEBUG_LEVEL_ISR ) 14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):%s queueing bh task.\n", 14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__,info->device_name); 14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds schedule_work(&info->task); 14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->bh_requested = 1; 14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&info->lock); 14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_ISR) 14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):mgslpc_isr(%d)exit.\n", 14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__,irq); 14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_HANDLED; 14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Initialize and start device. 14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int startup(MGSLPC_INFO * info) 14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval = 0; 14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):startup(%s)\n",__FILE__,__LINE__,info->device_name); 14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->flags & ASYNC_INITIALIZED) 14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info->tx_buf) { 14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* allocate a page of memory for a transmit buffer */ 14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL); 14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info->tx_buf) { 14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR"%s(%d):%s can't allocate transmit buffer\n", 14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__,info->device_name); 14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->pending_bh = 0; 14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_timer(&info->tx_timer); 14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_timer.data = (unsigned long)info; 14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_timer.function = tx_timeout; 14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Allocate and claim adapter resources */ 14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = claim_resources(info); 14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* perform existance check and diagnostics */ 14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ( !retval ) 14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = adapter_test(info); 14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ( retval ) { 14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (capable(CAP_SYS_ADMIN) && info->tty) 14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_bit(TTY_IO_ERROR, &info->tty->flags); 14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_resources(info); 14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* program hardware for current parameters */ 14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_change_params(info); 14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->tty) 14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_bit(TTY_IO_ERROR, &info->tty->flags); 14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->flags |= ASYNC_INITIALIZED; 14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Called by mgslpc_close() and mgslpc_hangup() to shutdown hardware 14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void shutdown(MGSLPC_INFO * info) 14981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 15001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(info->flags & ASYNC_INITIALIZED)) 15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):mgslpc_shutdown(%s)\n", 15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__, info->device_name ); 15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* clear status wait queue because status changes */ 15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* can't happen after shutting down the hardware */ 15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up_interruptible(&info->status_event_wait_q); 15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up_interruptible(&info->event_wait_q); 15121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds del_timer(&info->tx_timer); 15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->tx_buf) { 15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_page((unsigned long) info->tx_buf); 15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_buf = NULL; 15181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->lock,flags); 15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_stop(info); 15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_stop(info); 15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* TODO:disable interrupts instead of reset to preserve signal states */ 15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reset_device(info); 15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info->tty || info->tty->termios->c_cflag & HUPCL) { 15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS); 15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_signals(info); 15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock,flags); 15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_resources(info); 15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->tty) 15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_bit(TTY_IO_ERROR, &info->tty->flags); 15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->flags &= ~ASYNC_INITIALIZED; 15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mgslpc_program_hw(MGSLPC_INFO *info) 15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->lock,flags); 15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_stop(info); 15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_stop(info); 15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_count = info->tx_put = info->tx_get = 0; 15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.mode == MGSL_MODE_HDLC || info->netcount) 15541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdlc_mode(info); 15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds async_mode(info); 15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_signals(info); 15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->dcd_chkcount = 0; 15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->cts_chkcount = 0; 15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->ri_chkcount = 0; 15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->dsr_chkcount = 0; 15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq_enable(info, CHB, IRQ_DCD | IRQ_CTS); 15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port_irq_enable(info, (unsigned char) PVR_DSR | PVR_RI); 15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds get_signals(info); 15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->netcount || info->tty->termios->c_cflag & CREAD) 15701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_start(info); 15711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock,flags); 15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Reconfigure adapter based on new parameters 15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mgslpc_change_params(MGSLPC_INFO *info) 15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned cflag; 15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int bits_per_char; 15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info->tty || !info->tty->termios) 15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):mgslpc_change_params(%s)\n", 15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__, info->device_name ); 15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cflag = info->tty->termios->c_cflag; 15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if B0 rate (hangup) specified then negate DTR and RTS */ 15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* otherwise assert DTR and RTS */ 15931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cflag & CBAUD) 15941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR; 15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR); 15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* byte size and parity */ 15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cflag & CSIZE) { 16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CS5: info->params.data_bits = 5; break; 16021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CS6: info->params.data_bits = 6; break; 16031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CS7: info->params.data_bits = 7; break; 16041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CS8: info->params.data_bits = 8; break; 16051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: info->params.data_bits = 7; break; 16061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cflag & CSTOPB) 16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->params.stop_bits = 2; 16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 16111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->params.stop_bits = 1; 16121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->params.parity = ASYNC_PARITY_NONE; 16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cflag & PARENB) { 16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cflag & PARODD) 16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->params.parity = ASYNC_PARITY_ODD; 16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->params.parity = ASYNC_PARITY_EVEN; 16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CMSPAR 16201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cflag & CMSPAR) 16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->params.parity = ASYNC_PARITY_SPACE; 16221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 16231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* calculate number of jiffies to transmit a full 16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * FIFO (32 bytes) at specified data rate 16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bits_per_char = info->params.data_bits + 16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->params.stop_bits + 1; 16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if port data rate is set to 460800 or less then 16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * allow tty settings to override, otherwise keep the 16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * current data rate. 16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.data_rate <= 460800) { 16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->params.data_rate = tty_get_baud_rate(info->tty); 16371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ( info->params.data_rate ) { 16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->timeout = (32*HZ*bits_per_char) / 16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->params.data_rate; 16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->timeout += HZ/50; /* Add .02 seconds of slop */ 16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cflag & CRTSCTS) 16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->flags |= ASYNC_CTS_FLOW; 16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->flags &= ~ASYNC_CTS_FLOW; 16491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cflag & CLOCAL) 16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->flags &= ~ASYNC_CHECK_CD; 16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->flags |= ASYNC_CHECK_CD; 16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* process tty input control flags */ 16561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->read_status_mask = 0; 16581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (I_INPCK(info->tty)) 16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->read_status_mask |= BIT7 | BIT6; 16601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (I_IGNPAR(info->tty)) 16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->ignore_status_mask |= BIT7 | BIT6; 16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_program_hw(info); 16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Add a character to the transmit buffer 16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mgslpc_put_char(struct tty_struct *tty, unsigned char ch) 16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; 16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) { 16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk( "%s(%d):mgslpc_put_char(%d) on %s\n", 16751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__,ch,info->device_name); 16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mgslpc_paranoia_check(info, tty->name, "mgslpc_put_char")) 16791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 16801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!tty || !info->tx_buf) 16821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 16831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->lock,flags); 16851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.mode == MGSL_MODE_ASYNC || !info->tx_active) { 16871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->tx_count < TXBUFSIZE - 1) { 16881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_buf[info->tx_put++] = ch; 16891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_put &= TXBUFSIZE-1; 16901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_count++; 16911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock,flags); 16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Enable transmitter so remaining characters in the 16981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * transmit buffer are sent. 16991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mgslpc_flush_chars(struct tty_struct *tty) 17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; 17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 17061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk( "%s(%d):mgslpc_flush_chars() entry on %s tx_count=%d\n", 17071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__,info->device_name,info->tx_count); 17081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mgslpc_paranoia_check(info, tty->name, "mgslpc_flush_chars")) 17101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 17111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->tx_count <= 0 || tty->stopped || 17131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty->hw_stopped || !info->tx_buf) 17141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 17151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 17171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk( "%s(%d):mgslpc_flush_chars() entry on %s starting transmitter\n", 17181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__,info->device_name); 17191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->lock,flags); 17211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info->tx_active) 17221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_start(info); 17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock,flags); 17241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Send a block of data 17271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Arguments: 17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 17301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * tty pointer to tty information structure 17311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * buf pointer to buffer containing send data 17321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * count size of send data in bytes 17331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 17341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns: number of characters written 17351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 17361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mgslpc_write(struct tty_struct * tty, 17371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const unsigned char *buf, int count) 17381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int c, ret = 0; 17401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; 17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 17421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 17441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk( "%s(%d):mgslpc_write(%s) count=%d\n", 17451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__,info->device_name,count); 17461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mgslpc_paranoia_check(info, tty->name, "mgslpc_write") || 17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !tty || !info->tx_buf) 17491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 17501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.mode == MGSL_MODE_HDLC) { 17521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (count > TXBUFSIZE) { 17531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EIO; 17541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 17551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->tx_active) 17571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 17581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (info->tx_count) 17591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto start; 17601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (;;) { 17631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds c = min(count, 17641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds min(TXBUFSIZE - info->tx_count - 1, 17651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds TXBUFSIZE - info->tx_put)); 17661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (c <= 0) 17671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 17681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(info->tx_buf + info->tx_put, buf, c); 17701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->lock,flags); 17721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_put = (info->tx_put + c) & (TXBUFSIZE-1); 17731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_count += c; 17741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock,flags); 17751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf += c; 17771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count -= c; 17781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret += c; 17791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstart: 17811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->tx_count && !tty->stopped && !tty->hw_stopped) { 17821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->lock,flags); 17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info->tx_active) 17841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_start(info); 17851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock,flags); 17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscleanup: 17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 17891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk( "%s(%d):mgslpc_write(%s) returning=%d\n", 17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__,info->device_name,ret); 17911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 17921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Return the count of free bytes in transmit buffer 17951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 17961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mgslpc_write_room(struct tty_struct *tty) 17971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; 17991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 18001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mgslpc_paranoia_check(info, tty->name, "mgslpc_write_room")) 18021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 18031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.mode == MGSL_MODE_HDLC) { 18051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* HDLC (frame oriented) mode */ 18061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->tx_active) 18071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 18081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 18091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return HDLC_MAX_FRAME_SIZE; 18101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 18111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = TXBUFSIZE - info->tx_count - 1; 18121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret < 0) 18131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = 0; 18141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 18171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):mgslpc_write_room(%s)=%d\n", 18181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__, info->device_name, ret); 18191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 18201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Return the count of bytes in transmit buffer 18231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 18241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mgslpc_chars_in_buffer(struct tty_struct *tty) 18251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 18261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; 18271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 18281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 18301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):mgslpc_chars_in_buffer(%s)\n", 18311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__, info->device_name ); 18321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mgslpc_paranoia_check(info, tty->name, "mgslpc_chars_in_buffer")) 18341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 18351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.mode == MGSL_MODE_HDLC) 18371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = info->tx_active ? info->max_frame_size : 0; 18381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 18391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = info->tx_count; 18401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 18421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):mgslpc_chars_in_buffer(%s)=%d\n", 18431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__, info->device_name, rc); 18441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 18461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Discard all data in the send buffer 18491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 18501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mgslpc_flush_buffer(struct tty_struct *tty) 18511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 18521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; 18531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 18541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 18561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):mgslpc_flush_buffer(%s) entry\n", 18571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__, info->device_name ); 18581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mgslpc_paranoia_check(info, tty->name, "mgslpc_flush_buffer")) 18601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 18611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->lock,flags); 18631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_count = info->tx_put = info->tx_get = 0; 18641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds del_timer(&info->tx_timer); 18651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock,flags); 18661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up_interruptible(&tty->write_wait); 18681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_wakeup(tty); 18691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Send a high-priority XON/XOFF character 18721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 18731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mgslpc_send_xchar(struct tty_struct *tty, char ch) 18741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 18751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; 18761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 18771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 18791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):mgslpc_send_xchar(%s,%d)\n", 18801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__, info->device_name, ch ); 18811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mgslpc_paranoia_check(info, tty->name, "mgslpc_send_xchar")) 18831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 18841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->x_char = ch; 18861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ch) { 18871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->lock,flags); 18881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info->tx_enabled) 18891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_start(info); 18901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock,flags); 18911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Signal remote device to throttle send data (our receive data) 18951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 18961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mgslpc_throttle(struct tty_struct * tty) 18971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 18981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; 18991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 19001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 19021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):mgslpc_throttle(%s) entry\n", 19031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__, info->device_name ); 19041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mgslpc_paranoia_check(info, tty->name, "mgslpc_throttle")) 19061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 19071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (I_IXOFF(tty)) 19091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_send_xchar(tty, STOP_CHAR(tty)); 19101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tty->termios->c_cflag & CRTSCTS) { 19121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->lock,flags); 19131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->serial_signals &= ~SerialSignal_RTS; 19141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_signals(info); 19151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock,flags); 19161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 19181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Signal remote device to stop throttling send data (our receive data) 19201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 19211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mgslpc_unthrottle(struct tty_struct * tty) 19221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 19231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; 19241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 19251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 19271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):mgslpc_unthrottle(%s) entry\n", 19281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__, info->device_name ); 19291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mgslpc_paranoia_check(info, tty->name, "mgslpc_unthrottle")) 19311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 19321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (I_IXOFF(tty)) { 19341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->x_char) 19351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->x_char = 0; 19361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 19371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_send_xchar(tty, START_CHAR(tty)); 19381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tty->termios->c_cflag & CRTSCTS) { 19411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->lock,flags); 19421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->serial_signals |= SerialSignal_RTS; 19431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_signals(info); 19441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock,flags); 19451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 19471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* get the current serial statistics 19491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 19501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int get_stats(MGSLPC_INFO * info, struct mgsl_icount __user *user_icount) 19511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 19521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 19531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 19541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("get_params(%s)\n", info->device_name); 19551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds COPY_TO_USER(err,user_icount, &info->icount, sizeof(struct mgsl_icount)); 19561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 19571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 19581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 19591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 19601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* get the current serial parameters 19621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 19631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int get_params(MGSLPC_INFO * info, MGSL_PARAMS __user *user_params) 19641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 19651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 19661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 19671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("get_params(%s)\n", info->device_name); 19681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds COPY_TO_USER(err,user_params, &info->params, sizeof(MGSL_PARAMS)); 19691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 19701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 19711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 19721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 19731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* set the serial parameters 19751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 19761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Arguments: 19771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 19781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * info pointer to device instance data 19791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * new_params user buffer containing new serial params 19801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 19811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns: 0 if success, otherwise error code 19821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 19831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int set_params(MGSLPC_INFO * info, MGSL_PARAMS __user *new_params) 19841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 19851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 19861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSL_PARAMS tmp_params; 19871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 19881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 19901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):set_params %s\n", __FILE__,__LINE__, 19911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->device_name ); 19921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds COPY_FROM_USER(err,&tmp_params, new_params, sizeof(MGSL_PARAMS)); 19931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) { 19941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ( debug_level >= DEBUG_LEVEL_INFO ) 19951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk( "%s(%d):set_params(%s) user buffer copy failed\n", 19961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__,info->device_name); 19971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 19981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->lock,flags); 20011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(&info->params,&tmp_params,sizeof(MGSL_PARAMS)); 20021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock,flags); 20031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_change_params(info); 20051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 20071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 20081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int get_txidle(MGSLPC_INFO * info, int __user *idle_mode) 20101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 20111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 20121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 20131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("get_txidle(%s)=%d\n", info->device_name, info->idle_mode); 20141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds COPY_TO_USER(err,idle_mode, &info->idle_mode, sizeof(int)); 20151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 20161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 20171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 20181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 20191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int set_txidle(MGSLPC_INFO * info, int idle_mode) 20211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 20221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 20231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 20241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("set_txidle(%s,%d)\n", info->device_name, idle_mode); 20251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->lock,flags); 20261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->idle_mode = idle_mode; 20271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_set_idle(info); 20281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock,flags); 20291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 20301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 20311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int get_interface(MGSLPC_INFO * info, int __user *if_mode) 20331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 20341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 20351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 20361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("get_interface(%s)=%d\n", info->device_name, info->if_mode); 20371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds COPY_TO_USER(err,if_mode, &info->if_mode, sizeof(int)); 20381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 20391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 20401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 20411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 20421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int set_interface(MGSLPC_INFO * info, int if_mode) 20441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 20451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 20461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char val; 20471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 20481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("set_interface(%s,%d)\n", info->device_name, if_mode); 20491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->lock,flags); 20501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->if_mode = if_mode; 20511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = read_reg(info, PVR) & 0x0f; 20531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (info->if_mode) 20541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 20551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MGSL_INTERFACE_RS232: val |= PVR_RS232; break; 20561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MGSL_INTERFACE_V35: val |= PVR_V35; break; 20571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MGSL_INTERFACE_RS422: val |= PVR_RS422; break; 20581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, PVR, val); 20601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock,flags); 20621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 20631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 20641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int set_txenable(MGSLPC_INFO * info, int enable) 20661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 20671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 20681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 20701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("set_txenable(%s,%d)\n", info->device_name, enable); 20711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->lock,flags); 20731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (enable) { 20741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info->tx_enabled) 20751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_start(info); 20761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 20771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->tx_enabled) 20781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_stop(info); 20791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock,flags); 20811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 20821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 20831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tx_abort(MGSLPC_INFO * info) 20851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 20861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 20871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 20891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("tx_abort(%s)\n", info->device_name); 20901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->lock,flags); 20921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->tx_active && info->tx_count && 20931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->params.mode == MGSL_MODE_HDLC) { 20941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* clear data count so FIFO is not filled on next IRQ. 20951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This results in underrun and abort transmission. 20961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 20971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_count = info->tx_put = info->tx_get = 0; 20981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_aborting = TRUE; 20991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock,flags); 21011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 21021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 21031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int set_rxenable(MGSLPC_INFO * info, int enable) 21051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 21061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 21071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 21091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("set_rxenable(%s,%d)\n", info->device_name, enable); 21101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->lock,flags); 21121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (enable) { 21131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info->rx_enabled) 21141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_start(info); 21151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 21161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->rx_enabled) 21171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_stop(info); 21181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock,flags); 21201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 21211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 21221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* wait for specified event to occur 21241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 21251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Arguments: info pointer to device instance data 21261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * mask pointer to bitmask of events to wait for 21271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Return Value: 0 if successful and bit mask updated with 21281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of events triggerred, 21291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * otherwise error code 21301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 21311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int wait_events(MGSLPC_INFO * info, int __user *mask_ptr) 21321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 21331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 21341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int s; 21351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc=0; 21361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mgsl_icount cprev, cnow; 21371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int events; 21381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int mask; 21391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct _input_signal_events oldsigs, newsigs; 21401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DECLARE_WAITQUEUE(wait, current); 21411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds COPY_FROM_USER(rc,&mask, mask_ptr, sizeof(int)); 21431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc) 21441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 21451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 21471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("wait_events(%s,%d)\n", info->device_name, mask); 21481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->lock,flags); 21501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* return immediately if state matches requested events */ 21521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds get_signals(info); 21531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s = info->serial_signals; 21541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds events = mask & 21551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ( ((s & SerialSignal_DSR) ? MgslEvent_DsrActive:MgslEvent_DsrInactive) + 21561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((s & SerialSignal_DCD) ? MgslEvent_DcdActive:MgslEvent_DcdInactive) + 21571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((s & SerialSignal_CTS) ? MgslEvent_CtsActive:MgslEvent_CtsInactive) + 21581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((s & SerialSignal_RI) ? MgslEvent_RiActive :MgslEvent_RiInactive) ); 21591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (events) { 21601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock,flags); 21611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 21621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* save current irq counts */ 21651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cprev = info->icount; 21661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds oldsigs = info->input_signal_events; 21671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((info->params.mode == MGSL_MODE_HDLC) && 21691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (mask & MgslEvent_ExitHuntMode)) 21701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq_enable(info, CHA, IRQ_EXITHUNT); 21711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_current_state(TASK_INTERRUPTIBLE); 21731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds add_wait_queue(&info->event_wait_q, &wait); 21741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock,flags); 21761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for(;;) { 21791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds schedule(); 21801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (signal_pending(current)) { 21811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -ERESTARTSYS; 21821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 21831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* get current irq counts */ 21861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->lock,flags); 21871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cnow = info->icount; 21881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newsigs = info->input_signal_events; 21891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_current_state(TASK_INTERRUPTIBLE); 21901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock,flags); 21911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if no change, wait aborted for some reason */ 21931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (newsigs.dsr_up == oldsigs.dsr_up && 21941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newsigs.dsr_down == oldsigs.dsr_down && 21951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newsigs.dcd_up == oldsigs.dcd_up && 21961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newsigs.dcd_down == oldsigs.dcd_down && 21971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newsigs.cts_up == oldsigs.cts_up && 21981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newsigs.cts_down == oldsigs.cts_down && 21991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newsigs.ri_up == oldsigs.ri_up && 22001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newsigs.ri_down == oldsigs.ri_down && 22011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cnow.exithunt == cprev.exithunt && 22021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cnow.rxidle == cprev.rxidle) { 22031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EIO; 22041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 22051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds events = mask & 22081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ( (newsigs.dsr_up != oldsigs.dsr_up ? MgslEvent_DsrActive:0) + 22091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (newsigs.dsr_down != oldsigs.dsr_down ? MgslEvent_DsrInactive:0) + 22101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (newsigs.dcd_up != oldsigs.dcd_up ? MgslEvent_DcdActive:0) + 22111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (newsigs.dcd_down != oldsigs.dcd_down ? MgslEvent_DcdInactive:0) + 22121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (newsigs.cts_up != oldsigs.cts_up ? MgslEvent_CtsActive:0) + 22131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (newsigs.cts_down != oldsigs.cts_down ? MgslEvent_CtsInactive:0) + 22141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (newsigs.ri_up != oldsigs.ri_up ? MgslEvent_RiActive:0) + 22151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (newsigs.ri_down != oldsigs.ri_down ? MgslEvent_RiInactive:0) + 22161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (cnow.exithunt != cprev.exithunt ? MgslEvent_ExitHuntMode:0) + 22171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (cnow.rxidle != cprev.rxidle ? MgslEvent_IdleReceived:0) ); 22181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (events) 22191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 22201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cprev = cnow; 22221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds oldsigs = newsigs; 22231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds remove_wait_queue(&info->event_wait_q, &wait); 22261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_current_state(TASK_RUNNING); 22271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mask & MgslEvent_ExitHuntMode) { 22291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->lock,flags); 22301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!waitqueue_active(&info->event_wait_q)) 22311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq_disable(info, CHA, IRQ_EXITHUNT); 22321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock,flags); 22331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit: 22351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc == 0) 22361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PUT_USER(rc, events, mask_ptr); 22371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 22381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 22391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int modem_input_wait(MGSLPC_INFO *info,int arg) 22411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 22421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 22431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 22441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mgsl_icount cprev, cnow; 22451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DECLARE_WAITQUEUE(wait, current); 22461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* save current irq counts */ 22481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->lock,flags); 22491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cprev = info->icount; 22501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds add_wait_queue(&info->status_event_wait_q, &wait); 22511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_current_state(TASK_INTERRUPTIBLE); 22521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock,flags); 22531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for(;;) { 22551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds schedule(); 22561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (signal_pending(current)) { 22571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -ERESTARTSYS; 22581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 22591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* get new irq counts */ 22621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->lock,flags); 22631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cnow = info->icount; 22641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_current_state(TASK_INTERRUPTIBLE); 22651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock,flags); 22661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if no change, wait aborted for some reason */ 22681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && 22691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) { 22701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EIO; 22711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 22721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* check for change in caller specified modem input */ 22751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((arg & TIOCM_RNG && cnow.rng != cprev.rng) || 22761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (arg & TIOCM_DSR && cnow.dsr != cprev.dsr) || 22771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (arg & TIOCM_CD && cnow.dcd != cprev.dcd) || 22781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (arg & TIOCM_CTS && cnow.cts != cprev.cts)) { 22791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = 0; 22801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 22811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cprev = cnow; 22841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds remove_wait_queue(&info->status_event_wait_q, &wait); 22861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_current_state(TASK_RUNNING); 22871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 22881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 22891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* return the state of the serial control and status signals 22911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 22921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tiocmget(struct tty_struct *tty, struct file *file) 22931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 22941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; 22951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int result; 22961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 22971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->lock,flags); 22991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds get_signals(info); 23001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock,flags); 23011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = ((info->serial_signals & SerialSignal_RTS) ? TIOCM_RTS:0) + 23031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((info->serial_signals & SerialSignal_DTR) ? TIOCM_DTR:0) + 23041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((info->serial_signals & SerialSignal_DCD) ? TIOCM_CAR:0) + 23051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((info->serial_signals & SerialSignal_RI) ? TIOCM_RNG:0) + 23061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((info->serial_signals & SerialSignal_DSR) ? TIOCM_DSR:0) + 23071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((info->serial_signals & SerialSignal_CTS) ? TIOCM_CTS:0); 23081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 23101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):%s tiocmget() value=%08X\n", 23111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__, info->device_name, result ); 23121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return result; 23131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 23141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* set modem control signals (DTR/RTS) 23161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 23171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tiocmset(struct tty_struct *tty, struct file *file, 23181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int set, unsigned int clear) 23191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 23201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; 23211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 23221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 23241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):%s tiocmset(%x,%x)\n", 23251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__,info->device_name, set, clear); 23261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (set & TIOCM_RTS) 23281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->serial_signals |= SerialSignal_RTS; 23291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (set & TIOCM_DTR) 23301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->serial_signals |= SerialSignal_DTR; 23311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clear & TIOCM_RTS) 23321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->serial_signals &= ~SerialSignal_RTS; 23331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clear & TIOCM_DTR) 23341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->serial_signals &= ~SerialSignal_DTR; 23351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->lock,flags); 23371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_signals(info); 23381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock,flags); 23391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 23411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 23421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Set or clear transmit break condition 23441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 23451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Arguments: tty pointer to tty instance data 23461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * break_state -1=set break condition, 0=clear 23471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 23481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mgslpc_break(struct tty_struct *tty, int break_state) 23491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 23501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data; 23511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 23521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 23541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):mgslpc_break(%s,%d)\n", 23551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__, info->device_name, break_state); 23561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mgslpc_paranoia_check(info, tty->name, "mgslpc_break")) 23581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 23591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->lock,flags); 23611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (break_state == -1) 23621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_reg_bits(info, CHA+DAFO, BIT6); 23631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 23641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_reg_bits(info, CHA+DAFO, BIT6); 23651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock,flags); 23661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 23671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Service an IOCTL request 23691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 23701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Arguments: 23711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 23721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * tty pointer to tty instance data 23731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * file pointer to associated file object for device 23741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cmd IOCTL command code 23751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * arg command argument/context 23761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 23771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Return Value: 0 if success, otherwise error code 23781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 23791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mgslpc_ioctl(struct tty_struct *tty, struct file * file, 23801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int cmd, unsigned long arg) 23811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 23821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data; 23831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 23851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):mgslpc_ioctl %s cmd=%08X\n", __FILE__,__LINE__, 23861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->device_name, cmd ); 23871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mgslpc_paranoia_check(info, tty->name, "mgslpc_ioctl")) 23891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 23901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && 23921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { 23931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tty->flags & (1 << TTY_IO_ERROR)) 23941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 23951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ioctl_common(info, cmd, arg); 23981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 23991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint ioctl_common(MGSLPC_INFO *info, unsigned int cmd, unsigned long arg) 24011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 24021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int error; 24031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mgsl_icount cnow; /* kernel counter temps */ 24041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct serial_icounter_struct __user *p_cuser; /* user space */ 24051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __user *argp = (void __user *)arg; 24061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 24071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) { 24091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MGSL_IOCGPARAMS: 24101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return get_params(info, argp); 24111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MGSL_IOCSPARAMS: 24121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return set_params(info, argp); 24131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MGSL_IOCGTXIDLE: 24141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return get_txidle(info, argp); 24151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MGSL_IOCSTXIDLE: 24161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return set_txidle(info, (int)arg); 24171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MGSL_IOCGIF: 24181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return get_interface(info, argp); 24191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MGSL_IOCSIF: 24201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return set_interface(info,(int)arg); 24211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MGSL_IOCTXENABLE: 24221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return set_txenable(info,(int)arg); 24231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MGSL_IOCRXENABLE: 24241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return set_rxenable(info,(int)arg); 24251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MGSL_IOCTXABORT: 24261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return tx_abort(info); 24271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MGSL_IOCGSTATS: 24281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return get_stats(info, argp); 24291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MGSL_IOCWAITEVENT: 24301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return wait_events(info, argp); 24311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case TIOCMIWAIT: 24321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return modem_input_wait(info,(int)arg); 24331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case TIOCGICOUNT: 24341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->lock,flags); 24351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cnow = info->icount; 24361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock,flags); 24371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p_cuser = argp; 24381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PUT_USER(error,cnow.cts, &p_cuser->cts); 24391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (error) return error; 24401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PUT_USER(error,cnow.dsr, &p_cuser->dsr); 24411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (error) return error; 24421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PUT_USER(error,cnow.rng, &p_cuser->rng); 24431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (error) return error; 24441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PUT_USER(error,cnow.dcd, &p_cuser->dcd); 24451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (error) return error; 24461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PUT_USER(error,cnow.rx, &p_cuser->rx); 24471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (error) return error; 24481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PUT_USER(error,cnow.tx, &p_cuser->tx); 24491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (error) return error; 24501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PUT_USER(error,cnow.frame, &p_cuser->frame); 24511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (error) return error; 24521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PUT_USER(error,cnow.overrun, &p_cuser->overrun); 24531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (error) return error; 24541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PUT_USER(error,cnow.parity, &p_cuser->parity); 24551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (error) return error; 24561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PUT_USER(error,cnow.brk, &p_cuser->brk); 24571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (error) return error; 24581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PUT_USER(error,cnow.buf_overrun, &p_cuser->buf_overrun); 24591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (error) return error; 24601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 24611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 24621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOIOCTLCMD; 24631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 24651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 24661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Set new termios settings 24681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 24691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Arguments: 24701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 24711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * tty pointer to tty structure 24721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * termios pointer to buffer to hold returned old termios 24731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 24741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mgslpc_set_termios(struct tty_struct *tty, struct termios *old_termios) 24751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 24761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; 24771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 24781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 24801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):mgslpc_set_termios %s\n", __FILE__,__LINE__, 24811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty->driver->name ); 24821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* just return if nothing has changed */ 24841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((tty->termios->c_cflag == old_termios->c_cflag) 24851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && (RELEVANT_IFLAG(tty->termios->c_iflag) 24861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds == RELEVANT_IFLAG(old_termios->c_iflag))) 24871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 24881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_change_params(info); 24901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Handle transition to B0 status */ 24921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (old_termios->c_cflag & CBAUD && 24931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !(tty->termios->c_cflag & CBAUD)) { 24941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR); 24951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->lock,flags); 24961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_signals(info); 24971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock,flags); 24981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Handle transition away from B0 status */ 25011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(old_termios->c_cflag & CBAUD) && 25021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty->termios->c_cflag & CBAUD) { 25031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->serial_signals |= SerialSignal_DTR; 25041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(tty->termios->c_cflag & CRTSCTS) || 25051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !test_bit(TTY_THROTTLED, &tty->flags)) { 25061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->serial_signals |= SerialSignal_RTS; 25071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->lock,flags); 25091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_signals(info); 25101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock,flags); 25111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Handle turning off CRTSCTS */ 25141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (old_termios->c_cflag & CRTSCTS && 25151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !(tty->termios->c_cflag & CRTSCTS)) { 25161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty->hw_stopped = 0; 25171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_release(tty); 25181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 25201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mgslpc_close(struct tty_struct *tty, struct file * filp) 25221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 25231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data; 25241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mgslpc_paranoia_check(info, tty->name, "mgslpc_close")) 25261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 25271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 25291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):mgslpc_close(%s) entry, count=%d\n", 25301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__, info->device_name, info->count); 25311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info->count) 25331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 25341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tty_hung_up_p(filp)) 25361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 25371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((tty->count == 1) && (info->count != 1)) { 25391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 25401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * tty->count is 1 and the tty structure will be freed. 25411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * info->count should be one in this case. 25421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if it's not, correct it so that the port is shutdown. 25431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 25441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("mgslpc_close: bad refcount; tty->count is 1, " 25451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "info->count is %d\n", info->count); 25461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->count = 1; 25471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->count--; 25501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if at least one open remaining, leave hardware active */ 25521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->count) 25531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 25541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->flags |= ASYNC_CLOSING; 25561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* set tty->closing to notify line discipline to 25581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * only process XON/XOFF characters. Only the N_TTY 25591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * discipline appears to use this (ppp does not). 25601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 25611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty->closing = 1; 25621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* wait for transmit data to clear all layers */ 25641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) { 25661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 25671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):mgslpc_close(%s) calling tty_wait_until_sent\n", 25681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__, info->device_name ); 25691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_wait_until_sent(tty, info->closing_wait); 25701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->flags & ASYNC_INITIALIZED) 25731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_wait_until_sent(tty, info->timeout); 25741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tty->driver->flush_buffer) 25761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty->driver->flush_buffer(tty); 25771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ldisc_flush_buffer(tty); 25791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds shutdown(info); 25811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty->closing = 0; 25831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tty = NULL; 25841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->blocked_open) { 25861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->close_delay) { 25871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msleep_interruptible(jiffies_to_msecs(info->close_delay)); 25881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up_interruptible(&info->open_wait); 25901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); 25931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up_interruptible(&info->close_wait); 25951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscleanup: 25971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 25981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):mgslpc_close(%s) exit, count=%d\n", __FILE__,__LINE__, 25991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty->driver->name, info->count); 26001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 26011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Wait until the transmitter is empty. 26031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 26041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mgslpc_wait_until_sent(struct tty_struct *tty, int timeout) 26051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 26061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data; 26071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long orig_jiffies, char_time; 26081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info ) 26101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 26111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 26131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):mgslpc_wait_until_sent(%s) entry\n", 26141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__, info->device_name ); 26151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mgslpc_paranoia_check(info, tty->name, "mgslpc_wait_until_sent")) 26171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 26181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(info->flags & ASYNC_INITIALIZED)) 26201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 26211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds orig_jiffies = jiffies; 26231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Set check interval to 1/5 of estimated time to 26251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * send a character, and make it at least 1. The check 26261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * interval should also be less than the timeout. 26271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note: use tight timings here to satisfy the NIST-PCTS. 26281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 26291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ( info->params.data_rate ) { 26311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char_time = info->timeout/(32 * 5); 26321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!char_time) 26331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char_time++; 26341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 26351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char_time = 1; 26361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (timeout) 26381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char_time = min_t(unsigned long, char_time, timeout); 26391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.mode == MGSL_MODE_HDLC) { 26411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (info->tx_active) { 26421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msleep_interruptible(jiffies_to_msecs(char_time)); 26431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (signal_pending(current)) 26441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 26451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (timeout && time_after(jiffies, orig_jiffies + timeout)) 26461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 26471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 26481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 26491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while ((info->tx_count || info->tx_active) && 26501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_enabled) { 26511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msleep_interruptible(jiffies_to_msecs(char_time)); 26521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (signal_pending(current)) 26531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 26541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (timeout && time_after(jiffies, orig_jiffies + timeout)) 26551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 26561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 26571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 26581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit: 26601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 26611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):mgslpc_wait_until_sent(%s) exit\n", 26621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__, info->device_name ); 26631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 26641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Called by tty_hangup() when a hangup is signaled. 26661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is the same as closing all open files for the port. 26671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 26681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mgslpc_hangup(struct tty_struct *tty) 26691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 26701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data; 26711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 26731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):mgslpc_hangup(%s)\n", 26741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__, info->device_name ); 26751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mgslpc_paranoia_check(info, tty->name, "mgslpc_hangup")) 26771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 26781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_flush_buffer(tty); 26801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds shutdown(info); 26811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->count = 0; 26831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->flags &= ~ASYNC_NORMAL_ACTIVE; 26841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tty = NULL; 26851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up_interruptible(&info->open_wait); 26871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 26881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Block the current process until the specified port 26901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is ready to be opened. 26911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 26921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int block_til_ready(struct tty_struct *tty, struct file *filp, 26931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info) 26941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 26951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DECLARE_WAITQUEUE(wait, current); 26961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 26971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int do_clocal = 0, extra_count = 0; 26981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 26991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 27011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):block_til_ready on %s\n", 27021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__, tty->driver->name ); 27031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){ 27051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* nonblock mode is set or port is not enabled */ 27061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* just verify that callout device is not active */ 27071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->flags |= ASYNC_NORMAL_ACTIVE; 27081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 27091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 27101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tty->termios->c_cflag & CLOCAL) 27121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do_clocal = 1; 27131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Wait for carrier detect and the line to become 27151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * free (i.e., not in use by the callout). While we are in 27161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this loop, info->count is dropped by one, so that 27171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * mgslpc_close() knows when to free things. We restore it upon 27181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * exit, either normal or abnormal. 27191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 27201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = 0; 27221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds add_wait_queue(&info->open_wait, &wait); 27231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 27251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):block_til_ready before block on %s count=%d\n", 27261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__, tty->driver->name, info->count ); 27271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->lock, flags); 27291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!tty_hung_up_p(filp)) { 27301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds extra_count = 1; 27311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->count--; 27321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 27331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock, flags); 27341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->blocked_open++; 27351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (1) { 27371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((tty->termios->c_cflag & CBAUD)) { 27381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->lock,flags); 27391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR; 27401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_signals(info); 27411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock,flags); 27421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 27431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_current_state(TASK_INTERRUPTIBLE); 27451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)){ 27471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = (info->flags & ASYNC_HUP_NOTIFY) ? 27481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds -EAGAIN : -ERESTARTSYS; 27491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 27501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 27511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->lock,flags); 27531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds get_signals(info); 27541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock,flags); 27551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(info->flags & ASYNC_CLOSING) && 27571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (do_clocal || (info->serial_signals & SerialSignal_DCD)) ) { 27581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 27591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 27601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (signal_pending(current)) { 27621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -ERESTARTSYS; 27631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 27641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 27651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 27671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):block_til_ready blocking on %s count=%d\n", 27681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__, tty->driver->name, info->count ); 27691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds schedule(); 27711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 27721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_current_state(TASK_RUNNING); 27741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds remove_wait_queue(&info->open_wait, &wait); 27751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (extra_count) 27771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->count++; 27781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->blocked_open--; 27791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 27811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):block_til_ready after blocking on %s count=%d\n", 27821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__, tty->driver->name, info->count ); 27831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!retval) 27851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->flags |= ASYNC_NORMAL_ACTIVE; 27861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 27881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 27891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mgslpc_open(struct tty_struct *tty, struct file * filp) 27911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 27921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info; 27931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval, line; 27941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 27951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* verify range of specified line number */ 27971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds line = tty->index; 27981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((line < 0) || (line >= mgslpc_device_count)) { 27991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):mgslpc_open with invalid line #%d.\n", 28001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__,line); 28011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 28021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 28031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* find the info structure for the specified line */ 28051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info = mgslpc_device_list; 28061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while(info && info->line != line) 28071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info = info->next_device; 28081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mgslpc_paranoia_check(info, tty->name, "mgslpc_open")) 28091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 28101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty->driver_data = info; 28121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tty = tty; 28131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 28151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):mgslpc_open(%s), old ref count = %d\n", 28161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__,tty->driver->name, info->count); 28171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If port is closing, signal caller to try again */ 28191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tty_hung_up_p(filp) || info->flags & ASYNC_CLOSING){ 28201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->flags & ASYNC_CLOSING) 28211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds interruptible_sleep_on(&info->close_wait); 28221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = ((info->flags & ASYNC_HUP_NOTIFY) ? 28231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds -EAGAIN : -ERESTARTSYS); 28241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 28251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 28261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; 28281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->netlock, flags); 28301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->netcount) { 28311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -EBUSY; 28321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->netlock, flags); 28331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 28341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 28351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->count++; 28361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->netlock, flags); 28371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->count == 1) { 28391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1st open on this device, init hardware */ 28401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = startup(info); 28411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval < 0) 28421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 28431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 28441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = block_til_ready(tty, filp, info); 28461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) { 28471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 28481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):block_til_ready(%s) returned %d\n", 28491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__, info->device_name, retval); 28501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 28511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 28521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 28541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):mgslpc_open(%s) success\n", 28551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__, info->device_name); 28561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = 0; 28571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscleanup: 28591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) { 28601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tty->count == 1) 28611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tty = NULL; /* tty layer will release tty struct */ 28621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(info->count) 28631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->count--; 28641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 28651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 28671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 28681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 28701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * /proc fs routines.... 28711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 28721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int line_info(char *buf, MGSLPC_INFO *info) 28741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 28751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char stat_buf[30]; 28761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 28771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 28781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = sprintf(buf, "%s:io:%04X irq:%d", 28801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->device_name, info->io_base, info->irq_level); 28811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* output current serial signal states */ 28831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->lock,flags); 28841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds get_signals(info); 28851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock,flags); 28861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stat_buf[0] = 0; 28881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stat_buf[1] = 0; 28891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->serial_signals & SerialSignal_RTS) 28901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcat(stat_buf, "|RTS"); 28911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->serial_signals & SerialSignal_CTS) 28921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcat(stat_buf, "|CTS"); 28931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->serial_signals & SerialSignal_DTR) 28941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcat(stat_buf, "|DTR"); 28951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->serial_signals & SerialSignal_DSR) 28961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcat(stat_buf, "|DSR"); 28971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->serial_signals & SerialSignal_DCD) 28981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcat(stat_buf, "|CD"); 28991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->serial_signals & SerialSignal_RI) 29001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcat(stat_buf, "|RI"); 29011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.mode == MGSL_MODE_HDLC) { 29031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret += sprintf(buf+ret, " HDLC txok:%d rxok:%d", 29041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->icount.txok, info->icount.rxok); 29051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->icount.txunder) 29061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret += sprintf(buf+ret, " txunder:%d", info->icount.txunder); 29071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->icount.txabort) 29081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret += sprintf(buf+ret, " txabort:%d", info->icount.txabort); 29091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->icount.rxshort) 29101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret += sprintf(buf+ret, " rxshort:%d", info->icount.rxshort); 29111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->icount.rxlong) 29121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret += sprintf(buf+ret, " rxlong:%d", info->icount.rxlong); 29131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->icount.rxover) 29141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret += sprintf(buf+ret, " rxover:%d", info->icount.rxover); 29151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->icount.rxcrc) 29161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret += sprintf(buf+ret, " rxcrc:%d", info->icount.rxcrc); 29171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 29181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret += sprintf(buf+ret, " ASYNC tx:%d rx:%d", 29191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->icount.tx, info->icount.rx); 29201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->icount.frame) 29211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret += sprintf(buf+ret, " fe:%d", info->icount.frame); 29221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->icount.parity) 29231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret += sprintf(buf+ret, " pe:%d", info->icount.parity); 29241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->icount.brk) 29251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret += sprintf(buf+ret, " brk:%d", info->icount.brk); 29261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->icount.overrun) 29271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret += sprintf(buf+ret, " oe:%d", info->icount.overrun); 29281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 29291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Append serial signal status to end */ 29311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret += sprintf(buf+ret, " %s\n", stat_buf+1); 29321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret += sprintf(buf+ret, "txactive=%d bh_req=%d bh_run=%d pending_bh=%x\n", 29341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_active,info->bh_requested,info->bh_running, 29351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->pending_bh); 29361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 29381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 29391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Called to print information about devices 29411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 29421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mgslpc_read_proc(char *page, char **start, off_t off, int count, 29431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int *eof, void *data) 29441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 29451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int len = 0, l; 29461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds off_t begin = 0; 29471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info; 29481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len += sprintf(page, "synclink driver:%s\n", driver_version); 29501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info = mgslpc_device_list; 29521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while( info ) { 29531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds l = line_info(page + len, info); 29541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len += l; 29551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (len+begin > off+count) 29561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto done; 29571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (len+begin < off) { 29581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds begin += len; 29591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = 0; 29601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 29611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info = info->next_device; 29621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 29631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *eof = 1; 29651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdone: 29661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (off >= len+begin) 29671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 29681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *start = page + (off-begin); 29691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ((count < begin+len-off) ? count : begin+len-off); 29701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 29711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint rx_alloc_buffers(MGSLPC_INFO *info) 29731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 29741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* each buffer has header and data */ 29751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->rx_buf_size = sizeof(RXBUF) + info->max_frame_size; 29761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* calculate total allocation size for 8 buffers */ 29781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->rx_buf_total_size = info->rx_buf_size * 8; 29791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* limit total allocated memory */ 29811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->rx_buf_total_size > 0x10000) 29821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->rx_buf_total_size = 0x10000; 29831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* calculate number of buffers */ 29851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->rx_buf_count = info->rx_buf_total_size / info->rx_buf_size; 29861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->rx_buf = kmalloc(info->rx_buf_total_size, GFP_KERNEL); 29881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->rx_buf == NULL) 29891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 29901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_reset_buffers(info); 29921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 29931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 29941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid rx_free_buffers(MGSLPC_INFO *info) 29961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 29971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->rx_buf) 29981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(info->rx_buf); 29991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->rx_buf = NULL; 30001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 30011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint claim_resources(MGSLPC_INFO *info) 30031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 30041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rx_alloc_buffers(info) < 0 ) { 30051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk( "Cant allocate rx buffer %s\n", info->device_name); 30061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_resources(info); 30071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 30081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 30091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 30101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 30111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid release_resources(MGSLPC_INFO *info) 30131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 30141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 30151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("release_resources(%s)\n", info->device_name); 30161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_free_buffers(info); 30171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 30181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Add the specified device instance data structure to the 30201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * global linked list of devices and increment the device count. 30211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 30221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Arguments: info pointer to device instance data 30231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 30241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid mgslpc_add_device(MGSLPC_INFO *info) 30251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 30261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->next_device = NULL; 30271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->line = mgslpc_device_count; 30281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sprintf(info->device_name,"ttySLP%d",info->line); 30291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->line < MAX_DEVICE_COUNT) { 30311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (maxframe[info->line]) 30321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->max_frame_size = maxframe[info->line]; 30331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->dosyncppp = dosyncppp[info->line]; 30341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 30351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_device_count++; 30371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!mgslpc_device_list) 30391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_device_list = info; 30401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 30411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *current_dev = mgslpc_device_list; 30421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while( current_dev->next_device ) 30431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds current_dev = current_dev->next_device; 30441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds current_dev->next_device = info; 30451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 30461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->max_frame_size < 4096) 30481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->max_frame_size = 4096; 30491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (info->max_frame_size > 65535) 30501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->max_frame_size = 65535; 30511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk( "SyncLink PC Card %s:IO=%04X IRQ=%d\n", 30531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->device_name, info->io_base, info->irq_level); 30541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_HDLC 30561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdlcdev_init(info); 30571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 30581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 30591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid mgslpc_remove_device(MGSLPC_INFO *remove_info) 30611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 30621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = mgslpc_device_list; 30631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *last = NULL; 30641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while(info) { 30661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info == remove_info) { 30671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (last) 30681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds last->next_device = info->next_device; 30691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 30701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_device_list = info->next_device; 30711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_HDLC 30721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdlcdev_exit(info); 30731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 30741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_resources(info); 30751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(info); 30761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_device_count--; 30771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 30781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 30791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds last = info; 30801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info = info->next_device; 30811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 30821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 30831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30844af48c8c16dfc37400f63633373dd180b5540eadDominik Brodowskistatic struct pcmcia_device_id mgslpc_ids[] = { 30854af48c8c16dfc37400f63633373dd180b5540eadDominik Brodowski PCMCIA_DEVICE_MANF_CARD(0x02c5, 0x0050), 30864af48c8c16dfc37400f63633373dd180b5540eadDominik Brodowski PCMCIA_DEVICE_NULL 30874af48c8c16dfc37400f63633373dd180b5540eadDominik Brodowski}; 30884af48c8c16dfc37400f63633373dd180b5540eadDominik BrodowskiMODULE_DEVICE_TABLE(pcmcia, mgslpc_ids); 30894af48c8c16dfc37400f63633373dd180b5540eadDominik Brodowski 30901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pcmcia_driver mgslpc_driver = { 30911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .owner = THIS_MODULE, 30921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .drv = { 30931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "synclink_cs", 30941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }, 30951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .attach = mgslpc_attach, 30961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .detach = mgslpc_detach, 30974af48c8c16dfc37400f63633373dd180b5540eadDominik Brodowski .id_table = mgslpc_ids, 30981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 30991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct tty_operations mgslpc_ops = { 31011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .open = mgslpc_open, 31021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .close = mgslpc_close, 31031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write = mgslpc_write, 31041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .put_char = mgslpc_put_char, 31051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .flush_chars = mgslpc_flush_chars, 31061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write_room = mgslpc_write_room, 31071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .chars_in_buffer = mgslpc_chars_in_buffer, 31081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .flush_buffer = mgslpc_flush_buffer, 31091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .ioctl = mgslpc_ioctl, 31101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .throttle = mgslpc_throttle, 31111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .unthrottle = mgslpc_unthrottle, 31121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .send_xchar = mgslpc_send_xchar, 31131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .break_ctl = mgslpc_break, 31141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .wait_until_sent = mgslpc_wait_until_sent, 31151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .read_proc = mgslpc_read_proc, 31161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .set_termios = mgslpc_set_termios, 31171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .stop = tx_pause, 31181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .start = tx_release, 31191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .hangup = mgslpc_hangup, 31201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .tiocmget = tiocmget, 31211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .tiocmset = tiocmset, 31221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 31231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void synclink_cs_cleanup(void) 31251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 31261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 31271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("Unloading %s: version %s\n", driver_name, driver_version); 31291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while(mgslpc_device_list) 31311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_remove_device(mgslpc_device_list); 31321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (serial_driver) { 31341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((rc = tty_unregister_driver(serial_driver))) 31351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d) failed to unregister tty driver err=%d\n", 31361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__,rc); 31371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds put_tty_driver(serial_driver); 31381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 31391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcmcia_unregister_driver(&mgslpc_driver); 31411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(dev_list != NULL); 31421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 31431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init synclink_cs_init(void) 31451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 31461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 31471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (break_on_load) { 31491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_get_text_ptr(); 31501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BREAKPOINT(); 31511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 31521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s %s\n", driver_name, driver_version); 31541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((rc = pcmcia_register_driver(&mgslpc_driver)) < 0) 31561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 31571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial_driver = alloc_tty_driver(MAX_DEVICE_COUNT); 31591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!serial_driver) { 31601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -ENOMEM; 31611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 31621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 31631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Initialize the tty_driver structure */ 31651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial_driver->owner = THIS_MODULE; 31671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial_driver->driver_name = "synclink_cs"; 31681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial_driver->name = "ttySLP"; 31691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial_driver->major = ttymajor; 31701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial_driver->minor_start = 64; 31711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial_driver->type = TTY_DRIVER_TYPE_SERIAL; 31721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial_driver->subtype = SERIAL_TYPE_NORMAL; 31731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial_driver->init_termios = tty_std_termios; 31741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial_driver->init_termios.c_cflag = 31751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds B9600 | CS8 | CREAD | HUPCL | CLOCAL; 31761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial_driver->flags = TTY_DRIVER_REAL_RAW; 31771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_set_operations(serial_driver, &mgslpc_ops); 31781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((rc = tty_register_driver(serial_driver)) < 0) { 31801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):Couldn't register serial driver\n", 31811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__); 31821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds put_tty_driver(serial_driver); 31831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial_driver = NULL; 31841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 31851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 31861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s %s, tty major#%d\n", 31881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds driver_name, driver_version, 31891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial_driver->major); 31901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 31921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserror: 31941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds synclink_cs_cleanup(); 31951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 31961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 31971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit synclink_cs_exit(void) 31991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 32001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds synclink_cs_cleanup(); 32011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 32021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(synclink_cs_init); 32041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(synclink_cs_exit); 32051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mgslpc_set_rate(MGSLPC_INFO *info, unsigned char channel, unsigned int rate) 32071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 32081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int M, N; 32091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char val; 32101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* note:standard BRG mode is broken in V3.2 chip 32121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * so enhanced mode is always used 32131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 32141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rate) { 32161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds N = 3686400 / rate; 32171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!N) 32181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds N = 1; 32191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds N >>= 1; 32201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (M = 1; N > 64 && M < 16; M++) 32211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds N >>= 1; 32221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds N--; 32231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* BGR[5..0] = N 32251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * BGR[9..6] = M 32261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * BGR[7..0] contained in BGR register 32271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * BGR[9..8] contained in CCR2[7..6] 32281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * divisor = (N+1)*2^M 32291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 32301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note: M *must* not be zero (causes asymetric duty cycle) 32311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 32321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, (unsigned char) (channel + BGR), 32331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned char) ((M << 6) + N)); 32341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = read_reg(info, (unsigned char) (channel + CCR2)) & 0x3f; 32351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= ((M << 4) & 0xc0); 32361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, (unsigned char) (channel + CCR2), val); 32371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 32381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 32391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Enabled the AUX clock output at the specified frequency. 32411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 32421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void enable_auxclk(MGSLPC_INFO *info) 32431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 32441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char val; 32451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* MODE 32471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 32481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07..06 MDS[1..0] 10 = transparent HDLC mode 32491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 05 ADM Address Mode, 0 = no addr recognition 32501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04 TMD Timer Mode, 0 = external 32511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 03 RAC Receiver Active, 0 = inactive 32521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 02 RTS 0=RTS active during xmit, 1=RTS always active 32531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 01 TRS Timer Resolution, 1=512 32541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 00 TLP Test Loop, 0 = no loop 32551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 32561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1000 0010 32571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 32581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = 0x82; 32591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* channel B RTS is used to enable AUXCLK driver on SP505 */ 32611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.mode == MGSL_MODE_HDLC && info->params.clock_speed) 32621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT2; 32631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHB + MODE, val); 32641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* CCR0 32661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 32671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07 PU Power Up, 1=active, 0=power down 32681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 06 MCE Master Clock Enable, 1=enabled 32691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 05 Reserved, 0 32701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04..02 SC[2..0] Encoding 32711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 01..00 SM[1..0] Serial Mode, 00=HDLC 32721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 32731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 11000000 32741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 32751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHB + CCR0, 0xc0); 32761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* CCR1 32781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 32791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07 SFLG Shared Flag, 0 = disable shared flags 32801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 06 GALP Go Active On Loop, 0 = not used 32811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 05 GLP Go On Loop, 0 = not used 32821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04 ODS Output Driver Select, 1=TxD is push-pull output 32831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 03 ITF Interframe Time Fill, 0=mark, 1=flag 32841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 02..00 CM[2..0] Clock Mode 32851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 32861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0001 0111 32871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 32881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHB + CCR1, 0x17); 32891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* CCR2 (Channel B) 32911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 32921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07..06 BGR[9..8] Baud rate bits 9..8 32931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 05 BDF Baud rate divisor factor, 0=1, 1=BGR value 32941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04 SSEL Clock source select, 1=submode b 32951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 03 TOE 0=TxCLK is input, 1=TxCLK is output 32961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 02 RWX Read/Write Exchange 0=disabled 32971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 01 C32, CRC select, 0=CRC-16, 1=CRC-32 32981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 00 DIV, data inversion 0=disabled, 1=enabled 32991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 33001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0011 1000 33011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 33021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.mode == MGSL_MODE_HDLC && info->params.clock_speed) 33031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHB + CCR2, 0x38); 33041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 33051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHB + CCR2, 0x30); 33061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* CCR4 33081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 33091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07 MCK4 Master Clock Divide by 4, 1=enabled 33101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 06 EBRG Enhanced Baud Rate Generator Mode, 1=enabled 33111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 05 TST1 Test Pin, 0=normal operation 33121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04 ICD Ivert Carrier Detect, 1=enabled (active low) 33131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 03..02 Reserved, must be 0 33141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 01..00 RFT[1..0] RxFIFO Threshold 00=32 bytes 33151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 33161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0101 0000 33171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 33181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHB + CCR4, 0x50); 33191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if auxclk not enabled, set internal BRG so 33211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * CTS transitions can be detected (requires TxC) 33221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 33231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.mode == MGSL_MODE_HDLC && info->params.clock_speed) 33241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_set_rate(info, CHB, info->params.clock_speed); 33251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 33261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_set_rate(info, CHB, 921600); 33271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 33281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void loopback_enable(MGSLPC_INFO *info) 33301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 33311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char val; 33321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* CCR1:02..00 CM[2..0] Clock Mode = 111 (clock mode 7) */ 33341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = read_reg(info, CHA + CCR1) | (BIT2 + BIT1 + BIT0); 33351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + CCR1, val); 33361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* CCR2:04 SSEL Clock source select, 1=submode b */ 33381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = read_reg(info, CHA + CCR2) | (BIT4 + BIT5); 33391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + CCR2, val); 33401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* set LinkSpeed if available, otherwise default to 2Mbps */ 33421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.clock_speed) 33431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_set_rate(info, CHA, info->params.clock_speed); 33441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 33451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_set_rate(info, CHA, 1843200); 33461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* MODE:00 TLP Test Loop, 1=loopback enabled */ 33481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = read_reg(info, CHA + MODE) | BIT0; 33491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + MODE, val); 33501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 33511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid hdlc_mode(MGSLPC_INFO *info) 33531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 33541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char val; 33551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char clkmode, clksubmode; 33561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* disable all interrupts */ 33581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq_disable(info, CHA, 0xffff); 33591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq_disable(info, CHB, 0xffff); 33601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port_irq_disable(info, 0xff); 33611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* assume clock mode 0a, rcv=RxC xmt=TxC */ 33631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clkmode = clksubmode = 0; 33641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.flags & HDLC_FLAG_RXC_DPLL 33651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && info->params.flags & HDLC_FLAG_TXC_DPLL) { 33661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* clock mode 7a, rcv = DPLL, xmt = DPLL */ 33671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clkmode = 7; 33681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (info->params.flags & HDLC_FLAG_RXC_BRG 33691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && info->params.flags & HDLC_FLAG_TXC_BRG) { 33701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* clock mode 7b, rcv = BRG, xmt = BRG */ 33711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clkmode = 7; 33721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clksubmode = 1; 33731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (info->params.flags & HDLC_FLAG_RXC_DPLL) { 33741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.flags & HDLC_FLAG_TXC_BRG) { 33751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* clock mode 6b, rcv = DPLL, xmt = BRG/16 */ 33761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clkmode = 6; 33771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clksubmode = 1; 33781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 33791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* clock mode 6a, rcv = DPLL, xmt = TxC */ 33801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clkmode = 6; 33811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 33821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (info->params.flags & HDLC_FLAG_TXC_BRG) { 33831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* clock mode 0b, rcv = RxC, xmt = BRG */ 33841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clksubmode = 1; 33851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 33861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* MODE 33881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 33891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07..06 MDS[1..0] 10 = transparent HDLC mode 33901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 05 ADM Address Mode, 0 = no addr recognition 33911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04 TMD Timer Mode, 0 = external 33921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 03 RAC Receiver Active, 0 = inactive 33931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 02 RTS 0=RTS active during xmit, 1=RTS always active 33941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 01 TRS Timer Resolution, 1=512 33951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 00 TLP Test Loop, 0 = no loop 33961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 33971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1000 0010 33981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 33991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = 0x82; 34001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.loopback) 34011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT0; 34021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* preserve RTS state */ 34041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->serial_signals & SerialSignal_RTS) 34051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT2; 34061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + MODE, val); 34071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* CCR0 34091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 34101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07 PU Power Up, 1=active, 0=power down 34111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 06 MCE Master Clock Enable, 1=enabled 34121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 05 Reserved, 0 34131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04..02 SC[2..0] Encoding 34141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 01..00 SM[1..0] Serial Mode, 00=HDLC 34151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 34161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 11000000 34171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 34181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = 0xc0; 34191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (info->params.encoding) 34201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 34211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HDLC_ENCODING_NRZI: 34221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT3; 34231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 34241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HDLC_ENCODING_BIPHASE_SPACE: 34251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT4; 34261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; // FM0 34271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HDLC_ENCODING_BIPHASE_MARK: 34281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT4 + BIT2; 34291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; // FM1 34301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HDLC_ENCODING_BIPHASE_LEVEL: 34311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT4 + BIT3; 34321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; // Manchester 34331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 34341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + CCR0, val); 34351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* CCR1 34371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 34381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07 SFLG Shared Flag, 0 = disable shared flags 34391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 06 GALP Go Active On Loop, 0 = not used 34401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 05 GLP Go On Loop, 0 = not used 34411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04 ODS Output Driver Select, 1=TxD is push-pull output 34421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 03 ITF Interframe Time Fill, 0=mark, 1=flag 34431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 02..00 CM[2..0] Clock Mode 34441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 34451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0001 0000 34461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 34471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = 0x10 + clkmode; 34481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + CCR1, val); 34491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* CCR2 34511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 34521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07..06 BGR[9..8] Baud rate bits 9..8 34531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 05 BDF Baud rate divisor factor, 0=1, 1=BGR value 34541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04 SSEL Clock source select, 1=submode b 34551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 03 TOE 0=TxCLK is input, 0=TxCLK is input 34561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 02 RWX Read/Write Exchange 0=disabled 34571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 01 C32, CRC select, 0=CRC-16, 1=CRC-32 34581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 00 DIV, data inversion 0=disabled, 1=enabled 34591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 34601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0000 0000 34611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 34621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = 0x00; 34631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clkmode == 2 || clkmode == 3 || clkmode == 6 34641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || clkmode == 7 || (clkmode == 0 && clksubmode == 1)) 34651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT5; 34661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clksubmode) 34671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT4; 34681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.crc_type == HDLC_CRC_32_CCITT) 34691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT1; 34701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.encoding == HDLC_ENCODING_NRZB) 34711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT0; 34721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + CCR2, val); 34731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* CCR3 34751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 34761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07..06 PRE[1..0] Preamble count 00=1, 01=2, 10=4, 11=8 34771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 05 EPT Enable preamble transmission, 1=enabled 34781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04 RADD Receive address pushed to FIFO, 0=disabled 34791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 03 CRL CRC Reset Level, 0=FFFF 34801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 02 RCRC Rx CRC 0=On 1=Off 34811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 01 TCRC Tx CRC 0=On 1=Off 34821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 00 PSD DPLL Phase Shift Disable 34831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 34841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0000 0000 34851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 34861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = 0x00; 34871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.crc_type == HDLC_CRC_NONE) 34881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT2 + BIT1; 34891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.preamble != HDLC_PREAMBLE_PATTERN_NONE) 34901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT5; 34911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (info->params.preamble_length) 34921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 34931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HDLC_PREAMBLE_LENGTH_16BITS: 34941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT6; 34951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 34961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HDLC_PREAMBLE_LENGTH_32BITS: 34971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT6; 34981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 34991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HDLC_PREAMBLE_LENGTH_64BITS: 35001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT7 + BIT6; 35011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 35021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 35031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + CCR3, val); 35041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* PRE - Preamble pattern */ 35061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = 0; 35071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (info->params.preamble) 35081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 35091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HDLC_PREAMBLE_PATTERN_FLAGS: val = 0x7e; break; 35101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HDLC_PREAMBLE_PATTERN_10: val = 0xaa; break; 35111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HDLC_PREAMBLE_PATTERN_01: val = 0x55; break; 35121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HDLC_PREAMBLE_PATTERN_ONES: val = 0xff; break; 35131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 35141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + PRE, val); 35151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* CCR4 35171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 35181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07 MCK4 Master Clock Divide by 4, 1=enabled 35191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 06 EBRG Enhanced Baud Rate Generator Mode, 1=enabled 35201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 05 TST1 Test Pin, 0=normal operation 35211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04 ICD Ivert Carrier Detect, 1=enabled (active low) 35221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 03..02 Reserved, must be 0 35231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 01..00 RFT[1..0] RxFIFO Threshold 00=32 bytes 35241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 35251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0101 0000 35261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 35271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = 0x50; 35281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + CCR4, val); 35291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.flags & HDLC_FLAG_RXC_DPLL) 35301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_set_rate(info, CHA, info->params.clock_speed * 16); 35311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 35321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_set_rate(info, CHA, info->params.clock_speed); 35331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* RLCR Receive length check register 35351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 35361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 7 1=enable receive length check 35371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 6..0 Max frame length = (RL + 1) * 32 35381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 35391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + RLCR, 0); 35401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* XBCH Transmit Byte Count High 35421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 35431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07 DMA mode, 0 = interrupt driven 35441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 06 NRM, 0=ABM (ignored) 35451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 05 CAS Carrier Auto Start 35461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04 XC Transmit Continuously (ignored) 35471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 03..00 XBC[10..8] Transmit byte count bits 10..8 35481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 35491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0000 0000 35501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 35511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = 0x00; 35521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.flags & HDLC_FLAG_AUTO_DCD) 35531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT5; 35541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + XBCH, val); 35551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enable_auxclk(info); 35561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.loopback || info->testing_irq) 35571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds loopback_enable(info); 35581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.flags & HDLC_FLAG_AUTO_CTS) 35591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 35601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq_enable(info, CHB, IRQ_CTS); 35611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* PVR[3] 1=AUTO CTS active */ 35621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_reg_bits(info, CHA + PVR, BIT3); 35631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 35641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_reg_bits(info, CHA + PVR, BIT3); 35651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq_enable(info, CHA, 35671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IRQ_RXEOM + IRQ_RXFIFO + IRQ_ALLSENT + 35681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IRQ_UNDERRUN + IRQ_TXFIFO); 35691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds issue_command(info, CHA, CMD_TXRESET + CMD_RXRESET); 35701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wait_command_complete(info, CHA); 35711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read_reg16(info, CHA + ISR); /* clear pending IRQs */ 35721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Master clock mode enabled above to allow reset commands 35741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to complete even if no data clocks are present. 35751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 35761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Disable master clock mode for normal communications because 35771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * V3.2 of the ESCC2 has a bug that prevents the transmit all sent 35781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * IRQ when in master clock mode. 35791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 35801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Leave master clock mode enabled for IRQ test because the 35811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * timer IRQ used by the test can only happen in master clock mode. 35821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 35831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info->testing_irq) 35841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_reg_bits(info, CHA + CCR0, BIT6); 35851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_set_idle(info); 35871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_stop(info); 35891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_stop(info); 35901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 35911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid rx_stop(MGSLPC_INFO *info) 35931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 35941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_ISR) 35951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):rx_stop(%s)\n", 35961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__, info->device_name ); 35971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* MODE:03 RAC Receiver Active, 0=inactive */ 35991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_reg_bits(info, CHA + MODE, BIT3); 36001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->rx_enabled = 0; 36021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->rx_overflow = 0; 36031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 36041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid rx_start(MGSLPC_INFO *info) 36061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 36071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_ISR) 36081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):rx_start(%s)\n", 36091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__, info->device_name ); 36101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_reset_buffers(info); 36121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->rx_enabled = 0; 36131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->rx_overflow = 0; 36141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* MODE:03 RAC Receiver Active, 1=active */ 36161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_reg_bits(info, CHA + MODE, BIT3); 36171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->rx_enabled = 1; 36191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 36201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid tx_start(MGSLPC_INFO *info) 36221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 36231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_ISR) 36241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):tx_start(%s)\n", 36251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__, info->device_name ); 36261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->tx_count) { 36281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If auto RTS enabled and RTS is inactive, then assert */ 36291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* RTS and set a flag indicating that the driver should */ 36301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* negate RTS when the transmission completes. */ 36311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->drop_rts_on_tx_done = 0; 36321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.flags & HDLC_FLAG_AUTO_RTS) { 36341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds get_signals(info); 36351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(info->serial_signals & SerialSignal_RTS)) { 36361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->serial_signals |= SerialSignal_RTS; 36371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_signals(info); 36381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->drop_rts_on_tx_done = 1; 36391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 36401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 36411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.mode == MGSL_MODE_ASYNC) { 36431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info->tx_active) { 36441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_active = 1; 36451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_ready(info); 36461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 36471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 36481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_active = 1; 36491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_ready(info); 36501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_timer.expires = jiffies + msecs_to_jiffies(5000); 36511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds add_timer(&info->tx_timer); 36521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 36531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 36541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info->tx_enabled) 36561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_enabled = 1; 36571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 36581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid tx_stop(MGSLPC_INFO *info) 36601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 36611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_ISR) 36621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):tx_stop(%s)\n", 36631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__, info->device_name ); 36641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds del_timer(&info->tx_timer); 36661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_enabled = 0; 36681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_active = 0; 36691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 36701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Reset the adapter to a known state and prepare it for further use. 36721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 36731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid reset_device(MGSLPC_INFO *info) 36741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 36751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* power up both channels (set BIT7) */ 36761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + CCR0, 0x80); 36771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHB + CCR0, 0x80); 36781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + MODE, 0); 36791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHB + MODE, 0); 36801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* disable all interrupts */ 36821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq_disable(info, CHA, 0xffff); 36831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq_disable(info, CHB, 0xffff); 36841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port_irq_disable(info, 0xff); 36851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* PCR Port Configuration Register 36871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 36881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07..04 DEC[3..0] Serial I/F select outputs 36891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 03 output, 1=AUTO CTS control enabled 36901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 02 RI Ring Indicator input 0=active 36911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 01 DSR input 0=active 36921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 00 DTR output 0=active 36931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 36941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0000 0110 36951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 36961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, PCR, 0x06); 36971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* PVR Port Value Register 36991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 37001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07..04 DEC[3..0] Serial I/F select (0000=disabled) 37011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 03 AUTO CTS output 1=enabled 37021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 02 RI Ring Indicator input 37031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 01 DSR input 37041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 00 DTR output (1=inactive) 37051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 37061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0000 0001 37071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 37081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// write_reg(info, PVR, PVR_DTR); 37091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* IPC Interrupt Port Configuration 37111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 37121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07 VIS 1=Masked interrupts visible 37131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 06..05 Reserved, 0 37141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04..03 SLA Slave address, 00 ignored 37151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 02 CASM Cascading Mode, 1=daisy chain 37161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 01..00 IC[1..0] Interrupt Config, 01=push-pull output, active low 37171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 37181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0000 0101 37191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 37201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, IPC, 0x05); 37211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 37221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid async_mode(MGSLPC_INFO *info) 37241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 37251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char val; 37261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* disable all interrupts */ 37281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq_disable(info, CHA, 0xffff); 37291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq_disable(info, CHB, 0xffff); 37301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port_irq_disable(info, 0xff); 37311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* MODE 37331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 37341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07 Reserved, 0 37351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 06 FRTS RTS State, 0=active 37361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 05 FCTS Flow Control on CTS 37371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04 FLON Flow Control Enable 37381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 03 RAC Receiver Active, 0 = inactive 37391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 02 RTS 0=Auto RTS, 1=manual RTS 37401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 01 TRS Timer Resolution, 1=512 37411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 00 TLP Test Loop, 0 = no loop 37421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 37431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0000 0110 37441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 37451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = 0x06; 37461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.loopback) 37471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT0; 37481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* preserve RTS state */ 37501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(info->serial_signals & SerialSignal_RTS)) 37511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT6; 37521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + MODE, val); 37531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* CCR0 37551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 37561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07 PU Power Up, 1=active, 0=power down 37571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 06 MCE Master Clock Enable, 1=enabled 37581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 05 Reserved, 0 37591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04..02 SC[2..0] Encoding, 000=NRZ 37601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 01..00 SM[1..0] Serial Mode, 11=Async 37611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 37621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1000 0011 37631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 37641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + CCR0, 0x83); 37651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* CCR1 37671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 37681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07..05 Reserved, 0 37691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04 ODS Output Driver Select, 1=TxD is push-pull output 37701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 03 BCR Bit Clock Rate, 1=16x 37711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 02..00 CM[2..0] Clock Mode, 111=BRG 37721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 37731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0001 1111 37741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 37751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + CCR1, 0x1f); 37761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* CCR2 (channel A) 37781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 37791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07..06 BGR[9..8] Baud rate bits 9..8 37801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 05 BDF Baud rate divisor factor, 0=1, 1=BGR value 37811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04 SSEL Clock source select, 1=submode b 37821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 03 TOE 0=TxCLK is input, 0=TxCLK is input 37831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 02 RWX Read/Write Exchange 0=disabled 37841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 01 Reserved, 0 37851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 00 DIV, data inversion 0=disabled, 1=enabled 37861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 37871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0001 0000 37881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 37891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + CCR2, 0x10); 37901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* CCR3 37921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 37931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07..01 Reserved, 0 37941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 00 PSD DPLL Phase Shift Disable 37951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 37961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0000 0000 37971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 37981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + CCR3, 0); 37991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* CCR4 38011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 38021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07 MCK4 Master Clock Divide by 4, 1=enabled 38031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 06 EBRG Enhanced Baud Rate Generator Mode, 1=enabled 38041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 05 TST1 Test Pin, 0=normal operation 38051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04 ICD Ivert Carrier Detect, 1=enabled (active low) 38061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 03..00 Reserved, must be 0 38071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 38081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0101 0000 38091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 38101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + CCR4, 0x50); 38111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_set_rate(info, CHA, info->params.data_rate * 16); 38121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* DAFO Data Format 38141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 38151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07 Reserved, 0 38161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 06 XBRK transmit break, 0=normal operation 38171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 05 Stop bits (0=1, 1=2) 38181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04..03 PAR[1..0] Parity (01=odd, 10=even) 38191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 02 PAREN Parity Enable 38201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 01..00 CHL[1..0] Character Length (00=8, 01=7) 38211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 38221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 38231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = 0x00; 38241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.data_bits != 8) 38251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT0; /* 7 bits */ 38261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.stop_bits != 1) 38271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT5; 38281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.parity != ASYNC_PARITY_NONE) 38291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 38301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT2; /* Parity enable */ 38311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.parity == ASYNC_PARITY_ODD) 38321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT3; 38331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 38341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT4; 38351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 38361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + DAFO, val); 38371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* RFC Rx FIFO Control 38391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 38401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07 Reserved, 0 38411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 06 DPS, 1=parity bit not stored in data byte 38421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 05 DXS, 0=all data stored in FIFO (including XON/XOFF) 38431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04 RFDF Rx FIFO Data Format, 1=status byte stored in FIFO 38441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 03..02 RFTH[1..0], rx threshold, 11=16 status + 16 data byte 38451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 01 Reserved, 0 38461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 00 TCDE Terminate Char Detect Enable, 0=disabled 38471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 38481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0101 1100 38491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 38501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + RFC, 0x5c); 38511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* RLCR Receive length check register 38531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 38541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Max frame length = (RL + 1) * 32 38551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 38561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + RLCR, 0); 38571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* XBCH Transmit Byte Count High 38591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 38601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 07 DMA mode, 0 = interrupt driven 38611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 06 NRM, 0=ABM (ignored) 38621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 05 CAS Carrier Auto Start 38631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04 XC Transmit Continuously (ignored) 38641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 03..00 XBC[10..8] Transmit byte count bits 10..8 38651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 38661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0000 0000 38671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 38681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = 0x00; 38691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.flags & HDLC_FLAG_AUTO_DCD) 38701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT5; 38711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + XBCH, val); 38721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.flags & HDLC_FLAG_AUTO_CTS) 38731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq_enable(info, CHA, IRQ_CTS); 38741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* MODE:03 RAC Receiver Active, 1=active */ 38761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_reg_bits(info, CHA + MODE, BIT3); 38771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enable_auxclk(info); 38781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.flags & HDLC_FLAG_AUTO_CTS) { 38791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq_enable(info, CHB, IRQ_CTS); 38801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* PVR[3] 1=AUTO CTS active */ 38811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_reg_bits(info, CHA + PVR, BIT3); 38821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 38831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_reg_bits(info, CHA + PVR, BIT3); 38841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq_enable(info, CHA, 38851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IRQ_RXEOM + IRQ_RXFIFO + IRQ_BREAK_ON + IRQ_RXTIME + 38861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IRQ_ALLSENT + IRQ_TXFIFO); 38871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds issue_command(info, CHA, CMD_TXRESET + CMD_RXRESET); 38881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wait_command_complete(info, CHA); 38891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read_reg16(info, CHA + ISR); /* clear pending IRQs */ 38901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 38911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Set the HDLC idle mode for the transmitter. 38931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 38941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid tx_set_idle(MGSLPC_INFO *info) 38951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 38961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Note: ESCC2 only supports flags and one idle modes */ 38971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->idle_mode == HDLC_TXIDLE_FLAGS) 38981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_reg_bits(info, CHA + CCR1, BIT3); 38991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 39001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_reg_bits(info, CHA + CCR1, BIT3); 39011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 39021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* get state of the V24 status (input) signals. 39041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 39051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid get_signals(MGSLPC_INFO *info) 39061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 39071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char status = 0; 39081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* preserve DTR and RTS */ 39101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->serial_signals &= SerialSignal_DTR + SerialSignal_RTS; 39111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (read_reg(info, CHB + VSTR) & BIT7) 39131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->serial_signals |= SerialSignal_DCD; 39141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (read_reg(info, CHB + STAR) & BIT1) 39151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->serial_signals |= SerialSignal_CTS; 39161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = read_reg(info, CHA + PVR); 39181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(status & PVR_RI)) 39191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->serial_signals |= SerialSignal_RI; 39201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(status & PVR_DSR)) 39211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->serial_signals |= SerialSignal_DSR; 39221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 39231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Set the state of DTR and RTS based on contents of 39251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * serial_signals member of device extension. 39261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 39271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid set_signals(MGSLPC_INFO *info) 39281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 39291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char val; 39301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = read_reg(info, CHA + MODE); 39321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.mode == MGSL_MODE_ASYNC) { 39331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->serial_signals & SerialSignal_RTS) 39341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val &= ~BIT6; 39351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 39361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT6; 39371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 39381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->serial_signals & SerialSignal_RTS) 39391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= BIT2; 39401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 39411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val &= ~BIT2; 39421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 39431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + MODE, val); 39441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->serial_signals & SerialSignal_DTR) 39461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_reg_bits(info, CHA + PVR, PVR_DTR); 39471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 39481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_reg_bits(info, CHA + PVR, PVR_DTR); 39491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 39501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid rx_reset_buffers(MGSLPC_INFO *info) 39521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 39531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds RXBUF *buf; 39541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 39551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->rx_put = 0; 39571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->rx_get = 0; 39581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->rx_frame_count = 0; 39591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i=0 ; i < info->rx_buf_count ; i++) { 39601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf = (RXBUF*)(info->rx_buf + (i * info->rx_buf_size)); 39611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf->status = buf->count = 0; 39621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 39631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 39641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Attempt to return a received HDLC frame 39661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Only frames received without errors are returned. 39671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 39681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns 1 if frame returned, otherwise 0 39691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 39701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint rx_get_frame(MGSLPC_INFO *info) 39711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 39721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short status; 39731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds RXBUF *buf; 39741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int framesize = 0; 39751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 39761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tty_struct *tty = info->tty; 39771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int return_frame = 0; 39781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->rx_frame_count == 0) 39801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 39811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf = (RXBUF*)(info->rx_buf + (info->rx_get * info->rx_buf_size)); 39831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = buf->status; 39851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 07 VFR 1=valid frame 39871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 06 RDO 1=data overrun 39881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 05 CRC 1=OK, 0=error 39891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04 RAB 1=frame aborted 39901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 39911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((status & 0xf0) != 0xA0) { 39921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(status & BIT7) || (status & BIT4)) 39931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->icount.rxabort++; 39941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (status & BIT6) 39951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->icount.rxover++; 39961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (!(status & BIT5)) { 39971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->icount.rxcrc++; 39981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.crc_type & HDLC_CRC_RETURN_EX) 39991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return_frame = 1; 40001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 40011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds framesize = 0; 40021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_HDLC 40031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 40041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device_stats *stats = hdlc_stats(info->netdev); 40051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stats->rx_errors++; 40061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stats->rx_frame_errors++; 40071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 40081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 40091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 40101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return_frame = 1; 40111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (return_frame) 40131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds framesize = buf->count; 40141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_BH) 40161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):rx_get_frame(%s) status=%04X size=%d\n", 40171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__,info->device_name,status,framesize); 40181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_DATA) 40201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds trace_block(info, buf->data, framesize, 0); 40211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (framesize) { 40231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((info->params.crc_type & HDLC_CRC_RETURN_EX && 40241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds framesize+1 > info->max_frame_size) || 40251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds framesize > info->max_frame_size) 40261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->icount.rxlong++; 40271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 40281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & BIT5) 40291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->icount.rxok++; 40301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->params.crc_type & HDLC_CRC_RETURN_EX) { 40321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *(buf->data + framesize) = status & BIT5 ? RX_OK:RX_CRC_ERROR; 40331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ++framesize; 40341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 40351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_HDLC 40371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->netcount) 40381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdlcdev_rx(info, buf->data, framesize); 40391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 40401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 40411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ldisc_receive_buf(tty, buf->data, info->flag_buf, framesize); 40421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 40431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 40441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->lock,flags); 40461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf->status = buf->count = 0; 40471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->rx_frame_count--; 40481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->rx_get++; 40491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->rx_get >= info->rx_buf_count) 40501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->rx_get = 0; 40511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock,flags); 40521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 40541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 40551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsBOOLEAN register_test(MGSLPC_INFO *info) 40571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 40581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds static unsigned char patterns[] = 40591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 0x00, 0xff, 0xaa, 0x55, 0x69, 0x96, 0x0f }; 40601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds static unsigned int count = sizeof(patterns) / sizeof(patterns[0]); 40611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int i; 40621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BOOLEAN rc = TRUE; 40631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 40641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->lock,flags); 40661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reset_device(info); 40671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < count; i++) { 40691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, XAD1, patterns[i]); 40701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, XAD2, patterns[(i + 1) % count]); 40711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((read_reg(info, XAD1) != patterns[i]) || 40721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (read_reg(info, XAD2) != patterns[(i + 1) % count])) { 40731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = FALSE; 40741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 40751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 40761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 40771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock,flags); 40791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 40801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 40811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsBOOLEAN irq_test(MGSLPC_INFO *info) 40831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 40841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long end_time; 40851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 40861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->lock,flags); 40881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reset_device(info); 40891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->testing_irq = TRUE; 40911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdlc_mode(info); 40921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->irq_occurred = FALSE; 40941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* init hdlc mode */ 40961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq_enable(info, CHA, IRQ_TIMER); 40981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_reg(info, CHA + TIMR, 0); /* 512 cycles */ 40991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds issue_command(info, CHA, CMD_START_TIMER); 41001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock,flags); 41021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds end_time=100; 41041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while(end_time-- && !info->irq_occurred) { 41051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msleep_interruptible(10); 41061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 41071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->testing_irq = FALSE; 41091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->lock,flags); 41111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reset_device(info); 41121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock,flags); 41131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return info->irq_occurred ? TRUE : FALSE; 41151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 41161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint adapter_test(MGSLPC_INFO *info) 41181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 41191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!register_test(info)) { 41201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->init_error = DiagStatus_AddressFailure; 41211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk( "%s(%d):Register test failure for device %s Addr=%04X\n", 41221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__,info->device_name, (unsigned short)(info->io_base) ); 41231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 41241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 41251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!irq_test(info)) { 41271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->init_error = DiagStatus_IrqFailure; 41281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk( "%s(%d):Interrupt test failure for device %s IRQ=%d\n", 41291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__,info->device_name, (unsigned short)(info->irq_level) ); 41301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 41311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 41321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 41341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s(%d):device %s passed diagnostics\n", 41351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__,info->device_name); 41361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 41371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 41381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid trace_block(MGSLPC_INFO *info,const char* data, int count, int xmit) 41401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 41411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 41421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int linecount; 41431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (xmit) 41441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s tx data:\n",info->device_name); 41451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 41461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s rx data:\n",info->device_name); 41471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while(count) { 41491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (count > 16) 41501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds linecount = 16; 41511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 41521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds linecount = count; 41531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for(i=0;i<linecount;i++) 41551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%02X ",(unsigned char)data[i]); 41561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for(;i<17;i++) 41571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(" "); 41581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for(i=0;i<linecount;i++) { 41591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data[i]>=040 && data[i]<=0176) 41601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%c",data[i]); 41611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 41621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("."); 41631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 41641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("\n"); 41651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data += linecount; 41671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count -= linecount; 41681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 41691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 41701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* HDLC frame time out 41721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * update stats and do tx completion processing 41731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 41741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid tx_timeout(unsigned long context) 41751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 41761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = (MGSLPC_INFO*)context; 41771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 41781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ( debug_level >= DEBUG_LEVEL_INFO ) 41801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk( "%s(%d):tx_timeout(%s)\n", 41811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FILE__,__LINE__,info->device_name); 41821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(info->tx_active && 41831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->params.mode == MGSL_MODE_HDLC) { 41841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->icount.txtimeout++; 41851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 41861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->lock,flags); 41871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_active = 0; 41881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_count = info->tx_put = info->tx_get = 0; 41891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock,flags); 41911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_HDLC 41931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->netcount) 41941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdlcdev_tx_done(info); 41951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 41961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 41971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh_transmit(info); 41981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 41991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_HDLC 42011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 42031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * called by generic HDLC layer when protocol selected (PPP, frame relay, etc.) 42041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * set encoding and frame check sequence (FCS) options 42051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 42061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dev pointer to network device structure 42071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * encoding serial encoding setting 42081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * parity FCS setting 42091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 42101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns 0 if success, otherwise error code 42111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 42121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int hdlcdev_attach(struct net_device *dev, unsigned short encoding, 42131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short parity) 42141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 42151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = dev_to_port(dev); 42161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char new_encoding; 42171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short new_crctype; 42181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* return error if TTY interface open */ 42201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->count) 42211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 42221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (encoding) 42241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 42251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ENCODING_NRZ: new_encoding = HDLC_ENCODING_NRZ; break; 42261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ENCODING_NRZI: new_encoding = HDLC_ENCODING_NRZI_SPACE; break; 42271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ENCODING_FM_MARK: new_encoding = HDLC_ENCODING_BIPHASE_MARK; break; 42281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ENCODING_FM_SPACE: new_encoding = HDLC_ENCODING_BIPHASE_SPACE; break; 42291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ENCODING_MANCHESTER: new_encoding = HDLC_ENCODING_BIPHASE_LEVEL; break; 42301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: return -EINVAL; 42311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 42321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (parity) 42341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 42351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PARITY_NONE: new_crctype = HDLC_CRC_NONE; break; 42361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PARITY_CRC16_PR1_CCITT: new_crctype = HDLC_CRC_16_CCITT; break; 42371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PARITY_CRC32_PR1_CCITT: new_crctype = HDLC_CRC_32_CCITT; break; 42381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: return -EINVAL; 42391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 42401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->params.encoding = new_encoding; 42421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->params.crc_type = new_crctype;; 42431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if network interface up, reprogram hardware */ 42451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->netcount) 42461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_program_hw(info); 42471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 42491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 42501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 42521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * called by generic HDLC layer to send frame 42531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 42541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * skb socket buffer containing HDLC frame 42551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dev pointer to network device structure 42561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 42571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns 0 if success, otherwise error code 42581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 42591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev) 42601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 42611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = dev_to_port(dev); 42621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device_stats *stats = hdlc_stats(dev); 42631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 42641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 42661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "%s:hdlc_xmit(%s)\n",__FILE__,dev->name); 42671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* stop sending until this frame completes */ 42691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_stop_queue(dev); 42701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* copy data to device buffers */ 42721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(info->tx_buf, skb->data, skb->len); 42731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_get = 0; 42741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->tx_put = info->tx_count = skb->len; 42751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* update network statistics */ 42771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stats->tx_packets++; 42781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stats->tx_bytes += skb->len; 42791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* done with socket buffer, so free it */ 42811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_kfree_skb(skb); 42821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* save start time for transmit timeout detection */ 42841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->trans_start = jiffies; 42851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* start hardware transmitter if necessary */ 42871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->lock,flags); 42881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!info->tx_active) 42891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_start(info); 42901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock,flags); 42911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 42931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 42941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 42961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * called by network layer when interface enabled 42971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * claim resources and initialize hardware 42981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 42991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dev pointer to network device structure 43001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 43011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns 0 if success, otherwise error code 43021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 43031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int hdlcdev_open(struct net_device *dev) 43041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 43051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = dev_to_port(dev); 43061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 43071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 43081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 43101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s:hdlcdev_open(%s)\n",__FILE__,dev->name); 43111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* generic HDLC layer open processing */ 43131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((rc = hdlc_open(dev))) 43141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 43151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* arbitrate between network and tty opens */ 43171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->netlock, flags); 43181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->count != 0 || info->netcount != 0) { 43191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING "%s: hdlc_open returning busy\n", dev->name); 43201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->netlock, flags); 43211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 43221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 43231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->netcount=1; 43241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->netlock, flags); 43251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* claim resources and init adapter */ 43271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((rc = startup(info)) != 0) { 43281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->netlock, flags); 43291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->netcount=0; 43301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->netlock, flags); 43311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 43321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 43331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* assert DTR and RTS, apply hardware settings */ 43351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR; 43361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_program_hw(info); 43371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* enable network layer transmit */ 43391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->trans_start = jiffies; 43401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_start_queue(dev); 43411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* inform generic HDLC layer of current DCD status */ 43431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->lock, flags); 43441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds get_signals(info); 43451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock, flags); 43461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdlc_set_carrier(info->serial_signals & SerialSignal_DCD, dev); 43471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 43491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 43501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 43521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * called by network layer when interface is disabled 43531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * shutdown hardware and release resources 43541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 43551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dev pointer to network device structure 43561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 43571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns 0 if success, otherwise error code 43581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 43591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int hdlcdev_close(struct net_device *dev) 43601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 43611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = dev_to_port(dev); 43621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 43631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 43651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s:hdlcdev_close(%s)\n",__FILE__,dev->name); 43661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_stop_queue(dev); 43681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* shutdown adapter and release resources */ 43701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds shutdown(info); 43711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdlc_close(dev); 43731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->netlock, flags); 43751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->netcount=0; 43761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->netlock, flags); 43771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 43791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 43801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 43821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * called by network layer to process IOCTL call to network device 43831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 43841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dev pointer to network device structure 43851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ifr pointer to network interface request structure 43861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cmd IOCTL command code 43871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 43881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns 0 if success, otherwise error code 43891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 43901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) 43911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 43921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const size_t size = sizeof(sync_serial_settings); 43931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sync_serial_settings new_line; 43941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sync_serial_settings __user *line = ifr->ifr_settings.ifs_ifsu.sync; 43951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = dev_to_port(dev); 43961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int flags; 43971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 43991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s:hdlcdev_ioctl(%s)\n",__FILE__,dev->name); 44001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 44011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* return error if TTY interface open */ 44021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->count) 44031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 44041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 44051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cmd != SIOCWANDEV) 44061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return hdlc_ioctl(dev, ifr, cmd); 44071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 44081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch(ifr->ifr_settings.type) { 44091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case IF_GET_IFACE: /* return current sync_serial_settings */ 44101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 44111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ifr->ifr_settings.type = IF_IFACE_SYNC_SERIAL; 44121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ifr->ifr_settings.size < size) { 44131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ifr->ifr_settings.size = size; /* data size wanted */ 44141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOBUFS; 44151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 44161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 44171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flags = info->params.flags & (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | 44181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | 44191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | 44201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); 44211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 44221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (flags){ 44231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN): new_line.clock_type = CLOCK_EXT; break; 44241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_INT; break; 44251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_TXINT; break; 44261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN): new_line.clock_type = CLOCK_TXFROMRX; break; 44271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: new_line.clock_type = CLOCK_DEFAULT; 44281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 44291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 44301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_line.clock_rate = info->params.clock_speed; 44311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_line.loopback = info->params.loopback ? 1:0; 44321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 44331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_to_user(line, &new_line, size)) 44341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 44351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 44361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 44371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case IF_IFACE_SYNC_SERIAL: /* set sync_serial_settings */ 44381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 44391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(!capable(CAP_NET_ADMIN)) 44401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EPERM; 44411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(&new_line, line, size)) 44421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 44431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 44441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (new_line.clock_type) 44451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 44461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CLOCK_EXT: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN; break; 44471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CLOCK_TXFROMRX: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN; break; 44481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CLOCK_INT: flags = HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG; break; 44491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CLOCK_TXINT: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG; break; 44501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CLOCK_DEFAULT: flags = info->params.flags & 44511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | 44521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | 44531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | 44541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); break; 44551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: return -EINVAL; 44561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 44571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 44581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (new_line.loopback != 0 && new_line.loopback != 1) 44591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 44601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 44611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->params.flags &= ~(HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | 44621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | 44631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | 44641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); 44651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->params.flags |= flags; 44661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 44671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->params.loopback = new_line.loopback; 44681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 44691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (flags & (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG)) 44701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->params.clock_speed = new_line.clock_rate; 44711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 44721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->params.clock_speed = 0; 44731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 44741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if network interface up, reprogram hardware */ 44751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->netcount) 44761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mgslpc_program_hw(info); 44771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 44781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 44791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 44801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return hdlc_ioctl(dev, ifr, cmd); 44811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 44821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 44831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 44841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 44851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * called by network layer when transmit timeout is detected 44861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 44871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dev pointer to network device structure 44881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 44891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void hdlcdev_tx_timeout(struct net_device *dev) 44901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 44911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MGSLPC_INFO *info = dev_to_port(dev); 44921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device_stats *stats = hdlc_stats(dev); 44931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 44941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 44951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 44961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("hdlcdev_tx_timeout(%s)\n",dev->name); 44971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 44981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stats->tx_errors++; 44991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stats->tx_aborted_errors++; 45001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 45011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&info->lock,flags); 45021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_stop(info); 45031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&info->lock,flags); 45041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 45051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_wake_queue(dev); 45061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 45071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 45081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 45091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * called by device driver when transmit completes 45101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * reenable network layer transmit if stopped 45111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 45121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * info pointer to device instance information 45131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 45141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void hdlcdev_tx_done(MGSLPC_INFO *info) 45151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 45161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (netif_queue_stopped(info->netdev)) 45171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_wake_queue(info->netdev); 45181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 45191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 45201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 45211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * called by device driver when frame received 45221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pass frame to network layer 45231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 45241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * info pointer to device instance information 45251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * buf pointer to buffer contianing frame data 45261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * size count of data bytes in buf 45271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 45281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void hdlcdev_rx(MGSLPC_INFO *info, char *buf, int size) 45291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 45301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb = dev_alloc_skb(size); 45311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev = info->netdev; 45321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device_stats *stats = hdlc_stats(dev); 45331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 45341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug_level >= DEBUG_LEVEL_INFO) 45351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("hdlcdev_rx(%s)\n",dev->name); 45361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 45371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (skb == NULL) { 45381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_NOTICE "%s: can't alloc skb, dropping packet\n", dev->name); 45391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stats->rx_dropped++; 45401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 45411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 45421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 45431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(skb_put(skb, size),buf,size); 45441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 45451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb->protocol = hdlc_type_trans(skb, info->netdev); 45461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 45471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stats->rx_packets++; 45481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stats->rx_bytes += size; 45491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 45501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_rx(skb); 45511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 45521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->netdev->last_rx = jiffies; 45531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 45541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 45551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 45561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * called by device driver when adding device instance 45571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * do generic HDLC initialization 45581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 45591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * info pointer to device instance information 45601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 45611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns 0 if success, otherwise error code 45621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 45631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int hdlcdev_init(MGSLPC_INFO *info) 45641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 45651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 45661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev; 45671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdlc_device *hdlc; 45681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 45691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* allocate and initialize network and HDLC layer objects */ 45701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 45711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(dev = alloc_hdlcdev(info))) { 45721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "%s:hdlc device allocation failure\n",__FILE__); 45731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 45741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 45751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 45761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* for network layer reporting purposes only */ 45771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->base_addr = info->io_base; 45781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->irq = info->irq_level; 45791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 45801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* network layer callbacks and settings */ 45811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->do_ioctl = hdlcdev_ioctl; 45821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->open = hdlcdev_open; 45831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->stop = hdlcdev_close; 45841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->tx_timeout = hdlcdev_tx_timeout; 45851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->watchdog_timeo = 10*HZ; 45861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->tx_queue_len = 50; 45871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 45881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* generic HDLC layer callbacks and settings */ 45891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdlc = dev_to_hdlc(dev); 45901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdlc->attach = hdlcdev_attach; 45911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdlc->xmit = hdlcdev_xmit; 45921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 45931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* register objects with HDLC layer */ 45941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((rc = register_hdlc_device(dev))) { 45951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING "%s:unable to register hdlc device\n",__FILE__); 45961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_netdev(dev); 45971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 45981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 45991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 46001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->netdev = dev; 46011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 46021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 46031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 46041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 46051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * called by device driver when removing device instance 46061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * do generic HDLC cleanup 46071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 46081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * info pointer to device instance information 46091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 46101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void hdlcdev_exit(MGSLPC_INFO *info) 46111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 46121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unregister_hdlc_device(info->netdev); 46131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_netdev(info->netdev); 46141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->netdev = NULL; 46151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 46161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 46171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_HDLC */ 46181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4619