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