xref: /OK3568_Linux_fs/kernel/drivers/char/pcmcia/synclink_cs.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * linux/drivers/char/pcmcia/synclink_cs.c
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * $Id: synclink_cs.c,v 4.34 2005/09/08 13:20:54 paulkf Exp $
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * Device driver for Microgate SyncLink PC Card
7*4882a593Smuzhiyun  * multiprotocol serial adapter.
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * written by Paul Fulghum for Microgate Corporation
10*4882a593Smuzhiyun  * paulkf@microgate.com
11*4882a593Smuzhiyun  *
12*4882a593Smuzhiyun  * Microgate and SyncLink are trademarks of Microgate Corporation
13*4882a593Smuzhiyun  *
14*4882a593Smuzhiyun  * This code is released under the GNU General Public License (GPL)
15*4882a593Smuzhiyun  *
16*4882a593Smuzhiyun  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
17*4882a593Smuzhiyun  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18*4882a593Smuzhiyun  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19*4882a593Smuzhiyun  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20*4882a593Smuzhiyun  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21*4882a593Smuzhiyun  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22*4882a593Smuzhiyun  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23*4882a593Smuzhiyun  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24*4882a593Smuzhiyun  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25*4882a593Smuzhiyun  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
26*4882a593Smuzhiyun  * OF THE POSSIBILITY OF SUCH DAMAGE.
27*4882a593Smuzhiyun  */
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun #define VERSION(ver,rel,seq) (((ver)<<16) | ((rel)<<8) | (seq))
30*4882a593Smuzhiyun #if defined(__i386__)
31*4882a593Smuzhiyun #  define BREAKPOINT() asm("   int $3");
32*4882a593Smuzhiyun #else
33*4882a593Smuzhiyun #  define BREAKPOINT() { }
34*4882a593Smuzhiyun #endif
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun #define MAX_DEVICE_COUNT 4
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun #include <linux/module.h>
39*4882a593Smuzhiyun #include <linux/errno.h>
40*4882a593Smuzhiyun #include <linux/signal.h>
41*4882a593Smuzhiyun #include <linux/sched.h>
42*4882a593Smuzhiyun #include <linux/timer.h>
43*4882a593Smuzhiyun #include <linux/time.h>
44*4882a593Smuzhiyun #include <linux/interrupt.h>
45*4882a593Smuzhiyun #include <linux/tty.h>
46*4882a593Smuzhiyun #include <linux/tty_flip.h>
47*4882a593Smuzhiyun #include <linux/serial.h>
48*4882a593Smuzhiyun #include <linux/major.h>
49*4882a593Smuzhiyun #include <linux/string.h>
50*4882a593Smuzhiyun #include <linux/fcntl.h>
51*4882a593Smuzhiyun #include <linux/ptrace.h>
52*4882a593Smuzhiyun #include <linux/ioport.h>
53*4882a593Smuzhiyun #include <linux/mm.h>
54*4882a593Smuzhiyun #include <linux/seq_file.h>
55*4882a593Smuzhiyun #include <linux/slab.h>
56*4882a593Smuzhiyun #include <linux/netdevice.h>
57*4882a593Smuzhiyun #include <linux/vmalloc.h>
58*4882a593Smuzhiyun #include <linux/init.h>
59*4882a593Smuzhiyun #include <linux/delay.h>
60*4882a593Smuzhiyun #include <linux/ioctl.h>
61*4882a593Smuzhiyun #include <linux/synclink.h>
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun #include <asm/io.h>
64*4882a593Smuzhiyun #include <asm/irq.h>
65*4882a593Smuzhiyun #include <asm/dma.h>
66*4882a593Smuzhiyun #include <linux/bitops.h>
67*4882a593Smuzhiyun #include <asm/types.h>
68*4882a593Smuzhiyun #include <linux/termios.h>
69*4882a593Smuzhiyun #include <linux/workqueue.h>
70*4882a593Smuzhiyun #include <linux/hdlc.h>
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun #include <pcmcia/cistpl.h>
73*4882a593Smuzhiyun #include <pcmcia/cisreg.h>
74*4882a593Smuzhiyun #include <pcmcia/ds.h>
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun #if defined(CONFIG_HDLC) || (defined(CONFIG_HDLC_MODULE) && defined(CONFIG_SYNCLINK_CS_MODULE))
77*4882a593Smuzhiyun #define SYNCLINK_GENERIC_HDLC 1
78*4882a593Smuzhiyun #else
79*4882a593Smuzhiyun #define SYNCLINK_GENERIC_HDLC 0
80*4882a593Smuzhiyun #endif
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun #define GET_USER(error,value,addr) error = get_user(value,addr)
83*4882a593Smuzhiyun #define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0
84*4882a593Smuzhiyun #define PUT_USER(error,value,addr) error = put_user(value,addr)
85*4882a593Smuzhiyun #define COPY_TO_USER(error,dest,src,size) error = copy_to_user(dest,src,size) ? -EFAULT : 0
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun #include <linux/uaccess.h>
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun static MGSL_PARAMS default_params = {
90*4882a593Smuzhiyun 	MGSL_MODE_HDLC,			/* unsigned long mode */
91*4882a593Smuzhiyun 	0,				/* unsigned char loopback; */
92*4882a593Smuzhiyun 	HDLC_FLAG_UNDERRUN_ABORT15,	/* unsigned short flags; */
93*4882a593Smuzhiyun 	HDLC_ENCODING_NRZI_SPACE,	/* unsigned char encoding; */
94*4882a593Smuzhiyun 	0,				/* unsigned long clock_speed; */
95*4882a593Smuzhiyun 	0xff,				/* unsigned char addr_filter; */
96*4882a593Smuzhiyun 	HDLC_CRC_16_CCITT,		/* unsigned short crc_type; */
97*4882a593Smuzhiyun 	HDLC_PREAMBLE_LENGTH_8BITS,	/* unsigned char preamble_length; */
98*4882a593Smuzhiyun 	HDLC_PREAMBLE_PATTERN_NONE,	/* unsigned char preamble; */
99*4882a593Smuzhiyun 	9600,				/* unsigned long data_rate; */
100*4882a593Smuzhiyun 	8,				/* unsigned char data_bits; */
101*4882a593Smuzhiyun 	1,				/* unsigned char stop_bits; */
102*4882a593Smuzhiyun 	ASYNC_PARITY_NONE		/* unsigned char parity; */
103*4882a593Smuzhiyun };
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun typedef struct {
106*4882a593Smuzhiyun 	int count;
107*4882a593Smuzhiyun 	unsigned char status;
108*4882a593Smuzhiyun 	char data[1];
109*4882a593Smuzhiyun } RXBUF;
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun /* The queue of BH actions to be performed */
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun #define BH_RECEIVE  1
114*4882a593Smuzhiyun #define BH_TRANSMIT 2
115*4882a593Smuzhiyun #define BH_STATUS   4
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun #define IO_PIN_SHUTDOWN_LIMIT 100
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun #define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun struct _input_signal_events {
122*4882a593Smuzhiyun 	int	ri_up;
123*4882a593Smuzhiyun 	int	ri_down;
124*4882a593Smuzhiyun 	int	dsr_up;
125*4882a593Smuzhiyun 	int	dsr_down;
126*4882a593Smuzhiyun 	int	dcd_up;
127*4882a593Smuzhiyun 	int	dcd_down;
128*4882a593Smuzhiyun 	int	cts_up;
129*4882a593Smuzhiyun 	int	cts_down;
130*4882a593Smuzhiyun };
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun /*
134*4882a593Smuzhiyun  * Device instance data structure
135*4882a593Smuzhiyun  */
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun typedef struct _mgslpc_info {
138*4882a593Smuzhiyun 	struct tty_port		port;
139*4882a593Smuzhiyun 	void *if_ptr;	/* General purpose pointer (used by SPPP) */
140*4882a593Smuzhiyun 	int			magic;
141*4882a593Smuzhiyun 	int			line;
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	struct mgsl_icount	icount;
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	int			timeout;
146*4882a593Smuzhiyun 	int			x_char;		/* xon/xoff character */
147*4882a593Smuzhiyun 	unsigned char		read_status_mask;
148*4882a593Smuzhiyun 	unsigned char		ignore_status_mask;
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	unsigned char *tx_buf;
151*4882a593Smuzhiyun 	int            tx_put;
152*4882a593Smuzhiyun 	int            tx_get;
153*4882a593Smuzhiyun 	int            tx_count;
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	/* circular list of fixed length rx buffers */
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 	unsigned char  *rx_buf;        /* memory allocated for all rx buffers */
158*4882a593Smuzhiyun 	int            rx_buf_total_size; /* size of memory allocated for rx buffers */
159*4882a593Smuzhiyun 	int            rx_put;         /* index of next empty rx buffer */
160*4882a593Smuzhiyun 	int            rx_get;         /* index of next full rx buffer */
161*4882a593Smuzhiyun 	int            rx_buf_size;    /* size in bytes of single rx buffer */
162*4882a593Smuzhiyun 	int            rx_buf_count;   /* total number of rx buffers */
163*4882a593Smuzhiyun 	int            rx_frame_count; /* number of full rx buffers */
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	wait_queue_head_t	status_event_wait_q;
166*4882a593Smuzhiyun 	wait_queue_head_t	event_wait_q;
167*4882a593Smuzhiyun 	struct timer_list	tx_timer;	/* HDLC transmit timeout timer */
168*4882a593Smuzhiyun 	struct _mgslpc_info	*next_device;	/* device list link */
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	unsigned short imra_value;
171*4882a593Smuzhiyun 	unsigned short imrb_value;
172*4882a593Smuzhiyun 	unsigned char  pim_value;
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	spinlock_t lock;
175*4882a593Smuzhiyun 	struct work_struct task;		/* task structure for scheduling bh */
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 	u32 max_frame_size;
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun 	u32 pending_bh;
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	bool bh_running;
182*4882a593Smuzhiyun 	bool bh_requested;
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	int dcd_chkcount; /* check counts to prevent */
185*4882a593Smuzhiyun 	int cts_chkcount; /* too many IRQs if a signal */
186*4882a593Smuzhiyun 	int dsr_chkcount; /* is floating */
187*4882a593Smuzhiyun 	int ri_chkcount;
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 	bool rx_enabled;
190*4882a593Smuzhiyun 	bool rx_overflow;
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	bool tx_enabled;
193*4882a593Smuzhiyun 	bool tx_active;
194*4882a593Smuzhiyun 	bool tx_aborting;
195*4882a593Smuzhiyun 	u32 idle_mode;
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	int if_mode; /* serial interface selection (RS-232, v.35 etc) */
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	char device_name[25];		/* device instance name */
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	unsigned int io_base;	/* base I/O address of adapter */
202*4882a593Smuzhiyun 	unsigned int irq_level;
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 	MGSL_PARAMS params;		/* communications parameters */
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	unsigned char serial_signals;	/* current serial signal states */
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 	bool irq_occurred;		/* for diagnostics use */
209*4882a593Smuzhiyun 	char testing_irq;
210*4882a593Smuzhiyun 	unsigned int init_error;	/* startup error (DIAGS)	*/
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 	char *flag_buf;
213*4882a593Smuzhiyun 	bool drop_rts_on_tx_done;
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	struct	_input_signal_events	input_signal_events;
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun 	/* PCMCIA support */
218*4882a593Smuzhiyun 	struct pcmcia_device	*p_dev;
219*4882a593Smuzhiyun 	int		      stop;
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun 	/* SPPP/Cisco HDLC device parts */
222*4882a593Smuzhiyun 	int netcount;
223*4882a593Smuzhiyun 	spinlock_t netlock;
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun #if SYNCLINK_GENERIC_HDLC
226*4882a593Smuzhiyun 	struct net_device *netdev;
227*4882a593Smuzhiyun #endif
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun } MGSLPC_INFO;
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun #define MGSLPC_MAGIC 0x5402
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun /*
234*4882a593Smuzhiyun  * The size of the serial xmit buffer is 1 page, or 4096 bytes
235*4882a593Smuzhiyun  */
236*4882a593Smuzhiyun #define TXBUFSIZE 4096
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun #define CHA     0x00   /* channel A offset */
240*4882a593Smuzhiyun #define CHB     0x40   /* channel B offset */
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun /*
243*4882a593Smuzhiyun  *  FIXME: PPC has PVR defined in asm/reg.h.  For now we just undef it.
244*4882a593Smuzhiyun  */
245*4882a593Smuzhiyun #undef PVR
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun #define RXFIFO  0
248*4882a593Smuzhiyun #define TXFIFO  0
249*4882a593Smuzhiyun #define STAR    0x20
250*4882a593Smuzhiyun #define CMDR    0x20
251*4882a593Smuzhiyun #define RSTA    0x21
252*4882a593Smuzhiyun #define PRE     0x21
253*4882a593Smuzhiyun #define MODE    0x22
254*4882a593Smuzhiyun #define TIMR    0x23
255*4882a593Smuzhiyun #define XAD1    0x24
256*4882a593Smuzhiyun #define XAD2    0x25
257*4882a593Smuzhiyun #define RAH1    0x26
258*4882a593Smuzhiyun #define RAH2    0x27
259*4882a593Smuzhiyun #define DAFO    0x27
260*4882a593Smuzhiyun #define RAL1    0x28
261*4882a593Smuzhiyun #define RFC     0x28
262*4882a593Smuzhiyun #define RHCR    0x29
263*4882a593Smuzhiyun #define RAL2    0x29
264*4882a593Smuzhiyun #define RBCL    0x2a
265*4882a593Smuzhiyun #define XBCL    0x2a
266*4882a593Smuzhiyun #define RBCH    0x2b
267*4882a593Smuzhiyun #define XBCH    0x2b
268*4882a593Smuzhiyun #define CCR0    0x2c
269*4882a593Smuzhiyun #define CCR1    0x2d
270*4882a593Smuzhiyun #define CCR2    0x2e
271*4882a593Smuzhiyun #define CCR3    0x2f
272*4882a593Smuzhiyun #define VSTR    0x34
273*4882a593Smuzhiyun #define BGR     0x34
274*4882a593Smuzhiyun #define RLCR    0x35
275*4882a593Smuzhiyun #define AML     0x36
276*4882a593Smuzhiyun #define AMH     0x37
277*4882a593Smuzhiyun #define GIS     0x38
278*4882a593Smuzhiyun #define IVA     0x38
279*4882a593Smuzhiyun #define IPC     0x39
280*4882a593Smuzhiyun #define ISR     0x3a
281*4882a593Smuzhiyun #define IMR     0x3a
282*4882a593Smuzhiyun #define PVR     0x3c
283*4882a593Smuzhiyun #define PIS     0x3d
284*4882a593Smuzhiyun #define PIM     0x3d
285*4882a593Smuzhiyun #define PCR     0x3e
286*4882a593Smuzhiyun #define CCR4    0x3f
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun // IMR/ISR
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun #define IRQ_BREAK_ON    BIT15   // rx break detected
291*4882a593Smuzhiyun #define IRQ_DATAOVERRUN BIT14	// receive data overflow
292*4882a593Smuzhiyun #define IRQ_ALLSENT     BIT13	// all sent
293*4882a593Smuzhiyun #define IRQ_UNDERRUN    BIT12	// transmit data underrun
294*4882a593Smuzhiyun #define IRQ_TIMER       BIT11	// timer interrupt
295*4882a593Smuzhiyun #define IRQ_CTS         BIT10	// CTS status change
296*4882a593Smuzhiyun #define IRQ_TXREPEAT    BIT9	// tx message repeat
297*4882a593Smuzhiyun #define IRQ_TXFIFO      BIT8	// transmit pool ready
298*4882a593Smuzhiyun #define IRQ_RXEOM       BIT7	// receive message end
299*4882a593Smuzhiyun #define IRQ_EXITHUNT    BIT6	// receive frame start
300*4882a593Smuzhiyun #define IRQ_RXTIME      BIT6    // rx char timeout
301*4882a593Smuzhiyun #define IRQ_DCD         BIT2	// carrier detect status change
302*4882a593Smuzhiyun #define IRQ_OVERRUN     BIT1	// receive frame overflow
303*4882a593Smuzhiyun #define IRQ_RXFIFO      BIT0	// receive pool full
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun // STAR
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun #define XFW   BIT6		// transmit FIFO write enable
308*4882a593Smuzhiyun #define CEC   BIT2		// command executing
309*4882a593Smuzhiyun #define CTS   BIT1		// CTS state
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun #define PVR_DTR      BIT0
312*4882a593Smuzhiyun #define PVR_DSR      BIT1
313*4882a593Smuzhiyun #define PVR_RI       BIT2
314*4882a593Smuzhiyun #define PVR_AUTOCTS  BIT3
315*4882a593Smuzhiyun #define PVR_RS232    0x20   /* 0010b */
316*4882a593Smuzhiyun #define PVR_V35      0xe0   /* 1110b */
317*4882a593Smuzhiyun #define PVR_RS422    0x40   /* 0100b */
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun /* Register access functions */
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun #define write_reg(info, reg, val) outb((val),(info)->io_base + (reg))
322*4882a593Smuzhiyun #define read_reg(info, reg) inb((info)->io_base + (reg))
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun #define read_reg16(info, reg) inw((info)->io_base + (reg))
325*4882a593Smuzhiyun #define write_reg16(info, reg, val) outw((val), (info)->io_base + (reg))
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun #define set_reg_bits(info, reg, mask) \
328*4882a593Smuzhiyun 	write_reg(info, (reg), \
329*4882a593Smuzhiyun 		 (unsigned char) (read_reg(info, (reg)) | (mask)))
330*4882a593Smuzhiyun #define clear_reg_bits(info, reg, mask) \
331*4882a593Smuzhiyun 	write_reg(info, (reg), \
332*4882a593Smuzhiyun 		 (unsigned char) (read_reg(info, (reg)) & ~(mask)))
333*4882a593Smuzhiyun /*
334*4882a593Smuzhiyun  * interrupt enable/disable routines
335*4882a593Smuzhiyun  */
irq_disable(MGSLPC_INFO * info,unsigned char channel,unsigned short mask)336*4882a593Smuzhiyun static void irq_disable(MGSLPC_INFO *info, unsigned char channel, unsigned short mask)
337*4882a593Smuzhiyun {
338*4882a593Smuzhiyun 	if (channel == CHA) {
339*4882a593Smuzhiyun 		info->imra_value |= mask;
340*4882a593Smuzhiyun 		write_reg16(info, CHA + IMR, info->imra_value);
341*4882a593Smuzhiyun 	} else {
342*4882a593Smuzhiyun 		info->imrb_value |= mask;
343*4882a593Smuzhiyun 		write_reg16(info, CHB + IMR, info->imrb_value);
344*4882a593Smuzhiyun 	}
345*4882a593Smuzhiyun }
irq_enable(MGSLPC_INFO * info,unsigned char channel,unsigned short mask)346*4882a593Smuzhiyun static void irq_enable(MGSLPC_INFO *info, unsigned char channel, unsigned short mask)
347*4882a593Smuzhiyun {
348*4882a593Smuzhiyun 	if (channel == CHA) {
349*4882a593Smuzhiyun 		info->imra_value &= ~mask;
350*4882a593Smuzhiyun 		write_reg16(info, CHA + IMR, info->imra_value);
351*4882a593Smuzhiyun 	} else {
352*4882a593Smuzhiyun 		info->imrb_value &= ~mask;
353*4882a593Smuzhiyun 		write_reg16(info, CHB + IMR, info->imrb_value);
354*4882a593Smuzhiyun 	}
355*4882a593Smuzhiyun }
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun #define port_irq_disable(info, mask) \
358*4882a593Smuzhiyun 	{ info->pim_value |= (mask); write_reg(info, PIM, info->pim_value); }
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun #define port_irq_enable(info, mask) \
361*4882a593Smuzhiyun 	{ info->pim_value &= ~(mask); write_reg(info, PIM, info->pim_value); }
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun static void rx_start(MGSLPC_INFO *info);
364*4882a593Smuzhiyun static void rx_stop(MGSLPC_INFO *info);
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun static void tx_start(MGSLPC_INFO *info, struct tty_struct *tty);
367*4882a593Smuzhiyun static void tx_stop(MGSLPC_INFO *info);
368*4882a593Smuzhiyun static void tx_set_idle(MGSLPC_INFO *info);
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun static void get_signals(MGSLPC_INFO *info);
371*4882a593Smuzhiyun static void set_signals(MGSLPC_INFO *info);
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun static void reset_device(MGSLPC_INFO *info);
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun static void hdlc_mode(MGSLPC_INFO *info);
376*4882a593Smuzhiyun static void async_mode(MGSLPC_INFO *info);
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun static void tx_timeout(struct timer_list *t);
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun static int carrier_raised(struct tty_port *port);
381*4882a593Smuzhiyun static void dtr_rts(struct tty_port *port, int onoff);
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun #if SYNCLINK_GENERIC_HDLC
384*4882a593Smuzhiyun #define dev_to_port(D) (dev_to_hdlc(D)->priv)
385*4882a593Smuzhiyun static void hdlcdev_tx_done(MGSLPC_INFO *info);
386*4882a593Smuzhiyun static void hdlcdev_rx(MGSLPC_INFO *info, char *buf, int size);
387*4882a593Smuzhiyun static int  hdlcdev_init(MGSLPC_INFO *info);
388*4882a593Smuzhiyun static void hdlcdev_exit(MGSLPC_INFO *info);
389*4882a593Smuzhiyun #endif
390*4882a593Smuzhiyun 
391*4882a593Smuzhiyun static void trace_block(MGSLPC_INFO *info,const char* data, int count, int xmit);
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun static bool register_test(MGSLPC_INFO *info);
394*4882a593Smuzhiyun static bool irq_test(MGSLPC_INFO *info);
395*4882a593Smuzhiyun static int adapter_test(MGSLPC_INFO *info);
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun static int claim_resources(MGSLPC_INFO *info);
398*4882a593Smuzhiyun static void release_resources(MGSLPC_INFO *info);
399*4882a593Smuzhiyun static int mgslpc_add_device(MGSLPC_INFO *info);
400*4882a593Smuzhiyun static void mgslpc_remove_device(MGSLPC_INFO *info);
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun static bool rx_get_frame(MGSLPC_INFO *info, struct tty_struct *tty);
403*4882a593Smuzhiyun static void rx_reset_buffers(MGSLPC_INFO *info);
404*4882a593Smuzhiyun static int  rx_alloc_buffers(MGSLPC_INFO *info);
405*4882a593Smuzhiyun static void rx_free_buffers(MGSLPC_INFO *info);
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun static irqreturn_t mgslpc_isr(int irq, void *dev_id);
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun /*
410*4882a593Smuzhiyun  * Bottom half interrupt handlers
411*4882a593Smuzhiyun  */
412*4882a593Smuzhiyun static void bh_handler(struct work_struct *work);
413*4882a593Smuzhiyun static void bh_transmit(MGSLPC_INFO *info, struct tty_struct *tty);
414*4882a593Smuzhiyun static void bh_status(MGSLPC_INFO *info);
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun /*
417*4882a593Smuzhiyun  * ioctl handlers
418*4882a593Smuzhiyun  */
419*4882a593Smuzhiyun static int tiocmget(struct tty_struct *tty);
420*4882a593Smuzhiyun static int tiocmset(struct tty_struct *tty,
421*4882a593Smuzhiyun 					unsigned int set, unsigned int clear);
422*4882a593Smuzhiyun static int get_stats(MGSLPC_INFO *info, struct mgsl_icount __user *user_icount);
423*4882a593Smuzhiyun static int get_params(MGSLPC_INFO *info, MGSL_PARAMS __user *user_params);
424*4882a593Smuzhiyun static int set_params(MGSLPC_INFO *info, MGSL_PARAMS __user *new_params, struct tty_struct *tty);
425*4882a593Smuzhiyun static int get_txidle(MGSLPC_INFO *info, int __user *idle_mode);
426*4882a593Smuzhiyun static int set_txidle(MGSLPC_INFO *info, int idle_mode);
427*4882a593Smuzhiyun static int set_txenable(MGSLPC_INFO *info, int enable, struct tty_struct *tty);
428*4882a593Smuzhiyun static int tx_abort(MGSLPC_INFO *info);
429*4882a593Smuzhiyun static int set_rxenable(MGSLPC_INFO *info, int enable);
430*4882a593Smuzhiyun static int wait_events(MGSLPC_INFO *info, int __user *mask);
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun static MGSLPC_INFO *mgslpc_device_list = NULL;
433*4882a593Smuzhiyun static int mgslpc_device_count = 0;
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun /*
436*4882a593Smuzhiyun  * Set this param to non-zero to load eax with the
437*4882a593Smuzhiyun  * .text section address and breakpoint on module load.
438*4882a593Smuzhiyun  * This is useful for use with gdb and add-symbol-file command.
439*4882a593Smuzhiyun  */
440*4882a593Smuzhiyun static bool break_on_load;
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun /*
443*4882a593Smuzhiyun  * Driver major number, defaults to zero to get auto
444*4882a593Smuzhiyun  * assigned major number. May be forced as module parameter.
445*4882a593Smuzhiyun  */
446*4882a593Smuzhiyun static int ttymajor=0;
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun static int debug_level = 0;
449*4882a593Smuzhiyun static int maxframe[MAX_DEVICE_COUNT] = {0,};
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun module_param(break_on_load, bool, 0);
452*4882a593Smuzhiyun module_param(ttymajor, int, 0);
453*4882a593Smuzhiyun module_param(debug_level, int, 0);
454*4882a593Smuzhiyun module_param_array(maxframe, int, NULL, 0);
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun MODULE_LICENSE("GPL");
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun static char *driver_name = "SyncLink PC Card driver";
459*4882a593Smuzhiyun static char *driver_version = "$Revision: 4.34 $";
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun static struct tty_driver *serial_driver;
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun /* number of characters left in xmit buffer before we ask for more */
464*4882a593Smuzhiyun #define WAKEUP_CHARS 256
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun static void mgslpc_change_params(MGSLPC_INFO *info, struct tty_struct *tty);
467*4882a593Smuzhiyun static void mgslpc_wait_until_sent(struct tty_struct *tty, int timeout);
468*4882a593Smuzhiyun 
469*4882a593Smuzhiyun /* PCMCIA prototypes */
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun static int mgslpc_config(struct pcmcia_device *link);
472*4882a593Smuzhiyun static void mgslpc_release(u_long arg);
473*4882a593Smuzhiyun static void mgslpc_detach(struct pcmcia_device *p_dev);
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun /*
476*4882a593Smuzhiyun  * 1st function defined in .text section. Calling this function in
477*4882a593Smuzhiyun  * init_module() followed by a breakpoint allows a remote debugger
478*4882a593Smuzhiyun  * (gdb) to get the .text address for the add-symbol-file command.
479*4882a593Smuzhiyun  * This allows remote debugging of dynamically loadable modules.
480*4882a593Smuzhiyun  */
mgslpc_get_text_ptr(void)481*4882a593Smuzhiyun static void* mgslpc_get_text_ptr(void)
482*4882a593Smuzhiyun {
483*4882a593Smuzhiyun 	return mgslpc_get_text_ptr;
484*4882a593Smuzhiyun }
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun /**
487*4882a593Smuzhiyun  * line discipline callback wrappers
488*4882a593Smuzhiyun  *
489*4882a593Smuzhiyun  * The wrappers maintain line discipline references
490*4882a593Smuzhiyun  * while calling into the line discipline.
491*4882a593Smuzhiyun  *
492*4882a593Smuzhiyun  * ldisc_receive_buf  - pass receive data to line discipline
493*4882a593Smuzhiyun  */
494*4882a593Smuzhiyun 
ldisc_receive_buf(struct tty_struct * tty,const __u8 * data,char * flags,int count)495*4882a593Smuzhiyun static void ldisc_receive_buf(struct tty_struct *tty,
496*4882a593Smuzhiyun 			      const __u8 *data, char *flags, int count)
497*4882a593Smuzhiyun {
498*4882a593Smuzhiyun 	struct tty_ldisc *ld;
499*4882a593Smuzhiyun 	if (!tty)
500*4882a593Smuzhiyun 		return;
501*4882a593Smuzhiyun 	ld = tty_ldisc_ref(tty);
502*4882a593Smuzhiyun 	if (ld) {
503*4882a593Smuzhiyun 		if (ld->ops->receive_buf)
504*4882a593Smuzhiyun 			ld->ops->receive_buf(tty, data, flags, count);
505*4882a593Smuzhiyun 		tty_ldisc_deref(ld);
506*4882a593Smuzhiyun 	}
507*4882a593Smuzhiyun }
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun static const struct tty_port_operations mgslpc_port_ops = {
510*4882a593Smuzhiyun 	.carrier_raised = carrier_raised,
511*4882a593Smuzhiyun 	.dtr_rts = dtr_rts
512*4882a593Smuzhiyun };
513*4882a593Smuzhiyun 
mgslpc_probe(struct pcmcia_device * link)514*4882a593Smuzhiyun static int mgslpc_probe(struct pcmcia_device *link)
515*4882a593Smuzhiyun {
516*4882a593Smuzhiyun 	MGSLPC_INFO *info;
517*4882a593Smuzhiyun 	int ret;
518*4882a593Smuzhiyun 
519*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
520*4882a593Smuzhiyun 		printk("mgslpc_attach\n");
521*4882a593Smuzhiyun 
522*4882a593Smuzhiyun 	info = kzalloc(sizeof(MGSLPC_INFO), GFP_KERNEL);
523*4882a593Smuzhiyun 	if (!info) {
524*4882a593Smuzhiyun 		printk("Error can't allocate device instance data\n");
525*4882a593Smuzhiyun 		return -ENOMEM;
526*4882a593Smuzhiyun 	}
527*4882a593Smuzhiyun 
528*4882a593Smuzhiyun 	info->magic = MGSLPC_MAGIC;
529*4882a593Smuzhiyun 	tty_port_init(&info->port);
530*4882a593Smuzhiyun 	info->port.ops = &mgslpc_port_ops;
531*4882a593Smuzhiyun 	INIT_WORK(&info->task, bh_handler);
532*4882a593Smuzhiyun 	info->max_frame_size = 4096;
533*4882a593Smuzhiyun 	info->port.close_delay = 5*HZ/10;
534*4882a593Smuzhiyun 	info->port.closing_wait = 30*HZ;
535*4882a593Smuzhiyun 	init_waitqueue_head(&info->status_event_wait_q);
536*4882a593Smuzhiyun 	init_waitqueue_head(&info->event_wait_q);
537*4882a593Smuzhiyun 	spin_lock_init(&info->lock);
538*4882a593Smuzhiyun 	spin_lock_init(&info->netlock);
539*4882a593Smuzhiyun 	memcpy(&info->params,&default_params,sizeof(MGSL_PARAMS));
540*4882a593Smuzhiyun 	info->idle_mode = HDLC_TXIDLE_FLAGS;
541*4882a593Smuzhiyun 	info->imra_value = 0xffff;
542*4882a593Smuzhiyun 	info->imrb_value = 0xffff;
543*4882a593Smuzhiyun 	info->pim_value = 0xff;
544*4882a593Smuzhiyun 
545*4882a593Smuzhiyun 	info->p_dev = link;
546*4882a593Smuzhiyun 	link->priv = info;
547*4882a593Smuzhiyun 
548*4882a593Smuzhiyun 	/* Initialize the struct pcmcia_device structure */
549*4882a593Smuzhiyun 
550*4882a593Smuzhiyun 	ret = mgslpc_config(link);
551*4882a593Smuzhiyun 	if (ret != 0)
552*4882a593Smuzhiyun 		goto failed;
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun 	ret = mgslpc_add_device(info);
555*4882a593Smuzhiyun 	if (ret != 0)
556*4882a593Smuzhiyun 		goto failed_release;
557*4882a593Smuzhiyun 
558*4882a593Smuzhiyun 	return 0;
559*4882a593Smuzhiyun 
560*4882a593Smuzhiyun failed_release:
561*4882a593Smuzhiyun 	mgslpc_release((u_long)link);
562*4882a593Smuzhiyun failed:
563*4882a593Smuzhiyun 	tty_port_destroy(&info->port);
564*4882a593Smuzhiyun 	kfree(info);
565*4882a593Smuzhiyun 	return ret;
566*4882a593Smuzhiyun }
567*4882a593Smuzhiyun 
568*4882a593Smuzhiyun /* Card has been inserted.
569*4882a593Smuzhiyun  */
570*4882a593Smuzhiyun 
mgslpc_ioprobe(struct pcmcia_device * p_dev,void * priv_data)571*4882a593Smuzhiyun static int mgslpc_ioprobe(struct pcmcia_device *p_dev, void *priv_data)
572*4882a593Smuzhiyun {
573*4882a593Smuzhiyun 	return pcmcia_request_io(p_dev);
574*4882a593Smuzhiyun }
575*4882a593Smuzhiyun 
mgslpc_config(struct pcmcia_device * link)576*4882a593Smuzhiyun static int mgslpc_config(struct pcmcia_device *link)
577*4882a593Smuzhiyun {
578*4882a593Smuzhiyun 	MGSLPC_INFO *info = link->priv;
579*4882a593Smuzhiyun 	int ret;
580*4882a593Smuzhiyun 
581*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
582*4882a593Smuzhiyun 		printk("mgslpc_config(0x%p)\n", link);
583*4882a593Smuzhiyun 
584*4882a593Smuzhiyun 	link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
585*4882a593Smuzhiyun 
586*4882a593Smuzhiyun 	ret = pcmcia_loop_config(link, mgslpc_ioprobe, NULL);
587*4882a593Smuzhiyun 	if (ret != 0)
588*4882a593Smuzhiyun 		goto failed;
589*4882a593Smuzhiyun 
590*4882a593Smuzhiyun 	link->config_index = 8;
591*4882a593Smuzhiyun 	link->config_regs = PRESENT_OPTION;
592*4882a593Smuzhiyun 
593*4882a593Smuzhiyun 	ret = pcmcia_request_irq(link, mgslpc_isr);
594*4882a593Smuzhiyun 	if (ret)
595*4882a593Smuzhiyun 		goto failed;
596*4882a593Smuzhiyun 	ret = pcmcia_enable_device(link);
597*4882a593Smuzhiyun 	if (ret)
598*4882a593Smuzhiyun 		goto failed;
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun 	info->io_base = link->resource[0]->start;
601*4882a593Smuzhiyun 	info->irq_level = link->irq;
602*4882a593Smuzhiyun 	return 0;
603*4882a593Smuzhiyun 
604*4882a593Smuzhiyun failed:
605*4882a593Smuzhiyun 	mgslpc_release((u_long)link);
606*4882a593Smuzhiyun 	return -ENODEV;
607*4882a593Smuzhiyun }
608*4882a593Smuzhiyun 
609*4882a593Smuzhiyun /* Card has been removed.
610*4882a593Smuzhiyun  * Unregister device and release PCMCIA configuration.
611*4882a593Smuzhiyun  * If device is open, postpone until it is closed.
612*4882a593Smuzhiyun  */
mgslpc_release(u_long arg)613*4882a593Smuzhiyun static void mgslpc_release(u_long arg)
614*4882a593Smuzhiyun {
615*4882a593Smuzhiyun 	struct pcmcia_device *link = (struct pcmcia_device *)arg;
616*4882a593Smuzhiyun 
617*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
618*4882a593Smuzhiyun 		printk("mgslpc_release(0x%p)\n", link);
619*4882a593Smuzhiyun 
620*4882a593Smuzhiyun 	pcmcia_disable_device(link);
621*4882a593Smuzhiyun }
622*4882a593Smuzhiyun 
mgslpc_detach(struct pcmcia_device * link)623*4882a593Smuzhiyun static void mgslpc_detach(struct pcmcia_device *link)
624*4882a593Smuzhiyun {
625*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
626*4882a593Smuzhiyun 		printk("mgslpc_detach(0x%p)\n", link);
627*4882a593Smuzhiyun 
628*4882a593Smuzhiyun 	((MGSLPC_INFO *)link->priv)->stop = 1;
629*4882a593Smuzhiyun 	mgslpc_release((u_long)link);
630*4882a593Smuzhiyun 
631*4882a593Smuzhiyun 	mgslpc_remove_device((MGSLPC_INFO *)link->priv);
632*4882a593Smuzhiyun }
633*4882a593Smuzhiyun 
mgslpc_suspend(struct pcmcia_device * link)634*4882a593Smuzhiyun static int mgslpc_suspend(struct pcmcia_device *link)
635*4882a593Smuzhiyun {
636*4882a593Smuzhiyun 	MGSLPC_INFO *info = link->priv;
637*4882a593Smuzhiyun 
638*4882a593Smuzhiyun 	info->stop = 1;
639*4882a593Smuzhiyun 
640*4882a593Smuzhiyun 	return 0;
641*4882a593Smuzhiyun }
642*4882a593Smuzhiyun 
mgslpc_resume(struct pcmcia_device * link)643*4882a593Smuzhiyun static int mgslpc_resume(struct pcmcia_device *link)
644*4882a593Smuzhiyun {
645*4882a593Smuzhiyun 	MGSLPC_INFO *info = link->priv;
646*4882a593Smuzhiyun 
647*4882a593Smuzhiyun 	info->stop = 0;
648*4882a593Smuzhiyun 
649*4882a593Smuzhiyun 	return 0;
650*4882a593Smuzhiyun }
651*4882a593Smuzhiyun 
652*4882a593Smuzhiyun 
mgslpc_paranoia_check(MGSLPC_INFO * info,char * name,const char * routine)653*4882a593Smuzhiyun static inline bool mgslpc_paranoia_check(MGSLPC_INFO *info,
654*4882a593Smuzhiyun 					char *name, const char *routine)
655*4882a593Smuzhiyun {
656*4882a593Smuzhiyun #ifdef MGSLPC_PARANOIA_CHECK
657*4882a593Smuzhiyun 	static const char *badmagic =
658*4882a593Smuzhiyun 		"Warning: bad magic number for mgsl struct (%s) in %s\n";
659*4882a593Smuzhiyun 	static const char *badinfo =
660*4882a593Smuzhiyun 		"Warning: null mgslpc_info for (%s) in %s\n";
661*4882a593Smuzhiyun 
662*4882a593Smuzhiyun 	if (!info) {
663*4882a593Smuzhiyun 		printk(badinfo, name, routine);
664*4882a593Smuzhiyun 		return true;
665*4882a593Smuzhiyun 	}
666*4882a593Smuzhiyun 	if (info->magic != MGSLPC_MAGIC) {
667*4882a593Smuzhiyun 		printk(badmagic, name, routine);
668*4882a593Smuzhiyun 		return true;
669*4882a593Smuzhiyun 	}
670*4882a593Smuzhiyun #else
671*4882a593Smuzhiyun 	if (!info)
672*4882a593Smuzhiyun 		return true;
673*4882a593Smuzhiyun #endif
674*4882a593Smuzhiyun 	return false;
675*4882a593Smuzhiyun }
676*4882a593Smuzhiyun 
677*4882a593Smuzhiyun 
678*4882a593Smuzhiyun #define CMD_RXFIFO      BIT7	// release current rx FIFO
679*4882a593Smuzhiyun #define CMD_RXRESET     BIT6	// receiver reset
680*4882a593Smuzhiyun #define CMD_RXFIFO_READ BIT5
681*4882a593Smuzhiyun #define CMD_START_TIMER BIT4
682*4882a593Smuzhiyun #define CMD_TXFIFO      BIT3	// release current tx FIFO
683*4882a593Smuzhiyun #define CMD_TXEOM       BIT1	// transmit end message
684*4882a593Smuzhiyun #define CMD_TXRESET     BIT0	// transmit reset
685*4882a593Smuzhiyun 
wait_command_complete(MGSLPC_INFO * info,unsigned char channel)686*4882a593Smuzhiyun static bool wait_command_complete(MGSLPC_INFO *info, unsigned char channel)
687*4882a593Smuzhiyun {
688*4882a593Smuzhiyun 	int i = 0;
689*4882a593Smuzhiyun 	/* wait for command completion */
690*4882a593Smuzhiyun 	while (read_reg(info, (unsigned char)(channel+STAR)) & BIT2) {
691*4882a593Smuzhiyun 		udelay(1);
692*4882a593Smuzhiyun 		if (i++ == 1000)
693*4882a593Smuzhiyun 			return false;
694*4882a593Smuzhiyun 	}
695*4882a593Smuzhiyun 	return true;
696*4882a593Smuzhiyun }
697*4882a593Smuzhiyun 
issue_command(MGSLPC_INFO * info,unsigned char channel,unsigned char cmd)698*4882a593Smuzhiyun static void issue_command(MGSLPC_INFO *info, unsigned char channel, unsigned char cmd)
699*4882a593Smuzhiyun {
700*4882a593Smuzhiyun 	wait_command_complete(info, channel);
701*4882a593Smuzhiyun 	write_reg(info, (unsigned char) (channel + CMDR), cmd);
702*4882a593Smuzhiyun }
703*4882a593Smuzhiyun 
tx_pause(struct tty_struct * tty)704*4882a593Smuzhiyun static void tx_pause(struct tty_struct *tty)
705*4882a593Smuzhiyun {
706*4882a593Smuzhiyun 	MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
707*4882a593Smuzhiyun 	unsigned long flags;
708*4882a593Smuzhiyun 
709*4882a593Smuzhiyun 	if (mgslpc_paranoia_check(info, tty->name, "tx_pause"))
710*4882a593Smuzhiyun 		return;
711*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
712*4882a593Smuzhiyun 		printk("tx_pause(%s)\n", info->device_name);
713*4882a593Smuzhiyun 
714*4882a593Smuzhiyun 	spin_lock_irqsave(&info->lock, flags);
715*4882a593Smuzhiyun 	if (info->tx_enabled)
716*4882a593Smuzhiyun 		tx_stop(info);
717*4882a593Smuzhiyun 	spin_unlock_irqrestore(&info->lock, flags);
718*4882a593Smuzhiyun }
719*4882a593Smuzhiyun 
tx_release(struct tty_struct * tty)720*4882a593Smuzhiyun static void tx_release(struct tty_struct *tty)
721*4882a593Smuzhiyun {
722*4882a593Smuzhiyun 	MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
723*4882a593Smuzhiyun 	unsigned long flags;
724*4882a593Smuzhiyun 
725*4882a593Smuzhiyun 	if (mgslpc_paranoia_check(info, tty->name, "tx_release"))
726*4882a593Smuzhiyun 		return;
727*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
728*4882a593Smuzhiyun 		printk("tx_release(%s)\n", info->device_name);
729*4882a593Smuzhiyun 
730*4882a593Smuzhiyun 	spin_lock_irqsave(&info->lock, flags);
731*4882a593Smuzhiyun 	if (!info->tx_enabled)
732*4882a593Smuzhiyun 		tx_start(info, tty);
733*4882a593Smuzhiyun 	spin_unlock_irqrestore(&info->lock, flags);
734*4882a593Smuzhiyun }
735*4882a593Smuzhiyun 
736*4882a593Smuzhiyun /* Return next bottom half action to perform.
737*4882a593Smuzhiyun  * or 0 if nothing to do.
738*4882a593Smuzhiyun  */
bh_action(MGSLPC_INFO * info)739*4882a593Smuzhiyun static int bh_action(MGSLPC_INFO *info)
740*4882a593Smuzhiyun {
741*4882a593Smuzhiyun 	unsigned long flags;
742*4882a593Smuzhiyun 	int rc = 0;
743*4882a593Smuzhiyun 
744*4882a593Smuzhiyun 	spin_lock_irqsave(&info->lock, flags);
745*4882a593Smuzhiyun 
746*4882a593Smuzhiyun 	if (info->pending_bh & BH_RECEIVE) {
747*4882a593Smuzhiyun 		info->pending_bh &= ~BH_RECEIVE;
748*4882a593Smuzhiyun 		rc = BH_RECEIVE;
749*4882a593Smuzhiyun 	} else if (info->pending_bh & BH_TRANSMIT) {
750*4882a593Smuzhiyun 		info->pending_bh &= ~BH_TRANSMIT;
751*4882a593Smuzhiyun 		rc = BH_TRANSMIT;
752*4882a593Smuzhiyun 	} else if (info->pending_bh & BH_STATUS) {
753*4882a593Smuzhiyun 		info->pending_bh &= ~BH_STATUS;
754*4882a593Smuzhiyun 		rc = BH_STATUS;
755*4882a593Smuzhiyun 	}
756*4882a593Smuzhiyun 
757*4882a593Smuzhiyun 	if (!rc) {
758*4882a593Smuzhiyun 		/* Mark BH routine as complete */
759*4882a593Smuzhiyun 		info->bh_running = false;
760*4882a593Smuzhiyun 		info->bh_requested = false;
761*4882a593Smuzhiyun 	}
762*4882a593Smuzhiyun 
763*4882a593Smuzhiyun 	spin_unlock_irqrestore(&info->lock, flags);
764*4882a593Smuzhiyun 
765*4882a593Smuzhiyun 	return rc;
766*4882a593Smuzhiyun }
767*4882a593Smuzhiyun 
bh_handler(struct work_struct * work)768*4882a593Smuzhiyun static void bh_handler(struct work_struct *work)
769*4882a593Smuzhiyun {
770*4882a593Smuzhiyun 	MGSLPC_INFO *info = container_of(work, MGSLPC_INFO, task);
771*4882a593Smuzhiyun 	struct tty_struct *tty;
772*4882a593Smuzhiyun 	int action;
773*4882a593Smuzhiyun 
774*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_BH)
775*4882a593Smuzhiyun 		printk("%s(%d):bh_handler(%s) entry\n",
776*4882a593Smuzhiyun 			__FILE__,__LINE__,info->device_name);
777*4882a593Smuzhiyun 
778*4882a593Smuzhiyun 	info->bh_running = true;
779*4882a593Smuzhiyun 	tty = tty_port_tty_get(&info->port);
780*4882a593Smuzhiyun 
781*4882a593Smuzhiyun 	while((action = bh_action(info)) != 0) {
782*4882a593Smuzhiyun 
783*4882a593Smuzhiyun 		/* Process work item */
784*4882a593Smuzhiyun 		if (debug_level >= DEBUG_LEVEL_BH)
785*4882a593Smuzhiyun 			printk("%s(%d):bh_handler() work item action=%d\n",
786*4882a593Smuzhiyun 				__FILE__,__LINE__,action);
787*4882a593Smuzhiyun 
788*4882a593Smuzhiyun 		switch (action) {
789*4882a593Smuzhiyun 
790*4882a593Smuzhiyun 		case BH_RECEIVE:
791*4882a593Smuzhiyun 			while(rx_get_frame(info, tty));
792*4882a593Smuzhiyun 			break;
793*4882a593Smuzhiyun 		case BH_TRANSMIT:
794*4882a593Smuzhiyun 			bh_transmit(info, tty);
795*4882a593Smuzhiyun 			break;
796*4882a593Smuzhiyun 		case BH_STATUS:
797*4882a593Smuzhiyun 			bh_status(info);
798*4882a593Smuzhiyun 			break;
799*4882a593Smuzhiyun 		default:
800*4882a593Smuzhiyun 			/* unknown work item ID */
801*4882a593Smuzhiyun 			printk("Unknown work item ID=%08X!\n", action);
802*4882a593Smuzhiyun 			break;
803*4882a593Smuzhiyun 		}
804*4882a593Smuzhiyun 	}
805*4882a593Smuzhiyun 
806*4882a593Smuzhiyun 	tty_kref_put(tty);
807*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_BH)
808*4882a593Smuzhiyun 		printk("%s(%d):bh_handler(%s) exit\n",
809*4882a593Smuzhiyun 			__FILE__,__LINE__,info->device_name);
810*4882a593Smuzhiyun }
811*4882a593Smuzhiyun 
bh_transmit(MGSLPC_INFO * info,struct tty_struct * tty)812*4882a593Smuzhiyun static void bh_transmit(MGSLPC_INFO *info, struct tty_struct *tty)
813*4882a593Smuzhiyun {
814*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_BH)
815*4882a593Smuzhiyun 		printk("bh_transmit() entry on %s\n", info->device_name);
816*4882a593Smuzhiyun 
817*4882a593Smuzhiyun 	if (tty)
818*4882a593Smuzhiyun 		tty_wakeup(tty);
819*4882a593Smuzhiyun }
820*4882a593Smuzhiyun 
bh_status(MGSLPC_INFO * info)821*4882a593Smuzhiyun static void bh_status(MGSLPC_INFO *info)
822*4882a593Smuzhiyun {
823*4882a593Smuzhiyun 	info->ri_chkcount = 0;
824*4882a593Smuzhiyun 	info->dsr_chkcount = 0;
825*4882a593Smuzhiyun 	info->dcd_chkcount = 0;
826*4882a593Smuzhiyun 	info->cts_chkcount = 0;
827*4882a593Smuzhiyun }
828*4882a593Smuzhiyun 
829*4882a593Smuzhiyun /* eom: non-zero = end of frame */
rx_ready_hdlc(MGSLPC_INFO * info,int eom)830*4882a593Smuzhiyun static void rx_ready_hdlc(MGSLPC_INFO *info, int eom)
831*4882a593Smuzhiyun {
832*4882a593Smuzhiyun 	unsigned char data[2];
833*4882a593Smuzhiyun 	unsigned char fifo_count, read_count, i;
834*4882a593Smuzhiyun 	RXBUF *buf = (RXBUF*)(info->rx_buf + (info->rx_put * info->rx_buf_size));
835*4882a593Smuzhiyun 
836*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_ISR)
837*4882a593Smuzhiyun 		printk("%s(%d):rx_ready_hdlc(eom=%d)\n", __FILE__, __LINE__, eom);
838*4882a593Smuzhiyun 
839*4882a593Smuzhiyun 	if (!info->rx_enabled)
840*4882a593Smuzhiyun 		return;
841*4882a593Smuzhiyun 
842*4882a593Smuzhiyun 	if (info->rx_frame_count >= info->rx_buf_count) {
843*4882a593Smuzhiyun 		/* no more free buffers */
844*4882a593Smuzhiyun 		issue_command(info, CHA, CMD_RXRESET);
845*4882a593Smuzhiyun 		info->pending_bh |= BH_RECEIVE;
846*4882a593Smuzhiyun 		info->rx_overflow = true;
847*4882a593Smuzhiyun 		info->icount.buf_overrun++;
848*4882a593Smuzhiyun 		return;
849*4882a593Smuzhiyun 	}
850*4882a593Smuzhiyun 
851*4882a593Smuzhiyun 	if (eom) {
852*4882a593Smuzhiyun 		/* end of frame, get FIFO count from RBCL register */
853*4882a593Smuzhiyun 		fifo_count = (unsigned char)(read_reg(info, CHA+RBCL) & 0x1f);
854*4882a593Smuzhiyun 		if (fifo_count == 0)
855*4882a593Smuzhiyun 			fifo_count = 32;
856*4882a593Smuzhiyun 	} else
857*4882a593Smuzhiyun 		fifo_count = 32;
858*4882a593Smuzhiyun 
859*4882a593Smuzhiyun 	do {
860*4882a593Smuzhiyun 		if (fifo_count == 1) {
861*4882a593Smuzhiyun 			read_count = 1;
862*4882a593Smuzhiyun 			data[0] = read_reg(info, CHA + RXFIFO);
863*4882a593Smuzhiyun 		} else {
864*4882a593Smuzhiyun 			read_count = 2;
865*4882a593Smuzhiyun 			*((unsigned short *) data) = read_reg16(info, CHA + RXFIFO);
866*4882a593Smuzhiyun 		}
867*4882a593Smuzhiyun 		fifo_count -= read_count;
868*4882a593Smuzhiyun 		if (!fifo_count && eom)
869*4882a593Smuzhiyun 			buf->status = data[--read_count];
870*4882a593Smuzhiyun 
871*4882a593Smuzhiyun 		for (i = 0; i < read_count; i++) {
872*4882a593Smuzhiyun 			if (buf->count >= info->max_frame_size) {
873*4882a593Smuzhiyun 				/* frame too large, reset receiver and reset current buffer */
874*4882a593Smuzhiyun 				issue_command(info, CHA, CMD_RXRESET);
875*4882a593Smuzhiyun 				buf->count = 0;
876*4882a593Smuzhiyun 				return;
877*4882a593Smuzhiyun 			}
878*4882a593Smuzhiyun 			*(buf->data + buf->count) = data[i];
879*4882a593Smuzhiyun 			buf->count++;
880*4882a593Smuzhiyun 		}
881*4882a593Smuzhiyun 	} while (fifo_count);
882*4882a593Smuzhiyun 
883*4882a593Smuzhiyun 	if (eom) {
884*4882a593Smuzhiyun 		info->pending_bh |= BH_RECEIVE;
885*4882a593Smuzhiyun 		info->rx_frame_count++;
886*4882a593Smuzhiyun 		info->rx_put++;
887*4882a593Smuzhiyun 		if (info->rx_put >= info->rx_buf_count)
888*4882a593Smuzhiyun 			info->rx_put = 0;
889*4882a593Smuzhiyun 	}
890*4882a593Smuzhiyun 	issue_command(info, CHA, CMD_RXFIFO);
891*4882a593Smuzhiyun }
892*4882a593Smuzhiyun 
rx_ready_async(MGSLPC_INFO * info,int tcd)893*4882a593Smuzhiyun static void rx_ready_async(MGSLPC_INFO *info, int tcd)
894*4882a593Smuzhiyun {
895*4882a593Smuzhiyun 	struct tty_port *port = &info->port;
896*4882a593Smuzhiyun 	unsigned char data, status, flag;
897*4882a593Smuzhiyun 	int fifo_count;
898*4882a593Smuzhiyun 	int work = 0;
899*4882a593Smuzhiyun 	struct mgsl_icount *icount = &info->icount;
900*4882a593Smuzhiyun 
901*4882a593Smuzhiyun 	if (tcd) {
902*4882a593Smuzhiyun 		/* early termination, get FIFO count from RBCL register */
903*4882a593Smuzhiyun 		fifo_count = (unsigned char)(read_reg(info, CHA+RBCL) & 0x1f);
904*4882a593Smuzhiyun 
905*4882a593Smuzhiyun 		/* Zero fifo count could mean 0 or 32 bytes available.
906*4882a593Smuzhiyun 		 * If BIT5 of STAR is set then at least 1 byte is available.
907*4882a593Smuzhiyun 		 */
908*4882a593Smuzhiyun 		if (!fifo_count && (read_reg(info,CHA+STAR) & BIT5))
909*4882a593Smuzhiyun 			fifo_count = 32;
910*4882a593Smuzhiyun 	} else
911*4882a593Smuzhiyun 		fifo_count = 32;
912*4882a593Smuzhiyun 
913*4882a593Smuzhiyun 	tty_buffer_request_room(port, fifo_count);
914*4882a593Smuzhiyun 	/* Flush received async data to receive data buffer. */
915*4882a593Smuzhiyun 	while (fifo_count) {
916*4882a593Smuzhiyun 		data   = read_reg(info, CHA + RXFIFO);
917*4882a593Smuzhiyun 		status = read_reg(info, CHA + RXFIFO);
918*4882a593Smuzhiyun 		fifo_count -= 2;
919*4882a593Smuzhiyun 
920*4882a593Smuzhiyun 		icount->rx++;
921*4882a593Smuzhiyun 		flag = TTY_NORMAL;
922*4882a593Smuzhiyun 
923*4882a593Smuzhiyun 		// if no frameing/crc error then save data
924*4882a593Smuzhiyun 		// BIT7:parity error
925*4882a593Smuzhiyun 		// BIT6:framing error
926*4882a593Smuzhiyun 
927*4882a593Smuzhiyun 		if (status & (BIT7 + BIT6)) {
928*4882a593Smuzhiyun 			if (status & BIT7)
929*4882a593Smuzhiyun 				icount->parity++;
930*4882a593Smuzhiyun 			else
931*4882a593Smuzhiyun 				icount->frame++;
932*4882a593Smuzhiyun 
933*4882a593Smuzhiyun 			/* discard char if tty control flags say so */
934*4882a593Smuzhiyun 			if (status & info->ignore_status_mask)
935*4882a593Smuzhiyun 				continue;
936*4882a593Smuzhiyun 
937*4882a593Smuzhiyun 			status &= info->read_status_mask;
938*4882a593Smuzhiyun 
939*4882a593Smuzhiyun 			if (status & BIT7)
940*4882a593Smuzhiyun 				flag = TTY_PARITY;
941*4882a593Smuzhiyun 			else if (status & BIT6)
942*4882a593Smuzhiyun 				flag = TTY_FRAME;
943*4882a593Smuzhiyun 		}
944*4882a593Smuzhiyun 		work += tty_insert_flip_char(port, data, flag);
945*4882a593Smuzhiyun 	}
946*4882a593Smuzhiyun 	issue_command(info, CHA, CMD_RXFIFO);
947*4882a593Smuzhiyun 
948*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_ISR) {
949*4882a593Smuzhiyun 		printk("%s(%d):rx_ready_async",
950*4882a593Smuzhiyun 			__FILE__,__LINE__);
951*4882a593Smuzhiyun 		printk("%s(%d):rx=%d brk=%d parity=%d frame=%d overrun=%d\n",
952*4882a593Smuzhiyun 			__FILE__,__LINE__,icount->rx,icount->brk,
953*4882a593Smuzhiyun 			icount->parity,icount->frame,icount->overrun);
954*4882a593Smuzhiyun 	}
955*4882a593Smuzhiyun 
956*4882a593Smuzhiyun 	if (work)
957*4882a593Smuzhiyun 		tty_flip_buffer_push(port);
958*4882a593Smuzhiyun }
959*4882a593Smuzhiyun 
960*4882a593Smuzhiyun 
tx_done(MGSLPC_INFO * info,struct tty_struct * tty)961*4882a593Smuzhiyun static void tx_done(MGSLPC_INFO *info, struct tty_struct *tty)
962*4882a593Smuzhiyun {
963*4882a593Smuzhiyun 	if (!info->tx_active)
964*4882a593Smuzhiyun 		return;
965*4882a593Smuzhiyun 
966*4882a593Smuzhiyun 	info->tx_active = false;
967*4882a593Smuzhiyun 	info->tx_aborting = false;
968*4882a593Smuzhiyun 
969*4882a593Smuzhiyun 	if (info->params.mode == MGSL_MODE_ASYNC)
970*4882a593Smuzhiyun 		return;
971*4882a593Smuzhiyun 
972*4882a593Smuzhiyun 	info->tx_count = info->tx_put = info->tx_get = 0;
973*4882a593Smuzhiyun 	del_timer(&info->tx_timer);
974*4882a593Smuzhiyun 
975*4882a593Smuzhiyun 	if (info->drop_rts_on_tx_done) {
976*4882a593Smuzhiyun 		get_signals(info);
977*4882a593Smuzhiyun 		if (info->serial_signals & SerialSignal_RTS) {
978*4882a593Smuzhiyun 			info->serial_signals &= ~SerialSignal_RTS;
979*4882a593Smuzhiyun 			set_signals(info);
980*4882a593Smuzhiyun 		}
981*4882a593Smuzhiyun 		info->drop_rts_on_tx_done = false;
982*4882a593Smuzhiyun 	}
983*4882a593Smuzhiyun 
984*4882a593Smuzhiyun #if SYNCLINK_GENERIC_HDLC
985*4882a593Smuzhiyun 	if (info->netcount)
986*4882a593Smuzhiyun 		hdlcdev_tx_done(info);
987*4882a593Smuzhiyun 	else
988*4882a593Smuzhiyun #endif
989*4882a593Smuzhiyun 	{
990*4882a593Smuzhiyun 		if (tty && (tty->stopped || tty->hw_stopped)) {
991*4882a593Smuzhiyun 			tx_stop(info);
992*4882a593Smuzhiyun 			return;
993*4882a593Smuzhiyun 		}
994*4882a593Smuzhiyun 		info->pending_bh |= BH_TRANSMIT;
995*4882a593Smuzhiyun 	}
996*4882a593Smuzhiyun }
997*4882a593Smuzhiyun 
tx_ready(MGSLPC_INFO * info,struct tty_struct * tty)998*4882a593Smuzhiyun static void tx_ready(MGSLPC_INFO *info, struct tty_struct *tty)
999*4882a593Smuzhiyun {
1000*4882a593Smuzhiyun 	unsigned char fifo_count = 32;
1001*4882a593Smuzhiyun 	int c;
1002*4882a593Smuzhiyun 
1003*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_ISR)
1004*4882a593Smuzhiyun 		printk("%s(%d):tx_ready(%s)\n", __FILE__, __LINE__, info->device_name);
1005*4882a593Smuzhiyun 
1006*4882a593Smuzhiyun 	if (info->params.mode == MGSL_MODE_HDLC) {
1007*4882a593Smuzhiyun 		if (!info->tx_active)
1008*4882a593Smuzhiyun 			return;
1009*4882a593Smuzhiyun 	} else {
1010*4882a593Smuzhiyun 		if (tty && (tty->stopped || tty->hw_stopped)) {
1011*4882a593Smuzhiyun 			tx_stop(info);
1012*4882a593Smuzhiyun 			return;
1013*4882a593Smuzhiyun 		}
1014*4882a593Smuzhiyun 		if (!info->tx_count)
1015*4882a593Smuzhiyun 			info->tx_active = false;
1016*4882a593Smuzhiyun 	}
1017*4882a593Smuzhiyun 
1018*4882a593Smuzhiyun 	if (!info->tx_count)
1019*4882a593Smuzhiyun 		return;
1020*4882a593Smuzhiyun 
1021*4882a593Smuzhiyun 	while (info->tx_count && fifo_count) {
1022*4882a593Smuzhiyun 		c = min(2, min_t(int, fifo_count, min(info->tx_count, TXBUFSIZE - info->tx_get)));
1023*4882a593Smuzhiyun 
1024*4882a593Smuzhiyun 		if (c == 1) {
1025*4882a593Smuzhiyun 			write_reg(info, CHA + TXFIFO, *(info->tx_buf + info->tx_get));
1026*4882a593Smuzhiyun 		} else {
1027*4882a593Smuzhiyun 			write_reg16(info, CHA + TXFIFO,
1028*4882a593Smuzhiyun 					  *((unsigned short*)(info->tx_buf + info->tx_get)));
1029*4882a593Smuzhiyun 		}
1030*4882a593Smuzhiyun 		info->tx_count -= c;
1031*4882a593Smuzhiyun 		info->tx_get = (info->tx_get + c) & (TXBUFSIZE - 1);
1032*4882a593Smuzhiyun 		fifo_count -= c;
1033*4882a593Smuzhiyun 	}
1034*4882a593Smuzhiyun 
1035*4882a593Smuzhiyun 	if (info->params.mode == MGSL_MODE_ASYNC) {
1036*4882a593Smuzhiyun 		if (info->tx_count < WAKEUP_CHARS)
1037*4882a593Smuzhiyun 			info->pending_bh |= BH_TRANSMIT;
1038*4882a593Smuzhiyun 		issue_command(info, CHA, CMD_TXFIFO);
1039*4882a593Smuzhiyun 	} else {
1040*4882a593Smuzhiyun 		if (info->tx_count)
1041*4882a593Smuzhiyun 			issue_command(info, CHA, CMD_TXFIFO);
1042*4882a593Smuzhiyun 		else
1043*4882a593Smuzhiyun 			issue_command(info, CHA, CMD_TXFIFO + CMD_TXEOM);
1044*4882a593Smuzhiyun 	}
1045*4882a593Smuzhiyun }
1046*4882a593Smuzhiyun 
cts_change(MGSLPC_INFO * info,struct tty_struct * tty)1047*4882a593Smuzhiyun static void cts_change(MGSLPC_INFO *info, struct tty_struct *tty)
1048*4882a593Smuzhiyun {
1049*4882a593Smuzhiyun 	get_signals(info);
1050*4882a593Smuzhiyun 	if ((info->cts_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT)
1051*4882a593Smuzhiyun 		irq_disable(info, CHB, IRQ_CTS);
1052*4882a593Smuzhiyun 	info->icount.cts++;
1053*4882a593Smuzhiyun 	if (info->serial_signals & SerialSignal_CTS)
1054*4882a593Smuzhiyun 		info->input_signal_events.cts_up++;
1055*4882a593Smuzhiyun 	else
1056*4882a593Smuzhiyun 		info->input_signal_events.cts_down++;
1057*4882a593Smuzhiyun 	wake_up_interruptible(&info->status_event_wait_q);
1058*4882a593Smuzhiyun 	wake_up_interruptible(&info->event_wait_q);
1059*4882a593Smuzhiyun 
1060*4882a593Smuzhiyun 	if (tty && tty_port_cts_enabled(&info->port)) {
1061*4882a593Smuzhiyun 		if (tty->hw_stopped) {
1062*4882a593Smuzhiyun 			if (info->serial_signals & SerialSignal_CTS) {
1063*4882a593Smuzhiyun 				if (debug_level >= DEBUG_LEVEL_ISR)
1064*4882a593Smuzhiyun 					printk("CTS tx start...");
1065*4882a593Smuzhiyun 				tty->hw_stopped = 0;
1066*4882a593Smuzhiyun 				tx_start(info, tty);
1067*4882a593Smuzhiyun 				info->pending_bh |= BH_TRANSMIT;
1068*4882a593Smuzhiyun 				return;
1069*4882a593Smuzhiyun 			}
1070*4882a593Smuzhiyun 		} else {
1071*4882a593Smuzhiyun 			if (!(info->serial_signals & SerialSignal_CTS)) {
1072*4882a593Smuzhiyun 				if (debug_level >= DEBUG_LEVEL_ISR)
1073*4882a593Smuzhiyun 					printk("CTS tx stop...");
1074*4882a593Smuzhiyun 				tty->hw_stopped = 1;
1075*4882a593Smuzhiyun 				tx_stop(info);
1076*4882a593Smuzhiyun 			}
1077*4882a593Smuzhiyun 		}
1078*4882a593Smuzhiyun 	}
1079*4882a593Smuzhiyun 	info->pending_bh |= BH_STATUS;
1080*4882a593Smuzhiyun }
1081*4882a593Smuzhiyun 
dcd_change(MGSLPC_INFO * info,struct tty_struct * tty)1082*4882a593Smuzhiyun static void dcd_change(MGSLPC_INFO *info, struct tty_struct *tty)
1083*4882a593Smuzhiyun {
1084*4882a593Smuzhiyun 	get_signals(info);
1085*4882a593Smuzhiyun 	if ((info->dcd_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT)
1086*4882a593Smuzhiyun 		irq_disable(info, CHB, IRQ_DCD);
1087*4882a593Smuzhiyun 	info->icount.dcd++;
1088*4882a593Smuzhiyun 	if (info->serial_signals & SerialSignal_DCD) {
1089*4882a593Smuzhiyun 		info->input_signal_events.dcd_up++;
1090*4882a593Smuzhiyun 	}
1091*4882a593Smuzhiyun 	else
1092*4882a593Smuzhiyun 		info->input_signal_events.dcd_down++;
1093*4882a593Smuzhiyun #if SYNCLINK_GENERIC_HDLC
1094*4882a593Smuzhiyun 	if (info->netcount) {
1095*4882a593Smuzhiyun 		if (info->serial_signals & SerialSignal_DCD)
1096*4882a593Smuzhiyun 			netif_carrier_on(info->netdev);
1097*4882a593Smuzhiyun 		else
1098*4882a593Smuzhiyun 			netif_carrier_off(info->netdev);
1099*4882a593Smuzhiyun 	}
1100*4882a593Smuzhiyun #endif
1101*4882a593Smuzhiyun 	wake_up_interruptible(&info->status_event_wait_q);
1102*4882a593Smuzhiyun 	wake_up_interruptible(&info->event_wait_q);
1103*4882a593Smuzhiyun 
1104*4882a593Smuzhiyun 	if (tty_port_check_carrier(&info->port)) {
1105*4882a593Smuzhiyun 		if (debug_level >= DEBUG_LEVEL_ISR)
1106*4882a593Smuzhiyun 			printk("%s CD now %s...", info->device_name,
1107*4882a593Smuzhiyun 			       (info->serial_signals & SerialSignal_DCD) ? "on" : "off");
1108*4882a593Smuzhiyun 		if (info->serial_signals & SerialSignal_DCD)
1109*4882a593Smuzhiyun 			wake_up_interruptible(&info->port.open_wait);
1110*4882a593Smuzhiyun 		else {
1111*4882a593Smuzhiyun 			if (debug_level >= DEBUG_LEVEL_ISR)
1112*4882a593Smuzhiyun 				printk("doing serial hangup...");
1113*4882a593Smuzhiyun 			if (tty)
1114*4882a593Smuzhiyun 				tty_hangup(tty);
1115*4882a593Smuzhiyun 		}
1116*4882a593Smuzhiyun 	}
1117*4882a593Smuzhiyun 	info->pending_bh |= BH_STATUS;
1118*4882a593Smuzhiyun }
1119*4882a593Smuzhiyun 
dsr_change(MGSLPC_INFO * info)1120*4882a593Smuzhiyun static void dsr_change(MGSLPC_INFO *info)
1121*4882a593Smuzhiyun {
1122*4882a593Smuzhiyun 	get_signals(info);
1123*4882a593Smuzhiyun 	if ((info->dsr_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT)
1124*4882a593Smuzhiyun 		port_irq_disable(info, PVR_DSR);
1125*4882a593Smuzhiyun 	info->icount.dsr++;
1126*4882a593Smuzhiyun 	if (info->serial_signals & SerialSignal_DSR)
1127*4882a593Smuzhiyun 		info->input_signal_events.dsr_up++;
1128*4882a593Smuzhiyun 	else
1129*4882a593Smuzhiyun 		info->input_signal_events.dsr_down++;
1130*4882a593Smuzhiyun 	wake_up_interruptible(&info->status_event_wait_q);
1131*4882a593Smuzhiyun 	wake_up_interruptible(&info->event_wait_q);
1132*4882a593Smuzhiyun 	info->pending_bh |= BH_STATUS;
1133*4882a593Smuzhiyun }
1134*4882a593Smuzhiyun 
ri_change(MGSLPC_INFO * info)1135*4882a593Smuzhiyun static void ri_change(MGSLPC_INFO *info)
1136*4882a593Smuzhiyun {
1137*4882a593Smuzhiyun 	get_signals(info);
1138*4882a593Smuzhiyun 	if ((info->ri_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT)
1139*4882a593Smuzhiyun 		port_irq_disable(info, PVR_RI);
1140*4882a593Smuzhiyun 	info->icount.rng++;
1141*4882a593Smuzhiyun 	if (info->serial_signals & SerialSignal_RI)
1142*4882a593Smuzhiyun 		info->input_signal_events.ri_up++;
1143*4882a593Smuzhiyun 	else
1144*4882a593Smuzhiyun 		info->input_signal_events.ri_down++;
1145*4882a593Smuzhiyun 	wake_up_interruptible(&info->status_event_wait_q);
1146*4882a593Smuzhiyun 	wake_up_interruptible(&info->event_wait_q);
1147*4882a593Smuzhiyun 	info->pending_bh |= BH_STATUS;
1148*4882a593Smuzhiyun }
1149*4882a593Smuzhiyun 
1150*4882a593Smuzhiyun /* Interrupt service routine entry point.
1151*4882a593Smuzhiyun  *
1152*4882a593Smuzhiyun  * Arguments:
1153*4882a593Smuzhiyun  *
1154*4882a593Smuzhiyun  * irq     interrupt number that caused interrupt
1155*4882a593Smuzhiyun  * dev_id  device ID supplied during interrupt registration
1156*4882a593Smuzhiyun  */
mgslpc_isr(int dummy,void * dev_id)1157*4882a593Smuzhiyun static irqreturn_t mgslpc_isr(int dummy, void *dev_id)
1158*4882a593Smuzhiyun {
1159*4882a593Smuzhiyun 	MGSLPC_INFO *info = dev_id;
1160*4882a593Smuzhiyun 	struct tty_struct *tty;
1161*4882a593Smuzhiyun 	unsigned short isr;
1162*4882a593Smuzhiyun 	unsigned char gis, pis;
1163*4882a593Smuzhiyun 	int count=0;
1164*4882a593Smuzhiyun 
1165*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_ISR)
1166*4882a593Smuzhiyun 		printk("mgslpc_isr(%d) entry.\n", info->irq_level);
1167*4882a593Smuzhiyun 
1168*4882a593Smuzhiyun 	if (!(info->p_dev->_locked))
1169*4882a593Smuzhiyun 		return IRQ_HANDLED;
1170*4882a593Smuzhiyun 
1171*4882a593Smuzhiyun 	tty = tty_port_tty_get(&info->port);
1172*4882a593Smuzhiyun 
1173*4882a593Smuzhiyun 	spin_lock(&info->lock);
1174*4882a593Smuzhiyun 
1175*4882a593Smuzhiyun 	while ((gis = read_reg(info, CHA + GIS))) {
1176*4882a593Smuzhiyun 		if (debug_level >= DEBUG_LEVEL_ISR)
1177*4882a593Smuzhiyun 			printk("mgslpc_isr %s gis=%04X\n", info->device_name,gis);
1178*4882a593Smuzhiyun 
1179*4882a593Smuzhiyun 		if ((gis & 0x70) || count > 1000) {
1180*4882a593Smuzhiyun 			printk("synclink_cs:hardware failed or ejected\n");
1181*4882a593Smuzhiyun 			break;
1182*4882a593Smuzhiyun 		}
1183*4882a593Smuzhiyun 		count++;
1184*4882a593Smuzhiyun 
1185*4882a593Smuzhiyun 		if (gis & (BIT1 | BIT0)) {
1186*4882a593Smuzhiyun 			isr = read_reg16(info, CHB + ISR);
1187*4882a593Smuzhiyun 			if (isr & IRQ_DCD)
1188*4882a593Smuzhiyun 				dcd_change(info, tty);
1189*4882a593Smuzhiyun 			if (isr & IRQ_CTS)
1190*4882a593Smuzhiyun 				cts_change(info, tty);
1191*4882a593Smuzhiyun 		}
1192*4882a593Smuzhiyun 		if (gis & (BIT3 | BIT2))
1193*4882a593Smuzhiyun 		{
1194*4882a593Smuzhiyun 			isr = read_reg16(info, CHA + ISR);
1195*4882a593Smuzhiyun 			if (isr & IRQ_TIMER) {
1196*4882a593Smuzhiyun 				info->irq_occurred = true;
1197*4882a593Smuzhiyun 				irq_disable(info, CHA, IRQ_TIMER);
1198*4882a593Smuzhiyun 			}
1199*4882a593Smuzhiyun 
1200*4882a593Smuzhiyun 			/* receive IRQs */
1201*4882a593Smuzhiyun 			if (isr & IRQ_EXITHUNT) {
1202*4882a593Smuzhiyun 				info->icount.exithunt++;
1203*4882a593Smuzhiyun 				wake_up_interruptible(&info->event_wait_q);
1204*4882a593Smuzhiyun 			}
1205*4882a593Smuzhiyun 			if (isr & IRQ_BREAK_ON) {
1206*4882a593Smuzhiyun 				info->icount.brk++;
1207*4882a593Smuzhiyun 				if (info->port.flags & ASYNC_SAK)
1208*4882a593Smuzhiyun 					do_SAK(tty);
1209*4882a593Smuzhiyun 			}
1210*4882a593Smuzhiyun 			if (isr & IRQ_RXTIME) {
1211*4882a593Smuzhiyun 				issue_command(info, CHA, CMD_RXFIFO_READ);
1212*4882a593Smuzhiyun 			}
1213*4882a593Smuzhiyun 			if (isr & (IRQ_RXEOM | IRQ_RXFIFO)) {
1214*4882a593Smuzhiyun 				if (info->params.mode == MGSL_MODE_HDLC)
1215*4882a593Smuzhiyun 					rx_ready_hdlc(info, isr & IRQ_RXEOM);
1216*4882a593Smuzhiyun 				else
1217*4882a593Smuzhiyun 					rx_ready_async(info, isr & IRQ_RXEOM);
1218*4882a593Smuzhiyun 			}
1219*4882a593Smuzhiyun 
1220*4882a593Smuzhiyun 			/* transmit IRQs */
1221*4882a593Smuzhiyun 			if (isr & IRQ_UNDERRUN) {
1222*4882a593Smuzhiyun 				if (info->tx_aborting)
1223*4882a593Smuzhiyun 					info->icount.txabort++;
1224*4882a593Smuzhiyun 				else
1225*4882a593Smuzhiyun 					info->icount.txunder++;
1226*4882a593Smuzhiyun 				tx_done(info, tty);
1227*4882a593Smuzhiyun 			}
1228*4882a593Smuzhiyun 			else if (isr & IRQ_ALLSENT) {
1229*4882a593Smuzhiyun 				info->icount.txok++;
1230*4882a593Smuzhiyun 				tx_done(info, tty);
1231*4882a593Smuzhiyun 			}
1232*4882a593Smuzhiyun 			else if (isr & IRQ_TXFIFO)
1233*4882a593Smuzhiyun 				tx_ready(info, tty);
1234*4882a593Smuzhiyun 		}
1235*4882a593Smuzhiyun 		if (gis & BIT7) {
1236*4882a593Smuzhiyun 			pis = read_reg(info, CHA + PIS);
1237*4882a593Smuzhiyun 			if (pis & BIT1)
1238*4882a593Smuzhiyun 				dsr_change(info);
1239*4882a593Smuzhiyun 			if (pis & BIT2)
1240*4882a593Smuzhiyun 				ri_change(info);
1241*4882a593Smuzhiyun 		}
1242*4882a593Smuzhiyun 	}
1243*4882a593Smuzhiyun 
1244*4882a593Smuzhiyun 	/* Request bottom half processing if there's something
1245*4882a593Smuzhiyun 	 * for it to do and the bh is not already running
1246*4882a593Smuzhiyun 	 */
1247*4882a593Smuzhiyun 
1248*4882a593Smuzhiyun 	if (info->pending_bh && !info->bh_running && !info->bh_requested) {
1249*4882a593Smuzhiyun 		if (debug_level >= DEBUG_LEVEL_ISR)
1250*4882a593Smuzhiyun 			printk("%s(%d):%s queueing bh task.\n",
1251*4882a593Smuzhiyun 				__FILE__,__LINE__,info->device_name);
1252*4882a593Smuzhiyun 		schedule_work(&info->task);
1253*4882a593Smuzhiyun 		info->bh_requested = true;
1254*4882a593Smuzhiyun 	}
1255*4882a593Smuzhiyun 
1256*4882a593Smuzhiyun 	spin_unlock(&info->lock);
1257*4882a593Smuzhiyun 	tty_kref_put(tty);
1258*4882a593Smuzhiyun 
1259*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_ISR)
1260*4882a593Smuzhiyun 		printk("%s(%d):mgslpc_isr(%d)exit.\n",
1261*4882a593Smuzhiyun 		       __FILE__, __LINE__, info->irq_level);
1262*4882a593Smuzhiyun 
1263*4882a593Smuzhiyun 	return IRQ_HANDLED;
1264*4882a593Smuzhiyun }
1265*4882a593Smuzhiyun 
1266*4882a593Smuzhiyun /* Initialize and start device.
1267*4882a593Smuzhiyun  */
startup(MGSLPC_INFO * info,struct tty_struct * tty)1268*4882a593Smuzhiyun static int startup(MGSLPC_INFO * info, struct tty_struct *tty)
1269*4882a593Smuzhiyun {
1270*4882a593Smuzhiyun 	int retval = 0;
1271*4882a593Smuzhiyun 
1272*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
1273*4882a593Smuzhiyun 		printk("%s(%d):startup(%s)\n", __FILE__, __LINE__, info->device_name);
1274*4882a593Smuzhiyun 
1275*4882a593Smuzhiyun 	if (tty_port_initialized(&info->port))
1276*4882a593Smuzhiyun 		return 0;
1277*4882a593Smuzhiyun 
1278*4882a593Smuzhiyun 	if (!info->tx_buf) {
1279*4882a593Smuzhiyun 		/* allocate a page of memory for a transmit buffer */
1280*4882a593Smuzhiyun 		info->tx_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
1281*4882a593Smuzhiyun 		if (!info->tx_buf) {
1282*4882a593Smuzhiyun 			printk(KERN_ERR"%s(%d):%s can't allocate transmit buffer\n",
1283*4882a593Smuzhiyun 				__FILE__, __LINE__, info->device_name);
1284*4882a593Smuzhiyun 			return -ENOMEM;
1285*4882a593Smuzhiyun 		}
1286*4882a593Smuzhiyun 	}
1287*4882a593Smuzhiyun 
1288*4882a593Smuzhiyun 	info->pending_bh = 0;
1289*4882a593Smuzhiyun 
1290*4882a593Smuzhiyun 	memset(&info->icount, 0, sizeof(info->icount));
1291*4882a593Smuzhiyun 
1292*4882a593Smuzhiyun 	timer_setup(&info->tx_timer, tx_timeout, 0);
1293*4882a593Smuzhiyun 
1294*4882a593Smuzhiyun 	/* Allocate and claim adapter resources */
1295*4882a593Smuzhiyun 	retval = claim_resources(info);
1296*4882a593Smuzhiyun 
1297*4882a593Smuzhiyun 	/* perform existence check and diagnostics */
1298*4882a593Smuzhiyun 	if (!retval)
1299*4882a593Smuzhiyun 		retval = adapter_test(info);
1300*4882a593Smuzhiyun 
1301*4882a593Smuzhiyun 	if (retval) {
1302*4882a593Smuzhiyun 		if (capable(CAP_SYS_ADMIN) && tty)
1303*4882a593Smuzhiyun 			set_bit(TTY_IO_ERROR, &tty->flags);
1304*4882a593Smuzhiyun 		release_resources(info);
1305*4882a593Smuzhiyun 		return retval;
1306*4882a593Smuzhiyun 	}
1307*4882a593Smuzhiyun 
1308*4882a593Smuzhiyun 	/* program hardware for current parameters */
1309*4882a593Smuzhiyun 	mgslpc_change_params(info, tty);
1310*4882a593Smuzhiyun 
1311*4882a593Smuzhiyun 	if (tty)
1312*4882a593Smuzhiyun 		clear_bit(TTY_IO_ERROR, &tty->flags);
1313*4882a593Smuzhiyun 
1314*4882a593Smuzhiyun 	tty_port_set_initialized(&info->port, 1);
1315*4882a593Smuzhiyun 
1316*4882a593Smuzhiyun 	return 0;
1317*4882a593Smuzhiyun }
1318*4882a593Smuzhiyun 
1319*4882a593Smuzhiyun /* Called by mgslpc_close() and mgslpc_hangup() to shutdown hardware
1320*4882a593Smuzhiyun  */
shutdown(MGSLPC_INFO * info,struct tty_struct * tty)1321*4882a593Smuzhiyun static void shutdown(MGSLPC_INFO * info, struct tty_struct *tty)
1322*4882a593Smuzhiyun {
1323*4882a593Smuzhiyun 	unsigned long flags;
1324*4882a593Smuzhiyun 
1325*4882a593Smuzhiyun 	if (!tty_port_initialized(&info->port))
1326*4882a593Smuzhiyun 		return;
1327*4882a593Smuzhiyun 
1328*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
1329*4882a593Smuzhiyun 		printk("%s(%d):mgslpc_shutdown(%s)\n",
1330*4882a593Smuzhiyun 			 __FILE__, __LINE__, info->device_name);
1331*4882a593Smuzhiyun 
1332*4882a593Smuzhiyun 	/* clear status wait queue because status changes */
1333*4882a593Smuzhiyun 	/* can't happen after shutting down the hardware */
1334*4882a593Smuzhiyun 	wake_up_interruptible(&info->status_event_wait_q);
1335*4882a593Smuzhiyun 	wake_up_interruptible(&info->event_wait_q);
1336*4882a593Smuzhiyun 
1337*4882a593Smuzhiyun 	del_timer_sync(&info->tx_timer);
1338*4882a593Smuzhiyun 
1339*4882a593Smuzhiyun 	if (info->tx_buf) {
1340*4882a593Smuzhiyun 		free_page((unsigned long) info->tx_buf);
1341*4882a593Smuzhiyun 		info->tx_buf = NULL;
1342*4882a593Smuzhiyun 	}
1343*4882a593Smuzhiyun 
1344*4882a593Smuzhiyun 	spin_lock_irqsave(&info->lock, flags);
1345*4882a593Smuzhiyun 
1346*4882a593Smuzhiyun 	rx_stop(info);
1347*4882a593Smuzhiyun 	tx_stop(info);
1348*4882a593Smuzhiyun 
1349*4882a593Smuzhiyun 	/* TODO:disable interrupts instead of reset to preserve signal states */
1350*4882a593Smuzhiyun 	reset_device(info);
1351*4882a593Smuzhiyun 
1352*4882a593Smuzhiyun 	if (!tty || C_HUPCL(tty)) {
1353*4882a593Smuzhiyun 		info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR);
1354*4882a593Smuzhiyun 		set_signals(info);
1355*4882a593Smuzhiyun 	}
1356*4882a593Smuzhiyun 
1357*4882a593Smuzhiyun 	spin_unlock_irqrestore(&info->lock, flags);
1358*4882a593Smuzhiyun 
1359*4882a593Smuzhiyun 	release_resources(info);
1360*4882a593Smuzhiyun 
1361*4882a593Smuzhiyun 	if (tty)
1362*4882a593Smuzhiyun 		set_bit(TTY_IO_ERROR, &tty->flags);
1363*4882a593Smuzhiyun 
1364*4882a593Smuzhiyun 	tty_port_set_initialized(&info->port, 0);
1365*4882a593Smuzhiyun }
1366*4882a593Smuzhiyun 
mgslpc_program_hw(MGSLPC_INFO * info,struct tty_struct * tty)1367*4882a593Smuzhiyun static void mgslpc_program_hw(MGSLPC_INFO *info, struct tty_struct *tty)
1368*4882a593Smuzhiyun {
1369*4882a593Smuzhiyun 	unsigned long flags;
1370*4882a593Smuzhiyun 
1371*4882a593Smuzhiyun 	spin_lock_irqsave(&info->lock, flags);
1372*4882a593Smuzhiyun 
1373*4882a593Smuzhiyun 	rx_stop(info);
1374*4882a593Smuzhiyun 	tx_stop(info);
1375*4882a593Smuzhiyun 	info->tx_count = info->tx_put = info->tx_get = 0;
1376*4882a593Smuzhiyun 
1377*4882a593Smuzhiyun 	if (info->params.mode == MGSL_MODE_HDLC || info->netcount)
1378*4882a593Smuzhiyun 		hdlc_mode(info);
1379*4882a593Smuzhiyun 	else
1380*4882a593Smuzhiyun 		async_mode(info);
1381*4882a593Smuzhiyun 
1382*4882a593Smuzhiyun 	set_signals(info);
1383*4882a593Smuzhiyun 
1384*4882a593Smuzhiyun 	info->dcd_chkcount = 0;
1385*4882a593Smuzhiyun 	info->cts_chkcount = 0;
1386*4882a593Smuzhiyun 	info->ri_chkcount = 0;
1387*4882a593Smuzhiyun 	info->dsr_chkcount = 0;
1388*4882a593Smuzhiyun 
1389*4882a593Smuzhiyun 	irq_enable(info, CHB, IRQ_DCD | IRQ_CTS);
1390*4882a593Smuzhiyun 	port_irq_enable(info, (unsigned char) PVR_DSR | PVR_RI);
1391*4882a593Smuzhiyun 	get_signals(info);
1392*4882a593Smuzhiyun 
1393*4882a593Smuzhiyun 	if (info->netcount || (tty && C_CREAD(tty)))
1394*4882a593Smuzhiyun 		rx_start(info);
1395*4882a593Smuzhiyun 
1396*4882a593Smuzhiyun 	spin_unlock_irqrestore(&info->lock, flags);
1397*4882a593Smuzhiyun }
1398*4882a593Smuzhiyun 
1399*4882a593Smuzhiyun /* Reconfigure adapter based on new parameters
1400*4882a593Smuzhiyun  */
mgslpc_change_params(MGSLPC_INFO * info,struct tty_struct * tty)1401*4882a593Smuzhiyun static void mgslpc_change_params(MGSLPC_INFO *info, struct tty_struct *tty)
1402*4882a593Smuzhiyun {
1403*4882a593Smuzhiyun 	unsigned cflag;
1404*4882a593Smuzhiyun 	int bits_per_char;
1405*4882a593Smuzhiyun 
1406*4882a593Smuzhiyun 	if (!tty)
1407*4882a593Smuzhiyun 		return;
1408*4882a593Smuzhiyun 
1409*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
1410*4882a593Smuzhiyun 		printk("%s(%d):mgslpc_change_params(%s)\n",
1411*4882a593Smuzhiyun 			 __FILE__, __LINE__, info->device_name);
1412*4882a593Smuzhiyun 
1413*4882a593Smuzhiyun 	cflag = tty->termios.c_cflag;
1414*4882a593Smuzhiyun 
1415*4882a593Smuzhiyun 	/* if B0 rate (hangup) specified then negate RTS and DTR */
1416*4882a593Smuzhiyun 	/* otherwise assert RTS and DTR */
1417*4882a593Smuzhiyun 	if (cflag & CBAUD)
1418*4882a593Smuzhiyun 		info->serial_signals |= SerialSignal_RTS | SerialSignal_DTR;
1419*4882a593Smuzhiyun 	else
1420*4882a593Smuzhiyun 		info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR);
1421*4882a593Smuzhiyun 
1422*4882a593Smuzhiyun 	/* byte size and parity */
1423*4882a593Smuzhiyun 
1424*4882a593Smuzhiyun 	switch (cflag & CSIZE) {
1425*4882a593Smuzhiyun 	case CS5: info->params.data_bits = 5; break;
1426*4882a593Smuzhiyun 	case CS6: info->params.data_bits = 6; break;
1427*4882a593Smuzhiyun 	case CS7: info->params.data_bits = 7; break;
1428*4882a593Smuzhiyun 	case CS8: info->params.data_bits = 8; break;
1429*4882a593Smuzhiyun 	default:  info->params.data_bits = 7; break;
1430*4882a593Smuzhiyun 	}
1431*4882a593Smuzhiyun 
1432*4882a593Smuzhiyun 	if (cflag & CSTOPB)
1433*4882a593Smuzhiyun 		info->params.stop_bits = 2;
1434*4882a593Smuzhiyun 	else
1435*4882a593Smuzhiyun 		info->params.stop_bits = 1;
1436*4882a593Smuzhiyun 
1437*4882a593Smuzhiyun 	info->params.parity = ASYNC_PARITY_NONE;
1438*4882a593Smuzhiyun 	if (cflag & PARENB) {
1439*4882a593Smuzhiyun 		if (cflag & PARODD)
1440*4882a593Smuzhiyun 			info->params.parity = ASYNC_PARITY_ODD;
1441*4882a593Smuzhiyun 		else
1442*4882a593Smuzhiyun 			info->params.parity = ASYNC_PARITY_EVEN;
1443*4882a593Smuzhiyun #ifdef CMSPAR
1444*4882a593Smuzhiyun 		if (cflag & CMSPAR)
1445*4882a593Smuzhiyun 			info->params.parity = ASYNC_PARITY_SPACE;
1446*4882a593Smuzhiyun #endif
1447*4882a593Smuzhiyun 	}
1448*4882a593Smuzhiyun 
1449*4882a593Smuzhiyun 	/* calculate number of jiffies to transmit a full
1450*4882a593Smuzhiyun 	 * FIFO (32 bytes) at specified data rate
1451*4882a593Smuzhiyun 	 */
1452*4882a593Smuzhiyun 	bits_per_char = info->params.data_bits +
1453*4882a593Smuzhiyun 			info->params.stop_bits + 1;
1454*4882a593Smuzhiyun 
1455*4882a593Smuzhiyun 	/* if port data rate is set to 460800 or less then
1456*4882a593Smuzhiyun 	 * allow tty settings to override, otherwise keep the
1457*4882a593Smuzhiyun 	 * current data rate.
1458*4882a593Smuzhiyun 	 */
1459*4882a593Smuzhiyun 	if (info->params.data_rate <= 460800) {
1460*4882a593Smuzhiyun 		info->params.data_rate = tty_get_baud_rate(tty);
1461*4882a593Smuzhiyun 	}
1462*4882a593Smuzhiyun 
1463*4882a593Smuzhiyun 	if (info->params.data_rate) {
1464*4882a593Smuzhiyun 		info->timeout = (32*HZ*bits_per_char) /
1465*4882a593Smuzhiyun 				info->params.data_rate;
1466*4882a593Smuzhiyun 	}
1467*4882a593Smuzhiyun 	info->timeout += HZ/50;		/* Add .02 seconds of slop */
1468*4882a593Smuzhiyun 
1469*4882a593Smuzhiyun 	tty_port_set_cts_flow(&info->port, cflag & CRTSCTS);
1470*4882a593Smuzhiyun 	tty_port_set_check_carrier(&info->port, ~cflag & CLOCAL);
1471*4882a593Smuzhiyun 
1472*4882a593Smuzhiyun 	/* process tty input control flags */
1473*4882a593Smuzhiyun 
1474*4882a593Smuzhiyun 	info->read_status_mask = 0;
1475*4882a593Smuzhiyun 	if (I_INPCK(tty))
1476*4882a593Smuzhiyun 		info->read_status_mask |= BIT7 | BIT6;
1477*4882a593Smuzhiyun 	if (I_IGNPAR(tty))
1478*4882a593Smuzhiyun 		info->ignore_status_mask |= BIT7 | BIT6;
1479*4882a593Smuzhiyun 
1480*4882a593Smuzhiyun 	mgslpc_program_hw(info, tty);
1481*4882a593Smuzhiyun }
1482*4882a593Smuzhiyun 
1483*4882a593Smuzhiyun /* Add a character to the transmit buffer
1484*4882a593Smuzhiyun  */
mgslpc_put_char(struct tty_struct * tty,unsigned char ch)1485*4882a593Smuzhiyun static int mgslpc_put_char(struct tty_struct *tty, unsigned char ch)
1486*4882a593Smuzhiyun {
1487*4882a593Smuzhiyun 	MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
1488*4882a593Smuzhiyun 	unsigned long flags;
1489*4882a593Smuzhiyun 
1490*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO) {
1491*4882a593Smuzhiyun 		printk("%s(%d):mgslpc_put_char(%d) on %s\n",
1492*4882a593Smuzhiyun 			__FILE__, __LINE__, ch, info->device_name);
1493*4882a593Smuzhiyun 	}
1494*4882a593Smuzhiyun 
1495*4882a593Smuzhiyun 	if (mgslpc_paranoia_check(info, tty->name, "mgslpc_put_char"))
1496*4882a593Smuzhiyun 		return 0;
1497*4882a593Smuzhiyun 
1498*4882a593Smuzhiyun 	if (!info->tx_buf)
1499*4882a593Smuzhiyun 		return 0;
1500*4882a593Smuzhiyun 
1501*4882a593Smuzhiyun 	spin_lock_irqsave(&info->lock, flags);
1502*4882a593Smuzhiyun 
1503*4882a593Smuzhiyun 	if (info->params.mode == MGSL_MODE_ASYNC || !info->tx_active) {
1504*4882a593Smuzhiyun 		if (info->tx_count < TXBUFSIZE - 1) {
1505*4882a593Smuzhiyun 			info->tx_buf[info->tx_put++] = ch;
1506*4882a593Smuzhiyun 			info->tx_put &= TXBUFSIZE-1;
1507*4882a593Smuzhiyun 			info->tx_count++;
1508*4882a593Smuzhiyun 		}
1509*4882a593Smuzhiyun 	}
1510*4882a593Smuzhiyun 
1511*4882a593Smuzhiyun 	spin_unlock_irqrestore(&info->lock, flags);
1512*4882a593Smuzhiyun 	return 1;
1513*4882a593Smuzhiyun }
1514*4882a593Smuzhiyun 
1515*4882a593Smuzhiyun /* Enable transmitter so remaining characters in the
1516*4882a593Smuzhiyun  * transmit buffer are sent.
1517*4882a593Smuzhiyun  */
mgslpc_flush_chars(struct tty_struct * tty)1518*4882a593Smuzhiyun static void mgslpc_flush_chars(struct tty_struct *tty)
1519*4882a593Smuzhiyun {
1520*4882a593Smuzhiyun 	MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
1521*4882a593Smuzhiyun 	unsigned long flags;
1522*4882a593Smuzhiyun 
1523*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
1524*4882a593Smuzhiyun 		printk("%s(%d):mgslpc_flush_chars() entry on %s tx_count=%d\n",
1525*4882a593Smuzhiyun 			__FILE__, __LINE__, info->device_name, info->tx_count);
1526*4882a593Smuzhiyun 
1527*4882a593Smuzhiyun 	if (mgslpc_paranoia_check(info, tty->name, "mgslpc_flush_chars"))
1528*4882a593Smuzhiyun 		return;
1529*4882a593Smuzhiyun 
1530*4882a593Smuzhiyun 	if (info->tx_count <= 0 || tty->stopped ||
1531*4882a593Smuzhiyun 	    tty->hw_stopped || !info->tx_buf)
1532*4882a593Smuzhiyun 		return;
1533*4882a593Smuzhiyun 
1534*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
1535*4882a593Smuzhiyun 		printk("%s(%d):mgslpc_flush_chars() entry on %s starting transmitter\n",
1536*4882a593Smuzhiyun 			__FILE__, __LINE__, info->device_name);
1537*4882a593Smuzhiyun 
1538*4882a593Smuzhiyun 	spin_lock_irqsave(&info->lock, flags);
1539*4882a593Smuzhiyun 	if (!info->tx_active)
1540*4882a593Smuzhiyun 		tx_start(info, tty);
1541*4882a593Smuzhiyun 	spin_unlock_irqrestore(&info->lock, flags);
1542*4882a593Smuzhiyun }
1543*4882a593Smuzhiyun 
1544*4882a593Smuzhiyun /* Send a block of data
1545*4882a593Smuzhiyun  *
1546*4882a593Smuzhiyun  * Arguments:
1547*4882a593Smuzhiyun  *
1548*4882a593Smuzhiyun  * tty        pointer to tty information structure
1549*4882a593Smuzhiyun  * buf	      pointer to buffer containing send data
1550*4882a593Smuzhiyun  * count      size of send data in bytes
1551*4882a593Smuzhiyun  *
1552*4882a593Smuzhiyun  * Returns: number of characters written
1553*4882a593Smuzhiyun  */
mgslpc_write(struct tty_struct * tty,const unsigned char * buf,int count)1554*4882a593Smuzhiyun static int mgslpc_write(struct tty_struct * tty,
1555*4882a593Smuzhiyun 			const unsigned char *buf, int count)
1556*4882a593Smuzhiyun {
1557*4882a593Smuzhiyun 	int c, ret = 0;
1558*4882a593Smuzhiyun 	MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
1559*4882a593Smuzhiyun 	unsigned long flags;
1560*4882a593Smuzhiyun 
1561*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
1562*4882a593Smuzhiyun 		printk("%s(%d):mgslpc_write(%s) count=%d\n",
1563*4882a593Smuzhiyun 			__FILE__, __LINE__, info->device_name, count);
1564*4882a593Smuzhiyun 
1565*4882a593Smuzhiyun 	if (mgslpc_paranoia_check(info, tty->name, "mgslpc_write") ||
1566*4882a593Smuzhiyun 		!info->tx_buf)
1567*4882a593Smuzhiyun 		goto cleanup;
1568*4882a593Smuzhiyun 
1569*4882a593Smuzhiyun 	if (info->params.mode == MGSL_MODE_HDLC) {
1570*4882a593Smuzhiyun 		if (count > TXBUFSIZE) {
1571*4882a593Smuzhiyun 			ret = -EIO;
1572*4882a593Smuzhiyun 			goto cleanup;
1573*4882a593Smuzhiyun 		}
1574*4882a593Smuzhiyun 		if (info->tx_active)
1575*4882a593Smuzhiyun 			goto cleanup;
1576*4882a593Smuzhiyun 		else if (info->tx_count)
1577*4882a593Smuzhiyun 			goto start;
1578*4882a593Smuzhiyun 	}
1579*4882a593Smuzhiyun 
1580*4882a593Smuzhiyun 	for (;;) {
1581*4882a593Smuzhiyun 		c = min(count,
1582*4882a593Smuzhiyun 			min(TXBUFSIZE - info->tx_count - 1,
1583*4882a593Smuzhiyun 			    TXBUFSIZE - info->tx_put));
1584*4882a593Smuzhiyun 		if (c <= 0)
1585*4882a593Smuzhiyun 			break;
1586*4882a593Smuzhiyun 
1587*4882a593Smuzhiyun 		memcpy(info->tx_buf + info->tx_put, buf, c);
1588*4882a593Smuzhiyun 
1589*4882a593Smuzhiyun 		spin_lock_irqsave(&info->lock, flags);
1590*4882a593Smuzhiyun 		info->tx_put = (info->tx_put + c) & (TXBUFSIZE-1);
1591*4882a593Smuzhiyun 		info->tx_count += c;
1592*4882a593Smuzhiyun 		spin_unlock_irqrestore(&info->lock, flags);
1593*4882a593Smuzhiyun 
1594*4882a593Smuzhiyun 		buf += c;
1595*4882a593Smuzhiyun 		count -= c;
1596*4882a593Smuzhiyun 		ret += c;
1597*4882a593Smuzhiyun 	}
1598*4882a593Smuzhiyun start:
1599*4882a593Smuzhiyun 	if (info->tx_count && !tty->stopped && !tty->hw_stopped) {
1600*4882a593Smuzhiyun 		spin_lock_irqsave(&info->lock, flags);
1601*4882a593Smuzhiyun 		if (!info->tx_active)
1602*4882a593Smuzhiyun 			tx_start(info, tty);
1603*4882a593Smuzhiyun 		spin_unlock_irqrestore(&info->lock, flags);
1604*4882a593Smuzhiyun 	}
1605*4882a593Smuzhiyun cleanup:
1606*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
1607*4882a593Smuzhiyun 		printk("%s(%d):mgslpc_write(%s) returning=%d\n",
1608*4882a593Smuzhiyun 			__FILE__, __LINE__, info->device_name, ret);
1609*4882a593Smuzhiyun 	return ret;
1610*4882a593Smuzhiyun }
1611*4882a593Smuzhiyun 
1612*4882a593Smuzhiyun /* Return the count of free bytes in transmit buffer
1613*4882a593Smuzhiyun  */
mgslpc_write_room(struct tty_struct * tty)1614*4882a593Smuzhiyun static int mgslpc_write_room(struct tty_struct *tty)
1615*4882a593Smuzhiyun {
1616*4882a593Smuzhiyun 	MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
1617*4882a593Smuzhiyun 	int ret;
1618*4882a593Smuzhiyun 
1619*4882a593Smuzhiyun 	if (mgslpc_paranoia_check(info, tty->name, "mgslpc_write_room"))
1620*4882a593Smuzhiyun 		return 0;
1621*4882a593Smuzhiyun 
1622*4882a593Smuzhiyun 	if (info->params.mode == MGSL_MODE_HDLC) {
1623*4882a593Smuzhiyun 		/* HDLC (frame oriented) mode */
1624*4882a593Smuzhiyun 		if (info->tx_active)
1625*4882a593Smuzhiyun 			return 0;
1626*4882a593Smuzhiyun 		else
1627*4882a593Smuzhiyun 			return HDLC_MAX_FRAME_SIZE;
1628*4882a593Smuzhiyun 	} else {
1629*4882a593Smuzhiyun 		ret = TXBUFSIZE - info->tx_count - 1;
1630*4882a593Smuzhiyun 		if (ret < 0)
1631*4882a593Smuzhiyun 			ret = 0;
1632*4882a593Smuzhiyun 	}
1633*4882a593Smuzhiyun 
1634*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
1635*4882a593Smuzhiyun 		printk("%s(%d):mgslpc_write_room(%s)=%d\n",
1636*4882a593Smuzhiyun 			 __FILE__, __LINE__, info->device_name, ret);
1637*4882a593Smuzhiyun 	return ret;
1638*4882a593Smuzhiyun }
1639*4882a593Smuzhiyun 
1640*4882a593Smuzhiyun /* Return the count of bytes in transmit buffer
1641*4882a593Smuzhiyun  */
mgslpc_chars_in_buffer(struct tty_struct * tty)1642*4882a593Smuzhiyun static int mgslpc_chars_in_buffer(struct tty_struct *tty)
1643*4882a593Smuzhiyun {
1644*4882a593Smuzhiyun 	MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
1645*4882a593Smuzhiyun 	int rc;
1646*4882a593Smuzhiyun 
1647*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
1648*4882a593Smuzhiyun 		printk("%s(%d):mgslpc_chars_in_buffer(%s)\n",
1649*4882a593Smuzhiyun 			 __FILE__, __LINE__, info->device_name);
1650*4882a593Smuzhiyun 
1651*4882a593Smuzhiyun 	if (mgslpc_paranoia_check(info, tty->name, "mgslpc_chars_in_buffer"))
1652*4882a593Smuzhiyun 		return 0;
1653*4882a593Smuzhiyun 
1654*4882a593Smuzhiyun 	if (info->params.mode == MGSL_MODE_HDLC)
1655*4882a593Smuzhiyun 		rc = info->tx_active ? info->max_frame_size : 0;
1656*4882a593Smuzhiyun 	else
1657*4882a593Smuzhiyun 		rc = info->tx_count;
1658*4882a593Smuzhiyun 
1659*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
1660*4882a593Smuzhiyun 		printk("%s(%d):mgslpc_chars_in_buffer(%s)=%d\n",
1661*4882a593Smuzhiyun 			 __FILE__, __LINE__, info->device_name, rc);
1662*4882a593Smuzhiyun 
1663*4882a593Smuzhiyun 	return rc;
1664*4882a593Smuzhiyun }
1665*4882a593Smuzhiyun 
1666*4882a593Smuzhiyun /* Discard all data in the send buffer
1667*4882a593Smuzhiyun  */
mgslpc_flush_buffer(struct tty_struct * tty)1668*4882a593Smuzhiyun static void mgslpc_flush_buffer(struct tty_struct *tty)
1669*4882a593Smuzhiyun {
1670*4882a593Smuzhiyun 	MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
1671*4882a593Smuzhiyun 	unsigned long flags;
1672*4882a593Smuzhiyun 
1673*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
1674*4882a593Smuzhiyun 		printk("%s(%d):mgslpc_flush_buffer(%s) entry\n",
1675*4882a593Smuzhiyun 			 __FILE__, __LINE__, info->device_name);
1676*4882a593Smuzhiyun 
1677*4882a593Smuzhiyun 	if (mgslpc_paranoia_check(info, tty->name, "mgslpc_flush_buffer"))
1678*4882a593Smuzhiyun 		return;
1679*4882a593Smuzhiyun 
1680*4882a593Smuzhiyun 	spin_lock_irqsave(&info->lock, flags);
1681*4882a593Smuzhiyun 	info->tx_count = info->tx_put = info->tx_get = 0;
1682*4882a593Smuzhiyun 	del_timer(&info->tx_timer);
1683*4882a593Smuzhiyun 	spin_unlock_irqrestore(&info->lock, flags);
1684*4882a593Smuzhiyun 
1685*4882a593Smuzhiyun 	wake_up_interruptible(&tty->write_wait);
1686*4882a593Smuzhiyun 	tty_wakeup(tty);
1687*4882a593Smuzhiyun }
1688*4882a593Smuzhiyun 
1689*4882a593Smuzhiyun /* Send a high-priority XON/XOFF character
1690*4882a593Smuzhiyun  */
mgslpc_send_xchar(struct tty_struct * tty,char ch)1691*4882a593Smuzhiyun static void mgslpc_send_xchar(struct tty_struct *tty, char ch)
1692*4882a593Smuzhiyun {
1693*4882a593Smuzhiyun 	MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
1694*4882a593Smuzhiyun 	unsigned long flags;
1695*4882a593Smuzhiyun 
1696*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
1697*4882a593Smuzhiyun 		printk("%s(%d):mgslpc_send_xchar(%s,%d)\n",
1698*4882a593Smuzhiyun 			 __FILE__, __LINE__, info->device_name, ch);
1699*4882a593Smuzhiyun 
1700*4882a593Smuzhiyun 	if (mgslpc_paranoia_check(info, tty->name, "mgslpc_send_xchar"))
1701*4882a593Smuzhiyun 		return;
1702*4882a593Smuzhiyun 
1703*4882a593Smuzhiyun 	info->x_char = ch;
1704*4882a593Smuzhiyun 	if (ch) {
1705*4882a593Smuzhiyun 		spin_lock_irqsave(&info->lock, flags);
1706*4882a593Smuzhiyun 		if (!info->tx_enabled)
1707*4882a593Smuzhiyun 			tx_start(info, tty);
1708*4882a593Smuzhiyun 		spin_unlock_irqrestore(&info->lock, flags);
1709*4882a593Smuzhiyun 	}
1710*4882a593Smuzhiyun }
1711*4882a593Smuzhiyun 
1712*4882a593Smuzhiyun /* Signal remote device to throttle send data (our receive data)
1713*4882a593Smuzhiyun  */
mgslpc_throttle(struct tty_struct * tty)1714*4882a593Smuzhiyun static void mgslpc_throttle(struct tty_struct * tty)
1715*4882a593Smuzhiyun {
1716*4882a593Smuzhiyun 	MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
1717*4882a593Smuzhiyun 	unsigned long flags;
1718*4882a593Smuzhiyun 
1719*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
1720*4882a593Smuzhiyun 		printk("%s(%d):mgslpc_throttle(%s) entry\n",
1721*4882a593Smuzhiyun 			 __FILE__, __LINE__, info->device_name);
1722*4882a593Smuzhiyun 
1723*4882a593Smuzhiyun 	if (mgslpc_paranoia_check(info, tty->name, "mgslpc_throttle"))
1724*4882a593Smuzhiyun 		return;
1725*4882a593Smuzhiyun 
1726*4882a593Smuzhiyun 	if (I_IXOFF(tty))
1727*4882a593Smuzhiyun 		mgslpc_send_xchar(tty, STOP_CHAR(tty));
1728*4882a593Smuzhiyun 
1729*4882a593Smuzhiyun 	if (C_CRTSCTS(tty)) {
1730*4882a593Smuzhiyun 		spin_lock_irqsave(&info->lock, flags);
1731*4882a593Smuzhiyun 		info->serial_signals &= ~SerialSignal_RTS;
1732*4882a593Smuzhiyun 		set_signals(info);
1733*4882a593Smuzhiyun 		spin_unlock_irqrestore(&info->lock, flags);
1734*4882a593Smuzhiyun 	}
1735*4882a593Smuzhiyun }
1736*4882a593Smuzhiyun 
1737*4882a593Smuzhiyun /* Signal remote device to stop throttling send data (our receive data)
1738*4882a593Smuzhiyun  */
mgslpc_unthrottle(struct tty_struct * tty)1739*4882a593Smuzhiyun static void mgslpc_unthrottle(struct tty_struct * tty)
1740*4882a593Smuzhiyun {
1741*4882a593Smuzhiyun 	MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
1742*4882a593Smuzhiyun 	unsigned long flags;
1743*4882a593Smuzhiyun 
1744*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
1745*4882a593Smuzhiyun 		printk("%s(%d):mgslpc_unthrottle(%s) entry\n",
1746*4882a593Smuzhiyun 			 __FILE__, __LINE__, info->device_name);
1747*4882a593Smuzhiyun 
1748*4882a593Smuzhiyun 	if (mgslpc_paranoia_check(info, tty->name, "mgslpc_unthrottle"))
1749*4882a593Smuzhiyun 		return;
1750*4882a593Smuzhiyun 
1751*4882a593Smuzhiyun 	if (I_IXOFF(tty)) {
1752*4882a593Smuzhiyun 		if (info->x_char)
1753*4882a593Smuzhiyun 			info->x_char = 0;
1754*4882a593Smuzhiyun 		else
1755*4882a593Smuzhiyun 			mgslpc_send_xchar(tty, START_CHAR(tty));
1756*4882a593Smuzhiyun 	}
1757*4882a593Smuzhiyun 
1758*4882a593Smuzhiyun 	if (C_CRTSCTS(tty)) {
1759*4882a593Smuzhiyun 		spin_lock_irqsave(&info->lock, flags);
1760*4882a593Smuzhiyun 		info->serial_signals |= SerialSignal_RTS;
1761*4882a593Smuzhiyun 		set_signals(info);
1762*4882a593Smuzhiyun 		spin_unlock_irqrestore(&info->lock, flags);
1763*4882a593Smuzhiyun 	}
1764*4882a593Smuzhiyun }
1765*4882a593Smuzhiyun 
1766*4882a593Smuzhiyun /* get the current serial statistics
1767*4882a593Smuzhiyun  */
get_stats(MGSLPC_INFO * info,struct mgsl_icount __user * user_icount)1768*4882a593Smuzhiyun static int get_stats(MGSLPC_INFO * info, struct mgsl_icount __user *user_icount)
1769*4882a593Smuzhiyun {
1770*4882a593Smuzhiyun 	int err;
1771*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
1772*4882a593Smuzhiyun 		printk("get_params(%s)\n", info->device_name);
1773*4882a593Smuzhiyun 	if (!user_icount) {
1774*4882a593Smuzhiyun 		memset(&info->icount, 0, sizeof(info->icount));
1775*4882a593Smuzhiyun 	} else {
1776*4882a593Smuzhiyun 		COPY_TO_USER(err, user_icount, &info->icount, sizeof(struct mgsl_icount));
1777*4882a593Smuzhiyun 		if (err)
1778*4882a593Smuzhiyun 			return -EFAULT;
1779*4882a593Smuzhiyun 	}
1780*4882a593Smuzhiyun 	return 0;
1781*4882a593Smuzhiyun }
1782*4882a593Smuzhiyun 
1783*4882a593Smuzhiyun /* get the current serial parameters
1784*4882a593Smuzhiyun  */
get_params(MGSLPC_INFO * info,MGSL_PARAMS __user * user_params)1785*4882a593Smuzhiyun static int get_params(MGSLPC_INFO * info, MGSL_PARAMS __user *user_params)
1786*4882a593Smuzhiyun {
1787*4882a593Smuzhiyun 	int err;
1788*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
1789*4882a593Smuzhiyun 		printk("get_params(%s)\n", info->device_name);
1790*4882a593Smuzhiyun 	COPY_TO_USER(err,user_params, &info->params, sizeof(MGSL_PARAMS));
1791*4882a593Smuzhiyun 	if (err)
1792*4882a593Smuzhiyun 		return -EFAULT;
1793*4882a593Smuzhiyun 	return 0;
1794*4882a593Smuzhiyun }
1795*4882a593Smuzhiyun 
1796*4882a593Smuzhiyun /* set the serial parameters
1797*4882a593Smuzhiyun  *
1798*4882a593Smuzhiyun  * Arguments:
1799*4882a593Smuzhiyun  *
1800*4882a593Smuzhiyun  *	info		pointer to device instance data
1801*4882a593Smuzhiyun  *	new_params	user buffer containing new serial params
1802*4882a593Smuzhiyun  *
1803*4882a593Smuzhiyun  * Returns:	0 if success, otherwise error code
1804*4882a593Smuzhiyun  */
set_params(MGSLPC_INFO * info,MGSL_PARAMS __user * new_params,struct tty_struct * tty)1805*4882a593Smuzhiyun static int set_params(MGSLPC_INFO * info, MGSL_PARAMS __user *new_params, struct tty_struct *tty)
1806*4882a593Smuzhiyun {
1807*4882a593Smuzhiyun 	unsigned long flags;
1808*4882a593Smuzhiyun 	MGSL_PARAMS tmp_params;
1809*4882a593Smuzhiyun 	int err;
1810*4882a593Smuzhiyun 
1811*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
1812*4882a593Smuzhiyun 		printk("%s(%d):set_params %s\n", __FILE__,__LINE__,
1813*4882a593Smuzhiyun 			info->device_name);
1814*4882a593Smuzhiyun 	COPY_FROM_USER(err,&tmp_params, new_params, sizeof(MGSL_PARAMS));
1815*4882a593Smuzhiyun 	if (err) {
1816*4882a593Smuzhiyun 		if (debug_level >= DEBUG_LEVEL_INFO)
1817*4882a593Smuzhiyun 			printk("%s(%d):set_params(%s) user buffer copy failed\n",
1818*4882a593Smuzhiyun 				__FILE__, __LINE__, info->device_name);
1819*4882a593Smuzhiyun 		return -EFAULT;
1820*4882a593Smuzhiyun 	}
1821*4882a593Smuzhiyun 
1822*4882a593Smuzhiyun 	spin_lock_irqsave(&info->lock, flags);
1823*4882a593Smuzhiyun 	memcpy(&info->params,&tmp_params,sizeof(MGSL_PARAMS));
1824*4882a593Smuzhiyun 	spin_unlock_irqrestore(&info->lock, flags);
1825*4882a593Smuzhiyun 
1826*4882a593Smuzhiyun 	mgslpc_change_params(info, tty);
1827*4882a593Smuzhiyun 
1828*4882a593Smuzhiyun 	return 0;
1829*4882a593Smuzhiyun }
1830*4882a593Smuzhiyun 
get_txidle(MGSLPC_INFO * info,int __user * idle_mode)1831*4882a593Smuzhiyun static int get_txidle(MGSLPC_INFO * info, int __user *idle_mode)
1832*4882a593Smuzhiyun {
1833*4882a593Smuzhiyun 	int err;
1834*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
1835*4882a593Smuzhiyun 		printk("get_txidle(%s)=%d\n", info->device_name, info->idle_mode);
1836*4882a593Smuzhiyun 	COPY_TO_USER(err,idle_mode, &info->idle_mode, sizeof(int));
1837*4882a593Smuzhiyun 	if (err)
1838*4882a593Smuzhiyun 		return -EFAULT;
1839*4882a593Smuzhiyun 	return 0;
1840*4882a593Smuzhiyun }
1841*4882a593Smuzhiyun 
set_txidle(MGSLPC_INFO * info,int idle_mode)1842*4882a593Smuzhiyun static int set_txidle(MGSLPC_INFO * info, int idle_mode)
1843*4882a593Smuzhiyun {
1844*4882a593Smuzhiyun 	unsigned long flags;
1845*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
1846*4882a593Smuzhiyun 		printk("set_txidle(%s,%d)\n", info->device_name, idle_mode);
1847*4882a593Smuzhiyun 	spin_lock_irqsave(&info->lock, flags);
1848*4882a593Smuzhiyun 	info->idle_mode = idle_mode;
1849*4882a593Smuzhiyun 	tx_set_idle(info);
1850*4882a593Smuzhiyun 	spin_unlock_irqrestore(&info->lock, flags);
1851*4882a593Smuzhiyun 	return 0;
1852*4882a593Smuzhiyun }
1853*4882a593Smuzhiyun 
get_interface(MGSLPC_INFO * info,int __user * if_mode)1854*4882a593Smuzhiyun static int get_interface(MGSLPC_INFO * info, int __user *if_mode)
1855*4882a593Smuzhiyun {
1856*4882a593Smuzhiyun 	int err;
1857*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
1858*4882a593Smuzhiyun 		printk("get_interface(%s)=%d\n", info->device_name, info->if_mode);
1859*4882a593Smuzhiyun 	COPY_TO_USER(err,if_mode, &info->if_mode, sizeof(int));
1860*4882a593Smuzhiyun 	if (err)
1861*4882a593Smuzhiyun 		return -EFAULT;
1862*4882a593Smuzhiyun 	return 0;
1863*4882a593Smuzhiyun }
1864*4882a593Smuzhiyun 
set_interface(MGSLPC_INFO * info,int if_mode)1865*4882a593Smuzhiyun static int set_interface(MGSLPC_INFO * info, int if_mode)
1866*4882a593Smuzhiyun {
1867*4882a593Smuzhiyun 	unsigned long flags;
1868*4882a593Smuzhiyun 	unsigned char val;
1869*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
1870*4882a593Smuzhiyun 		printk("set_interface(%s,%d)\n", info->device_name, if_mode);
1871*4882a593Smuzhiyun 	spin_lock_irqsave(&info->lock, flags);
1872*4882a593Smuzhiyun 	info->if_mode = if_mode;
1873*4882a593Smuzhiyun 
1874*4882a593Smuzhiyun 	val = read_reg(info, PVR) & 0x0f;
1875*4882a593Smuzhiyun 	switch (info->if_mode)
1876*4882a593Smuzhiyun 	{
1877*4882a593Smuzhiyun 	case MGSL_INTERFACE_RS232: val |= PVR_RS232; break;
1878*4882a593Smuzhiyun 	case MGSL_INTERFACE_V35:   val |= PVR_V35;   break;
1879*4882a593Smuzhiyun 	case MGSL_INTERFACE_RS422: val |= PVR_RS422; break;
1880*4882a593Smuzhiyun 	}
1881*4882a593Smuzhiyun 	write_reg(info, PVR, val);
1882*4882a593Smuzhiyun 
1883*4882a593Smuzhiyun 	spin_unlock_irqrestore(&info->lock, flags);
1884*4882a593Smuzhiyun 	return 0;
1885*4882a593Smuzhiyun }
1886*4882a593Smuzhiyun 
set_txenable(MGSLPC_INFO * info,int enable,struct tty_struct * tty)1887*4882a593Smuzhiyun static int set_txenable(MGSLPC_INFO * info, int enable, struct tty_struct *tty)
1888*4882a593Smuzhiyun {
1889*4882a593Smuzhiyun 	unsigned long flags;
1890*4882a593Smuzhiyun 
1891*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
1892*4882a593Smuzhiyun 		printk("set_txenable(%s,%d)\n", info->device_name, enable);
1893*4882a593Smuzhiyun 
1894*4882a593Smuzhiyun 	spin_lock_irqsave(&info->lock, flags);
1895*4882a593Smuzhiyun 	if (enable) {
1896*4882a593Smuzhiyun 		if (!info->tx_enabled)
1897*4882a593Smuzhiyun 			tx_start(info, tty);
1898*4882a593Smuzhiyun 	} else {
1899*4882a593Smuzhiyun 		if (info->tx_enabled)
1900*4882a593Smuzhiyun 			tx_stop(info);
1901*4882a593Smuzhiyun 	}
1902*4882a593Smuzhiyun 	spin_unlock_irqrestore(&info->lock, flags);
1903*4882a593Smuzhiyun 	return 0;
1904*4882a593Smuzhiyun }
1905*4882a593Smuzhiyun 
tx_abort(MGSLPC_INFO * info)1906*4882a593Smuzhiyun static int tx_abort(MGSLPC_INFO * info)
1907*4882a593Smuzhiyun {
1908*4882a593Smuzhiyun 	unsigned long flags;
1909*4882a593Smuzhiyun 
1910*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
1911*4882a593Smuzhiyun 		printk("tx_abort(%s)\n", info->device_name);
1912*4882a593Smuzhiyun 
1913*4882a593Smuzhiyun 	spin_lock_irqsave(&info->lock, flags);
1914*4882a593Smuzhiyun 	if (info->tx_active && info->tx_count &&
1915*4882a593Smuzhiyun 	    info->params.mode == MGSL_MODE_HDLC) {
1916*4882a593Smuzhiyun 		/* clear data count so FIFO is not filled on next IRQ.
1917*4882a593Smuzhiyun 		 * This results in underrun and abort transmission.
1918*4882a593Smuzhiyun 		 */
1919*4882a593Smuzhiyun 		info->tx_count = info->tx_put = info->tx_get = 0;
1920*4882a593Smuzhiyun 		info->tx_aborting = true;
1921*4882a593Smuzhiyun 	}
1922*4882a593Smuzhiyun 	spin_unlock_irqrestore(&info->lock, flags);
1923*4882a593Smuzhiyun 	return 0;
1924*4882a593Smuzhiyun }
1925*4882a593Smuzhiyun 
set_rxenable(MGSLPC_INFO * info,int enable)1926*4882a593Smuzhiyun static int set_rxenable(MGSLPC_INFO * info, int enable)
1927*4882a593Smuzhiyun {
1928*4882a593Smuzhiyun 	unsigned long flags;
1929*4882a593Smuzhiyun 
1930*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
1931*4882a593Smuzhiyun 		printk("set_rxenable(%s,%d)\n", info->device_name, enable);
1932*4882a593Smuzhiyun 
1933*4882a593Smuzhiyun 	spin_lock_irqsave(&info->lock, flags);
1934*4882a593Smuzhiyun 	if (enable) {
1935*4882a593Smuzhiyun 		if (!info->rx_enabled)
1936*4882a593Smuzhiyun 			rx_start(info);
1937*4882a593Smuzhiyun 	} else {
1938*4882a593Smuzhiyun 		if (info->rx_enabled)
1939*4882a593Smuzhiyun 			rx_stop(info);
1940*4882a593Smuzhiyun 	}
1941*4882a593Smuzhiyun 	spin_unlock_irqrestore(&info->lock, flags);
1942*4882a593Smuzhiyun 	return 0;
1943*4882a593Smuzhiyun }
1944*4882a593Smuzhiyun 
1945*4882a593Smuzhiyun /* wait for specified event to occur
1946*4882a593Smuzhiyun  *
1947*4882a593Smuzhiyun  * Arguments:		info	pointer to device instance data
1948*4882a593Smuzhiyun  *			mask	pointer to bitmask of events to wait for
1949*4882a593Smuzhiyun  * Return Value:	0	if successful and bit mask updated with
1950*4882a593Smuzhiyun  *				of events triggerred,
1951*4882a593Smuzhiyun  *			otherwise error code
1952*4882a593Smuzhiyun  */
wait_events(MGSLPC_INFO * info,int __user * mask_ptr)1953*4882a593Smuzhiyun static int wait_events(MGSLPC_INFO * info, int __user *mask_ptr)
1954*4882a593Smuzhiyun {
1955*4882a593Smuzhiyun 	unsigned long flags;
1956*4882a593Smuzhiyun 	int s;
1957*4882a593Smuzhiyun 	int rc=0;
1958*4882a593Smuzhiyun 	struct mgsl_icount cprev, cnow;
1959*4882a593Smuzhiyun 	int events;
1960*4882a593Smuzhiyun 	int mask;
1961*4882a593Smuzhiyun 	struct	_input_signal_events oldsigs, newsigs;
1962*4882a593Smuzhiyun 	DECLARE_WAITQUEUE(wait, current);
1963*4882a593Smuzhiyun 
1964*4882a593Smuzhiyun 	COPY_FROM_USER(rc,&mask, mask_ptr, sizeof(int));
1965*4882a593Smuzhiyun 	if (rc)
1966*4882a593Smuzhiyun 		return  -EFAULT;
1967*4882a593Smuzhiyun 
1968*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
1969*4882a593Smuzhiyun 		printk("wait_events(%s,%d)\n", info->device_name, mask);
1970*4882a593Smuzhiyun 
1971*4882a593Smuzhiyun 	spin_lock_irqsave(&info->lock, flags);
1972*4882a593Smuzhiyun 
1973*4882a593Smuzhiyun 	/* return immediately if state matches requested events */
1974*4882a593Smuzhiyun 	get_signals(info);
1975*4882a593Smuzhiyun 	s = info->serial_signals;
1976*4882a593Smuzhiyun 	events = mask &
1977*4882a593Smuzhiyun 		( ((s & SerialSignal_DSR) ? MgslEvent_DsrActive:MgslEvent_DsrInactive) +
1978*4882a593Smuzhiyun 		  ((s & SerialSignal_DCD) ? MgslEvent_DcdActive:MgslEvent_DcdInactive) +
1979*4882a593Smuzhiyun 		  ((s & SerialSignal_CTS) ? MgslEvent_CtsActive:MgslEvent_CtsInactive) +
1980*4882a593Smuzhiyun 		  ((s & SerialSignal_RI)  ? MgslEvent_RiActive :MgslEvent_RiInactive) );
1981*4882a593Smuzhiyun 	if (events) {
1982*4882a593Smuzhiyun 		spin_unlock_irqrestore(&info->lock, flags);
1983*4882a593Smuzhiyun 		goto exit;
1984*4882a593Smuzhiyun 	}
1985*4882a593Smuzhiyun 
1986*4882a593Smuzhiyun 	/* save current irq counts */
1987*4882a593Smuzhiyun 	cprev = info->icount;
1988*4882a593Smuzhiyun 	oldsigs = info->input_signal_events;
1989*4882a593Smuzhiyun 
1990*4882a593Smuzhiyun 	if ((info->params.mode == MGSL_MODE_HDLC) &&
1991*4882a593Smuzhiyun 	    (mask & MgslEvent_ExitHuntMode))
1992*4882a593Smuzhiyun 		irq_enable(info, CHA, IRQ_EXITHUNT);
1993*4882a593Smuzhiyun 
1994*4882a593Smuzhiyun 	set_current_state(TASK_INTERRUPTIBLE);
1995*4882a593Smuzhiyun 	add_wait_queue(&info->event_wait_q, &wait);
1996*4882a593Smuzhiyun 
1997*4882a593Smuzhiyun 	spin_unlock_irqrestore(&info->lock, flags);
1998*4882a593Smuzhiyun 
1999*4882a593Smuzhiyun 
2000*4882a593Smuzhiyun 	for(;;) {
2001*4882a593Smuzhiyun 		schedule();
2002*4882a593Smuzhiyun 		if (signal_pending(current)) {
2003*4882a593Smuzhiyun 			rc = -ERESTARTSYS;
2004*4882a593Smuzhiyun 			break;
2005*4882a593Smuzhiyun 		}
2006*4882a593Smuzhiyun 
2007*4882a593Smuzhiyun 		/* get current irq counts */
2008*4882a593Smuzhiyun 		spin_lock_irqsave(&info->lock, flags);
2009*4882a593Smuzhiyun 		cnow = info->icount;
2010*4882a593Smuzhiyun 		newsigs = info->input_signal_events;
2011*4882a593Smuzhiyun 		set_current_state(TASK_INTERRUPTIBLE);
2012*4882a593Smuzhiyun 		spin_unlock_irqrestore(&info->lock, flags);
2013*4882a593Smuzhiyun 
2014*4882a593Smuzhiyun 		/* if no change, wait aborted for some reason */
2015*4882a593Smuzhiyun 		if (newsigs.dsr_up   == oldsigs.dsr_up   &&
2016*4882a593Smuzhiyun 		    newsigs.dsr_down == oldsigs.dsr_down &&
2017*4882a593Smuzhiyun 		    newsigs.dcd_up   == oldsigs.dcd_up   &&
2018*4882a593Smuzhiyun 		    newsigs.dcd_down == oldsigs.dcd_down &&
2019*4882a593Smuzhiyun 		    newsigs.cts_up   == oldsigs.cts_up   &&
2020*4882a593Smuzhiyun 		    newsigs.cts_down == oldsigs.cts_down &&
2021*4882a593Smuzhiyun 		    newsigs.ri_up    == oldsigs.ri_up    &&
2022*4882a593Smuzhiyun 		    newsigs.ri_down  == oldsigs.ri_down  &&
2023*4882a593Smuzhiyun 		    cnow.exithunt    == cprev.exithunt   &&
2024*4882a593Smuzhiyun 		    cnow.rxidle      == cprev.rxidle) {
2025*4882a593Smuzhiyun 			rc = -EIO;
2026*4882a593Smuzhiyun 			break;
2027*4882a593Smuzhiyun 		}
2028*4882a593Smuzhiyun 
2029*4882a593Smuzhiyun 		events = mask &
2030*4882a593Smuzhiyun 			( (newsigs.dsr_up   != oldsigs.dsr_up   ? MgslEvent_DsrActive:0)   +
2031*4882a593Smuzhiyun 			  (newsigs.dsr_down != oldsigs.dsr_down ? MgslEvent_DsrInactive:0) +
2032*4882a593Smuzhiyun 			  (newsigs.dcd_up   != oldsigs.dcd_up   ? MgslEvent_DcdActive:0)   +
2033*4882a593Smuzhiyun 			  (newsigs.dcd_down != oldsigs.dcd_down ? MgslEvent_DcdInactive:0) +
2034*4882a593Smuzhiyun 			  (newsigs.cts_up   != oldsigs.cts_up   ? MgslEvent_CtsActive:0)   +
2035*4882a593Smuzhiyun 			  (newsigs.cts_down != oldsigs.cts_down ? MgslEvent_CtsInactive:0) +
2036*4882a593Smuzhiyun 			  (newsigs.ri_up    != oldsigs.ri_up    ? MgslEvent_RiActive:0)    +
2037*4882a593Smuzhiyun 			  (newsigs.ri_down  != oldsigs.ri_down  ? MgslEvent_RiInactive:0)  +
2038*4882a593Smuzhiyun 			  (cnow.exithunt    != cprev.exithunt   ? MgslEvent_ExitHuntMode:0) +
2039*4882a593Smuzhiyun 			  (cnow.rxidle      != cprev.rxidle     ? MgslEvent_IdleReceived:0) );
2040*4882a593Smuzhiyun 		if (events)
2041*4882a593Smuzhiyun 			break;
2042*4882a593Smuzhiyun 
2043*4882a593Smuzhiyun 		cprev = cnow;
2044*4882a593Smuzhiyun 		oldsigs = newsigs;
2045*4882a593Smuzhiyun 	}
2046*4882a593Smuzhiyun 
2047*4882a593Smuzhiyun 	remove_wait_queue(&info->event_wait_q, &wait);
2048*4882a593Smuzhiyun 	set_current_state(TASK_RUNNING);
2049*4882a593Smuzhiyun 
2050*4882a593Smuzhiyun 	if (mask & MgslEvent_ExitHuntMode) {
2051*4882a593Smuzhiyun 		spin_lock_irqsave(&info->lock, flags);
2052*4882a593Smuzhiyun 		if (!waitqueue_active(&info->event_wait_q))
2053*4882a593Smuzhiyun 			irq_disable(info, CHA, IRQ_EXITHUNT);
2054*4882a593Smuzhiyun 		spin_unlock_irqrestore(&info->lock, flags);
2055*4882a593Smuzhiyun 	}
2056*4882a593Smuzhiyun exit:
2057*4882a593Smuzhiyun 	if (rc == 0)
2058*4882a593Smuzhiyun 		PUT_USER(rc, events, mask_ptr);
2059*4882a593Smuzhiyun 	return rc;
2060*4882a593Smuzhiyun }
2061*4882a593Smuzhiyun 
modem_input_wait(MGSLPC_INFO * info,int arg)2062*4882a593Smuzhiyun static int modem_input_wait(MGSLPC_INFO *info,int arg)
2063*4882a593Smuzhiyun {
2064*4882a593Smuzhiyun 	unsigned long flags;
2065*4882a593Smuzhiyun 	int rc;
2066*4882a593Smuzhiyun 	struct mgsl_icount cprev, cnow;
2067*4882a593Smuzhiyun 	DECLARE_WAITQUEUE(wait, current);
2068*4882a593Smuzhiyun 
2069*4882a593Smuzhiyun 	/* save current irq counts */
2070*4882a593Smuzhiyun 	spin_lock_irqsave(&info->lock, flags);
2071*4882a593Smuzhiyun 	cprev = info->icount;
2072*4882a593Smuzhiyun 	add_wait_queue(&info->status_event_wait_q, &wait);
2073*4882a593Smuzhiyun 	set_current_state(TASK_INTERRUPTIBLE);
2074*4882a593Smuzhiyun 	spin_unlock_irqrestore(&info->lock, flags);
2075*4882a593Smuzhiyun 
2076*4882a593Smuzhiyun 	for(;;) {
2077*4882a593Smuzhiyun 		schedule();
2078*4882a593Smuzhiyun 		if (signal_pending(current)) {
2079*4882a593Smuzhiyun 			rc = -ERESTARTSYS;
2080*4882a593Smuzhiyun 			break;
2081*4882a593Smuzhiyun 		}
2082*4882a593Smuzhiyun 
2083*4882a593Smuzhiyun 		/* get new irq counts */
2084*4882a593Smuzhiyun 		spin_lock_irqsave(&info->lock, flags);
2085*4882a593Smuzhiyun 		cnow = info->icount;
2086*4882a593Smuzhiyun 		set_current_state(TASK_INTERRUPTIBLE);
2087*4882a593Smuzhiyun 		spin_unlock_irqrestore(&info->lock, flags);
2088*4882a593Smuzhiyun 
2089*4882a593Smuzhiyun 		/* if no change, wait aborted for some reason */
2090*4882a593Smuzhiyun 		if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
2091*4882a593Smuzhiyun 		    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) {
2092*4882a593Smuzhiyun 			rc = -EIO;
2093*4882a593Smuzhiyun 			break;
2094*4882a593Smuzhiyun 		}
2095*4882a593Smuzhiyun 
2096*4882a593Smuzhiyun 		/* check for change in caller specified modem input */
2097*4882a593Smuzhiyun 		if ((arg & TIOCM_RNG && cnow.rng != cprev.rng) ||
2098*4882a593Smuzhiyun 		    (arg & TIOCM_DSR && cnow.dsr != cprev.dsr) ||
2099*4882a593Smuzhiyun 		    (arg & TIOCM_CD  && cnow.dcd != cprev.dcd) ||
2100*4882a593Smuzhiyun 		    (arg & TIOCM_CTS && cnow.cts != cprev.cts)) {
2101*4882a593Smuzhiyun 			rc = 0;
2102*4882a593Smuzhiyun 			break;
2103*4882a593Smuzhiyun 		}
2104*4882a593Smuzhiyun 
2105*4882a593Smuzhiyun 		cprev = cnow;
2106*4882a593Smuzhiyun 	}
2107*4882a593Smuzhiyun 	remove_wait_queue(&info->status_event_wait_q, &wait);
2108*4882a593Smuzhiyun 	set_current_state(TASK_RUNNING);
2109*4882a593Smuzhiyun 	return rc;
2110*4882a593Smuzhiyun }
2111*4882a593Smuzhiyun 
2112*4882a593Smuzhiyun /* return the state of the serial control and status signals
2113*4882a593Smuzhiyun  */
tiocmget(struct tty_struct * tty)2114*4882a593Smuzhiyun static int tiocmget(struct tty_struct *tty)
2115*4882a593Smuzhiyun {
2116*4882a593Smuzhiyun 	MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
2117*4882a593Smuzhiyun 	unsigned int result;
2118*4882a593Smuzhiyun 	unsigned long flags;
2119*4882a593Smuzhiyun 
2120*4882a593Smuzhiyun 	spin_lock_irqsave(&info->lock, flags);
2121*4882a593Smuzhiyun 	get_signals(info);
2122*4882a593Smuzhiyun 	spin_unlock_irqrestore(&info->lock, flags);
2123*4882a593Smuzhiyun 
2124*4882a593Smuzhiyun 	result = ((info->serial_signals & SerialSignal_RTS) ? TIOCM_RTS:0) +
2125*4882a593Smuzhiyun 		((info->serial_signals & SerialSignal_DTR) ? TIOCM_DTR:0) +
2126*4882a593Smuzhiyun 		((info->serial_signals & SerialSignal_DCD) ? TIOCM_CAR:0) +
2127*4882a593Smuzhiyun 		((info->serial_signals & SerialSignal_RI)  ? TIOCM_RNG:0) +
2128*4882a593Smuzhiyun 		((info->serial_signals & SerialSignal_DSR) ? TIOCM_DSR:0) +
2129*4882a593Smuzhiyun 		((info->serial_signals & SerialSignal_CTS) ? TIOCM_CTS:0);
2130*4882a593Smuzhiyun 
2131*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
2132*4882a593Smuzhiyun 		printk("%s(%d):%s tiocmget() value=%08X\n",
2133*4882a593Smuzhiyun 			 __FILE__, __LINE__, info->device_name, result);
2134*4882a593Smuzhiyun 	return result;
2135*4882a593Smuzhiyun }
2136*4882a593Smuzhiyun 
2137*4882a593Smuzhiyun /* set modem control signals (DTR/RTS)
2138*4882a593Smuzhiyun  */
tiocmset(struct tty_struct * tty,unsigned int set,unsigned int clear)2139*4882a593Smuzhiyun static int tiocmset(struct tty_struct *tty,
2140*4882a593Smuzhiyun 		    unsigned int set, unsigned int clear)
2141*4882a593Smuzhiyun {
2142*4882a593Smuzhiyun 	MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
2143*4882a593Smuzhiyun 	unsigned long flags;
2144*4882a593Smuzhiyun 
2145*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
2146*4882a593Smuzhiyun 		printk("%s(%d):%s tiocmset(%x,%x)\n",
2147*4882a593Smuzhiyun 			__FILE__, __LINE__, info->device_name, set, clear);
2148*4882a593Smuzhiyun 
2149*4882a593Smuzhiyun 	if (set & TIOCM_RTS)
2150*4882a593Smuzhiyun 		info->serial_signals |= SerialSignal_RTS;
2151*4882a593Smuzhiyun 	if (set & TIOCM_DTR)
2152*4882a593Smuzhiyun 		info->serial_signals |= SerialSignal_DTR;
2153*4882a593Smuzhiyun 	if (clear & TIOCM_RTS)
2154*4882a593Smuzhiyun 		info->serial_signals &= ~SerialSignal_RTS;
2155*4882a593Smuzhiyun 	if (clear & TIOCM_DTR)
2156*4882a593Smuzhiyun 		info->serial_signals &= ~SerialSignal_DTR;
2157*4882a593Smuzhiyun 
2158*4882a593Smuzhiyun 	spin_lock_irqsave(&info->lock, flags);
2159*4882a593Smuzhiyun 	set_signals(info);
2160*4882a593Smuzhiyun 	spin_unlock_irqrestore(&info->lock, flags);
2161*4882a593Smuzhiyun 
2162*4882a593Smuzhiyun 	return 0;
2163*4882a593Smuzhiyun }
2164*4882a593Smuzhiyun 
2165*4882a593Smuzhiyun /* Set or clear transmit break condition
2166*4882a593Smuzhiyun  *
2167*4882a593Smuzhiyun  * Arguments:		tty		pointer to tty instance data
2168*4882a593Smuzhiyun  *			break_state	-1=set break condition, 0=clear
2169*4882a593Smuzhiyun  */
mgslpc_break(struct tty_struct * tty,int break_state)2170*4882a593Smuzhiyun static int mgslpc_break(struct tty_struct *tty, int break_state)
2171*4882a593Smuzhiyun {
2172*4882a593Smuzhiyun 	MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data;
2173*4882a593Smuzhiyun 	unsigned long flags;
2174*4882a593Smuzhiyun 
2175*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
2176*4882a593Smuzhiyun 		printk("%s(%d):mgslpc_break(%s,%d)\n",
2177*4882a593Smuzhiyun 			 __FILE__, __LINE__, info->device_name, break_state);
2178*4882a593Smuzhiyun 
2179*4882a593Smuzhiyun 	if (mgslpc_paranoia_check(info, tty->name, "mgslpc_break"))
2180*4882a593Smuzhiyun 		return -EINVAL;
2181*4882a593Smuzhiyun 
2182*4882a593Smuzhiyun 	spin_lock_irqsave(&info->lock, flags);
2183*4882a593Smuzhiyun 	if (break_state == -1)
2184*4882a593Smuzhiyun 		set_reg_bits(info, CHA+DAFO, BIT6);
2185*4882a593Smuzhiyun 	else
2186*4882a593Smuzhiyun 		clear_reg_bits(info, CHA+DAFO, BIT6);
2187*4882a593Smuzhiyun 	spin_unlock_irqrestore(&info->lock, flags);
2188*4882a593Smuzhiyun 	return 0;
2189*4882a593Smuzhiyun }
2190*4882a593Smuzhiyun 
mgslpc_get_icount(struct tty_struct * tty,struct serial_icounter_struct * icount)2191*4882a593Smuzhiyun static int mgslpc_get_icount(struct tty_struct *tty,
2192*4882a593Smuzhiyun 				struct serial_icounter_struct *icount)
2193*4882a593Smuzhiyun {
2194*4882a593Smuzhiyun 	MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data;
2195*4882a593Smuzhiyun 	struct mgsl_icount cnow;	/* kernel counter temps */
2196*4882a593Smuzhiyun 	unsigned long flags;
2197*4882a593Smuzhiyun 
2198*4882a593Smuzhiyun 	spin_lock_irqsave(&info->lock, flags);
2199*4882a593Smuzhiyun 	cnow = info->icount;
2200*4882a593Smuzhiyun 	spin_unlock_irqrestore(&info->lock, flags);
2201*4882a593Smuzhiyun 
2202*4882a593Smuzhiyun 	icount->cts = cnow.cts;
2203*4882a593Smuzhiyun 	icount->dsr = cnow.dsr;
2204*4882a593Smuzhiyun 	icount->rng = cnow.rng;
2205*4882a593Smuzhiyun 	icount->dcd = cnow.dcd;
2206*4882a593Smuzhiyun 	icount->rx = cnow.rx;
2207*4882a593Smuzhiyun 	icount->tx = cnow.tx;
2208*4882a593Smuzhiyun 	icount->frame = cnow.frame;
2209*4882a593Smuzhiyun 	icount->overrun = cnow.overrun;
2210*4882a593Smuzhiyun 	icount->parity = cnow.parity;
2211*4882a593Smuzhiyun 	icount->brk = cnow.brk;
2212*4882a593Smuzhiyun 	icount->buf_overrun = cnow.buf_overrun;
2213*4882a593Smuzhiyun 
2214*4882a593Smuzhiyun 	return 0;
2215*4882a593Smuzhiyun }
2216*4882a593Smuzhiyun 
2217*4882a593Smuzhiyun /* Service an IOCTL request
2218*4882a593Smuzhiyun  *
2219*4882a593Smuzhiyun  * Arguments:
2220*4882a593Smuzhiyun  *
2221*4882a593Smuzhiyun  *	tty	pointer to tty instance data
2222*4882a593Smuzhiyun  *	cmd	IOCTL command code
2223*4882a593Smuzhiyun  *	arg	command argument/context
2224*4882a593Smuzhiyun  *
2225*4882a593Smuzhiyun  * Return Value:	0 if success, otherwise error code
2226*4882a593Smuzhiyun  */
mgslpc_ioctl(struct tty_struct * tty,unsigned int cmd,unsigned long arg)2227*4882a593Smuzhiyun static int mgslpc_ioctl(struct tty_struct *tty,
2228*4882a593Smuzhiyun 			unsigned int cmd, unsigned long arg)
2229*4882a593Smuzhiyun {
2230*4882a593Smuzhiyun 	MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data;
2231*4882a593Smuzhiyun 	void __user *argp = (void __user *)arg;
2232*4882a593Smuzhiyun 
2233*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
2234*4882a593Smuzhiyun 		printk("%s(%d):mgslpc_ioctl %s cmd=%08X\n", __FILE__, __LINE__,
2235*4882a593Smuzhiyun 			info->device_name, cmd);
2236*4882a593Smuzhiyun 
2237*4882a593Smuzhiyun 	if (mgslpc_paranoia_check(info, tty->name, "mgslpc_ioctl"))
2238*4882a593Smuzhiyun 		return -ENODEV;
2239*4882a593Smuzhiyun 
2240*4882a593Smuzhiyun 	if (cmd != TIOCMIWAIT) {
2241*4882a593Smuzhiyun 		if (tty_io_error(tty))
2242*4882a593Smuzhiyun 		    return -EIO;
2243*4882a593Smuzhiyun 	}
2244*4882a593Smuzhiyun 
2245*4882a593Smuzhiyun 	switch (cmd) {
2246*4882a593Smuzhiyun 	case MGSL_IOCGPARAMS:
2247*4882a593Smuzhiyun 		return get_params(info, argp);
2248*4882a593Smuzhiyun 	case MGSL_IOCSPARAMS:
2249*4882a593Smuzhiyun 		return set_params(info, argp, tty);
2250*4882a593Smuzhiyun 	case MGSL_IOCGTXIDLE:
2251*4882a593Smuzhiyun 		return get_txidle(info, argp);
2252*4882a593Smuzhiyun 	case MGSL_IOCSTXIDLE:
2253*4882a593Smuzhiyun 		return set_txidle(info, (int)arg);
2254*4882a593Smuzhiyun 	case MGSL_IOCGIF:
2255*4882a593Smuzhiyun 		return get_interface(info, argp);
2256*4882a593Smuzhiyun 	case MGSL_IOCSIF:
2257*4882a593Smuzhiyun 		return set_interface(info,(int)arg);
2258*4882a593Smuzhiyun 	case MGSL_IOCTXENABLE:
2259*4882a593Smuzhiyun 		return set_txenable(info,(int)arg, tty);
2260*4882a593Smuzhiyun 	case MGSL_IOCRXENABLE:
2261*4882a593Smuzhiyun 		return set_rxenable(info,(int)arg);
2262*4882a593Smuzhiyun 	case MGSL_IOCTXABORT:
2263*4882a593Smuzhiyun 		return tx_abort(info);
2264*4882a593Smuzhiyun 	case MGSL_IOCGSTATS:
2265*4882a593Smuzhiyun 		return get_stats(info, argp);
2266*4882a593Smuzhiyun 	case MGSL_IOCWAITEVENT:
2267*4882a593Smuzhiyun 		return wait_events(info, argp);
2268*4882a593Smuzhiyun 	case TIOCMIWAIT:
2269*4882a593Smuzhiyun 		return modem_input_wait(info,(int)arg);
2270*4882a593Smuzhiyun 	default:
2271*4882a593Smuzhiyun 		return -ENOIOCTLCMD;
2272*4882a593Smuzhiyun 	}
2273*4882a593Smuzhiyun 	return 0;
2274*4882a593Smuzhiyun }
2275*4882a593Smuzhiyun 
2276*4882a593Smuzhiyun /* Set new termios settings
2277*4882a593Smuzhiyun  *
2278*4882a593Smuzhiyun  * Arguments:
2279*4882a593Smuzhiyun  *
2280*4882a593Smuzhiyun  *	tty		pointer to tty structure
2281*4882a593Smuzhiyun  *	termios		pointer to buffer to hold returned old termios
2282*4882a593Smuzhiyun  */
mgslpc_set_termios(struct tty_struct * tty,struct ktermios * old_termios)2283*4882a593Smuzhiyun static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
2284*4882a593Smuzhiyun {
2285*4882a593Smuzhiyun 	MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
2286*4882a593Smuzhiyun 	unsigned long flags;
2287*4882a593Smuzhiyun 
2288*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
2289*4882a593Smuzhiyun 		printk("%s(%d):mgslpc_set_termios %s\n", __FILE__, __LINE__,
2290*4882a593Smuzhiyun 			tty->driver->name);
2291*4882a593Smuzhiyun 
2292*4882a593Smuzhiyun 	/* just return if nothing has changed */
2293*4882a593Smuzhiyun 	if ((tty->termios.c_cflag == old_termios->c_cflag)
2294*4882a593Smuzhiyun 	    && (RELEVANT_IFLAG(tty->termios.c_iflag)
2295*4882a593Smuzhiyun 		== RELEVANT_IFLAG(old_termios->c_iflag)))
2296*4882a593Smuzhiyun 	  return;
2297*4882a593Smuzhiyun 
2298*4882a593Smuzhiyun 	mgslpc_change_params(info, tty);
2299*4882a593Smuzhiyun 
2300*4882a593Smuzhiyun 	/* Handle transition to B0 status */
2301*4882a593Smuzhiyun 	if ((old_termios->c_cflag & CBAUD) && !C_BAUD(tty)) {
2302*4882a593Smuzhiyun 		info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR);
2303*4882a593Smuzhiyun 		spin_lock_irqsave(&info->lock, flags);
2304*4882a593Smuzhiyun 		set_signals(info);
2305*4882a593Smuzhiyun 		spin_unlock_irqrestore(&info->lock, flags);
2306*4882a593Smuzhiyun 	}
2307*4882a593Smuzhiyun 
2308*4882a593Smuzhiyun 	/* Handle transition away from B0 status */
2309*4882a593Smuzhiyun 	if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) {
2310*4882a593Smuzhiyun 		info->serial_signals |= SerialSignal_DTR;
2311*4882a593Smuzhiyun 		if (!C_CRTSCTS(tty) || !tty_throttled(tty))
2312*4882a593Smuzhiyun 			info->serial_signals |= SerialSignal_RTS;
2313*4882a593Smuzhiyun 		spin_lock_irqsave(&info->lock, flags);
2314*4882a593Smuzhiyun 		set_signals(info);
2315*4882a593Smuzhiyun 		spin_unlock_irqrestore(&info->lock, flags);
2316*4882a593Smuzhiyun 	}
2317*4882a593Smuzhiyun 
2318*4882a593Smuzhiyun 	/* Handle turning off CRTSCTS */
2319*4882a593Smuzhiyun 	if (old_termios->c_cflag & CRTSCTS && !C_CRTSCTS(tty)) {
2320*4882a593Smuzhiyun 		tty->hw_stopped = 0;
2321*4882a593Smuzhiyun 		tx_release(tty);
2322*4882a593Smuzhiyun 	}
2323*4882a593Smuzhiyun }
2324*4882a593Smuzhiyun 
mgslpc_close(struct tty_struct * tty,struct file * filp)2325*4882a593Smuzhiyun static void mgslpc_close(struct tty_struct *tty, struct file * filp)
2326*4882a593Smuzhiyun {
2327*4882a593Smuzhiyun 	MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data;
2328*4882a593Smuzhiyun 	struct tty_port *port = &info->port;
2329*4882a593Smuzhiyun 
2330*4882a593Smuzhiyun 	if (mgslpc_paranoia_check(info, tty->name, "mgslpc_close"))
2331*4882a593Smuzhiyun 		return;
2332*4882a593Smuzhiyun 
2333*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
2334*4882a593Smuzhiyun 		printk("%s(%d):mgslpc_close(%s) entry, count=%d\n",
2335*4882a593Smuzhiyun 			 __FILE__, __LINE__, info->device_name, port->count);
2336*4882a593Smuzhiyun 
2337*4882a593Smuzhiyun 	if (tty_port_close_start(port, tty, filp) == 0)
2338*4882a593Smuzhiyun 		goto cleanup;
2339*4882a593Smuzhiyun 
2340*4882a593Smuzhiyun 	if (tty_port_initialized(port))
2341*4882a593Smuzhiyun 		mgslpc_wait_until_sent(tty, info->timeout);
2342*4882a593Smuzhiyun 
2343*4882a593Smuzhiyun 	mgslpc_flush_buffer(tty);
2344*4882a593Smuzhiyun 
2345*4882a593Smuzhiyun 	tty_ldisc_flush(tty);
2346*4882a593Smuzhiyun 	shutdown(info, tty);
2347*4882a593Smuzhiyun 
2348*4882a593Smuzhiyun 	tty_port_close_end(port, tty);
2349*4882a593Smuzhiyun 	tty_port_tty_set(port, NULL);
2350*4882a593Smuzhiyun cleanup:
2351*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
2352*4882a593Smuzhiyun 		printk("%s(%d):mgslpc_close(%s) exit, count=%d\n", __FILE__, __LINE__,
2353*4882a593Smuzhiyun 			tty->driver->name, port->count);
2354*4882a593Smuzhiyun }
2355*4882a593Smuzhiyun 
2356*4882a593Smuzhiyun /* Wait until the transmitter is empty.
2357*4882a593Smuzhiyun  */
mgslpc_wait_until_sent(struct tty_struct * tty,int timeout)2358*4882a593Smuzhiyun static void mgslpc_wait_until_sent(struct tty_struct *tty, int timeout)
2359*4882a593Smuzhiyun {
2360*4882a593Smuzhiyun 	MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data;
2361*4882a593Smuzhiyun 	unsigned long orig_jiffies, char_time;
2362*4882a593Smuzhiyun 
2363*4882a593Smuzhiyun 	if (!info)
2364*4882a593Smuzhiyun 		return;
2365*4882a593Smuzhiyun 
2366*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
2367*4882a593Smuzhiyun 		printk("%s(%d):mgslpc_wait_until_sent(%s) entry\n",
2368*4882a593Smuzhiyun 			 __FILE__, __LINE__, info->device_name);
2369*4882a593Smuzhiyun 
2370*4882a593Smuzhiyun 	if (mgslpc_paranoia_check(info, tty->name, "mgslpc_wait_until_sent"))
2371*4882a593Smuzhiyun 		return;
2372*4882a593Smuzhiyun 
2373*4882a593Smuzhiyun 	if (!tty_port_initialized(&info->port))
2374*4882a593Smuzhiyun 		goto exit;
2375*4882a593Smuzhiyun 
2376*4882a593Smuzhiyun 	orig_jiffies = jiffies;
2377*4882a593Smuzhiyun 
2378*4882a593Smuzhiyun 	/* Set check interval to 1/5 of estimated time to
2379*4882a593Smuzhiyun 	 * send a character, and make it at least 1. The check
2380*4882a593Smuzhiyun 	 * interval should also be less than the timeout.
2381*4882a593Smuzhiyun 	 * Note: use tight timings here to satisfy the NIST-PCTS.
2382*4882a593Smuzhiyun 	 */
2383*4882a593Smuzhiyun 
2384*4882a593Smuzhiyun 	if (info->params.data_rate) {
2385*4882a593Smuzhiyun 	     	char_time = info->timeout/(32 * 5);
2386*4882a593Smuzhiyun 		if (!char_time)
2387*4882a593Smuzhiyun 			char_time++;
2388*4882a593Smuzhiyun 	} else
2389*4882a593Smuzhiyun 		char_time = 1;
2390*4882a593Smuzhiyun 
2391*4882a593Smuzhiyun 	if (timeout)
2392*4882a593Smuzhiyun 		char_time = min_t(unsigned long, char_time, timeout);
2393*4882a593Smuzhiyun 
2394*4882a593Smuzhiyun 	if (info->params.mode == MGSL_MODE_HDLC) {
2395*4882a593Smuzhiyun 		while (info->tx_active) {
2396*4882a593Smuzhiyun 			msleep_interruptible(jiffies_to_msecs(char_time));
2397*4882a593Smuzhiyun 			if (signal_pending(current))
2398*4882a593Smuzhiyun 				break;
2399*4882a593Smuzhiyun 			if (timeout && time_after(jiffies, orig_jiffies + timeout))
2400*4882a593Smuzhiyun 				break;
2401*4882a593Smuzhiyun 		}
2402*4882a593Smuzhiyun 	} else {
2403*4882a593Smuzhiyun 		while ((info->tx_count || info->tx_active) &&
2404*4882a593Smuzhiyun 			info->tx_enabled) {
2405*4882a593Smuzhiyun 			msleep_interruptible(jiffies_to_msecs(char_time));
2406*4882a593Smuzhiyun 			if (signal_pending(current))
2407*4882a593Smuzhiyun 				break;
2408*4882a593Smuzhiyun 			if (timeout && time_after(jiffies, orig_jiffies + timeout))
2409*4882a593Smuzhiyun 				break;
2410*4882a593Smuzhiyun 		}
2411*4882a593Smuzhiyun 	}
2412*4882a593Smuzhiyun 
2413*4882a593Smuzhiyun exit:
2414*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
2415*4882a593Smuzhiyun 		printk("%s(%d):mgslpc_wait_until_sent(%s) exit\n",
2416*4882a593Smuzhiyun 			 __FILE__, __LINE__, info->device_name);
2417*4882a593Smuzhiyun }
2418*4882a593Smuzhiyun 
2419*4882a593Smuzhiyun /* Called by tty_hangup() when a hangup is signaled.
2420*4882a593Smuzhiyun  * This is the same as closing all open files for the port.
2421*4882a593Smuzhiyun  */
mgslpc_hangup(struct tty_struct * tty)2422*4882a593Smuzhiyun static void mgslpc_hangup(struct tty_struct *tty)
2423*4882a593Smuzhiyun {
2424*4882a593Smuzhiyun 	MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data;
2425*4882a593Smuzhiyun 
2426*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
2427*4882a593Smuzhiyun 		printk("%s(%d):mgslpc_hangup(%s)\n",
2428*4882a593Smuzhiyun 			 __FILE__, __LINE__, info->device_name);
2429*4882a593Smuzhiyun 
2430*4882a593Smuzhiyun 	if (mgslpc_paranoia_check(info, tty->name, "mgslpc_hangup"))
2431*4882a593Smuzhiyun 		return;
2432*4882a593Smuzhiyun 
2433*4882a593Smuzhiyun 	mgslpc_flush_buffer(tty);
2434*4882a593Smuzhiyun 	shutdown(info, tty);
2435*4882a593Smuzhiyun 	tty_port_hangup(&info->port);
2436*4882a593Smuzhiyun }
2437*4882a593Smuzhiyun 
carrier_raised(struct tty_port * port)2438*4882a593Smuzhiyun static int carrier_raised(struct tty_port *port)
2439*4882a593Smuzhiyun {
2440*4882a593Smuzhiyun 	MGSLPC_INFO *info = container_of(port, MGSLPC_INFO, port);
2441*4882a593Smuzhiyun 	unsigned long flags;
2442*4882a593Smuzhiyun 
2443*4882a593Smuzhiyun 	spin_lock_irqsave(&info->lock, flags);
2444*4882a593Smuzhiyun 	get_signals(info);
2445*4882a593Smuzhiyun 	spin_unlock_irqrestore(&info->lock, flags);
2446*4882a593Smuzhiyun 
2447*4882a593Smuzhiyun 	if (info->serial_signals & SerialSignal_DCD)
2448*4882a593Smuzhiyun 		return 1;
2449*4882a593Smuzhiyun 	return 0;
2450*4882a593Smuzhiyun }
2451*4882a593Smuzhiyun 
dtr_rts(struct tty_port * port,int onoff)2452*4882a593Smuzhiyun static void dtr_rts(struct tty_port *port, int onoff)
2453*4882a593Smuzhiyun {
2454*4882a593Smuzhiyun 	MGSLPC_INFO *info = container_of(port, MGSLPC_INFO, port);
2455*4882a593Smuzhiyun 	unsigned long flags;
2456*4882a593Smuzhiyun 
2457*4882a593Smuzhiyun 	spin_lock_irqsave(&info->lock, flags);
2458*4882a593Smuzhiyun 	if (onoff)
2459*4882a593Smuzhiyun 		info->serial_signals |= SerialSignal_RTS | SerialSignal_DTR;
2460*4882a593Smuzhiyun 	else
2461*4882a593Smuzhiyun 		info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR);
2462*4882a593Smuzhiyun 	set_signals(info);
2463*4882a593Smuzhiyun 	spin_unlock_irqrestore(&info->lock, flags);
2464*4882a593Smuzhiyun }
2465*4882a593Smuzhiyun 
2466*4882a593Smuzhiyun 
mgslpc_open(struct tty_struct * tty,struct file * filp)2467*4882a593Smuzhiyun static int mgslpc_open(struct tty_struct *tty, struct file * filp)
2468*4882a593Smuzhiyun {
2469*4882a593Smuzhiyun 	MGSLPC_INFO	*info;
2470*4882a593Smuzhiyun 	struct tty_port *port;
2471*4882a593Smuzhiyun 	int		retval, line;
2472*4882a593Smuzhiyun 	unsigned long	flags;
2473*4882a593Smuzhiyun 
2474*4882a593Smuzhiyun 	/* verify range of specified line number */
2475*4882a593Smuzhiyun 	line = tty->index;
2476*4882a593Smuzhiyun 	if (line >= mgslpc_device_count) {
2477*4882a593Smuzhiyun 		printk("%s(%d):mgslpc_open with invalid line #%d.\n",
2478*4882a593Smuzhiyun 			__FILE__, __LINE__, line);
2479*4882a593Smuzhiyun 		return -ENODEV;
2480*4882a593Smuzhiyun 	}
2481*4882a593Smuzhiyun 
2482*4882a593Smuzhiyun 	/* find the info structure for the specified line */
2483*4882a593Smuzhiyun 	info = mgslpc_device_list;
2484*4882a593Smuzhiyun 	while(info && info->line != line)
2485*4882a593Smuzhiyun 		info = info->next_device;
2486*4882a593Smuzhiyun 	if (mgslpc_paranoia_check(info, tty->name, "mgslpc_open"))
2487*4882a593Smuzhiyun 		return -ENODEV;
2488*4882a593Smuzhiyun 
2489*4882a593Smuzhiyun 	port = &info->port;
2490*4882a593Smuzhiyun 	tty->driver_data = info;
2491*4882a593Smuzhiyun 	tty_port_tty_set(port, tty);
2492*4882a593Smuzhiyun 
2493*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
2494*4882a593Smuzhiyun 		printk("%s(%d):mgslpc_open(%s), old ref count = %d\n",
2495*4882a593Smuzhiyun 			 __FILE__, __LINE__, tty->driver->name, port->count);
2496*4882a593Smuzhiyun 
2497*4882a593Smuzhiyun 	port->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
2498*4882a593Smuzhiyun 
2499*4882a593Smuzhiyun 	spin_lock_irqsave(&info->netlock, flags);
2500*4882a593Smuzhiyun 	if (info->netcount) {
2501*4882a593Smuzhiyun 		retval = -EBUSY;
2502*4882a593Smuzhiyun 		spin_unlock_irqrestore(&info->netlock, flags);
2503*4882a593Smuzhiyun 		goto cleanup;
2504*4882a593Smuzhiyun 	}
2505*4882a593Smuzhiyun 	spin_lock(&port->lock);
2506*4882a593Smuzhiyun 	port->count++;
2507*4882a593Smuzhiyun 	spin_unlock(&port->lock);
2508*4882a593Smuzhiyun 	spin_unlock_irqrestore(&info->netlock, flags);
2509*4882a593Smuzhiyun 
2510*4882a593Smuzhiyun 	if (port->count == 1) {
2511*4882a593Smuzhiyun 		/* 1st open on this device, init hardware */
2512*4882a593Smuzhiyun 		retval = startup(info, tty);
2513*4882a593Smuzhiyun 		if (retval < 0)
2514*4882a593Smuzhiyun 			goto cleanup;
2515*4882a593Smuzhiyun 	}
2516*4882a593Smuzhiyun 
2517*4882a593Smuzhiyun 	retval = tty_port_block_til_ready(&info->port, tty, filp);
2518*4882a593Smuzhiyun 	if (retval) {
2519*4882a593Smuzhiyun 		if (debug_level >= DEBUG_LEVEL_INFO)
2520*4882a593Smuzhiyun 			printk("%s(%d):block_til_ready(%s) returned %d\n",
2521*4882a593Smuzhiyun 				 __FILE__, __LINE__, info->device_name, retval);
2522*4882a593Smuzhiyun 		goto cleanup;
2523*4882a593Smuzhiyun 	}
2524*4882a593Smuzhiyun 
2525*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
2526*4882a593Smuzhiyun 		printk("%s(%d):mgslpc_open(%s) success\n",
2527*4882a593Smuzhiyun 			 __FILE__, __LINE__, info->device_name);
2528*4882a593Smuzhiyun 	retval = 0;
2529*4882a593Smuzhiyun 
2530*4882a593Smuzhiyun cleanup:
2531*4882a593Smuzhiyun 	return retval;
2532*4882a593Smuzhiyun }
2533*4882a593Smuzhiyun 
2534*4882a593Smuzhiyun /*
2535*4882a593Smuzhiyun  * /proc fs routines....
2536*4882a593Smuzhiyun  */
2537*4882a593Smuzhiyun 
line_info(struct seq_file * m,MGSLPC_INFO * info)2538*4882a593Smuzhiyun static inline void line_info(struct seq_file *m, MGSLPC_INFO *info)
2539*4882a593Smuzhiyun {
2540*4882a593Smuzhiyun 	char	stat_buf[30];
2541*4882a593Smuzhiyun 	unsigned long flags;
2542*4882a593Smuzhiyun 
2543*4882a593Smuzhiyun 	seq_printf(m, "%s:io:%04X irq:%d",
2544*4882a593Smuzhiyun 		      info->device_name, info->io_base, info->irq_level);
2545*4882a593Smuzhiyun 
2546*4882a593Smuzhiyun 	/* output current serial signal states */
2547*4882a593Smuzhiyun 	spin_lock_irqsave(&info->lock, flags);
2548*4882a593Smuzhiyun 	get_signals(info);
2549*4882a593Smuzhiyun 	spin_unlock_irqrestore(&info->lock, flags);
2550*4882a593Smuzhiyun 
2551*4882a593Smuzhiyun 	stat_buf[0] = 0;
2552*4882a593Smuzhiyun 	stat_buf[1] = 0;
2553*4882a593Smuzhiyun 	if (info->serial_signals & SerialSignal_RTS)
2554*4882a593Smuzhiyun 		strcat(stat_buf, "|RTS");
2555*4882a593Smuzhiyun 	if (info->serial_signals & SerialSignal_CTS)
2556*4882a593Smuzhiyun 		strcat(stat_buf, "|CTS");
2557*4882a593Smuzhiyun 	if (info->serial_signals & SerialSignal_DTR)
2558*4882a593Smuzhiyun 		strcat(stat_buf, "|DTR");
2559*4882a593Smuzhiyun 	if (info->serial_signals & SerialSignal_DSR)
2560*4882a593Smuzhiyun 		strcat(stat_buf, "|DSR");
2561*4882a593Smuzhiyun 	if (info->serial_signals & SerialSignal_DCD)
2562*4882a593Smuzhiyun 		strcat(stat_buf, "|CD");
2563*4882a593Smuzhiyun 	if (info->serial_signals & SerialSignal_RI)
2564*4882a593Smuzhiyun 		strcat(stat_buf, "|RI");
2565*4882a593Smuzhiyun 
2566*4882a593Smuzhiyun 	if (info->params.mode == MGSL_MODE_HDLC) {
2567*4882a593Smuzhiyun 		seq_printf(m, " HDLC txok:%d rxok:%d",
2568*4882a593Smuzhiyun 			      info->icount.txok, info->icount.rxok);
2569*4882a593Smuzhiyun 		if (info->icount.txunder)
2570*4882a593Smuzhiyun 			seq_printf(m, " txunder:%d", info->icount.txunder);
2571*4882a593Smuzhiyun 		if (info->icount.txabort)
2572*4882a593Smuzhiyun 			seq_printf(m, " txabort:%d", info->icount.txabort);
2573*4882a593Smuzhiyun 		if (info->icount.rxshort)
2574*4882a593Smuzhiyun 			seq_printf(m, " rxshort:%d", info->icount.rxshort);
2575*4882a593Smuzhiyun 		if (info->icount.rxlong)
2576*4882a593Smuzhiyun 			seq_printf(m, " rxlong:%d", info->icount.rxlong);
2577*4882a593Smuzhiyun 		if (info->icount.rxover)
2578*4882a593Smuzhiyun 			seq_printf(m, " rxover:%d", info->icount.rxover);
2579*4882a593Smuzhiyun 		if (info->icount.rxcrc)
2580*4882a593Smuzhiyun 			seq_printf(m, " rxcrc:%d", info->icount.rxcrc);
2581*4882a593Smuzhiyun 	} else {
2582*4882a593Smuzhiyun 		seq_printf(m, " ASYNC tx:%d rx:%d",
2583*4882a593Smuzhiyun 			      info->icount.tx, info->icount.rx);
2584*4882a593Smuzhiyun 		if (info->icount.frame)
2585*4882a593Smuzhiyun 			seq_printf(m, " fe:%d", info->icount.frame);
2586*4882a593Smuzhiyun 		if (info->icount.parity)
2587*4882a593Smuzhiyun 			seq_printf(m, " pe:%d", info->icount.parity);
2588*4882a593Smuzhiyun 		if (info->icount.brk)
2589*4882a593Smuzhiyun 			seq_printf(m, " brk:%d", info->icount.brk);
2590*4882a593Smuzhiyun 		if (info->icount.overrun)
2591*4882a593Smuzhiyun 			seq_printf(m, " oe:%d", info->icount.overrun);
2592*4882a593Smuzhiyun 	}
2593*4882a593Smuzhiyun 
2594*4882a593Smuzhiyun 	/* Append serial signal status to end */
2595*4882a593Smuzhiyun 	seq_printf(m, " %s\n", stat_buf+1);
2596*4882a593Smuzhiyun 
2597*4882a593Smuzhiyun 	seq_printf(m, "txactive=%d bh_req=%d bh_run=%d pending_bh=%x\n",
2598*4882a593Smuzhiyun 		       info->tx_active,info->bh_requested,info->bh_running,
2599*4882a593Smuzhiyun 		       info->pending_bh);
2600*4882a593Smuzhiyun }
2601*4882a593Smuzhiyun 
2602*4882a593Smuzhiyun /* Called to print information about devices
2603*4882a593Smuzhiyun  */
mgslpc_proc_show(struct seq_file * m,void * v)2604*4882a593Smuzhiyun static int mgslpc_proc_show(struct seq_file *m, void *v)
2605*4882a593Smuzhiyun {
2606*4882a593Smuzhiyun 	MGSLPC_INFO *info;
2607*4882a593Smuzhiyun 
2608*4882a593Smuzhiyun 	seq_printf(m, "synclink driver:%s\n", driver_version);
2609*4882a593Smuzhiyun 
2610*4882a593Smuzhiyun 	info = mgslpc_device_list;
2611*4882a593Smuzhiyun 	while (info) {
2612*4882a593Smuzhiyun 		line_info(m, info);
2613*4882a593Smuzhiyun 		info = info->next_device;
2614*4882a593Smuzhiyun 	}
2615*4882a593Smuzhiyun 	return 0;
2616*4882a593Smuzhiyun }
2617*4882a593Smuzhiyun 
rx_alloc_buffers(MGSLPC_INFO * info)2618*4882a593Smuzhiyun static int rx_alloc_buffers(MGSLPC_INFO *info)
2619*4882a593Smuzhiyun {
2620*4882a593Smuzhiyun 	/* each buffer has header and data */
2621*4882a593Smuzhiyun 	info->rx_buf_size = sizeof(RXBUF) + info->max_frame_size;
2622*4882a593Smuzhiyun 
2623*4882a593Smuzhiyun 	/* calculate total allocation size for 8 buffers */
2624*4882a593Smuzhiyun 	info->rx_buf_total_size = info->rx_buf_size * 8;
2625*4882a593Smuzhiyun 
2626*4882a593Smuzhiyun 	/* limit total allocated memory */
2627*4882a593Smuzhiyun 	if (info->rx_buf_total_size > 0x10000)
2628*4882a593Smuzhiyun 		info->rx_buf_total_size = 0x10000;
2629*4882a593Smuzhiyun 
2630*4882a593Smuzhiyun 	/* calculate number of buffers */
2631*4882a593Smuzhiyun 	info->rx_buf_count = info->rx_buf_total_size / info->rx_buf_size;
2632*4882a593Smuzhiyun 
2633*4882a593Smuzhiyun 	info->rx_buf = kmalloc(info->rx_buf_total_size, GFP_KERNEL);
2634*4882a593Smuzhiyun 	if (info->rx_buf == NULL)
2635*4882a593Smuzhiyun 		return -ENOMEM;
2636*4882a593Smuzhiyun 
2637*4882a593Smuzhiyun 	/* unused flag buffer to satisfy receive_buf calling interface */
2638*4882a593Smuzhiyun 	info->flag_buf = kzalloc(info->max_frame_size, GFP_KERNEL);
2639*4882a593Smuzhiyun 	if (!info->flag_buf) {
2640*4882a593Smuzhiyun 		kfree(info->rx_buf);
2641*4882a593Smuzhiyun 		info->rx_buf = NULL;
2642*4882a593Smuzhiyun 		return -ENOMEM;
2643*4882a593Smuzhiyun 	}
2644*4882a593Smuzhiyun 
2645*4882a593Smuzhiyun 	rx_reset_buffers(info);
2646*4882a593Smuzhiyun 	return 0;
2647*4882a593Smuzhiyun }
2648*4882a593Smuzhiyun 
rx_free_buffers(MGSLPC_INFO * info)2649*4882a593Smuzhiyun static void rx_free_buffers(MGSLPC_INFO *info)
2650*4882a593Smuzhiyun {
2651*4882a593Smuzhiyun 	kfree(info->rx_buf);
2652*4882a593Smuzhiyun 	info->rx_buf = NULL;
2653*4882a593Smuzhiyun 	kfree(info->flag_buf);
2654*4882a593Smuzhiyun 	info->flag_buf = NULL;
2655*4882a593Smuzhiyun }
2656*4882a593Smuzhiyun 
claim_resources(MGSLPC_INFO * info)2657*4882a593Smuzhiyun static int claim_resources(MGSLPC_INFO *info)
2658*4882a593Smuzhiyun {
2659*4882a593Smuzhiyun 	if (rx_alloc_buffers(info) < 0) {
2660*4882a593Smuzhiyun 		printk("Can't allocate rx buffer %s\n", info->device_name);
2661*4882a593Smuzhiyun 		release_resources(info);
2662*4882a593Smuzhiyun 		return -ENODEV;
2663*4882a593Smuzhiyun 	}
2664*4882a593Smuzhiyun 	return 0;
2665*4882a593Smuzhiyun }
2666*4882a593Smuzhiyun 
release_resources(MGSLPC_INFO * info)2667*4882a593Smuzhiyun static void release_resources(MGSLPC_INFO *info)
2668*4882a593Smuzhiyun {
2669*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
2670*4882a593Smuzhiyun 		printk("release_resources(%s)\n", info->device_name);
2671*4882a593Smuzhiyun 	rx_free_buffers(info);
2672*4882a593Smuzhiyun }
2673*4882a593Smuzhiyun 
2674*4882a593Smuzhiyun /* Add the specified device instance data structure to the
2675*4882a593Smuzhiyun  * global linked list of devices and increment the device count.
2676*4882a593Smuzhiyun  *
2677*4882a593Smuzhiyun  * Arguments:		info	pointer to device instance data
2678*4882a593Smuzhiyun  */
mgslpc_add_device(MGSLPC_INFO * info)2679*4882a593Smuzhiyun static int mgslpc_add_device(MGSLPC_INFO *info)
2680*4882a593Smuzhiyun {
2681*4882a593Smuzhiyun 	MGSLPC_INFO *current_dev = NULL;
2682*4882a593Smuzhiyun 	struct device *tty_dev;
2683*4882a593Smuzhiyun 	int ret;
2684*4882a593Smuzhiyun 
2685*4882a593Smuzhiyun 	info->next_device = NULL;
2686*4882a593Smuzhiyun 	info->line = mgslpc_device_count;
2687*4882a593Smuzhiyun 	sprintf(info->device_name,"ttySLP%d",info->line);
2688*4882a593Smuzhiyun 
2689*4882a593Smuzhiyun 	if (info->line < MAX_DEVICE_COUNT) {
2690*4882a593Smuzhiyun 		if (maxframe[info->line])
2691*4882a593Smuzhiyun 			info->max_frame_size = maxframe[info->line];
2692*4882a593Smuzhiyun 	}
2693*4882a593Smuzhiyun 
2694*4882a593Smuzhiyun 	mgslpc_device_count++;
2695*4882a593Smuzhiyun 
2696*4882a593Smuzhiyun 	if (!mgslpc_device_list)
2697*4882a593Smuzhiyun 		mgslpc_device_list = info;
2698*4882a593Smuzhiyun 	else {
2699*4882a593Smuzhiyun 		current_dev = mgslpc_device_list;
2700*4882a593Smuzhiyun 		while (current_dev->next_device)
2701*4882a593Smuzhiyun 			current_dev = current_dev->next_device;
2702*4882a593Smuzhiyun 		current_dev->next_device = info;
2703*4882a593Smuzhiyun 	}
2704*4882a593Smuzhiyun 
2705*4882a593Smuzhiyun 	if (info->max_frame_size < 4096)
2706*4882a593Smuzhiyun 		info->max_frame_size = 4096;
2707*4882a593Smuzhiyun 	else if (info->max_frame_size > 65535)
2708*4882a593Smuzhiyun 		info->max_frame_size = 65535;
2709*4882a593Smuzhiyun 
2710*4882a593Smuzhiyun 	printk("SyncLink PC Card %s:IO=%04X IRQ=%d\n",
2711*4882a593Smuzhiyun 		info->device_name, info->io_base, info->irq_level);
2712*4882a593Smuzhiyun 
2713*4882a593Smuzhiyun #if SYNCLINK_GENERIC_HDLC
2714*4882a593Smuzhiyun 	ret = hdlcdev_init(info);
2715*4882a593Smuzhiyun 	if (ret != 0)
2716*4882a593Smuzhiyun 		goto failed;
2717*4882a593Smuzhiyun #endif
2718*4882a593Smuzhiyun 
2719*4882a593Smuzhiyun 	tty_dev = tty_port_register_device(&info->port, serial_driver, info->line,
2720*4882a593Smuzhiyun 			&info->p_dev->dev);
2721*4882a593Smuzhiyun 	if (IS_ERR(tty_dev)) {
2722*4882a593Smuzhiyun 		ret = PTR_ERR(tty_dev);
2723*4882a593Smuzhiyun #if SYNCLINK_GENERIC_HDLC
2724*4882a593Smuzhiyun 		hdlcdev_exit(info);
2725*4882a593Smuzhiyun #endif
2726*4882a593Smuzhiyun 		goto failed;
2727*4882a593Smuzhiyun 	}
2728*4882a593Smuzhiyun 
2729*4882a593Smuzhiyun 	return 0;
2730*4882a593Smuzhiyun 
2731*4882a593Smuzhiyun failed:
2732*4882a593Smuzhiyun 	if (current_dev)
2733*4882a593Smuzhiyun 		current_dev->next_device = NULL;
2734*4882a593Smuzhiyun 	else
2735*4882a593Smuzhiyun 		mgslpc_device_list = NULL;
2736*4882a593Smuzhiyun 	mgslpc_device_count--;
2737*4882a593Smuzhiyun 	return ret;
2738*4882a593Smuzhiyun }
2739*4882a593Smuzhiyun 
mgslpc_remove_device(MGSLPC_INFO * remove_info)2740*4882a593Smuzhiyun static void mgslpc_remove_device(MGSLPC_INFO *remove_info)
2741*4882a593Smuzhiyun {
2742*4882a593Smuzhiyun 	MGSLPC_INFO *info = mgslpc_device_list;
2743*4882a593Smuzhiyun 	MGSLPC_INFO *last = NULL;
2744*4882a593Smuzhiyun 
2745*4882a593Smuzhiyun 	while(info) {
2746*4882a593Smuzhiyun 		if (info == remove_info) {
2747*4882a593Smuzhiyun 			if (last)
2748*4882a593Smuzhiyun 				last->next_device = info->next_device;
2749*4882a593Smuzhiyun 			else
2750*4882a593Smuzhiyun 				mgslpc_device_list = info->next_device;
2751*4882a593Smuzhiyun 			tty_unregister_device(serial_driver, info->line);
2752*4882a593Smuzhiyun #if SYNCLINK_GENERIC_HDLC
2753*4882a593Smuzhiyun 			hdlcdev_exit(info);
2754*4882a593Smuzhiyun #endif
2755*4882a593Smuzhiyun 			release_resources(info);
2756*4882a593Smuzhiyun 			tty_port_destroy(&info->port);
2757*4882a593Smuzhiyun 			kfree(info);
2758*4882a593Smuzhiyun 			mgslpc_device_count--;
2759*4882a593Smuzhiyun 			return;
2760*4882a593Smuzhiyun 		}
2761*4882a593Smuzhiyun 		last = info;
2762*4882a593Smuzhiyun 		info = info->next_device;
2763*4882a593Smuzhiyun 	}
2764*4882a593Smuzhiyun }
2765*4882a593Smuzhiyun 
2766*4882a593Smuzhiyun static const struct pcmcia_device_id mgslpc_ids[] = {
2767*4882a593Smuzhiyun 	PCMCIA_DEVICE_MANF_CARD(0x02c5, 0x0050),
2768*4882a593Smuzhiyun 	PCMCIA_DEVICE_NULL
2769*4882a593Smuzhiyun };
2770*4882a593Smuzhiyun MODULE_DEVICE_TABLE(pcmcia, mgslpc_ids);
2771*4882a593Smuzhiyun 
2772*4882a593Smuzhiyun static struct pcmcia_driver mgslpc_driver = {
2773*4882a593Smuzhiyun 	.owner		= THIS_MODULE,
2774*4882a593Smuzhiyun 	.name		= "synclink_cs",
2775*4882a593Smuzhiyun 	.probe		= mgslpc_probe,
2776*4882a593Smuzhiyun 	.remove		= mgslpc_detach,
2777*4882a593Smuzhiyun 	.id_table	= mgslpc_ids,
2778*4882a593Smuzhiyun 	.suspend	= mgslpc_suspend,
2779*4882a593Smuzhiyun 	.resume		= mgslpc_resume,
2780*4882a593Smuzhiyun };
2781*4882a593Smuzhiyun 
2782*4882a593Smuzhiyun static const struct tty_operations mgslpc_ops = {
2783*4882a593Smuzhiyun 	.open = mgslpc_open,
2784*4882a593Smuzhiyun 	.close = mgslpc_close,
2785*4882a593Smuzhiyun 	.write = mgslpc_write,
2786*4882a593Smuzhiyun 	.put_char = mgslpc_put_char,
2787*4882a593Smuzhiyun 	.flush_chars = mgslpc_flush_chars,
2788*4882a593Smuzhiyun 	.write_room = mgslpc_write_room,
2789*4882a593Smuzhiyun 	.chars_in_buffer = mgslpc_chars_in_buffer,
2790*4882a593Smuzhiyun 	.flush_buffer = mgslpc_flush_buffer,
2791*4882a593Smuzhiyun 	.ioctl = mgslpc_ioctl,
2792*4882a593Smuzhiyun 	.throttle = mgslpc_throttle,
2793*4882a593Smuzhiyun 	.unthrottle = mgslpc_unthrottle,
2794*4882a593Smuzhiyun 	.send_xchar = mgslpc_send_xchar,
2795*4882a593Smuzhiyun 	.break_ctl = mgslpc_break,
2796*4882a593Smuzhiyun 	.wait_until_sent = mgslpc_wait_until_sent,
2797*4882a593Smuzhiyun 	.set_termios = mgslpc_set_termios,
2798*4882a593Smuzhiyun 	.stop = tx_pause,
2799*4882a593Smuzhiyun 	.start = tx_release,
2800*4882a593Smuzhiyun 	.hangup = mgslpc_hangup,
2801*4882a593Smuzhiyun 	.tiocmget = tiocmget,
2802*4882a593Smuzhiyun 	.tiocmset = tiocmset,
2803*4882a593Smuzhiyun 	.get_icount = mgslpc_get_icount,
2804*4882a593Smuzhiyun 	.proc_show = mgslpc_proc_show,
2805*4882a593Smuzhiyun };
2806*4882a593Smuzhiyun 
synclink_cs_init(void)2807*4882a593Smuzhiyun static int __init synclink_cs_init(void)
2808*4882a593Smuzhiyun {
2809*4882a593Smuzhiyun 	int rc;
2810*4882a593Smuzhiyun 
2811*4882a593Smuzhiyun 	if (break_on_load) {
2812*4882a593Smuzhiyun 		mgslpc_get_text_ptr();
2813*4882a593Smuzhiyun 		BREAKPOINT();
2814*4882a593Smuzhiyun 	}
2815*4882a593Smuzhiyun 
2816*4882a593Smuzhiyun 	serial_driver = tty_alloc_driver(MAX_DEVICE_COUNT,
2817*4882a593Smuzhiyun 			TTY_DRIVER_REAL_RAW |
2818*4882a593Smuzhiyun 			TTY_DRIVER_DYNAMIC_DEV);
2819*4882a593Smuzhiyun 	if (IS_ERR(serial_driver)) {
2820*4882a593Smuzhiyun 		rc = PTR_ERR(serial_driver);
2821*4882a593Smuzhiyun 		goto err;
2822*4882a593Smuzhiyun 	}
2823*4882a593Smuzhiyun 
2824*4882a593Smuzhiyun 	/* Initialize the tty_driver structure */
2825*4882a593Smuzhiyun 	serial_driver->driver_name = "synclink_cs";
2826*4882a593Smuzhiyun 	serial_driver->name = "ttySLP";
2827*4882a593Smuzhiyun 	serial_driver->major = ttymajor;
2828*4882a593Smuzhiyun 	serial_driver->minor_start = 64;
2829*4882a593Smuzhiyun 	serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
2830*4882a593Smuzhiyun 	serial_driver->subtype = SERIAL_TYPE_NORMAL;
2831*4882a593Smuzhiyun 	serial_driver->init_termios = tty_std_termios;
2832*4882a593Smuzhiyun 	serial_driver->init_termios.c_cflag =
2833*4882a593Smuzhiyun 	B9600 | CS8 | CREAD | HUPCL | CLOCAL;
2834*4882a593Smuzhiyun 	tty_set_operations(serial_driver, &mgslpc_ops);
2835*4882a593Smuzhiyun 
2836*4882a593Smuzhiyun 	rc = tty_register_driver(serial_driver);
2837*4882a593Smuzhiyun 	if (rc < 0) {
2838*4882a593Smuzhiyun 		printk(KERN_ERR "%s(%d):Couldn't register serial driver\n",
2839*4882a593Smuzhiyun 				__FILE__, __LINE__);
2840*4882a593Smuzhiyun 		goto err_put_tty;
2841*4882a593Smuzhiyun 	}
2842*4882a593Smuzhiyun 
2843*4882a593Smuzhiyun 	rc = pcmcia_register_driver(&mgslpc_driver);
2844*4882a593Smuzhiyun 	if (rc < 0)
2845*4882a593Smuzhiyun 		goto err_unreg_tty;
2846*4882a593Smuzhiyun 
2847*4882a593Smuzhiyun 	printk(KERN_INFO "%s %s, tty major#%d\n", driver_name, driver_version,
2848*4882a593Smuzhiyun 			serial_driver->major);
2849*4882a593Smuzhiyun 
2850*4882a593Smuzhiyun 	return 0;
2851*4882a593Smuzhiyun err_unreg_tty:
2852*4882a593Smuzhiyun 	tty_unregister_driver(serial_driver);
2853*4882a593Smuzhiyun err_put_tty:
2854*4882a593Smuzhiyun 	put_tty_driver(serial_driver);
2855*4882a593Smuzhiyun err:
2856*4882a593Smuzhiyun 	return rc;
2857*4882a593Smuzhiyun }
2858*4882a593Smuzhiyun 
synclink_cs_exit(void)2859*4882a593Smuzhiyun static void __exit synclink_cs_exit(void)
2860*4882a593Smuzhiyun {
2861*4882a593Smuzhiyun 	pcmcia_unregister_driver(&mgslpc_driver);
2862*4882a593Smuzhiyun 	tty_unregister_driver(serial_driver);
2863*4882a593Smuzhiyun 	put_tty_driver(serial_driver);
2864*4882a593Smuzhiyun }
2865*4882a593Smuzhiyun 
2866*4882a593Smuzhiyun module_init(synclink_cs_init);
2867*4882a593Smuzhiyun module_exit(synclink_cs_exit);
2868*4882a593Smuzhiyun 
mgslpc_set_rate(MGSLPC_INFO * info,unsigned char channel,unsigned int rate)2869*4882a593Smuzhiyun static void mgslpc_set_rate(MGSLPC_INFO *info, unsigned char channel, unsigned int rate)
2870*4882a593Smuzhiyun {
2871*4882a593Smuzhiyun 	unsigned int M, N;
2872*4882a593Smuzhiyun 	unsigned char val;
2873*4882a593Smuzhiyun 
2874*4882a593Smuzhiyun 	/* note:standard BRG mode is broken in V3.2 chip
2875*4882a593Smuzhiyun 	 * so enhanced mode is always used
2876*4882a593Smuzhiyun 	 */
2877*4882a593Smuzhiyun 
2878*4882a593Smuzhiyun 	if (rate) {
2879*4882a593Smuzhiyun 		N = 3686400 / rate;
2880*4882a593Smuzhiyun 		if (!N)
2881*4882a593Smuzhiyun 			N = 1;
2882*4882a593Smuzhiyun 		N >>= 1;
2883*4882a593Smuzhiyun 		for (M = 1; N > 64 && M < 16; M++)
2884*4882a593Smuzhiyun 			N >>= 1;
2885*4882a593Smuzhiyun 		N--;
2886*4882a593Smuzhiyun 
2887*4882a593Smuzhiyun 		/* BGR[5..0] = N
2888*4882a593Smuzhiyun 		 * BGR[9..6] = M
2889*4882a593Smuzhiyun 		 * BGR[7..0] contained in BGR register
2890*4882a593Smuzhiyun 		 * BGR[9..8] contained in CCR2[7..6]
2891*4882a593Smuzhiyun 		 * divisor = (N+1)*2^M
2892*4882a593Smuzhiyun 		 *
2893*4882a593Smuzhiyun 		 * Note: M *must* not be zero (causes asymetric duty cycle)
2894*4882a593Smuzhiyun 		 */
2895*4882a593Smuzhiyun 		write_reg(info, (unsigned char) (channel + BGR),
2896*4882a593Smuzhiyun 				  (unsigned char) ((M << 6) + N));
2897*4882a593Smuzhiyun 		val = read_reg(info, (unsigned char) (channel + CCR2)) & 0x3f;
2898*4882a593Smuzhiyun 		val |= ((M << 4) & 0xc0);
2899*4882a593Smuzhiyun 		write_reg(info, (unsigned char) (channel + CCR2), val);
2900*4882a593Smuzhiyun 	}
2901*4882a593Smuzhiyun }
2902*4882a593Smuzhiyun 
2903*4882a593Smuzhiyun /* Enabled the AUX clock output at the specified frequency.
2904*4882a593Smuzhiyun  */
enable_auxclk(MGSLPC_INFO * info)2905*4882a593Smuzhiyun static void enable_auxclk(MGSLPC_INFO *info)
2906*4882a593Smuzhiyun {
2907*4882a593Smuzhiyun 	unsigned char val;
2908*4882a593Smuzhiyun 
2909*4882a593Smuzhiyun 	/* MODE
2910*4882a593Smuzhiyun 	 *
2911*4882a593Smuzhiyun 	 * 07..06  MDS[1..0] 10 = transparent HDLC mode
2912*4882a593Smuzhiyun 	 * 05      ADM Address Mode, 0 = no addr recognition
2913*4882a593Smuzhiyun 	 * 04      TMD Timer Mode, 0 = external
2914*4882a593Smuzhiyun 	 * 03      RAC Receiver Active, 0 = inactive
2915*4882a593Smuzhiyun 	 * 02      RTS 0=RTS active during xmit, 1=RTS always active
2916*4882a593Smuzhiyun 	 * 01      TRS Timer Resolution, 1=512
2917*4882a593Smuzhiyun 	 * 00      TLP Test Loop, 0 = no loop
2918*4882a593Smuzhiyun 	 *
2919*4882a593Smuzhiyun 	 * 1000 0010
2920*4882a593Smuzhiyun 	 */
2921*4882a593Smuzhiyun 	val = 0x82;
2922*4882a593Smuzhiyun 
2923*4882a593Smuzhiyun 	/* channel B RTS is used to enable AUXCLK driver on SP505 */
2924*4882a593Smuzhiyun 	if (info->params.mode == MGSL_MODE_HDLC && info->params.clock_speed)
2925*4882a593Smuzhiyun 		val |= BIT2;
2926*4882a593Smuzhiyun 	write_reg(info, CHB + MODE, val);
2927*4882a593Smuzhiyun 
2928*4882a593Smuzhiyun 	/* CCR0
2929*4882a593Smuzhiyun 	 *
2930*4882a593Smuzhiyun 	 * 07      PU Power Up, 1=active, 0=power down
2931*4882a593Smuzhiyun 	 * 06      MCE Master Clock Enable, 1=enabled
2932*4882a593Smuzhiyun 	 * 05      Reserved, 0
2933*4882a593Smuzhiyun 	 * 04..02  SC[2..0] Encoding
2934*4882a593Smuzhiyun 	 * 01..00  SM[1..0] Serial Mode, 00=HDLC
2935*4882a593Smuzhiyun 	 *
2936*4882a593Smuzhiyun 	 * 11000000
2937*4882a593Smuzhiyun 	 */
2938*4882a593Smuzhiyun 	write_reg(info, CHB + CCR0, 0xc0);
2939*4882a593Smuzhiyun 
2940*4882a593Smuzhiyun 	/* CCR1
2941*4882a593Smuzhiyun 	 *
2942*4882a593Smuzhiyun 	 * 07      SFLG Shared Flag, 0 = disable shared flags
2943*4882a593Smuzhiyun 	 * 06      GALP Go Active On Loop, 0 = not used
2944*4882a593Smuzhiyun 	 * 05      GLP Go On Loop, 0 = not used
2945*4882a593Smuzhiyun 	 * 04      ODS Output Driver Select, 1=TxD is push-pull output
2946*4882a593Smuzhiyun 	 * 03      ITF Interframe Time Fill, 0=mark, 1=flag
2947*4882a593Smuzhiyun 	 * 02..00  CM[2..0] Clock Mode
2948*4882a593Smuzhiyun 	 *
2949*4882a593Smuzhiyun 	 * 0001 0111
2950*4882a593Smuzhiyun 	 */
2951*4882a593Smuzhiyun 	write_reg(info, CHB + CCR1, 0x17);
2952*4882a593Smuzhiyun 
2953*4882a593Smuzhiyun 	/* CCR2 (Channel B)
2954*4882a593Smuzhiyun 	 *
2955*4882a593Smuzhiyun 	 * 07..06  BGR[9..8] Baud rate bits 9..8
2956*4882a593Smuzhiyun 	 * 05      BDF Baud rate divisor factor, 0=1, 1=BGR value
2957*4882a593Smuzhiyun 	 * 04      SSEL Clock source select, 1=submode b
2958*4882a593Smuzhiyun 	 * 03      TOE 0=TxCLK is input, 1=TxCLK is output
2959*4882a593Smuzhiyun 	 * 02      RWX Read/Write Exchange 0=disabled
2960*4882a593Smuzhiyun 	 * 01      C32, CRC select, 0=CRC-16, 1=CRC-32
2961*4882a593Smuzhiyun 	 * 00      DIV, data inversion 0=disabled, 1=enabled
2962*4882a593Smuzhiyun 	 *
2963*4882a593Smuzhiyun 	 * 0011 1000
2964*4882a593Smuzhiyun 	 */
2965*4882a593Smuzhiyun 	if (info->params.mode == MGSL_MODE_HDLC && info->params.clock_speed)
2966*4882a593Smuzhiyun 		write_reg(info, CHB + CCR2, 0x38);
2967*4882a593Smuzhiyun 	else
2968*4882a593Smuzhiyun 		write_reg(info, CHB + CCR2, 0x30);
2969*4882a593Smuzhiyun 
2970*4882a593Smuzhiyun 	/* CCR4
2971*4882a593Smuzhiyun 	 *
2972*4882a593Smuzhiyun 	 * 07      MCK4 Master Clock Divide by 4, 1=enabled
2973*4882a593Smuzhiyun 	 * 06      EBRG Enhanced Baud Rate Generator Mode, 1=enabled
2974*4882a593Smuzhiyun 	 * 05      TST1 Test Pin, 0=normal operation
2975*4882a593Smuzhiyun 	 * 04      ICD Ivert Carrier Detect, 1=enabled (active low)
2976*4882a593Smuzhiyun 	 * 03..02  Reserved, must be 0
2977*4882a593Smuzhiyun 	 * 01..00  RFT[1..0] RxFIFO Threshold 00=32 bytes
2978*4882a593Smuzhiyun 	 *
2979*4882a593Smuzhiyun 	 * 0101 0000
2980*4882a593Smuzhiyun 	 */
2981*4882a593Smuzhiyun 	write_reg(info, CHB + CCR4, 0x50);
2982*4882a593Smuzhiyun 
2983*4882a593Smuzhiyun 	/* if auxclk not enabled, set internal BRG so
2984*4882a593Smuzhiyun 	 * CTS transitions can be detected (requires TxC)
2985*4882a593Smuzhiyun 	 */
2986*4882a593Smuzhiyun 	if (info->params.mode == MGSL_MODE_HDLC && info->params.clock_speed)
2987*4882a593Smuzhiyun 		mgslpc_set_rate(info, CHB, info->params.clock_speed);
2988*4882a593Smuzhiyun 	else
2989*4882a593Smuzhiyun 		mgslpc_set_rate(info, CHB, 921600);
2990*4882a593Smuzhiyun }
2991*4882a593Smuzhiyun 
loopback_enable(MGSLPC_INFO * info)2992*4882a593Smuzhiyun static void loopback_enable(MGSLPC_INFO *info)
2993*4882a593Smuzhiyun {
2994*4882a593Smuzhiyun 	unsigned char val;
2995*4882a593Smuzhiyun 
2996*4882a593Smuzhiyun 	/* CCR1:02..00  CM[2..0] Clock Mode = 111 (clock mode 7) */
2997*4882a593Smuzhiyun 	val = read_reg(info, CHA + CCR1) | (BIT2 | BIT1 | BIT0);
2998*4882a593Smuzhiyun 	write_reg(info, CHA + CCR1, val);
2999*4882a593Smuzhiyun 
3000*4882a593Smuzhiyun 	/* CCR2:04 SSEL Clock source select, 1=submode b */
3001*4882a593Smuzhiyun 	val = read_reg(info, CHA + CCR2) | (BIT4 | BIT5);
3002*4882a593Smuzhiyun 	write_reg(info, CHA + CCR2, val);
3003*4882a593Smuzhiyun 
3004*4882a593Smuzhiyun 	/* set LinkSpeed if available, otherwise default to 2Mbps */
3005*4882a593Smuzhiyun 	if (info->params.clock_speed)
3006*4882a593Smuzhiyun 		mgslpc_set_rate(info, CHA, info->params.clock_speed);
3007*4882a593Smuzhiyun 	else
3008*4882a593Smuzhiyun 		mgslpc_set_rate(info, CHA, 1843200);
3009*4882a593Smuzhiyun 
3010*4882a593Smuzhiyun 	/* MODE:00 TLP Test Loop, 1=loopback enabled */
3011*4882a593Smuzhiyun 	val = read_reg(info, CHA + MODE) | BIT0;
3012*4882a593Smuzhiyun 	write_reg(info, CHA + MODE, val);
3013*4882a593Smuzhiyun }
3014*4882a593Smuzhiyun 
hdlc_mode(MGSLPC_INFO * info)3015*4882a593Smuzhiyun static void hdlc_mode(MGSLPC_INFO *info)
3016*4882a593Smuzhiyun {
3017*4882a593Smuzhiyun 	unsigned char val;
3018*4882a593Smuzhiyun 	unsigned char clkmode, clksubmode;
3019*4882a593Smuzhiyun 
3020*4882a593Smuzhiyun 	/* disable all interrupts */
3021*4882a593Smuzhiyun 	irq_disable(info, CHA, 0xffff);
3022*4882a593Smuzhiyun 	irq_disable(info, CHB, 0xffff);
3023*4882a593Smuzhiyun 	port_irq_disable(info, 0xff);
3024*4882a593Smuzhiyun 
3025*4882a593Smuzhiyun 	/* assume clock mode 0a, rcv=RxC xmt=TxC */
3026*4882a593Smuzhiyun 	clkmode = clksubmode = 0;
3027*4882a593Smuzhiyun 	if (info->params.flags & HDLC_FLAG_RXC_DPLL
3028*4882a593Smuzhiyun 	    && info->params.flags & HDLC_FLAG_TXC_DPLL) {
3029*4882a593Smuzhiyun 		/* clock mode 7a, rcv = DPLL, xmt = DPLL */
3030*4882a593Smuzhiyun 		clkmode = 7;
3031*4882a593Smuzhiyun 	} else if (info->params.flags & HDLC_FLAG_RXC_BRG
3032*4882a593Smuzhiyun 		 && info->params.flags & HDLC_FLAG_TXC_BRG) {
3033*4882a593Smuzhiyun 		/* clock mode 7b, rcv = BRG, xmt = BRG */
3034*4882a593Smuzhiyun 		clkmode = 7;
3035*4882a593Smuzhiyun 		clksubmode = 1;
3036*4882a593Smuzhiyun 	} else if (info->params.flags & HDLC_FLAG_RXC_DPLL) {
3037*4882a593Smuzhiyun 		if (info->params.flags & HDLC_FLAG_TXC_BRG) {
3038*4882a593Smuzhiyun 			/* clock mode 6b, rcv = DPLL, xmt = BRG/16 */
3039*4882a593Smuzhiyun 			clkmode = 6;
3040*4882a593Smuzhiyun 			clksubmode = 1;
3041*4882a593Smuzhiyun 		} else {
3042*4882a593Smuzhiyun 			/* clock mode 6a, rcv = DPLL, xmt = TxC */
3043*4882a593Smuzhiyun 			clkmode = 6;
3044*4882a593Smuzhiyun 		}
3045*4882a593Smuzhiyun 	} else if (info->params.flags & HDLC_FLAG_TXC_BRG) {
3046*4882a593Smuzhiyun 		/* clock mode 0b, rcv = RxC, xmt = BRG */
3047*4882a593Smuzhiyun 		clksubmode = 1;
3048*4882a593Smuzhiyun 	}
3049*4882a593Smuzhiyun 
3050*4882a593Smuzhiyun 	/* MODE
3051*4882a593Smuzhiyun 	 *
3052*4882a593Smuzhiyun 	 * 07..06  MDS[1..0] 10 = transparent HDLC mode
3053*4882a593Smuzhiyun 	 * 05      ADM Address Mode, 0 = no addr recognition
3054*4882a593Smuzhiyun 	 * 04      TMD Timer Mode, 0 = external
3055*4882a593Smuzhiyun 	 * 03      RAC Receiver Active, 0 = inactive
3056*4882a593Smuzhiyun 	 * 02      RTS 0=RTS active during xmit, 1=RTS always active
3057*4882a593Smuzhiyun 	 * 01      TRS Timer Resolution, 1=512
3058*4882a593Smuzhiyun 	 * 00      TLP Test Loop, 0 = no loop
3059*4882a593Smuzhiyun 	 *
3060*4882a593Smuzhiyun 	 * 1000 0010
3061*4882a593Smuzhiyun 	 */
3062*4882a593Smuzhiyun 	val = 0x82;
3063*4882a593Smuzhiyun 	if (info->params.loopback)
3064*4882a593Smuzhiyun 		val |= BIT0;
3065*4882a593Smuzhiyun 
3066*4882a593Smuzhiyun 	/* preserve RTS state */
3067*4882a593Smuzhiyun 	if (info->serial_signals & SerialSignal_RTS)
3068*4882a593Smuzhiyun 		val |= BIT2;
3069*4882a593Smuzhiyun 	write_reg(info, CHA + MODE, val);
3070*4882a593Smuzhiyun 
3071*4882a593Smuzhiyun 	/* CCR0
3072*4882a593Smuzhiyun 	 *
3073*4882a593Smuzhiyun 	 * 07      PU Power Up, 1=active, 0=power down
3074*4882a593Smuzhiyun 	 * 06      MCE Master Clock Enable, 1=enabled
3075*4882a593Smuzhiyun 	 * 05      Reserved, 0
3076*4882a593Smuzhiyun 	 * 04..02  SC[2..0] Encoding
3077*4882a593Smuzhiyun 	 * 01..00  SM[1..0] Serial Mode, 00=HDLC
3078*4882a593Smuzhiyun 	 *
3079*4882a593Smuzhiyun 	 * 11000000
3080*4882a593Smuzhiyun 	 */
3081*4882a593Smuzhiyun 	val = 0xc0;
3082*4882a593Smuzhiyun 	switch (info->params.encoding)
3083*4882a593Smuzhiyun 	{
3084*4882a593Smuzhiyun 	case HDLC_ENCODING_NRZI:
3085*4882a593Smuzhiyun 		val |= BIT3;
3086*4882a593Smuzhiyun 		break;
3087*4882a593Smuzhiyun 	case HDLC_ENCODING_BIPHASE_SPACE:
3088*4882a593Smuzhiyun 		val |= BIT4;
3089*4882a593Smuzhiyun 		break;		// FM0
3090*4882a593Smuzhiyun 	case HDLC_ENCODING_BIPHASE_MARK:
3091*4882a593Smuzhiyun 		val |= BIT4 | BIT2;
3092*4882a593Smuzhiyun 		break;		// FM1
3093*4882a593Smuzhiyun 	case HDLC_ENCODING_BIPHASE_LEVEL:
3094*4882a593Smuzhiyun 		val |= BIT4 | BIT3;
3095*4882a593Smuzhiyun 		break;		// Manchester
3096*4882a593Smuzhiyun 	}
3097*4882a593Smuzhiyun 	write_reg(info, CHA + CCR0, val);
3098*4882a593Smuzhiyun 
3099*4882a593Smuzhiyun 	/* CCR1
3100*4882a593Smuzhiyun 	 *
3101*4882a593Smuzhiyun 	 * 07      SFLG Shared Flag, 0 = disable shared flags
3102*4882a593Smuzhiyun 	 * 06      GALP Go Active On Loop, 0 = not used
3103*4882a593Smuzhiyun 	 * 05      GLP Go On Loop, 0 = not used
3104*4882a593Smuzhiyun 	 * 04      ODS Output Driver Select, 1=TxD is push-pull output
3105*4882a593Smuzhiyun 	 * 03      ITF Interframe Time Fill, 0=mark, 1=flag
3106*4882a593Smuzhiyun 	 * 02..00  CM[2..0] Clock Mode
3107*4882a593Smuzhiyun 	 *
3108*4882a593Smuzhiyun 	 * 0001 0000
3109*4882a593Smuzhiyun 	 */
3110*4882a593Smuzhiyun 	val = 0x10 + clkmode;
3111*4882a593Smuzhiyun 	write_reg(info, CHA + CCR1, val);
3112*4882a593Smuzhiyun 
3113*4882a593Smuzhiyun 	/* CCR2
3114*4882a593Smuzhiyun 	 *
3115*4882a593Smuzhiyun 	 * 07..06  BGR[9..8] Baud rate bits 9..8
3116*4882a593Smuzhiyun 	 * 05      BDF Baud rate divisor factor, 0=1, 1=BGR value
3117*4882a593Smuzhiyun 	 * 04      SSEL Clock source select, 1=submode b
3118*4882a593Smuzhiyun 	 * 03      TOE 0=TxCLK is input, 0=TxCLK is input
3119*4882a593Smuzhiyun 	 * 02      RWX Read/Write Exchange 0=disabled
3120*4882a593Smuzhiyun 	 * 01      C32, CRC select, 0=CRC-16, 1=CRC-32
3121*4882a593Smuzhiyun 	 * 00      DIV, data inversion 0=disabled, 1=enabled
3122*4882a593Smuzhiyun 	 *
3123*4882a593Smuzhiyun 	 * 0000 0000
3124*4882a593Smuzhiyun 	 */
3125*4882a593Smuzhiyun 	val = 0x00;
3126*4882a593Smuzhiyun 	if (clkmode == 2 || clkmode == 3 || clkmode == 6
3127*4882a593Smuzhiyun 	    || clkmode == 7 || (clkmode == 0 && clksubmode == 1))
3128*4882a593Smuzhiyun 		val |= BIT5;
3129*4882a593Smuzhiyun 	if (clksubmode)
3130*4882a593Smuzhiyun 		val |= BIT4;
3131*4882a593Smuzhiyun 	if (info->params.crc_type == HDLC_CRC_32_CCITT)
3132*4882a593Smuzhiyun 		val |= BIT1;
3133*4882a593Smuzhiyun 	if (info->params.encoding == HDLC_ENCODING_NRZB)
3134*4882a593Smuzhiyun 		val |= BIT0;
3135*4882a593Smuzhiyun 	write_reg(info, CHA + CCR2, val);
3136*4882a593Smuzhiyun 
3137*4882a593Smuzhiyun 	/* CCR3
3138*4882a593Smuzhiyun 	 *
3139*4882a593Smuzhiyun 	 * 07..06  PRE[1..0] Preamble count 00=1, 01=2, 10=4, 11=8
3140*4882a593Smuzhiyun 	 * 05      EPT Enable preamble transmission, 1=enabled
3141*4882a593Smuzhiyun 	 * 04      RADD Receive address pushed to FIFO, 0=disabled
3142*4882a593Smuzhiyun 	 * 03      CRL CRC Reset Level, 0=FFFF
3143*4882a593Smuzhiyun 	 * 02      RCRC Rx CRC 0=On 1=Off
3144*4882a593Smuzhiyun 	 * 01      TCRC Tx CRC 0=On 1=Off
3145*4882a593Smuzhiyun 	 * 00      PSD DPLL Phase Shift Disable
3146*4882a593Smuzhiyun 	 *
3147*4882a593Smuzhiyun 	 * 0000 0000
3148*4882a593Smuzhiyun 	 */
3149*4882a593Smuzhiyun 	val = 0x00;
3150*4882a593Smuzhiyun 	if (info->params.crc_type == HDLC_CRC_NONE)
3151*4882a593Smuzhiyun 		val |= BIT2 | BIT1;
3152*4882a593Smuzhiyun 	if (info->params.preamble != HDLC_PREAMBLE_PATTERN_NONE)
3153*4882a593Smuzhiyun 		val |= BIT5;
3154*4882a593Smuzhiyun 	switch (info->params.preamble_length)
3155*4882a593Smuzhiyun 	{
3156*4882a593Smuzhiyun 	case HDLC_PREAMBLE_LENGTH_16BITS:
3157*4882a593Smuzhiyun 		val |= BIT6;
3158*4882a593Smuzhiyun 		break;
3159*4882a593Smuzhiyun 	case HDLC_PREAMBLE_LENGTH_32BITS:
3160*4882a593Smuzhiyun 		val |= BIT6;
3161*4882a593Smuzhiyun 		break;
3162*4882a593Smuzhiyun 	case HDLC_PREAMBLE_LENGTH_64BITS:
3163*4882a593Smuzhiyun 		val |= BIT7 | BIT6;
3164*4882a593Smuzhiyun 		break;
3165*4882a593Smuzhiyun 	}
3166*4882a593Smuzhiyun 	write_reg(info, CHA + CCR3, val);
3167*4882a593Smuzhiyun 
3168*4882a593Smuzhiyun 	/* PRE - Preamble pattern */
3169*4882a593Smuzhiyun 	val = 0;
3170*4882a593Smuzhiyun 	switch (info->params.preamble)
3171*4882a593Smuzhiyun 	{
3172*4882a593Smuzhiyun 	case HDLC_PREAMBLE_PATTERN_FLAGS: val = 0x7e; break;
3173*4882a593Smuzhiyun 	case HDLC_PREAMBLE_PATTERN_10:    val = 0xaa; break;
3174*4882a593Smuzhiyun 	case HDLC_PREAMBLE_PATTERN_01:    val = 0x55; break;
3175*4882a593Smuzhiyun 	case HDLC_PREAMBLE_PATTERN_ONES:  val = 0xff; break;
3176*4882a593Smuzhiyun 	}
3177*4882a593Smuzhiyun 	write_reg(info, CHA + PRE, val);
3178*4882a593Smuzhiyun 
3179*4882a593Smuzhiyun 	/* CCR4
3180*4882a593Smuzhiyun 	 *
3181*4882a593Smuzhiyun 	 * 07      MCK4 Master Clock Divide by 4, 1=enabled
3182*4882a593Smuzhiyun 	 * 06      EBRG Enhanced Baud Rate Generator Mode, 1=enabled
3183*4882a593Smuzhiyun 	 * 05      TST1 Test Pin, 0=normal operation
3184*4882a593Smuzhiyun 	 * 04      ICD Ivert Carrier Detect, 1=enabled (active low)
3185*4882a593Smuzhiyun 	 * 03..02  Reserved, must be 0
3186*4882a593Smuzhiyun 	 * 01..00  RFT[1..0] RxFIFO Threshold 00=32 bytes
3187*4882a593Smuzhiyun 	 *
3188*4882a593Smuzhiyun 	 * 0101 0000
3189*4882a593Smuzhiyun 	 */
3190*4882a593Smuzhiyun 	val = 0x50;
3191*4882a593Smuzhiyun 	write_reg(info, CHA + CCR4, val);
3192*4882a593Smuzhiyun 	if (info->params.flags & HDLC_FLAG_RXC_DPLL)
3193*4882a593Smuzhiyun 		mgslpc_set_rate(info, CHA, info->params.clock_speed * 16);
3194*4882a593Smuzhiyun 	else
3195*4882a593Smuzhiyun 		mgslpc_set_rate(info, CHA, info->params.clock_speed);
3196*4882a593Smuzhiyun 
3197*4882a593Smuzhiyun 	/* RLCR Receive length check register
3198*4882a593Smuzhiyun 	 *
3199*4882a593Smuzhiyun 	 * 7     1=enable receive length check
3200*4882a593Smuzhiyun 	 * 6..0  Max frame length = (RL + 1) * 32
3201*4882a593Smuzhiyun 	 */
3202*4882a593Smuzhiyun 	write_reg(info, CHA + RLCR, 0);
3203*4882a593Smuzhiyun 
3204*4882a593Smuzhiyun 	/* XBCH Transmit Byte Count High
3205*4882a593Smuzhiyun 	 *
3206*4882a593Smuzhiyun 	 * 07      DMA mode, 0 = interrupt driven
3207*4882a593Smuzhiyun 	 * 06      NRM, 0=ABM (ignored)
3208*4882a593Smuzhiyun 	 * 05      CAS Carrier Auto Start
3209*4882a593Smuzhiyun 	 * 04      XC Transmit Continuously (ignored)
3210*4882a593Smuzhiyun 	 * 03..00  XBC[10..8] Transmit byte count bits 10..8
3211*4882a593Smuzhiyun 	 *
3212*4882a593Smuzhiyun 	 * 0000 0000
3213*4882a593Smuzhiyun 	 */
3214*4882a593Smuzhiyun 	val = 0x00;
3215*4882a593Smuzhiyun 	if (info->params.flags & HDLC_FLAG_AUTO_DCD)
3216*4882a593Smuzhiyun 		val |= BIT5;
3217*4882a593Smuzhiyun 	write_reg(info, CHA + XBCH, val);
3218*4882a593Smuzhiyun 	enable_auxclk(info);
3219*4882a593Smuzhiyun 	if (info->params.loopback || info->testing_irq)
3220*4882a593Smuzhiyun 		loopback_enable(info);
3221*4882a593Smuzhiyun 	if (info->params.flags & HDLC_FLAG_AUTO_CTS)
3222*4882a593Smuzhiyun 	{
3223*4882a593Smuzhiyun 		irq_enable(info, CHB, IRQ_CTS);
3224*4882a593Smuzhiyun 		/* PVR[3] 1=AUTO CTS active */
3225*4882a593Smuzhiyun 		set_reg_bits(info, CHA + PVR, BIT3);
3226*4882a593Smuzhiyun 	} else
3227*4882a593Smuzhiyun 		clear_reg_bits(info, CHA + PVR, BIT3);
3228*4882a593Smuzhiyun 
3229*4882a593Smuzhiyun 	irq_enable(info, CHA,
3230*4882a593Smuzhiyun 			 IRQ_RXEOM | IRQ_RXFIFO | IRQ_ALLSENT |
3231*4882a593Smuzhiyun 			 IRQ_UNDERRUN | IRQ_TXFIFO);
3232*4882a593Smuzhiyun 	issue_command(info, CHA, CMD_TXRESET + CMD_RXRESET);
3233*4882a593Smuzhiyun 	wait_command_complete(info, CHA);
3234*4882a593Smuzhiyun 	read_reg16(info, CHA + ISR);	/* clear pending IRQs */
3235*4882a593Smuzhiyun 
3236*4882a593Smuzhiyun 	/* Master clock mode enabled above to allow reset commands
3237*4882a593Smuzhiyun 	 * to complete even if no data clocks are present.
3238*4882a593Smuzhiyun 	 *
3239*4882a593Smuzhiyun 	 * Disable master clock mode for normal communications because
3240*4882a593Smuzhiyun 	 * V3.2 of the ESCC2 has a bug that prevents the transmit all sent
3241*4882a593Smuzhiyun 	 * IRQ when in master clock mode.
3242*4882a593Smuzhiyun 	 *
3243*4882a593Smuzhiyun 	 * Leave master clock mode enabled for IRQ test because the
3244*4882a593Smuzhiyun 	 * timer IRQ used by the test can only happen in master clock mode.
3245*4882a593Smuzhiyun 	 */
3246*4882a593Smuzhiyun 	if (!info->testing_irq)
3247*4882a593Smuzhiyun 		clear_reg_bits(info, CHA + CCR0, BIT6);
3248*4882a593Smuzhiyun 
3249*4882a593Smuzhiyun 	tx_set_idle(info);
3250*4882a593Smuzhiyun 
3251*4882a593Smuzhiyun 	tx_stop(info);
3252*4882a593Smuzhiyun 	rx_stop(info);
3253*4882a593Smuzhiyun }
3254*4882a593Smuzhiyun 
rx_stop(MGSLPC_INFO * info)3255*4882a593Smuzhiyun static void rx_stop(MGSLPC_INFO *info)
3256*4882a593Smuzhiyun {
3257*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_ISR)
3258*4882a593Smuzhiyun 		printk("%s(%d):rx_stop(%s)\n",
3259*4882a593Smuzhiyun 			 __FILE__, __LINE__, info->device_name);
3260*4882a593Smuzhiyun 
3261*4882a593Smuzhiyun 	/* MODE:03 RAC Receiver Active, 0=inactive */
3262*4882a593Smuzhiyun 	clear_reg_bits(info, CHA + MODE, BIT3);
3263*4882a593Smuzhiyun 
3264*4882a593Smuzhiyun 	info->rx_enabled = false;
3265*4882a593Smuzhiyun 	info->rx_overflow = false;
3266*4882a593Smuzhiyun }
3267*4882a593Smuzhiyun 
rx_start(MGSLPC_INFO * info)3268*4882a593Smuzhiyun static void rx_start(MGSLPC_INFO *info)
3269*4882a593Smuzhiyun {
3270*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_ISR)
3271*4882a593Smuzhiyun 		printk("%s(%d):rx_start(%s)\n",
3272*4882a593Smuzhiyun 			 __FILE__, __LINE__, info->device_name);
3273*4882a593Smuzhiyun 
3274*4882a593Smuzhiyun 	rx_reset_buffers(info);
3275*4882a593Smuzhiyun 	info->rx_enabled = false;
3276*4882a593Smuzhiyun 	info->rx_overflow = false;
3277*4882a593Smuzhiyun 
3278*4882a593Smuzhiyun 	/* MODE:03 RAC Receiver Active, 1=active */
3279*4882a593Smuzhiyun 	set_reg_bits(info, CHA + MODE, BIT3);
3280*4882a593Smuzhiyun 
3281*4882a593Smuzhiyun 	info->rx_enabled = true;
3282*4882a593Smuzhiyun }
3283*4882a593Smuzhiyun 
tx_start(MGSLPC_INFO * info,struct tty_struct * tty)3284*4882a593Smuzhiyun static void tx_start(MGSLPC_INFO *info, struct tty_struct *tty)
3285*4882a593Smuzhiyun {
3286*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_ISR)
3287*4882a593Smuzhiyun 		printk("%s(%d):tx_start(%s)\n",
3288*4882a593Smuzhiyun 			 __FILE__, __LINE__, info->device_name);
3289*4882a593Smuzhiyun 
3290*4882a593Smuzhiyun 	if (info->tx_count) {
3291*4882a593Smuzhiyun 		/* If auto RTS enabled and RTS is inactive, then assert */
3292*4882a593Smuzhiyun 		/* RTS and set a flag indicating that the driver should */
3293*4882a593Smuzhiyun 		/* negate RTS when the transmission completes. */
3294*4882a593Smuzhiyun 		info->drop_rts_on_tx_done = false;
3295*4882a593Smuzhiyun 
3296*4882a593Smuzhiyun 		if (info->params.flags & HDLC_FLAG_AUTO_RTS) {
3297*4882a593Smuzhiyun 			get_signals(info);
3298*4882a593Smuzhiyun 			if (!(info->serial_signals & SerialSignal_RTS)) {
3299*4882a593Smuzhiyun 				info->serial_signals |= SerialSignal_RTS;
3300*4882a593Smuzhiyun 				set_signals(info);
3301*4882a593Smuzhiyun 				info->drop_rts_on_tx_done = true;
3302*4882a593Smuzhiyun 			}
3303*4882a593Smuzhiyun 		}
3304*4882a593Smuzhiyun 
3305*4882a593Smuzhiyun 		if (info->params.mode == MGSL_MODE_ASYNC) {
3306*4882a593Smuzhiyun 			if (!info->tx_active) {
3307*4882a593Smuzhiyun 				info->tx_active = true;
3308*4882a593Smuzhiyun 				tx_ready(info, tty);
3309*4882a593Smuzhiyun 			}
3310*4882a593Smuzhiyun 		} else {
3311*4882a593Smuzhiyun 			info->tx_active = true;
3312*4882a593Smuzhiyun 			tx_ready(info, tty);
3313*4882a593Smuzhiyun 			mod_timer(&info->tx_timer, jiffies +
3314*4882a593Smuzhiyun 					msecs_to_jiffies(5000));
3315*4882a593Smuzhiyun 		}
3316*4882a593Smuzhiyun 	}
3317*4882a593Smuzhiyun 
3318*4882a593Smuzhiyun 	if (!info->tx_enabled)
3319*4882a593Smuzhiyun 		info->tx_enabled = true;
3320*4882a593Smuzhiyun }
3321*4882a593Smuzhiyun 
tx_stop(MGSLPC_INFO * info)3322*4882a593Smuzhiyun static void tx_stop(MGSLPC_INFO *info)
3323*4882a593Smuzhiyun {
3324*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_ISR)
3325*4882a593Smuzhiyun 		printk("%s(%d):tx_stop(%s)\n",
3326*4882a593Smuzhiyun 			 __FILE__, __LINE__, info->device_name);
3327*4882a593Smuzhiyun 
3328*4882a593Smuzhiyun 	del_timer(&info->tx_timer);
3329*4882a593Smuzhiyun 
3330*4882a593Smuzhiyun 	info->tx_enabled = false;
3331*4882a593Smuzhiyun 	info->tx_active = false;
3332*4882a593Smuzhiyun }
3333*4882a593Smuzhiyun 
3334*4882a593Smuzhiyun /* Reset the adapter to a known state and prepare it for further use.
3335*4882a593Smuzhiyun  */
reset_device(MGSLPC_INFO * info)3336*4882a593Smuzhiyun static void reset_device(MGSLPC_INFO *info)
3337*4882a593Smuzhiyun {
3338*4882a593Smuzhiyun 	/* power up both channels (set BIT7) */
3339*4882a593Smuzhiyun 	write_reg(info, CHA + CCR0, 0x80);
3340*4882a593Smuzhiyun 	write_reg(info, CHB + CCR0, 0x80);
3341*4882a593Smuzhiyun 	write_reg(info, CHA + MODE, 0);
3342*4882a593Smuzhiyun 	write_reg(info, CHB + MODE, 0);
3343*4882a593Smuzhiyun 
3344*4882a593Smuzhiyun 	/* disable all interrupts */
3345*4882a593Smuzhiyun 	irq_disable(info, CHA, 0xffff);
3346*4882a593Smuzhiyun 	irq_disable(info, CHB, 0xffff);
3347*4882a593Smuzhiyun 	port_irq_disable(info, 0xff);
3348*4882a593Smuzhiyun 
3349*4882a593Smuzhiyun 	/* PCR Port Configuration Register
3350*4882a593Smuzhiyun 	 *
3351*4882a593Smuzhiyun 	 * 07..04  DEC[3..0] Serial I/F select outputs
3352*4882a593Smuzhiyun 	 * 03      output, 1=AUTO CTS control enabled
3353*4882a593Smuzhiyun 	 * 02      RI Ring Indicator input 0=active
3354*4882a593Smuzhiyun 	 * 01      DSR input 0=active
3355*4882a593Smuzhiyun 	 * 00      DTR output 0=active
3356*4882a593Smuzhiyun 	 *
3357*4882a593Smuzhiyun 	 * 0000 0110
3358*4882a593Smuzhiyun 	 */
3359*4882a593Smuzhiyun 	write_reg(info, PCR, 0x06);
3360*4882a593Smuzhiyun 
3361*4882a593Smuzhiyun 	/* PVR Port Value Register
3362*4882a593Smuzhiyun 	 *
3363*4882a593Smuzhiyun 	 * 07..04  DEC[3..0] Serial I/F select (0000=disabled)
3364*4882a593Smuzhiyun 	 * 03      AUTO CTS output 1=enabled
3365*4882a593Smuzhiyun 	 * 02      RI Ring Indicator input
3366*4882a593Smuzhiyun 	 * 01      DSR input
3367*4882a593Smuzhiyun 	 * 00      DTR output (1=inactive)
3368*4882a593Smuzhiyun 	 *
3369*4882a593Smuzhiyun 	 * 0000 0001
3370*4882a593Smuzhiyun 	 */
3371*4882a593Smuzhiyun //	write_reg(info, PVR, PVR_DTR);
3372*4882a593Smuzhiyun 
3373*4882a593Smuzhiyun 	/* IPC Interrupt Port Configuration
3374*4882a593Smuzhiyun 	 *
3375*4882a593Smuzhiyun 	 * 07      VIS 1=Masked interrupts visible
3376*4882a593Smuzhiyun 	 * 06..05  Reserved, 0
3377*4882a593Smuzhiyun 	 * 04..03  SLA Slave address, 00 ignored
3378*4882a593Smuzhiyun 	 * 02      CASM Cascading Mode, 1=daisy chain
3379*4882a593Smuzhiyun 	 * 01..00  IC[1..0] Interrupt Config, 01=push-pull output, active low
3380*4882a593Smuzhiyun 	 *
3381*4882a593Smuzhiyun 	 * 0000 0101
3382*4882a593Smuzhiyun 	 */
3383*4882a593Smuzhiyun 	write_reg(info, IPC, 0x05);
3384*4882a593Smuzhiyun }
3385*4882a593Smuzhiyun 
async_mode(MGSLPC_INFO * info)3386*4882a593Smuzhiyun static void async_mode(MGSLPC_INFO *info)
3387*4882a593Smuzhiyun {
3388*4882a593Smuzhiyun 	unsigned char val;
3389*4882a593Smuzhiyun 
3390*4882a593Smuzhiyun 	/* disable all interrupts */
3391*4882a593Smuzhiyun 	irq_disable(info, CHA, 0xffff);
3392*4882a593Smuzhiyun 	irq_disable(info, CHB, 0xffff);
3393*4882a593Smuzhiyun 	port_irq_disable(info, 0xff);
3394*4882a593Smuzhiyun 
3395*4882a593Smuzhiyun 	/* MODE
3396*4882a593Smuzhiyun 	 *
3397*4882a593Smuzhiyun 	 * 07      Reserved, 0
3398*4882a593Smuzhiyun 	 * 06      FRTS RTS State, 0=active
3399*4882a593Smuzhiyun 	 * 05      FCTS Flow Control on CTS
3400*4882a593Smuzhiyun 	 * 04      FLON Flow Control Enable
3401*4882a593Smuzhiyun 	 * 03      RAC Receiver Active, 0 = inactive
3402*4882a593Smuzhiyun 	 * 02      RTS 0=Auto RTS, 1=manual RTS
3403*4882a593Smuzhiyun 	 * 01      TRS Timer Resolution, 1=512
3404*4882a593Smuzhiyun 	 * 00      TLP Test Loop, 0 = no loop
3405*4882a593Smuzhiyun 	 *
3406*4882a593Smuzhiyun 	 * 0000 0110
3407*4882a593Smuzhiyun 	 */
3408*4882a593Smuzhiyun 	val = 0x06;
3409*4882a593Smuzhiyun 	if (info->params.loopback)
3410*4882a593Smuzhiyun 		val |= BIT0;
3411*4882a593Smuzhiyun 
3412*4882a593Smuzhiyun 	/* preserve RTS state */
3413*4882a593Smuzhiyun 	if (!(info->serial_signals & SerialSignal_RTS))
3414*4882a593Smuzhiyun 		val |= BIT6;
3415*4882a593Smuzhiyun 	write_reg(info, CHA + MODE, val);
3416*4882a593Smuzhiyun 
3417*4882a593Smuzhiyun 	/* CCR0
3418*4882a593Smuzhiyun 	 *
3419*4882a593Smuzhiyun 	 * 07      PU Power Up, 1=active, 0=power down
3420*4882a593Smuzhiyun 	 * 06      MCE Master Clock Enable, 1=enabled
3421*4882a593Smuzhiyun 	 * 05      Reserved, 0
3422*4882a593Smuzhiyun 	 * 04..02  SC[2..0] Encoding, 000=NRZ
3423*4882a593Smuzhiyun 	 * 01..00  SM[1..0] Serial Mode, 11=Async
3424*4882a593Smuzhiyun 	 *
3425*4882a593Smuzhiyun 	 * 1000 0011
3426*4882a593Smuzhiyun 	 */
3427*4882a593Smuzhiyun 	write_reg(info, CHA + CCR0, 0x83);
3428*4882a593Smuzhiyun 
3429*4882a593Smuzhiyun 	/* CCR1
3430*4882a593Smuzhiyun 	 *
3431*4882a593Smuzhiyun 	 * 07..05  Reserved, 0
3432*4882a593Smuzhiyun 	 * 04      ODS Output Driver Select, 1=TxD is push-pull output
3433*4882a593Smuzhiyun 	 * 03      BCR Bit Clock Rate, 1=16x
3434*4882a593Smuzhiyun 	 * 02..00  CM[2..0] Clock Mode, 111=BRG
3435*4882a593Smuzhiyun 	 *
3436*4882a593Smuzhiyun 	 * 0001 1111
3437*4882a593Smuzhiyun 	 */
3438*4882a593Smuzhiyun 	write_reg(info, CHA + CCR1, 0x1f);
3439*4882a593Smuzhiyun 
3440*4882a593Smuzhiyun 	/* CCR2 (channel A)
3441*4882a593Smuzhiyun 	 *
3442*4882a593Smuzhiyun 	 * 07..06  BGR[9..8] Baud rate bits 9..8
3443*4882a593Smuzhiyun 	 * 05      BDF Baud rate divisor factor, 0=1, 1=BGR value
3444*4882a593Smuzhiyun 	 * 04      SSEL Clock source select, 1=submode b
3445*4882a593Smuzhiyun 	 * 03      TOE 0=TxCLK is input, 0=TxCLK is input
3446*4882a593Smuzhiyun 	 * 02      RWX Read/Write Exchange 0=disabled
3447*4882a593Smuzhiyun 	 * 01      Reserved, 0
3448*4882a593Smuzhiyun 	 * 00      DIV, data inversion 0=disabled, 1=enabled
3449*4882a593Smuzhiyun 	 *
3450*4882a593Smuzhiyun 	 * 0001 0000
3451*4882a593Smuzhiyun 	 */
3452*4882a593Smuzhiyun 	write_reg(info, CHA + CCR2, 0x10);
3453*4882a593Smuzhiyun 
3454*4882a593Smuzhiyun 	/* CCR3
3455*4882a593Smuzhiyun 	 *
3456*4882a593Smuzhiyun 	 * 07..01  Reserved, 0
3457*4882a593Smuzhiyun 	 * 00      PSD DPLL Phase Shift Disable
3458*4882a593Smuzhiyun 	 *
3459*4882a593Smuzhiyun 	 * 0000 0000
3460*4882a593Smuzhiyun 	 */
3461*4882a593Smuzhiyun 	write_reg(info, CHA + CCR3, 0);
3462*4882a593Smuzhiyun 
3463*4882a593Smuzhiyun 	/* CCR4
3464*4882a593Smuzhiyun 	 *
3465*4882a593Smuzhiyun 	 * 07      MCK4 Master Clock Divide by 4, 1=enabled
3466*4882a593Smuzhiyun 	 * 06      EBRG Enhanced Baud Rate Generator Mode, 1=enabled
3467*4882a593Smuzhiyun 	 * 05      TST1 Test Pin, 0=normal operation
3468*4882a593Smuzhiyun 	 * 04      ICD Ivert Carrier Detect, 1=enabled (active low)
3469*4882a593Smuzhiyun 	 * 03..00  Reserved, must be 0
3470*4882a593Smuzhiyun 	 *
3471*4882a593Smuzhiyun 	 * 0101 0000
3472*4882a593Smuzhiyun 	 */
3473*4882a593Smuzhiyun 	write_reg(info, CHA + CCR4, 0x50);
3474*4882a593Smuzhiyun 	mgslpc_set_rate(info, CHA, info->params.data_rate * 16);
3475*4882a593Smuzhiyun 
3476*4882a593Smuzhiyun 	/* DAFO Data Format
3477*4882a593Smuzhiyun 	 *
3478*4882a593Smuzhiyun 	 * 07      Reserved, 0
3479*4882a593Smuzhiyun 	 * 06      XBRK transmit break, 0=normal operation
3480*4882a593Smuzhiyun 	 * 05      Stop bits (0=1, 1=2)
3481*4882a593Smuzhiyun 	 * 04..03  PAR[1..0] Parity (01=odd, 10=even)
3482*4882a593Smuzhiyun 	 * 02      PAREN Parity Enable
3483*4882a593Smuzhiyun 	 * 01..00  CHL[1..0] Character Length (00=8, 01=7)
3484*4882a593Smuzhiyun 	 *
3485*4882a593Smuzhiyun 	 */
3486*4882a593Smuzhiyun 	val = 0x00;
3487*4882a593Smuzhiyun 	if (info->params.data_bits != 8)
3488*4882a593Smuzhiyun 		val |= BIT0;	/* 7 bits */
3489*4882a593Smuzhiyun 	if (info->params.stop_bits != 1)
3490*4882a593Smuzhiyun 		val |= BIT5;
3491*4882a593Smuzhiyun 	if (info->params.parity != ASYNC_PARITY_NONE)
3492*4882a593Smuzhiyun 	{
3493*4882a593Smuzhiyun 		val |= BIT2;	/* Parity enable */
3494*4882a593Smuzhiyun 		if (info->params.parity == ASYNC_PARITY_ODD)
3495*4882a593Smuzhiyun 			val |= BIT3;
3496*4882a593Smuzhiyun 		else
3497*4882a593Smuzhiyun 			val |= BIT4;
3498*4882a593Smuzhiyun 	}
3499*4882a593Smuzhiyun 	write_reg(info, CHA + DAFO, val);
3500*4882a593Smuzhiyun 
3501*4882a593Smuzhiyun 	/* RFC Rx FIFO Control
3502*4882a593Smuzhiyun 	 *
3503*4882a593Smuzhiyun 	 * 07      Reserved, 0
3504*4882a593Smuzhiyun 	 * 06      DPS, 1=parity bit not stored in data byte
3505*4882a593Smuzhiyun 	 * 05      DXS, 0=all data stored in FIFO (including XON/XOFF)
3506*4882a593Smuzhiyun 	 * 04      RFDF Rx FIFO Data Format, 1=status byte stored in FIFO
3507*4882a593Smuzhiyun 	 * 03..02  RFTH[1..0], rx threshold, 11=16 status + 16 data byte
3508*4882a593Smuzhiyun 	 * 01      Reserved, 0
3509*4882a593Smuzhiyun 	 * 00      TCDE Terminate Char Detect Enable, 0=disabled
3510*4882a593Smuzhiyun 	 *
3511*4882a593Smuzhiyun 	 * 0101 1100
3512*4882a593Smuzhiyun 	 */
3513*4882a593Smuzhiyun 	write_reg(info, CHA + RFC, 0x5c);
3514*4882a593Smuzhiyun 
3515*4882a593Smuzhiyun 	/* RLCR Receive length check register
3516*4882a593Smuzhiyun 	 *
3517*4882a593Smuzhiyun 	 * Max frame length = (RL + 1) * 32
3518*4882a593Smuzhiyun 	 */
3519*4882a593Smuzhiyun 	write_reg(info, CHA + RLCR, 0);
3520*4882a593Smuzhiyun 
3521*4882a593Smuzhiyun 	/* XBCH Transmit Byte Count High
3522*4882a593Smuzhiyun 	 *
3523*4882a593Smuzhiyun 	 * 07      DMA mode, 0 = interrupt driven
3524*4882a593Smuzhiyun 	 * 06      NRM, 0=ABM (ignored)
3525*4882a593Smuzhiyun 	 * 05      CAS Carrier Auto Start
3526*4882a593Smuzhiyun 	 * 04      XC Transmit Continuously (ignored)
3527*4882a593Smuzhiyun 	 * 03..00  XBC[10..8] Transmit byte count bits 10..8
3528*4882a593Smuzhiyun 	 *
3529*4882a593Smuzhiyun 	 * 0000 0000
3530*4882a593Smuzhiyun 	 */
3531*4882a593Smuzhiyun 	val = 0x00;
3532*4882a593Smuzhiyun 	if (info->params.flags & HDLC_FLAG_AUTO_DCD)
3533*4882a593Smuzhiyun 		val |= BIT5;
3534*4882a593Smuzhiyun 	write_reg(info, CHA + XBCH, val);
3535*4882a593Smuzhiyun 	if (info->params.flags & HDLC_FLAG_AUTO_CTS)
3536*4882a593Smuzhiyun 		irq_enable(info, CHA, IRQ_CTS);
3537*4882a593Smuzhiyun 
3538*4882a593Smuzhiyun 	/* MODE:03 RAC Receiver Active, 1=active */
3539*4882a593Smuzhiyun 	set_reg_bits(info, CHA + MODE, BIT3);
3540*4882a593Smuzhiyun 	enable_auxclk(info);
3541*4882a593Smuzhiyun 	if (info->params.flags & HDLC_FLAG_AUTO_CTS) {
3542*4882a593Smuzhiyun 		irq_enable(info, CHB, IRQ_CTS);
3543*4882a593Smuzhiyun 		/* PVR[3] 1=AUTO CTS active */
3544*4882a593Smuzhiyun 		set_reg_bits(info, CHA + PVR, BIT3);
3545*4882a593Smuzhiyun 	} else
3546*4882a593Smuzhiyun 		clear_reg_bits(info, CHA + PVR, BIT3);
3547*4882a593Smuzhiyun 	irq_enable(info, CHA,
3548*4882a593Smuzhiyun 			  IRQ_RXEOM | IRQ_RXFIFO | IRQ_BREAK_ON | IRQ_RXTIME |
3549*4882a593Smuzhiyun 			  IRQ_ALLSENT | IRQ_TXFIFO);
3550*4882a593Smuzhiyun 	issue_command(info, CHA, CMD_TXRESET + CMD_RXRESET);
3551*4882a593Smuzhiyun 	wait_command_complete(info, CHA);
3552*4882a593Smuzhiyun 	read_reg16(info, CHA + ISR);	/* clear pending IRQs */
3553*4882a593Smuzhiyun }
3554*4882a593Smuzhiyun 
3555*4882a593Smuzhiyun /* Set the HDLC idle mode for the transmitter.
3556*4882a593Smuzhiyun  */
tx_set_idle(MGSLPC_INFO * info)3557*4882a593Smuzhiyun static void tx_set_idle(MGSLPC_INFO *info)
3558*4882a593Smuzhiyun {
3559*4882a593Smuzhiyun 	/* Note: ESCC2 only supports flags and one idle modes */
3560*4882a593Smuzhiyun 	if (info->idle_mode == HDLC_TXIDLE_FLAGS)
3561*4882a593Smuzhiyun 		set_reg_bits(info, CHA + CCR1, BIT3);
3562*4882a593Smuzhiyun 	else
3563*4882a593Smuzhiyun 		clear_reg_bits(info, CHA + CCR1, BIT3);
3564*4882a593Smuzhiyun }
3565*4882a593Smuzhiyun 
3566*4882a593Smuzhiyun /* get state of the V24 status (input) signals.
3567*4882a593Smuzhiyun  */
get_signals(MGSLPC_INFO * info)3568*4882a593Smuzhiyun static void get_signals(MGSLPC_INFO *info)
3569*4882a593Smuzhiyun {
3570*4882a593Smuzhiyun 	unsigned char status = 0;
3571*4882a593Smuzhiyun 
3572*4882a593Smuzhiyun 	/* preserve RTS and DTR */
3573*4882a593Smuzhiyun 	info->serial_signals &= SerialSignal_RTS | SerialSignal_DTR;
3574*4882a593Smuzhiyun 
3575*4882a593Smuzhiyun 	if (read_reg(info, CHB + VSTR) & BIT7)
3576*4882a593Smuzhiyun 		info->serial_signals |= SerialSignal_DCD;
3577*4882a593Smuzhiyun 	if (read_reg(info, CHB + STAR) & BIT1)
3578*4882a593Smuzhiyun 		info->serial_signals |= SerialSignal_CTS;
3579*4882a593Smuzhiyun 
3580*4882a593Smuzhiyun 	status = read_reg(info, CHA + PVR);
3581*4882a593Smuzhiyun 	if (!(status & PVR_RI))
3582*4882a593Smuzhiyun 		info->serial_signals |= SerialSignal_RI;
3583*4882a593Smuzhiyun 	if (!(status & PVR_DSR))
3584*4882a593Smuzhiyun 		info->serial_signals |= SerialSignal_DSR;
3585*4882a593Smuzhiyun }
3586*4882a593Smuzhiyun 
3587*4882a593Smuzhiyun /* Set the state of RTS and DTR based on contents of
3588*4882a593Smuzhiyun  * serial_signals member of device extension.
3589*4882a593Smuzhiyun  */
set_signals(MGSLPC_INFO * info)3590*4882a593Smuzhiyun static void set_signals(MGSLPC_INFO *info)
3591*4882a593Smuzhiyun {
3592*4882a593Smuzhiyun 	unsigned char val;
3593*4882a593Smuzhiyun 
3594*4882a593Smuzhiyun 	val = read_reg(info, CHA + MODE);
3595*4882a593Smuzhiyun 	if (info->params.mode == MGSL_MODE_ASYNC) {
3596*4882a593Smuzhiyun 		if (info->serial_signals & SerialSignal_RTS)
3597*4882a593Smuzhiyun 			val &= ~BIT6;
3598*4882a593Smuzhiyun 		else
3599*4882a593Smuzhiyun 			val |= BIT6;
3600*4882a593Smuzhiyun 	} else {
3601*4882a593Smuzhiyun 		if (info->serial_signals & SerialSignal_RTS)
3602*4882a593Smuzhiyun 			val |= BIT2;
3603*4882a593Smuzhiyun 		else
3604*4882a593Smuzhiyun 			val &= ~BIT2;
3605*4882a593Smuzhiyun 	}
3606*4882a593Smuzhiyun 	write_reg(info, CHA + MODE, val);
3607*4882a593Smuzhiyun 
3608*4882a593Smuzhiyun 	if (info->serial_signals & SerialSignal_DTR)
3609*4882a593Smuzhiyun 		clear_reg_bits(info, CHA + PVR, PVR_DTR);
3610*4882a593Smuzhiyun 	else
3611*4882a593Smuzhiyun 		set_reg_bits(info, CHA + PVR, PVR_DTR);
3612*4882a593Smuzhiyun }
3613*4882a593Smuzhiyun 
rx_reset_buffers(MGSLPC_INFO * info)3614*4882a593Smuzhiyun static void rx_reset_buffers(MGSLPC_INFO *info)
3615*4882a593Smuzhiyun {
3616*4882a593Smuzhiyun 	RXBUF *buf;
3617*4882a593Smuzhiyun 	int i;
3618*4882a593Smuzhiyun 
3619*4882a593Smuzhiyun 	info->rx_put = 0;
3620*4882a593Smuzhiyun 	info->rx_get = 0;
3621*4882a593Smuzhiyun 	info->rx_frame_count = 0;
3622*4882a593Smuzhiyun 	for (i=0 ; i < info->rx_buf_count ; i++) {
3623*4882a593Smuzhiyun 		buf = (RXBUF*)(info->rx_buf + (i * info->rx_buf_size));
3624*4882a593Smuzhiyun 		buf->status = buf->count = 0;
3625*4882a593Smuzhiyun 	}
3626*4882a593Smuzhiyun }
3627*4882a593Smuzhiyun 
3628*4882a593Smuzhiyun /* Attempt to return a received HDLC frame
3629*4882a593Smuzhiyun  * Only frames received without errors are returned.
3630*4882a593Smuzhiyun  *
3631*4882a593Smuzhiyun  * Returns true if frame returned, otherwise false
3632*4882a593Smuzhiyun  */
rx_get_frame(MGSLPC_INFO * info,struct tty_struct * tty)3633*4882a593Smuzhiyun static bool rx_get_frame(MGSLPC_INFO *info, struct tty_struct *tty)
3634*4882a593Smuzhiyun {
3635*4882a593Smuzhiyun 	unsigned short status;
3636*4882a593Smuzhiyun 	RXBUF *buf;
3637*4882a593Smuzhiyun 	unsigned int framesize = 0;
3638*4882a593Smuzhiyun 	unsigned long flags;
3639*4882a593Smuzhiyun 	bool return_frame = false;
3640*4882a593Smuzhiyun 
3641*4882a593Smuzhiyun 	if (info->rx_frame_count == 0)
3642*4882a593Smuzhiyun 		return false;
3643*4882a593Smuzhiyun 
3644*4882a593Smuzhiyun 	buf = (RXBUF*)(info->rx_buf + (info->rx_get * info->rx_buf_size));
3645*4882a593Smuzhiyun 
3646*4882a593Smuzhiyun 	status = buf->status;
3647*4882a593Smuzhiyun 
3648*4882a593Smuzhiyun 	/* 07  VFR  1=valid frame
3649*4882a593Smuzhiyun 	 * 06  RDO  1=data overrun
3650*4882a593Smuzhiyun 	 * 05  CRC  1=OK, 0=error
3651*4882a593Smuzhiyun 	 * 04  RAB  1=frame aborted
3652*4882a593Smuzhiyun 	 */
3653*4882a593Smuzhiyun 	if ((status & 0xf0) != 0xA0) {
3654*4882a593Smuzhiyun 		if (!(status & BIT7) || (status & BIT4))
3655*4882a593Smuzhiyun 			info->icount.rxabort++;
3656*4882a593Smuzhiyun 		else if (status & BIT6)
3657*4882a593Smuzhiyun 			info->icount.rxover++;
3658*4882a593Smuzhiyun 		else if (!(status & BIT5)) {
3659*4882a593Smuzhiyun 			info->icount.rxcrc++;
3660*4882a593Smuzhiyun 			if (info->params.crc_type & HDLC_CRC_RETURN_EX)
3661*4882a593Smuzhiyun 				return_frame = true;
3662*4882a593Smuzhiyun 		}
3663*4882a593Smuzhiyun 		framesize = 0;
3664*4882a593Smuzhiyun #if SYNCLINK_GENERIC_HDLC
3665*4882a593Smuzhiyun 		{
3666*4882a593Smuzhiyun 			info->netdev->stats.rx_errors++;
3667*4882a593Smuzhiyun 			info->netdev->stats.rx_frame_errors++;
3668*4882a593Smuzhiyun 		}
3669*4882a593Smuzhiyun #endif
3670*4882a593Smuzhiyun 	} else
3671*4882a593Smuzhiyun 		return_frame = true;
3672*4882a593Smuzhiyun 
3673*4882a593Smuzhiyun 	if (return_frame)
3674*4882a593Smuzhiyun 		framesize = buf->count;
3675*4882a593Smuzhiyun 
3676*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_BH)
3677*4882a593Smuzhiyun 		printk("%s(%d):rx_get_frame(%s) status=%04X size=%d\n",
3678*4882a593Smuzhiyun 			__FILE__, __LINE__, info->device_name, status, framesize);
3679*4882a593Smuzhiyun 
3680*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_DATA)
3681*4882a593Smuzhiyun 		trace_block(info, buf->data, framesize, 0);
3682*4882a593Smuzhiyun 
3683*4882a593Smuzhiyun 	if (framesize) {
3684*4882a593Smuzhiyun 		if ((info->params.crc_type & HDLC_CRC_RETURN_EX &&
3685*4882a593Smuzhiyun 		      framesize+1 > info->max_frame_size) ||
3686*4882a593Smuzhiyun 		    framesize > info->max_frame_size)
3687*4882a593Smuzhiyun 			info->icount.rxlong++;
3688*4882a593Smuzhiyun 		else {
3689*4882a593Smuzhiyun 			if (status & BIT5)
3690*4882a593Smuzhiyun 				info->icount.rxok++;
3691*4882a593Smuzhiyun 
3692*4882a593Smuzhiyun 			if (info->params.crc_type & HDLC_CRC_RETURN_EX) {
3693*4882a593Smuzhiyun 				*(buf->data + framesize) = status & BIT5 ? RX_OK:RX_CRC_ERROR;
3694*4882a593Smuzhiyun 				++framesize;
3695*4882a593Smuzhiyun 			}
3696*4882a593Smuzhiyun 
3697*4882a593Smuzhiyun #if SYNCLINK_GENERIC_HDLC
3698*4882a593Smuzhiyun 			if (info->netcount)
3699*4882a593Smuzhiyun 				hdlcdev_rx(info, buf->data, framesize);
3700*4882a593Smuzhiyun 			else
3701*4882a593Smuzhiyun #endif
3702*4882a593Smuzhiyun 				ldisc_receive_buf(tty, buf->data, info->flag_buf, framesize);
3703*4882a593Smuzhiyun 		}
3704*4882a593Smuzhiyun 	}
3705*4882a593Smuzhiyun 
3706*4882a593Smuzhiyun 	spin_lock_irqsave(&info->lock, flags);
3707*4882a593Smuzhiyun 	buf->status = buf->count = 0;
3708*4882a593Smuzhiyun 	info->rx_frame_count--;
3709*4882a593Smuzhiyun 	info->rx_get++;
3710*4882a593Smuzhiyun 	if (info->rx_get >= info->rx_buf_count)
3711*4882a593Smuzhiyun 		info->rx_get = 0;
3712*4882a593Smuzhiyun 	spin_unlock_irqrestore(&info->lock, flags);
3713*4882a593Smuzhiyun 
3714*4882a593Smuzhiyun 	return true;
3715*4882a593Smuzhiyun }
3716*4882a593Smuzhiyun 
register_test(MGSLPC_INFO * info)3717*4882a593Smuzhiyun static bool register_test(MGSLPC_INFO *info)
3718*4882a593Smuzhiyun {
3719*4882a593Smuzhiyun 	static unsigned char patterns[] =
3720*4882a593Smuzhiyun 	    { 0x00, 0xff, 0xaa, 0x55, 0x69, 0x96, 0x0f };
3721*4882a593Smuzhiyun 	static unsigned int count = ARRAY_SIZE(patterns);
3722*4882a593Smuzhiyun 	unsigned int i;
3723*4882a593Smuzhiyun 	bool rc = true;
3724*4882a593Smuzhiyun 	unsigned long flags;
3725*4882a593Smuzhiyun 
3726*4882a593Smuzhiyun 	spin_lock_irqsave(&info->lock, flags);
3727*4882a593Smuzhiyun 	reset_device(info);
3728*4882a593Smuzhiyun 
3729*4882a593Smuzhiyun 	for (i = 0; i < count; i++) {
3730*4882a593Smuzhiyun 		write_reg(info, XAD1, patterns[i]);
3731*4882a593Smuzhiyun 		write_reg(info, XAD2, patterns[(i + 1) % count]);
3732*4882a593Smuzhiyun 		if ((read_reg(info, XAD1) != patterns[i]) ||
3733*4882a593Smuzhiyun 		    (read_reg(info, XAD2) != patterns[(i + 1) % count])) {
3734*4882a593Smuzhiyun 			rc = false;
3735*4882a593Smuzhiyun 			break;
3736*4882a593Smuzhiyun 		}
3737*4882a593Smuzhiyun 	}
3738*4882a593Smuzhiyun 
3739*4882a593Smuzhiyun 	spin_unlock_irqrestore(&info->lock, flags);
3740*4882a593Smuzhiyun 	return rc;
3741*4882a593Smuzhiyun }
3742*4882a593Smuzhiyun 
irq_test(MGSLPC_INFO * info)3743*4882a593Smuzhiyun static bool irq_test(MGSLPC_INFO *info)
3744*4882a593Smuzhiyun {
3745*4882a593Smuzhiyun 	unsigned long end_time;
3746*4882a593Smuzhiyun 	unsigned long flags;
3747*4882a593Smuzhiyun 
3748*4882a593Smuzhiyun 	spin_lock_irqsave(&info->lock, flags);
3749*4882a593Smuzhiyun 	reset_device(info);
3750*4882a593Smuzhiyun 
3751*4882a593Smuzhiyun 	info->testing_irq = true;
3752*4882a593Smuzhiyun 	hdlc_mode(info);
3753*4882a593Smuzhiyun 
3754*4882a593Smuzhiyun 	info->irq_occurred = false;
3755*4882a593Smuzhiyun 
3756*4882a593Smuzhiyun 	/* init hdlc mode */
3757*4882a593Smuzhiyun 
3758*4882a593Smuzhiyun 	irq_enable(info, CHA, IRQ_TIMER);
3759*4882a593Smuzhiyun 	write_reg(info, CHA + TIMR, 0);	/* 512 cycles */
3760*4882a593Smuzhiyun 	issue_command(info, CHA, CMD_START_TIMER);
3761*4882a593Smuzhiyun 
3762*4882a593Smuzhiyun 	spin_unlock_irqrestore(&info->lock, flags);
3763*4882a593Smuzhiyun 
3764*4882a593Smuzhiyun 	end_time=100;
3765*4882a593Smuzhiyun 	while(end_time-- && !info->irq_occurred) {
3766*4882a593Smuzhiyun 		msleep_interruptible(10);
3767*4882a593Smuzhiyun 	}
3768*4882a593Smuzhiyun 
3769*4882a593Smuzhiyun 	info->testing_irq = false;
3770*4882a593Smuzhiyun 
3771*4882a593Smuzhiyun 	spin_lock_irqsave(&info->lock, flags);
3772*4882a593Smuzhiyun 	reset_device(info);
3773*4882a593Smuzhiyun 	spin_unlock_irqrestore(&info->lock, flags);
3774*4882a593Smuzhiyun 
3775*4882a593Smuzhiyun 	return info->irq_occurred;
3776*4882a593Smuzhiyun }
3777*4882a593Smuzhiyun 
adapter_test(MGSLPC_INFO * info)3778*4882a593Smuzhiyun static int adapter_test(MGSLPC_INFO *info)
3779*4882a593Smuzhiyun {
3780*4882a593Smuzhiyun 	if (!register_test(info)) {
3781*4882a593Smuzhiyun 		info->init_error = DiagStatus_AddressFailure;
3782*4882a593Smuzhiyun 		printk("%s(%d):Register test failure for device %s Addr=%04X\n",
3783*4882a593Smuzhiyun 			__FILE__, __LINE__, info->device_name, (unsigned short)(info->io_base));
3784*4882a593Smuzhiyun 		return -ENODEV;
3785*4882a593Smuzhiyun 	}
3786*4882a593Smuzhiyun 
3787*4882a593Smuzhiyun 	if (!irq_test(info)) {
3788*4882a593Smuzhiyun 		info->init_error = DiagStatus_IrqFailure;
3789*4882a593Smuzhiyun 		printk("%s(%d):Interrupt test failure for device %s IRQ=%d\n",
3790*4882a593Smuzhiyun 			__FILE__, __LINE__, info->device_name, (unsigned short)(info->irq_level));
3791*4882a593Smuzhiyun 		return -ENODEV;
3792*4882a593Smuzhiyun 	}
3793*4882a593Smuzhiyun 
3794*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
3795*4882a593Smuzhiyun 		printk("%s(%d):device %s passed diagnostics\n",
3796*4882a593Smuzhiyun 			__FILE__, __LINE__, info->device_name);
3797*4882a593Smuzhiyun 	return 0;
3798*4882a593Smuzhiyun }
3799*4882a593Smuzhiyun 
trace_block(MGSLPC_INFO * info,const char * data,int count,int xmit)3800*4882a593Smuzhiyun static void trace_block(MGSLPC_INFO *info,const char* data, int count, int xmit)
3801*4882a593Smuzhiyun {
3802*4882a593Smuzhiyun 	int i;
3803*4882a593Smuzhiyun 	int linecount;
3804*4882a593Smuzhiyun 	if (xmit)
3805*4882a593Smuzhiyun 		printk("%s tx data:\n", info->device_name);
3806*4882a593Smuzhiyun 	else
3807*4882a593Smuzhiyun 		printk("%s rx data:\n", info->device_name);
3808*4882a593Smuzhiyun 
3809*4882a593Smuzhiyun 	while(count) {
3810*4882a593Smuzhiyun 		if (count > 16)
3811*4882a593Smuzhiyun 			linecount = 16;
3812*4882a593Smuzhiyun 		else
3813*4882a593Smuzhiyun 			linecount = count;
3814*4882a593Smuzhiyun 
3815*4882a593Smuzhiyun 		for(i=0;i<linecount;i++)
3816*4882a593Smuzhiyun 			printk("%02X ", (unsigned char)data[i]);
3817*4882a593Smuzhiyun 		for(;i<17;i++)
3818*4882a593Smuzhiyun 			printk("   ");
3819*4882a593Smuzhiyun 		for(i=0;i<linecount;i++) {
3820*4882a593Smuzhiyun 			if (data[i]>=040 && data[i]<=0176)
3821*4882a593Smuzhiyun 				printk("%c", data[i]);
3822*4882a593Smuzhiyun 			else
3823*4882a593Smuzhiyun 				printk(".");
3824*4882a593Smuzhiyun 		}
3825*4882a593Smuzhiyun 		printk("\n");
3826*4882a593Smuzhiyun 
3827*4882a593Smuzhiyun 		data  += linecount;
3828*4882a593Smuzhiyun 		count -= linecount;
3829*4882a593Smuzhiyun 	}
3830*4882a593Smuzhiyun }
3831*4882a593Smuzhiyun 
3832*4882a593Smuzhiyun /* HDLC frame time out
3833*4882a593Smuzhiyun  * update stats and do tx completion processing
3834*4882a593Smuzhiyun  */
tx_timeout(struct timer_list * t)3835*4882a593Smuzhiyun static void tx_timeout(struct timer_list *t)
3836*4882a593Smuzhiyun {
3837*4882a593Smuzhiyun 	MGSLPC_INFO *info = from_timer(info, t, tx_timer);
3838*4882a593Smuzhiyun 	unsigned long flags;
3839*4882a593Smuzhiyun 
3840*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
3841*4882a593Smuzhiyun 		printk("%s(%d):tx_timeout(%s)\n",
3842*4882a593Smuzhiyun 			__FILE__, __LINE__, info->device_name);
3843*4882a593Smuzhiyun 	if (info->tx_active &&
3844*4882a593Smuzhiyun 	    info->params.mode == MGSL_MODE_HDLC) {
3845*4882a593Smuzhiyun 		info->icount.txtimeout++;
3846*4882a593Smuzhiyun 	}
3847*4882a593Smuzhiyun 	spin_lock_irqsave(&info->lock, flags);
3848*4882a593Smuzhiyun 	info->tx_active = false;
3849*4882a593Smuzhiyun 	info->tx_count = info->tx_put = info->tx_get = 0;
3850*4882a593Smuzhiyun 
3851*4882a593Smuzhiyun 	spin_unlock_irqrestore(&info->lock, flags);
3852*4882a593Smuzhiyun 
3853*4882a593Smuzhiyun #if SYNCLINK_GENERIC_HDLC
3854*4882a593Smuzhiyun 	if (info->netcount)
3855*4882a593Smuzhiyun 		hdlcdev_tx_done(info);
3856*4882a593Smuzhiyun 	else
3857*4882a593Smuzhiyun #endif
3858*4882a593Smuzhiyun 	{
3859*4882a593Smuzhiyun 		struct tty_struct *tty = tty_port_tty_get(&info->port);
3860*4882a593Smuzhiyun 		bh_transmit(info, tty);
3861*4882a593Smuzhiyun 		tty_kref_put(tty);
3862*4882a593Smuzhiyun 	}
3863*4882a593Smuzhiyun }
3864*4882a593Smuzhiyun 
3865*4882a593Smuzhiyun #if SYNCLINK_GENERIC_HDLC
3866*4882a593Smuzhiyun 
3867*4882a593Smuzhiyun /**
3868*4882a593Smuzhiyun  * called by generic HDLC layer when protocol selected (PPP, frame relay, etc.)
3869*4882a593Smuzhiyun  * set encoding and frame check sequence (FCS) options
3870*4882a593Smuzhiyun  *
3871*4882a593Smuzhiyun  * dev       pointer to network device structure
3872*4882a593Smuzhiyun  * encoding  serial encoding setting
3873*4882a593Smuzhiyun  * parity    FCS setting
3874*4882a593Smuzhiyun  *
3875*4882a593Smuzhiyun  * returns 0 if success, otherwise error code
3876*4882a593Smuzhiyun  */
hdlcdev_attach(struct net_device * dev,unsigned short encoding,unsigned short parity)3877*4882a593Smuzhiyun static int hdlcdev_attach(struct net_device *dev, unsigned short encoding,
3878*4882a593Smuzhiyun 			  unsigned short parity)
3879*4882a593Smuzhiyun {
3880*4882a593Smuzhiyun 	MGSLPC_INFO *info = dev_to_port(dev);
3881*4882a593Smuzhiyun 	struct tty_struct *tty;
3882*4882a593Smuzhiyun 	unsigned char  new_encoding;
3883*4882a593Smuzhiyun 	unsigned short new_crctype;
3884*4882a593Smuzhiyun 
3885*4882a593Smuzhiyun 	/* return error if TTY interface open */
3886*4882a593Smuzhiyun 	if (info->port.count)
3887*4882a593Smuzhiyun 		return -EBUSY;
3888*4882a593Smuzhiyun 
3889*4882a593Smuzhiyun 	switch (encoding)
3890*4882a593Smuzhiyun 	{
3891*4882a593Smuzhiyun 	case ENCODING_NRZ:        new_encoding = HDLC_ENCODING_NRZ; break;
3892*4882a593Smuzhiyun 	case ENCODING_NRZI:       new_encoding = HDLC_ENCODING_NRZI_SPACE; break;
3893*4882a593Smuzhiyun 	case ENCODING_FM_MARK:    new_encoding = HDLC_ENCODING_BIPHASE_MARK; break;
3894*4882a593Smuzhiyun 	case ENCODING_FM_SPACE:   new_encoding = HDLC_ENCODING_BIPHASE_SPACE; break;
3895*4882a593Smuzhiyun 	case ENCODING_MANCHESTER: new_encoding = HDLC_ENCODING_BIPHASE_LEVEL; break;
3896*4882a593Smuzhiyun 	default: return -EINVAL;
3897*4882a593Smuzhiyun 	}
3898*4882a593Smuzhiyun 
3899*4882a593Smuzhiyun 	switch (parity)
3900*4882a593Smuzhiyun 	{
3901*4882a593Smuzhiyun 	case PARITY_NONE:            new_crctype = HDLC_CRC_NONE; break;
3902*4882a593Smuzhiyun 	case PARITY_CRC16_PR1_CCITT: new_crctype = HDLC_CRC_16_CCITT; break;
3903*4882a593Smuzhiyun 	case PARITY_CRC32_PR1_CCITT: new_crctype = HDLC_CRC_32_CCITT; break;
3904*4882a593Smuzhiyun 	default: return -EINVAL;
3905*4882a593Smuzhiyun 	}
3906*4882a593Smuzhiyun 
3907*4882a593Smuzhiyun 	info->params.encoding = new_encoding;
3908*4882a593Smuzhiyun 	info->params.crc_type = new_crctype;
3909*4882a593Smuzhiyun 
3910*4882a593Smuzhiyun 	/* if network interface up, reprogram hardware */
3911*4882a593Smuzhiyun 	if (info->netcount) {
3912*4882a593Smuzhiyun 		tty = tty_port_tty_get(&info->port);
3913*4882a593Smuzhiyun 		mgslpc_program_hw(info, tty);
3914*4882a593Smuzhiyun 		tty_kref_put(tty);
3915*4882a593Smuzhiyun 	}
3916*4882a593Smuzhiyun 
3917*4882a593Smuzhiyun 	return 0;
3918*4882a593Smuzhiyun }
3919*4882a593Smuzhiyun 
3920*4882a593Smuzhiyun /**
3921*4882a593Smuzhiyun  * called by generic HDLC layer to send frame
3922*4882a593Smuzhiyun  *
3923*4882a593Smuzhiyun  * skb  socket buffer containing HDLC frame
3924*4882a593Smuzhiyun  * dev  pointer to network device structure
3925*4882a593Smuzhiyun  */
hdlcdev_xmit(struct sk_buff * skb,struct net_device * dev)3926*4882a593Smuzhiyun static netdev_tx_t hdlcdev_xmit(struct sk_buff *skb,
3927*4882a593Smuzhiyun 				      struct net_device *dev)
3928*4882a593Smuzhiyun {
3929*4882a593Smuzhiyun 	MGSLPC_INFO *info = dev_to_port(dev);
3930*4882a593Smuzhiyun 	unsigned long flags;
3931*4882a593Smuzhiyun 
3932*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
3933*4882a593Smuzhiyun 		printk(KERN_INFO "%s:hdlc_xmit(%s)\n", __FILE__, dev->name);
3934*4882a593Smuzhiyun 
3935*4882a593Smuzhiyun 	/* stop sending until this frame completes */
3936*4882a593Smuzhiyun 	netif_stop_queue(dev);
3937*4882a593Smuzhiyun 
3938*4882a593Smuzhiyun 	/* copy data to device buffers */
3939*4882a593Smuzhiyun 	skb_copy_from_linear_data(skb, info->tx_buf, skb->len);
3940*4882a593Smuzhiyun 	info->tx_get = 0;
3941*4882a593Smuzhiyun 	info->tx_put = info->tx_count = skb->len;
3942*4882a593Smuzhiyun 
3943*4882a593Smuzhiyun 	/* update network statistics */
3944*4882a593Smuzhiyun 	dev->stats.tx_packets++;
3945*4882a593Smuzhiyun 	dev->stats.tx_bytes += skb->len;
3946*4882a593Smuzhiyun 
3947*4882a593Smuzhiyun 	/* done with socket buffer, so free it */
3948*4882a593Smuzhiyun 	dev_kfree_skb(skb);
3949*4882a593Smuzhiyun 
3950*4882a593Smuzhiyun 	/* save start time for transmit timeout detection */
3951*4882a593Smuzhiyun 	netif_trans_update(dev);
3952*4882a593Smuzhiyun 
3953*4882a593Smuzhiyun 	/* start hardware transmitter if necessary */
3954*4882a593Smuzhiyun 	spin_lock_irqsave(&info->lock, flags);
3955*4882a593Smuzhiyun 	if (!info->tx_active) {
3956*4882a593Smuzhiyun 		struct tty_struct *tty = tty_port_tty_get(&info->port);
3957*4882a593Smuzhiyun 		tx_start(info, tty);
3958*4882a593Smuzhiyun 		tty_kref_put(tty);
3959*4882a593Smuzhiyun 	}
3960*4882a593Smuzhiyun 	spin_unlock_irqrestore(&info->lock, flags);
3961*4882a593Smuzhiyun 
3962*4882a593Smuzhiyun 	return NETDEV_TX_OK;
3963*4882a593Smuzhiyun }
3964*4882a593Smuzhiyun 
3965*4882a593Smuzhiyun /**
3966*4882a593Smuzhiyun  * called by network layer when interface enabled
3967*4882a593Smuzhiyun  * claim resources and initialize hardware
3968*4882a593Smuzhiyun  *
3969*4882a593Smuzhiyun  * dev  pointer to network device structure
3970*4882a593Smuzhiyun  *
3971*4882a593Smuzhiyun  * returns 0 if success, otherwise error code
3972*4882a593Smuzhiyun  */
hdlcdev_open(struct net_device * dev)3973*4882a593Smuzhiyun static int hdlcdev_open(struct net_device *dev)
3974*4882a593Smuzhiyun {
3975*4882a593Smuzhiyun 	MGSLPC_INFO *info = dev_to_port(dev);
3976*4882a593Smuzhiyun 	struct tty_struct *tty;
3977*4882a593Smuzhiyun 	int rc;
3978*4882a593Smuzhiyun 	unsigned long flags;
3979*4882a593Smuzhiyun 
3980*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
3981*4882a593Smuzhiyun 		printk("%s:hdlcdev_open(%s)\n", __FILE__, dev->name);
3982*4882a593Smuzhiyun 
3983*4882a593Smuzhiyun 	/* generic HDLC layer open processing */
3984*4882a593Smuzhiyun 	rc = hdlc_open(dev);
3985*4882a593Smuzhiyun 	if (rc != 0)
3986*4882a593Smuzhiyun 		return rc;
3987*4882a593Smuzhiyun 
3988*4882a593Smuzhiyun 	/* arbitrate between network and tty opens */
3989*4882a593Smuzhiyun 	spin_lock_irqsave(&info->netlock, flags);
3990*4882a593Smuzhiyun 	if (info->port.count != 0 || info->netcount != 0) {
3991*4882a593Smuzhiyun 		printk(KERN_WARNING "%s: hdlc_open returning busy\n", dev->name);
3992*4882a593Smuzhiyun 		spin_unlock_irqrestore(&info->netlock, flags);
3993*4882a593Smuzhiyun 		return -EBUSY;
3994*4882a593Smuzhiyun 	}
3995*4882a593Smuzhiyun 	info->netcount=1;
3996*4882a593Smuzhiyun 	spin_unlock_irqrestore(&info->netlock, flags);
3997*4882a593Smuzhiyun 
3998*4882a593Smuzhiyun 	tty = tty_port_tty_get(&info->port);
3999*4882a593Smuzhiyun 	/* claim resources and init adapter */
4000*4882a593Smuzhiyun 	rc = startup(info, tty);
4001*4882a593Smuzhiyun 	if (rc != 0) {
4002*4882a593Smuzhiyun 		tty_kref_put(tty);
4003*4882a593Smuzhiyun 		spin_lock_irqsave(&info->netlock, flags);
4004*4882a593Smuzhiyun 		info->netcount=0;
4005*4882a593Smuzhiyun 		spin_unlock_irqrestore(&info->netlock, flags);
4006*4882a593Smuzhiyun 		return rc;
4007*4882a593Smuzhiyun 	}
4008*4882a593Smuzhiyun 	/* assert RTS and DTR, apply hardware settings */
4009*4882a593Smuzhiyun 	info->serial_signals |= SerialSignal_RTS | SerialSignal_DTR;
4010*4882a593Smuzhiyun 	mgslpc_program_hw(info, tty);
4011*4882a593Smuzhiyun 	tty_kref_put(tty);
4012*4882a593Smuzhiyun 
4013*4882a593Smuzhiyun 	/* enable network layer transmit */
4014*4882a593Smuzhiyun 	netif_trans_update(dev);
4015*4882a593Smuzhiyun 	netif_start_queue(dev);
4016*4882a593Smuzhiyun 
4017*4882a593Smuzhiyun 	/* inform generic HDLC layer of current DCD status */
4018*4882a593Smuzhiyun 	spin_lock_irqsave(&info->lock, flags);
4019*4882a593Smuzhiyun 	get_signals(info);
4020*4882a593Smuzhiyun 	spin_unlock_irqrestore(&info->lock, flags);
4021*4882a593Smuzhiyun 	if (info->serial_signals & SerialSignal_DCD)
4022*4882a593Smuzhiyun 		netif_carrier_on(dev);
4023*4882a593Smuzhiyun 	else
4024*4882a593Smuzhiyun 		netif_carrier_off(dev);
4025*4882a593Smuzhiyun 	return 0;
4026*4882a593Smuzhiyun }
4027*4882a593Smuzhiyun 
4028*4882a593Smuzhiyun /**
4029*4882a593Smuzhiyun  * called by network layer when interface is disabled
4030*4882a593Smuzhiyun  * shutdown hardware and release resources
4031*4882a593Smuzhiyun  *
4032*4882a593Smuzhiyun  * dev  pointer to network device structure
4033*4882a593Smuzhiyun  *
4034*4882a593Smuzhiyun  * returns 0 if success, otherwise error code
4035*4882a593Smuzhiyun  */
hdlcdev_close(struct net_device * dev)4036*4882a593Smuzhiyun static int hdlcdev_close(struct net_device *dev)
4037*4882a593Smuzhiyun {
4038*4882a593Smuzhiyun 	MGSLPC_INFO *info = dev_to_port(dev);
4039*4882a593Smuzhiyun 	struct tty_struct *tty = tty_port_tty_get(&info->port);
4040*4882a593Smuzhiyun 	unsigned long flags;
4041*4882a593Smuzhiyun 
4042*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
4043*4882a593Smuzhiyun 		printk("%s:hdlcdev_close(%s)\n", __FILE__, dev->name);
4044*4882a593Smuzhiyun 
4045*4882a593Smuzhiyun 	netif_stop_queue(dev);
4046*4882a593Smuzhiyun 
4047*4882a593Smuzhiyun 	/* shutdown adapter and release resources */
4048*4882a593Smuzhiyun 	shutdown(info, tty);
4049*4882a593Smuzhiyun 	tty_kref_put(tty);
4050*4882a593Smuzhiyun 	hdlc_close(dev);
4051*4882a593Smuzhiyun 
4052*4882a593Smuzhiyun 	spin_lock_irqsave(&info->netlock, flags);
4053*4882a593Smuzhiyun 	info->netcount=0;
4054*4882a593Smuzhiyun 	spin_unlock_irqrestore(&info->netlock, flags);
4055*4882a593Smuzhiyun 
4056*4882a593Smuzhiyun 	return 0;
4057*4882a593Smuzhiyun }
4058*4882a593Smuzhiyun 
4059*4882a593Smuzhiyun /**
4060*4882a593Smuzhiyun  * called by network layer to process IOCTL call to network device
4061*4882a593Smuzhiyun  *
4062*4882a593Smuzhiyun  * dev  pointer to network device structure
4063*4882a593Smuzhiyun  * ifr  pointer to network interface request structure
4064*4882a593Smuzhiyun  * cmd  IOCTL command code
4065*4882a593Smuzhiyun  *
4066*4882a593Smuzhiyun  * returns 0 if success, otherwise error code
4067*4882a593Smuzhiyun  */
hdlcdev_ioctl(struct net_device * dev,struct ifreq * ifr,int cmd)4068*4882a593Smuzhiyun static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
4069*4882a593Smuzhiyun {
4070*4882a593Smuzhiyun 	const size_t size = sizeof(sync_serial_settings);
4071*4882a593Smuzhiyun 	sync_serial_settings new_line;
4072*4882a593Smuzhiyun 	sync_serial_settings __user *line = ifr->ifr_settings.ifs_ifsu.sync;
4073*4882a593Smuzhiyun 	MGSLPC_INFO *info = dev_to_port(dev);
4074*4882a593Smuzhiyun 	unsigned int flags;
4075*4882a593Smuzhiyun 
4076*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
4077*4882a593Smuzhiyun 		printk("%s:hdlcdev_ioctl(%s)\n", __FILE__, dev->name);
4078*4882a593Smuzhiyun 
4079*4882a593Smuzhiyun 	/* return error if TTY interface open */
4080*4882a593Smuzhiyun 	if (info->port.count)
4081*4882a593Smuzhiyun 		return -EBUSY;
4082*4882a593Smuzhiyun 
4083*4882a593Smuzhiyun 	if (cmd != SIOCWANDEV)
4084*4882a593Smuzhiyun 		return hdlc_ioctl(dev, ifr, cmd);
4085*4882a593Smuzhiyun 
4086*4882a593Smuzhiyun 	memset(&new_line, 0, size);
4087*4882a593Smuzhiyun 
4088*4882a593Smuzhiyun 	switch(ifr->ifr_settings.type) {
4089*4882a593Smuzhiyun 	case IF_GET_IFACE: /* return current sync_serial_settings */
4090*4882a593Smuzhiyun 
4091*4882a593Smuzhiyun 		ifr->ifr_settings.type = IF_IFACE_SYNC_SERIAL;
4092*4882a593Smuzhiyun 		if (ifr->ifr_settings.size < size) {
4093*4882a593Smuzhiyun 			ifr->ifr_settings.size = size; /* data size wanted */
4094*4882a593Smuzhiyun 			return -ENOBUFS;
4095*4882a593Smuzhiyun 		}
4096*4882a593Smuzhiyun 
4097*4882a593Smuzhiyun 		flags = info->params.flags & (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL |
4098*4882a593Smuzhiyun 					      HDLC_FLAG_RXC_BRG    | HDLC_FLAG_RXC_TXCPIN |
4099*4882a593Smuzhiyun 					      HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL |
4100*4882a593Smuzhiyun 					      HDLC_FLAG_TXC_BRG    | HDLC_FLAG_TXC_RXCPIN);
4101*4882a593Smuzhiyun 
4102*4882a593Smuzhiyun 		switch (flags){
4103*4882a593Smuzhiyun 		case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN): new_line.clock_type = CLOCK_EXT; break;
4104*4882a593Smuzhiyun 		case (HDLC_FLAG_RXC_BRG    | HDLC_FLAG_TXC_BRG):    new_line.clock_type = CLOCK_INT; break;
4105*4882a593Smuzhiyun 		case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG):    new_line.clock_type = CLOCK_TXINT; break;
4106*4882a593Smuzhiyun 		case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN): new_line.clock_type = CLOCK_TXFROMRX; break;
4107*4882a593Smuzhiyun 		default: new_line.clock_type = CLOCK_DEFAULT;
4108*4882a593Smuzhiyun 		}
4109*4882a593Smuzhiyun 
4110*4882a593Smuzhiyun 		new_line.clock_rate = info->params.clock_speed;
4111*4882a593Smuzhiyun 		new_line.loopback   = info->params.loopback ? 1:0;
4112*4882a593Smuzhiyun 
4113*4882a593Smuzhiyun 		if (copy_to_user(line, &new_line, size))
4114*4882a593Smuzhiyun 			return -EFAULT;
4115*4882a593Smuzhiyun 		return 0;
4116*4882a593Smuzhiyun 
4117*4882a593Smuzhiyun 	case IF_IFACE_SYNC_SERIAL: /* set sync_serial_settings */
4118*4882a593Smuzhiyun 
4119*4882a593Smuzhiyun 		if(!capable(CAP_NET_ADMIN))
4120*4882a593Smuzhiyun 			return -EPERM;
4121*4882a593Smuzhiyun 		if (copy_from_user(&new_line, line, size))
4122*4882a593Smuzhiyun 			return -EFAULT;
4123*4882a593Smuzhiyun 
4124*4882a593Smuzhiyun 		switch (new_line.clock_type)
4125*4882a593Smuzhiyun 		{
4126*4882a593Smuzhiyun 		case CLOCK_EXT:      flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN; break;
4127*4882a593Smuzhiyun 		case CLOCK_TXFROMRX: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN; break;
4128*4882a593Smuzhiyun 		case CLOCK_INT:      flags = HDLC_FLAG_RXC_BRG    | HDLC_FLAG_TXC_BRG;    break;
4129*4882a593Smuzhiyun 		case CLOCK_TXINT:    flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG;    break;
4130*4882a593Smuzhiyun 		case CLOCK_DEFAULT:  flags = info->params.flags &
4131*4882a593Smuzhiyun 					     (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL |
4132*4882a593Smuzhiyun 					      HDLC_FLAG_RXC_BRG    | HDLC_FLAG_RXC_TXCPIN |
4133*4882a593Smuzhiyun 					      HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL |
4134*4882a593Smuzhiyun 					      HDLC_FLAG_TXC_BRG    | HDLC_FLAG_TXC_RXCPIN); break;
4135*4882a593Smuzhiyun 		default: return -EINVAL;
4136*4882a593Smuzhiyun 		}
4137*4882a593Smuzhiyun 
4138*4882a593Smuzhiyun 		if (new_line.loopback != 0 && new_line.loopback != 1)
4139*4882a593Smuzhiyun 			return -EINVAL;
4140*4882a593Smuzhiyun 
4141*4882a593Smuzhiyun 		info->params.flags &= ~(HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL |
4142*4882a593Smuzhiyun 					HDLC_FLAG_RXC_BRG    | HDLC_FLAG_RXC_TXCPIN |
4143*4882a593Smuzhiyun 					HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL |
4144*4882a593Smuzhiyun 					HDLC_FLAG_TXC_BRG    | HDLC_FLAG_TXC_RXCPIN);
4145*4882a593Smuzhiyun 		info->params.flags |= flags;
4146*4882a593Smuzhiyun 
4147*4882a593Smuzhiyun 		info->params.loopback = new_line.loopback;
4148*4882a593Smuzhiyun 
4149*4882a593Smuzhiyun 		if (flags & (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG))
4150*4882a593Smuzhiyun 			info->params.clock_speed = new_line.clock_rate;
4151*4882a593Smuzhiyun 		else
4152*4882a593Smuzhiyun 			info->params.clock_speed = 0;
4153*4882a593Smuzhiyun 
4154*4882a593Smuzhiyun 		/* if network interface up, reprogram hardware */
4155*4882a593Smuzhiyun 		if (info->netcount) {
4156*4882a593Smuzhiyun 			struct tty_struct *tty = tty_port_tty_get(&info->port);
4157*4882a593Smuzhiyun 			mgslpc_program_hw(info, tty);
4158*4882a593Smuzhiyun 			tty_kref_put(tty);
4159*4882a593Smuzhiyun 		}
4160*4882a593Smuzhiyun 		return 0;
4161*4882a593Smuzhiyun 
4162*4882a593Smuzhiyun 	default:
4163*4882a593Smuzhiyun 		return hdlc_ioctl(dev, ifr, cmd);
4164*4882a593Smuzhiyun 	}
4165*4882a593Smuzhiyun }
4166*4882a593Smuzhiyun 
4167*4882a593Smuzhiyun /**
4168*4882a593Smuzhiyun  * called by network layer when transmit timeout is detected
4169*4882a593Smuzhiyun  *
4170*4882a593Smuzhiyun  * dev  pointer to network device structure
4171*4882a593Smuzhiyun  */
hdlcdev_tx_timeout(struct net_device * dev,unsigned int txqueue)4172*4882a593Smuzhiyun static void hdlcdev_tx_timeout(struct net_device *dev, unsigned int txqueue)
4173*4882a593Smuzhiyun {
4174*4882a593Smuzhiyun 	MGSLPC_INFO *info = dev_to_port(dev);
4175*4882a593Smuzhiyun 	unsigned long flags;
4176*4882a593Smuzhiyun 
4177*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
4178*4882a593Smuzhiyun 		printk("hdlcdev_tx_timeout(%s)\n", dev->name);
4179*4882a593Smuzhiyun 
4180*4882a593Smuzhiyun 	dev->stats.tx_errors++;
4181*4882a593Smuzhiyun 	dev->stats.tx_aborted_errors++;
4182*4882a593Smuzhiyun 
4183*4882a593Smuzhiyun 	spin_lock_irqsave(&info->lock, flags);
4184*4882a593Smuzhiyun 	tx_stop(info);
4185*4882a593Smuzhiyun 	spin_unlock_irqrestore(&info->lock, flags);
4186*4882a593Smuzhiyun 
4187*4882a593Smuzhiyun 	netif_wake_queue(dev);
4188*4882a593Smuzhiyun }
4189*4882a593Smuzhiyun 
4190*4882a593Smuzhiyun /**
4191*4882a593Smuzhiyun  * called by device driver when transmit completes
4192*4882a593Smuzhiyun  * reenable network layer transmit if stopped
4193*4882a593Smuzhiyun  *
4194*4882a593Smuzhiyun  * info  pointer to device instance information
4195*4882a593Smuzhiyun  */
hdlcdev_tx_done(MGSLPC_INFO * info)4196*4882a593Smuzhiyun static void hdlcdev_tx_done(MGSLPC_INFO *info)
4197*4882a593Smuzhiyun {
4198*4882a593Smuzhiyun 	if (netif_queue_stopped(info->netdev))
4199*4882a593Smuzhiyun 		netif_wake_queue(info->netdev);
4200*4882a593Smuzhiyun }
4201*4882a593Smuzhiyun 
4202*4882a593Smuzhiyun /**
4203*4882a593Smuzhiyun  * called by device driver when frame received
4204*4882a593Smuzhiyun  * pass frame to network layer
4205*4882a593Smuzhiyun  *
4206*4882a593Smuzhiyun  * info  pointer to device instance information
4207*4882a593Smuzhiyun  * buf   pointer to buffer contianing frame data
4208*4882a593Smuzhiyun  * size  count of data bytes in buf
4209*4882a593Smuzhiyun  */
hdlcdev_rx(MGSLPC_INFO * info,char * buf,int size)4210*4882a593Smuzhiyun static void hdlcdev_rx(MGSLPC_INFO *info, char *buf, int size)
4211*4882a593Smuzhiyun {
4212*4882a593Smuzhiyun 	struct sk_buff *skb = dev_alloc_skb(size);
4213*4882a593Smuzhiyun 	struct net_device *dev = info->netdev;
4214*4882a593Smuzhiyun 
4215*4882a593Smuzhiyun 	if (debug_level >= DEBUG_LEVEL_INFO)
4216*4882a593Smuzhiyun 		printk("hdlcdev_rx(%s)\n", dev->name);
4217*4882a593Smuzhiyun 
4218*4882a593Smuzhiyun 	if (skb == NULL) {
4219*4882a593Smuzhiyun 		printk(KERN_NOTICE "%s: can't alloc skb, dropping packet\n", dev->name);
4220*4882a593Smuzhiyun 		dev->stats.rx_dropped++;
4221*4882a593Smuzhiyun 		return;
4222*4882a593Smuzhiyun 	}
4223*4882a593Smuzhiyun 
4224*4882a593Smuzhiyun 	skb_put_data(skb, buf, size);
4225*4882a593Smuzhiyun 
4226*4882a593Smuzhiyun 	skb->protocol = hdlc_type_trans(skb, dev);
4227*4882a593Smuzhiyun 
4228*4882a593Smuzhiyun 	dev->stats.rx_packets++;
4229*4882a593Smuzhiyun 	dev->stats.rx_bytes += size;
4230*4882a593Smuzhiyun 
4231*4882a593Smuzhiyun 	netif_rx(skb);
4232*4882a593Smuzhiyun }
4233*4882a593Smuzhiyun 
4234*4882a593Smuzhiyun static const struct net_device_ops hdlcdev_ops = {
4235*4882a593Smuzhiyun 	.ndo_open       = hdlcdev_open,
4236*4882a593Smuzhiyun 	.ndo_stop       = hdlcdev_close,
4237*4882a593Smuzhiyun 	.ndo_start_xmit = hdlc_start_xmit,
4238*4882a593Smuzhiyun 	.ndo_do_ioctl   = hdlcdev_ioctl,
4239*4882a593Smuzhiyun 	.ndo_tx_timeout = hdlcdev_tx_timeout,
4240*4882a593Smuzhiyun };
4241*4882a593Smuzhiyun 
4242*4882a593Smuzhiyun /**
4243*4882a593Smuzhiyun  * called by device driver when adding device instance
4244*4882a593Smuzhiyun  * do generic HDLC initialization
4245*4882a593Smuzhiyun  *
4246*4882a593Smuzhiyun  * info  pointer to device instance information
4247*4882a593Smuzhiyun  *
4248*4882a593Smuzhiyun  * returns 0 if success, otherwise error code
4249*4882a593Smuzhiyun  */
hdlcdev_init(MGSLPC_INFO * info)4250*4882a593Smuzhiyun static int hdlcdev_init(MGSLPC_INFO *info)
4251*4882a593Smuzhiyun {
4252*4882a593Smuzhiyun 	int rc;
4253*4882a593Smuzhiyun 	struct net_device *dev;
4254*4882a593Smuzhiyun 	hdlc_device *hdlc;
4255*4882a593Smuzhiyun 
4256*4882a593Smuzhiyun 	/* allocate and initialize network and HDLC layer objects */
4257*4882a593Smuzhiyun 
4258*4882a593Smuzhiyun 	dev = alloc_hdlcdev(info);
4259*4882a593Smuzhiyun 	if (dev == NULL) {
4260*4882a593Smuzhiyun 		printk(KERN_ERR "%s:hdlc device allocation failure\n", __FILE__);
4261*4882a593Smuzhiyun 		return -ENOMEM;
4262*4882a593Smuzhiyun 	}
4263*4882a593Smuzhiyun 
4264*4882a593Smuzhiyun 	/* for network layer reporting purposes only */
4265*4882a593Smuzhiyun 	dev->base_addr = info->io_base;
4266*4882a593Smuzhiyun 	dev->irq       = info->irq_level;
4267*4882a593Smuzhiyun 
4268*4882a593Smuzhiyun 	/* network layer callbacks and settings */
4269*4882a593Smuzhiyun 	dev->netdev_ops	    = &hdlcdev_ops;
4270*4882a593Smuzhiyun 	dev->watchdog_timeo = 10 * HZ;
4271*4882a593Smuzhiyun 	dev->tx_queue_len   = 50;
4272*4882a593Smuzhiyun 
4273*4882a593Smuzhiyun 	/* generic HDLC layer callbacks and settings */
4274*4882a593Smuzhiyun 	hdlc         = dev_to_hdlc(dev);
4275*4882a593Smuzhiyun 	hdlc->attach = hdlcdev_attach;
4276*4882a593Smuzhiyun 	hdlc->xmit   = hdlcdev_xmit;
4277*4882a593Smuzhiyun 
4278*4882a593Smuzhiyun 	/* register objects with HDLC layer */
4279*4882a593Smuzhiyun 	rc = register_hdlc_device(dev);
4280*4882a593Smuzhiyun 	if (rc) {
4281*4882a593Smuzhiyun 		printk(KERN_WARNING "%s:unable to register hdlc device\n", __FILE__);
4282*4882a593Smuzhiyun 		free_netdev(dev);
4283*4882a593Smuzhiyun 		return rc;
4284*4882a593Smuzhiyun 	}
4285*4882a593Smuzhiyun 
4286*4882a593Smuzhiyun 	info->netdev = dev;
4287*4882a593Smuzhiyun 	return 0;
4288*4882a593Smuzhiyun }
4289*4882a593Smuzhiyun 
4290*4882a593Smuzhiyun /**
4291*4882a593Smuzhiyun  * called by device driver when removing device instance
4292*4882a593Smuzhiyun  * do generic HDLC cleanup
4293*4882a593Smuzhiyun  *
4294*4882a593Smuzhiyun  * info  pointer to device instance information
4295*4882a593Smuzhiyun  */
hdlcdev_exit(MGSLPC_INFO * info)4296*4882a593Smuzhiyun static void hdlcdev_exit(MGSLPC_INFO *info)
4297*4882a593Smuzhiyun {
4298*4882a593Smuzhiyun 	unregister_hdlc_device(info->netdev);
4299*4882a593Smuzhiyun 	free_netdev(info->netdev);
4300*4882a593Smuzhiyun 	info->netdev = NULL;
4301*4882a593Smuzhiyun }
4302*4882a593Smuzhiyun 
4303*4882a593Smuzhiyun #endif /* CONFIG_HDLC */
4304*4882a593Smuzhiyun 
4305