Blame view

drivers/char/pcmcia/synclink_cs.c 109 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
  /*
   * linux/drivers/char/pcmcia/synclink_cs.c
   *
a7482a2e7   Paul Fulghum   [PATCH] synclink_...
4
   * $Id: synclink_cs.c,v 4.34 2005/09/08 13:20:54 paulkf Exp $
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
   *
   * Device driver for Microgate SyncLink PC Card
   * multiprotocol serial adapter.
   *
   * written by Paul Fulghum for Microgate Corporation
   * paulkf@microgate.com
   *
   * Microgate and SyncLink are trademarks of Microgate Corporation
   *
   * This code is released under the GNU General Public License (GPL)
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
   * OF THE POSSIBILITY OF SUCH DAMAGE.
   */
  
  #define VERSION(ver,rel,seq) (((ver)<<16) | ((rel)<<8) | (seq))
  #if defined(__i386__)
  #  define BREAKPOINT() asm("   int $3");
  #else
  #  define BREAKPOINT() { }
  #endif
  
  #define MAX_DEVICE_COUNT 4
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
38
39
40
41
42
43
  #include <linux/module.h>
  #include <linux/errno.h>
  #include <linux/signal.h>
  #include <linux/sched.h>
  #include <linux/timer.h>
  #include <linux/time.h>
  #include <linux/interrupt.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
45
46
47
48
49
50
51
52
  #include <linux/tty.h>
  #include <linux/tty_flip.h>
  #include <linux/serial.h>
  #include <linux/major.h>
  #include <linux/string.h>
  #include <linux/fcntl.h>
  #include <linux/ptrace.h>
  #include <linux/ioport.h>
  #include <linux/mm.h>
87687144b   Alexey Dobriyan   proc tty: switch ...
53
  #include <linux/seq_file.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
55
56
57
  #include <linux/slab.h>
  #include <linux/netdevice.h>
  #include <linux/vmalloc.h>
  #include <linux/init.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
59
  #include <linux/delay.h>
  #include <linux/ioctl.h>
3dd1247f4   Robert P. J. Day   synclink: standar...
60
  #include <linux/synclink.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
63
64
65
66
67
68
69
  #include <asm/io.h>
  #include <asm/irq.h>
  #include <asm/dma.h>
  #include <linux/bitops.h>
  #include <asm/types.h>
  #include <linux/termios.h>
  #include <linux/workqueue.h>
  #include <linux/hdlc.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
71
72
  #include <pcmcia/cistpl.h>
  #include <pcmcia/cisreg.h>
  #include <pcmcia/ds.h>
af69c7f92   Paul Fulghum   [PATCH] generic H...
73
74
75
76
  #if defined(CONFIG_HDLC) || (defined(CONFIG_HDLC_MODULE) && defined(CONFIG_SYNCLINK_CS_MODULE))
  #define SYNCLINK_GENERIC_HDLC 1
  #else
  #define SYNCLINK_GENERIC_HDLC 0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77
78
79
80
81
82
83
84
  #endif
  
  #define GET_USER(error,value,addr) error = get_user(value,addr)
  #define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0
  #define PUT_USER(error,value,addr) error = put_user(value,addr)
  #define COPY_TO_USER(error,dest,src,size) error = copy_to_user(dest,src,size) ? -EFAULT : 0
  
  #include <asm/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
  static MGSL_PARAMS default_params = {
  	MGSL_MODE_HDLC,			/* unsigned long mode */
  	0,				/* unsigned char loopback; */
  	HDLC_FLAG_UNDERRUN_ABORT15,	/* unsigned short flags; */
  	HDLC_ENCODING_NRZI_SPACE,	/* unsigned char encoding; */
  	0,				/* unsigned long clock_speed; */
  	0xff,				/* unsigned char addr_filter; */
  	HDLC_CRC_16_CCITT,		/* unsigned short crc_type; */
  	HDLC_PREAMBLE_LENGTH_8BITS,	/* unsigned char preamble_length; */
  	HDLC_PREAMBLE_PATTERN_NONE,	/* unsigned char preamble; */
  	9600,				/* unsigned long data_rate; */
  	8,				/* unsigned char data_bits; */
  	1,				/* unsigned char stop_bits; */
  	ASYNC_PARITY_NONE		/* unsigned char parity; */
  };
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
100
  typedef struct {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
  	int count;
  	unsigned char status;
  	char data[1];
  } RXBUF;
  
  /* The queue of BH actions to be performed */
  
  #define BH_RECEIVE  1
  #define BH_TRANSMIT 2
  #define BH_STATUS   4
  
  #define IO_PIN_SHUTDOWN_LIMIT 100
  
  #define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
  
  struct _input_signal_events {
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
117
  	int	ri_up;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118
119
120
121
122
123
124
125
126
127
128
129
130
  	int	ri_down;
  	int	dsr_up;
  	int	dsr_down;
  	int	dcd_up;
  	int	dcd_down;
  	int	cts_up;
  	int	cts_down;
  };
  
  
  /*
   * Device instance data structure
   */
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
131

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
132
  typedef struct _mgslpc_info {
eeb461343   Alan Cox   synclink_cs: Conv...
133
  	struct tty_port		port;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134
135
  	void *if_ptr;	/* General purpose pointer (used by SPPP) */
  	int			magic;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
  	int			line;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
137

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
138
  	struct mgsl_icount	icount;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
139

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140
141
  	int			timeout;
  	int			x_char;		/* xon/xoff character */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142
  	unsigned char		read_status_mask;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
143
  	unsigned char		ignore_status_mask;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
  
  	unsigned char *tx_buf;
  	int            tx_put;
  	int            tx_get;
  	int            tx_count;
  
  	/* circular list of fixed length rx buffers */
  
  	unsigned char  *rx_buf;        /* memory allocated for all rx buffers */
  	int            rx_buf_total_size; /* size of memory allocated for rx buffers */
  	int            rx_put;         /* index of next empty rx buffer */
  	int            rx_get;         /* index of next full rx buffer */
  	int            rx_buf_size;    /* size in bytes of single rx buffer */
  	int            rx_buf_count;   /* total number of rx buffers */
  	int            rx_frame_count; /* number of full rx buffers */
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
159

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
  	wait_queue_head_t	status_event_wait_q;
  	wait_queue_head_t	event_wait_q;
  	struct timer_list	tx_timer;	/* HDLC transmit timeout timer */
  	struct _mgslpc_info	*next_device;	/* device list link */
  
  	unsigned short imra_value;
  	unsigned short imrb_value;
  	unsigned char  pim_value;
  
  	spinlock_t lock;
  	struct work_struct task;		/* task structure for scheduling bh */
  
  	u32 max_frame_size;
  
  	u32 pending_bh;
0fab6de09   Joe Perches   synclink drivers ...
175
176
  	bool bh_running;
  	bool bh_requested;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
177

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
178
179
180
181
  	int dcd_chkcount; /* check counts to prevent */
  	int cts_chkcount; /* too many IRQs if a signal */
  	int dsr_chkcount; /* is floating */
  	int ri_chkcount;
0fab6de09   Joe Perches   synclink drivers ...
182
183
  	bool rx_enabled;
  	bool rx_overflow;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
184

0fab6de09   Joe Perches   synclink drivers ...
185
186
187
  	bool tx_enabled;
  	bool tx_active;
  	bool tx_aborting;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188
189
190
191
192
193
194
195
  	u32 idle_mode;
  
  	int if_mode; /* serial interface selection (RS-232, v.35 etc) */
  
  	char device_name[25];		/* device instance name */
  
  	unsigned int io_base;	/* base I/O address of adapter */
  	unsigned int irq_level;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
196

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
197
198
199
  	MGSL_PARAMS params;		/* communications parameters */
  
  	unsigned char serial_signals;	/* current serial signal states */
0fab6de09   Joe Perches   synclink drivers ...
200
  	bool irq_occurred;		/* for diagnostics use */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
201
202
  	char testing_irq;
  	unsigned int init_error;	/* startup error (DIAGS)	*/
a6b68a69f   Paul Fulghum   synclink fix ldis...
203
  	char *flag_buf;
0fab6de09   Joe Perches   synclink drivers ...
204
  	bool drop_rts_on_tx_done;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
205
206
207
208
  
  	struct	_input_signal_events	input_signal_events;
  
  	/* PCMCIA support */
fd238232c   Dominik Brodowski   [PATCH] pcmcia: e...
209
  	struct pcmcia_device	*p_dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
210
211
212
213
  	int		      stop;
  
  	/* SPPP/Cisco HDLC device parts */
  	int netcount;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
214
  	spinlock_t netlock;
af69c7f92   Paul Fulghum   [PATCH] generic H...
215
  #if SYNCLINK_GENERIC_HDLC
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
216
217
218
219
220
221
222
223
224
225
226
  	struct net_device *netdev;
  #endif
  
  } MGSLPC_INFO;
  
  #define MGSLPC_MAGIC 0x5402
  
  /*
   * The size of the serial xmit buffer is 1 page, or 4096 bytes
   */
  #define TXBUFSIZE 4096
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
227

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
  #define CHA     0x00   /* channel A offset */
  #define CHB     0x40   /* channel B offset */
  
  /*
   *  FIXME: PPC has PVR defined in asm/reg.h.  For now we just undef it.
   */
  #undef PVR
  
  #define RXFIFO  0
  #define TXFIFO  0
  #define STAR    0x20
  #define CMDR    0x20
  #define RSTA    0x21
  #define PRE     0x21
  #define MODE    0x22
  #define TIMR    0x23
  #define XAD1    0x24
  #define XAD2    0x25
  #define RAH1    0x26
  #define RAH2    0x27
  #define DAFO    0x27
  #define RAL1    0x28
  #define RFC     0x28
  #define RHCR    0x29
  #define RAL2    0x29
  #define RBCL    0x2a
  #define XBCL    0x2a
  #define RBCH    0x2b
  #define XBCH    0x2b
  #define CCR0    0x2c
  #define CCR1    0x2d
  #define CCR2    0x2e
  #define CCR3    0x2f
  #define VSTR    0x34
  #define BGR     0x34
  #define RLCR    0x35
  #define AML     0x36
  #define AMH     0x37
  #define GIS     0x38
  #define IVA     0x38
  #define IPC     0x39
  #define ISR     0x3a
  #define IMR     0x3a
  #define PVR     0x3c
  #define PIS     0x3d
  #define PIM     0x3d
  #define PCR     0x3e
  #define CCR4    0x3f
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
276

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
277
  // IMR/ISR
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
278

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
279
280
281
282
283
284
285
286
287
288
289
290
291
292
  #define IRQ_BREAK_ON    BIT15   // rx break detected
  #define IRQ_DATAOVERRUN BIT14	// receive data overflow
  #define IRQ_ALLSENT     BIT13	// all sent
  #define IRQ_UNDERRUN    BIT12	// transmit data underrun
  #define IRQ_TIMER       BIT11	// timer interrupt
  #define IRQ_CTS         BIT10	// CTS status change
  #define IRQ_TXREPEAT    BIT9	// tx message repeat
  #define IRQ_TXFIFO      BIT8	// transmit pool ready
  #define IRQ_RXEOM       BIT7	// receive message end
  #define IRQ_EXITHUNT    BIT6	// receive frame start
  #define IRQ_RXTIME      BIT6    // rx char timeout
  #define IRQ_DCD         BIT2	// carrier detect status change
  #define IRQ_OVERRUN     BIT1	// receive frame overflow
  #define IRQ_RXFIFO      BIT0	// receive pool full
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
293

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294
  // STAR
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
295

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296
297
298
  #define XFW   BIT6		// transmit FIFO write enable
  #define CEC   BIT2		// command executing
  #define CTS   BIT1		// CTS state
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
299

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
300
301
302
303
304
305
306
  #define PVR_DTR      BIT0
  #define PVR_DSR      BIT1
  #define PVR_RI       BIT2
  #define PVR_AUTOCTS  BIT3
  #define PVR_RS232    0x20   /* 0010b */
  #define PVR_V35      0xe0   /* 1110b */
  #define PVR_RS422    0x40   /* 0100b */
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
307
308
  
  /* Register access functions */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
309
310
  #define write_reg(info, reg, val) outb((val),(info)->io_base + (reg))
  #define read_reg(info, reg) inb((info)->io_base + (reg))
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
311
  #define read_reg16(info, reg) inw((info)->io_base + (reg))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
312
  #define write_reg16(info, reg, val) outw((val), (info)->io_base + (reg))
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
313

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
314
  #define set_reg_bits(info, reg, mask) \
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
315
  	write_reg(info, (reg), \
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
316
  		 (unsigned char) (read_reg(info, (reg)) | (mask)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
317
  #define clear_reg_bits(info, reg, mask) \
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
318
  	write_reg(info, (reg), \
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
319
  		 (unsigned char) (read_reg(info, (reg)) & ~(mask)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
320
321
  /*
   * interrupt enable/disable routines
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
322
323
   */
  static void irq_disable(MGSLPC_INFO *info, unsigned char channel, unsigned short mask)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
324
325
326
327
328
329
330
331
332
  {
  	if (channel == CHA) {
  		info->imra_value |= mask;
  		write_reg16(info, CHA + IMR, info->imra_value);
  	} else {
  		info->imrb_value |= mask;
  		write_reg16(info, CHB + IMR, info->imrb_value);
  	}
  }
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
333
  static void irq_enable(MGSLPC_INFO *info, unsigned char channel, unsigned short mask)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
334
335
336
337
338
339
340
341
342
343
344
  {
  	if (channel == CHA) {
  		info->imra_value &= ~mask;
  		write_reg16(info, CHA + IMR, info->imra_value);
  	} else {
  		info->imrb_value &= ~mask;
  		write_reg16(info, CHB + IMR, info->imrb_value);
  	}
  }
  
  #define port_irq_disable(info, mask) \
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
345
  	{ info->pim_value |= (mask); write_reg(info, PIM, info->pim_value); }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
346
347
  
  #define port_irq_enable(info, mask) \
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
348
  	{ info->pim_value &= ~(mask); write_reg(info, PIM, info->pim_value); }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
350
351
  
  static void rx_start(MGSLPC_INFO *info);
  static void rx_stop(MGSLPC_INFO *info);
eeb461343   Alan Cox   synclink_cs: Conv...
352
  static void tx_start(MGSLPC_INFO *info, struct tty_struct *tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
354
355
356
357
358
359
360
361
362
363
364
  static void tx_stop(MGSLPC_INFO *info);
  static void tx_set_idle(MGSLPC_INFO *info);
  
  static void get_signals(MGSLPC_INFO *info);
  static void set_signals(MGSLPC_INFO *info);
  
  static void reset_device(MGSLPC_INFO *info);
  
  static void hdlc_mode(MGSLPC_INFO *info);
  static void async_mode(MGSLPC_INFO *info);
  
  static void tx_timeout(unsigned long context);
eeb461343   Alan Cox   synclink_cs: Conv...
365
  static int carrier_raised(struct tty_port *port);
fcc8ac182   Alan Cox   tty: Add carrier ...
366
  static void dtr_rts(struct tty_port *port, int onoff);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367

af69c7f92   Paul Fulghum   [PATCH] generic H...
368
  #if SYNCLINK_GENERIC_HDLC
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
369
370
371
372
373
374
375
376
  #define dev_to_port(D) (dev_to_hdlc(D)->priv)
  static void hdlcdev_tx_done(MGSLPC_INFO *info);
  static void hdlcdev_rx(MGSLPC_INFO *info, char *buf, int size);
  static int  hdlcdev_init(MGSLPC_INFO *info);
  static void hdlcdev_exit(MGSLPC_INFO *info);
  #endif
  
  static void trace_block(MGSLPC_INFO *info,const char* data, int count, int xmit);
0fab6de09   Joe Perches   synclink drivers ...
377
378
  static bool register_test(MGSLPC_INFO *info);
  static bool irq_test(MGSLPC_INFO *info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
379
380
381
382
  static int adapter_test(MGSLPC_INFO *info);
  
  static int claim_resources(MGSLPC_INFO *info);
  static void release_resources(MGSLPC_INFO *info);
d34138d05   Alexey Khoroshilov   pcmcia: synclink_...
383
  static int mgslpc_add_device(MGSLPC_INFO *info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
384
  static void mgslpc_remove_device(MGSLPC_INFO *info);
eeb461343   Alan Cox   synclink_cs: Conv...
385
  static bool rx_get_frame(MGSLPC_INFO *info, struct tty_struct *tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
386
387
388
  static void rx_reset_buffers(MGSLPC_INFO *info);
  static int  rx_alloc_buffers(MGSLPC_INFO *info);
  static void rx_free_buffers(MGSLPC_INFO *info);
7d12e780e   David Howells   IRQ: Maintain reg...
389
  static irqreturn_t mgslpc_isr(int irq, void *dev_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
390
391
392
393
  
  /*
   * Bottom half interrupt handlers
   */
c4028958b   David Howells   WorkStruct: make ...
394
  static void bh_handler(struct work_struct *work);
eeb461343   Alan Cox   synclink_cs: Conv...
395
  static void bh_transmit(MGSLPC_INFO *info, struct tty_struct *tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
396
397
398
399
400
  static void bh_status(MGSLPC_INFO *info);
  
  /*
   * ioctl handlers
   */
60b33c133   Alan Cox   tiocmget: kill of...
401
  static int tiocmget(struct tty_struct *tty);
20b9d1771   Alan Cox   tiocmset: kill th...
402
403
  static int tiocmset(struct tty_struct *tty,
  					unsigned int set, unsigned int clear);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
404
405
  static int get_stats(MGSLPC_INFO *info, struct mgsl_icount __user *user_icount);
  static int get_params(MGSLPC_INFO *info, MGSL_PARAMS __user *user_params);
eeb461343   Alan Cox   synclink_cs: Conv...
406
  static int set_params(MGSLPC_INFO *info, MGSL_PARAMS __user *new_params, struct tty_struct *tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
407
408
  static int get_txidle(MGSLPC_INFO *info, int __user *idle_mode);
  static int set_txidle(MGSLPC_INFO *info, int idle_mode);
eeb461343   Alan Cox   synclink_cs: Conv...
409
  static int set_txenable(MGSLPC_INFO *info, int enable, struct tty_struct *tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
410
411
412
413
414
415
416
417
418
419
420
421
  static int tx_abort(MGSLPC_INFO *info);
  static int set_rxenable(MGSLPC_INFO *info, int enable);
  static int wait_events(MGSLPC_INFO *info, int __user *mask);
  
  static MGSLPC_INFO *mgslpc_device_list = NULL;
  static int mgslpc_device_count = 0;
  
  /*
   * Set this param to non-zero to load eax with the
   * .text section address and breakpoint on module load.
   * This is useful for use with gdb and add-symbol-file command.
   */
208250dd4   Shailendra Verma   char:pcmcia:syncl...
422
  static bool break_on_load;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423
424
425
426
427
428
429
430
431
  
  /*
   * Driver major number, defaults to zero to get auto
   * assigned major number. May be forced as module parameter.
   */
  static int ttymajor=0;
  
  static int debug_level = 0;
  static int maxframe[MAX_DEVICE_COUNT] = {0,};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
432
433
434
435
436
  
  module_param(break_on_load, bool, 0);
  module_param(ttymajor, int, 0);
  module_param(debug_level, int, 0);
  module_param_array(maxframe, int, NULL, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
437
438
439
440
  
  MODULE_LICENSE("GPL");
  
  static char *driver_name = "SyncLink PC Card driver";
a7482a2e7   Paul Fulghum   [PATCH] synclink_...
441
  static char *driver_version = "$Revision: 4.34 $";
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
443
444
445
446
  
  static struct tty_driver *serial_driver;
  
  /* number of characters left in xmit buffer before we ask for more */
  #define WAKEUP_CHARS 256
eeb461343   Alan Cox   synclink_cs: Conv...
447
  static void mgslpc_change_params(MGSLPC_INFO *info, struct tty_struct *tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
448
449
450
  static void mgslpc_wait_until_sent(struct tty_struct *tty, int timeout);
  
  /* PCMCIA prototypes */
15b99ac17   Dominik Brodowski   [PATCH] pcmcia: a...
451
  static int mgslpc_config(struct pcmcia_device *link);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
452
  static void mgslpc_release(u_long arg);
cc3b4866b   Dominik Brodowski   [PATCH] pcmcia: u...
453
  static void mgslpc_detach(struct pcmcia_device *p_dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
454

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
  /*
   * 1st function defined in .text section. Calling this function in
   * init_module() followed by a breakpoint allows a remote debugger
   * (gdb) to get the .text address for the add-symbol-file command.
   * This allows remote debugging of dynamically loadable modules.
   */
  static void* mgslpc_get_text_ptr(void)
  {
  	return mgslpc_get_text_ptr;
  }
  
  /**
   * line discipline callback wrappers
   *
   * The wrappers maintain line discipline references
   * while calling into the line discipline.
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472
473
   * ldisc_receive_buf  - pass receive data to line discipline
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
474
475
476
477
478
479
480
481
  static void ldisc_receive_buf(struct tty_struct *tty,
  			      const __u8 *data, char *flags, int count)
  {
  	struct tty_ldisc *ld;
  	if (!tty)
  		return;
  	ld = tty_ldisc_ref(tty);
  	if (ld) {
a352def21   Alan Cox   tty: Ldisc revamp
482
483
  		if (ld->ops->receive_buf)
  			ld->ops->receive_buf(tty, data, flags, count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
484
485
486
  		tty_ldisc_deref(ld);
  	}
  }
eeb461343   Alan Cox   synclink_cs: Conv...
487
488
  static const struct tty_port_operations mgslpc_port_ops = {
  	.carrier_raised = carrier_raised,
fcc8ac182   Alan Cox   tty: Add carrier ...
489
  	.dtr_rts = dtr_rts
eeb461343   Alan Cox   synclink_cs: Conv...
490
  };
15b99ac17   Dominik Brodowski   [PATCH] pcmcia: a...
491
  static int mgslpc_probe(struct pcmcia_device *link)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
492
  {
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
  	MGSLPC_INFO *info;
  	int ret;
  
  	if (debug_level >= DEBUG_LEVEL_INFO)
  		printk("mgslpc_attach
  ");
  
  	info = kzalloc(sizeof(MGSLPC_INFO), GFP_KERNEL);
  	if (!info) {
  		printk("Error can't allocate device instance data
  ");
  		return -ENOMEM;
  	}
  
  	info->magic = MGSLPC_MAGIC;
  	tty_port_init(&info->port);
  	info->port.ops = &mgslpc_port_ops;
  	INIT_WORK(&info->task, bh_handler);
  	info->max_frame_size = 4096;
  	info->port.close_delay = 5*HZ/10;
  	info->port.closing_wait = 30*HZ;
  	init_waitqueue_head(&info->status_event_wait_q);
  	init_waitqueue_head(&info->event_wait_q);
  	spin_lock_init(&info->lock);
  	spin_lock_init(&info->netlock);
  	memcpy(&info->params,&default_params,sizeof(MGSL_PARAMS));
  	info->idle_mode = HDLC_TXIDLE_FLAGS;
  	info->imra_value = 0xffff;
  	info->imrb_value = 0xffff;
  	info->pim_value = 0xff;
  
  	info->p_dev = link;
  	link->priv = info;
  
  	/* Initialize the struct pcmcia_device structure */
  
  	ret = mgslpc_config(link);
  	if (ret != 0)
  		goto failed;
  
  	ret = mgslpc_add_device(info);
  	if (ret != 0)
  		goto failed_release;
  
  	return 0;
d34138d05   Alexey Khoroshilov   pcmcia: synclink_...
538
539
  
  failed_release:
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
540
  	mgslpc_release((u_long)link);
d34138d05   Alexey Khoroshilov   pcmcia: synclink_...
541
  failed:
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
542
543
544
  	tty_port_destroy(&info->port);
  	kfree(info);
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
545
546
547
548
  }
  
  /* Card has been inserted.
   */
00990e7ce   Dominik Brodowski   pcmcia: use autoc...
549
  static int mgslpc_ioprobe(struct pcmcia_device *p_dev, void *priv_data)
aaa8cfdad   Dominik Brodowski   pcmcia: use pcmci...
550
  {
90abdc3b9   Dominik Brodowski   pcmcia: do not us...
551
  	return pcmcia_request_io(p_dev);
aaa8cfdad   Dominik Brodowski   pcmcia: use pcmci...
552
  }
15b99ac17   Dominik Brodowski   [PATCH] pcmcia: a...
553
  static int mgslpc_config(struct pcmcia_device *link)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
554
  {
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
555
556
  	MGSLPC_INFO *info = link->priv;
  	int ret;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
557

3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
558
559
560
  	if (debug_level >= DEBUG_LEVEL_INFO)
  		printk("mgslpc_config(0x%p)
  ", link);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
561

3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
562
  	link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
00990e7ce   Dominik Brodowski   pcmcia: use autoc...
563

3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
564
565
566
  	ret = pcmcia_loop_config(link, mgslpc_ioprobe, NULL);
  	if (ret != 0)
  		goto failed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
567

3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
568
569
  	link->config_index = 8;
  	link->config_regs = PRESENT_OPTION;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
570

3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
571
572
573
574
575
576
  	ret = pcmcia_request_irq(link, mgslpc_isr);
  	if (ret)
  		goto failed;
  	ret = pcmcia_enable_device(link);
  	if (ret)
  		goto failed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
577

3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
578
579
580
  	info->io_base = link->resource[0]->start;
  	info->irq_level = link->irq;
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
581

cbf624f0e   Dominik Brodowski   pcmcia: use dynam...
582
  failed:
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
583
584
  	mgslpc_release((u_long)link);
  	return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
585
586
587
588
589
590
591
592
  }
  
  /* Card has been removed.
   * Unregister device and release PCMCIA configuration.
   * If device is open, postpone until it is closed.
   */
  static void mgslpc_release(u_long arg)
  {
e2d409636   Dominik Brodowski   [PATCH] pcmcia: u...
593
  	struct pcmcia_device *link = (struct pcmcia_device *)arg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
594

e2d409636   Dominik Brodowski   [PATCH] pcmcia: u...
595
596
597
  	if (debug_level >= DEBUG_LEVEL_INFO)
  		printk("mgslpc_release(0x%p)
  ", link);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
598

e2d409636   Dominik Brodowski   [PATCH] pcmcia: u...
599
  	pcmcia_disable_device(link);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
600
  }
fba395eee   Dominik Brodowski   [PATCH] pcmcia: r...
601
  static void mgslpc_detach(struct pcmcia_device *link)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
602
  {
e2d409636   Dominik Brodowski   [PATCH] pcmcia: u...
603
604
605
  	if (debug_level >= DEBUG_LEVEL_INFO)
  		printk("mgslpc_detach(0x%p)
  ", link);
cc3b4866b   Dominik Brodowski   [PATCH] pcmcia: u...
606

e2d409636   Dominik Brodowski   [PATCH] pcmcia: u...
607
608
  	((MGSLPC_INFO *)link->priv)->stop = 1;
  	mgslpc_release((u_long)link);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
609

e2d409636   Dominik Brodowski   [PATCH] pcmcia: u...
610
  	mgslpc_remove_device((MGSLPC_INFO *)link->priv);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
611
  }
fba395eee   Dominik Brodowski   [PATCH] pcmcia: r...
612
  static int mgslpc_suspend(struct pcmcia_device *link)
98e4c28b7   Dominik Brodowski   [PATCH] pcmcia: n...
613
  {
98e4c28b7   Dominik Brodowski   [PATCH] pcmcia: n...
614
  	MGSLPC_INFO *info = link->priv;
98e4c28b7   Dominik Brodowski   [PATCH] pcmcia: n...
615
  	info->stop = 1;
98e4c28b7   Dominik Brodowski   [PATCH] pcmcia: n...
616
617
618
  
  	return 0;
  }
fba395eee   Dominik Brodowski   [PATCH] pcmcia: r...
619
  static int mgslpc_resume(struct pcmcia_device *link)
98e4c28b7   Dominik Brodowski   [PATCH] pcmcia: n...
620
  {
98e4c28b7   Dominik Brodowski   [PATCH] pcmcia: n...
621
  	MGSLPC_INFO *info = link->priv;
98e4c28b7   Dominik Brodowski   [PATCH] pcmcia: n...
622
623
624
625
  	info->stop = 0;
  
  	return 0;
  }
0fab6de09   Joe Perches   synclink drivers ...
626
  static inline bool mgslpc_paranoia_check(MGSLPC_INFO *info,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
627
628
629
630
631
632
633
634
635
636
637
638
  					char *name, const char *routine)
  {
  #ifdef MGSLPC_PARANOIA_CHECK
  	static const char *badmagic =
  		"Warning: bad magic number for mgsl struct (%s) in %s
  ";
  	static const char *badinfo =
  		"Warning: null mgslpc_info for (%s) in %s
  ";
  
  	if (!info) {
  		printk(badinfo, name, routine);
0fab6de09   Joe Perches   synclink drivers ...
639
  		return true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
640
641
642
  	}
  	if (info->magic != MGSLPC_MAGIC) {
  		printk(badmagic, name, routine);
0fab6de09   Joe Perches   synclink drivers ...
643
  		return true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
644
645
646
  	}
  #else
  	if (!info)
0fab6de09   Joe Perches   synclink drivers ...
647
  		return true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
648
  #endif
0fab6de09   Joe Perches   synclink drivers ...
649
  	return false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
650
651
652
653
654
655
656
657
658
659
  }
  
  
  #define CMD_RXFIFO      BIT7	// release current rx FIFO
  #define CMD_RXRESET     BIT6	// receiver reset
  #define CMD_RXFIFO_READ BIT5
  #define CMD_START_TIMER BIT4
  #define CMD_TXFIFO      BIT3	// release current tx FIFO
  #define CMD_TXEOM       BIT1	// transmit end message
  #define CMD_TXRESET     BIT0	// transmit reset
0fab6de09   Joe Perches   synclink drivers ...
660
  static bool wait_command_complete(MGSLPC_INFO *info, unsigned char channel)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
661
662
  {
  	int i = 0;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
663
  	/* wait for command completion */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
664
665
666
  	while (read_reg(info, (unsigned char)(channel+STAR)) & BIT2) {
  		udelay(1);
  		if (i++ == 1000)
0fab6de09   Joe Perches   synclink drivers ...
667
  			return false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
668
  	}
0fab6de09   Joe Perches   synclink drivers ...
669
  	return true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
670
  }
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
671
  static void issue_command(MGSLPC_INFO *info, unsigned char channel, unsigned char cmd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
672
673
674
675
676
677
678
679
680
  {
  	wait_command_complete(info, channel);
  	write_reg(info, (unsigned char) (channel + CMDR), cmd);
  }
  
  static void tx_pause(struct tty_struct *tty)
  {
  	MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
  	unsigned long flags;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
681

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
682
683
684
  	if (mgslpc_paranoia_check(info, tty->name, "tx_pause"))
  		return;
  	if (debug_level >= DEBUG_LEVEL_INFO)
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
685
686
  		printk("tx_pause(%s)
  ", info->device_name);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
687

3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
688
  	spin_lock_irqsave(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
689
  	if (info->tx_enabled)
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
690
691
  		tx_stop(info);
  	spin_unlock_irqrestore(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
692
693
694
695
696
697
  }
  
  static void tx_release(struct tty_struct *tty)
  {
  	MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
  	unsigned long flags;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
698

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
699
700
701
  	if (mgslpc_paranoia_check(info, tty->name, "tx_release"))
  		return;
  	if (debug_level >= DEBUG_LEVEL_INFO)
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
702
703
  		printk("tx_release(%s)
  ", info->device_name);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
704

3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
705
  	spin_lock_irqsave(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
706
  	if (!info->tx_enabled)
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
707
708
  		tx_start(info, tty);
  	spin_unlock_irqrestore(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
709
710
711
712
713
714
715
716
717
  }
  
  /* Return next bottom half action to perform.
   * or 0 if nothing to do.
   */
  static int bh_action(MGSLPC_INFO *info)
  {
  	unsigned long flags;
  	int rc = 0;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
718

3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
719
  	spin_lock_irqsave(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
720
721
722
723
724
725
726
727
728
729
730
731
732
733
  
  	if (info->pending_bh & BH_RECEIVE) {
  		info->pending_bh &= ~BH_RECEIVE;
  		rc = BH_RECEIVE;
  	} else if (info->pending_bh & BH_TRANSMIT) {
  		info->pending_bh &= ~BH_TRANSMIT;
  		rc = BH_TRANSMIT;
  	} else if (info->pending_bh & BH_STATUS) {
  		info->pending_bh &= ~BH_STATUS;
  		rc = BH_STATUS;
  	}
  
  	if (!rc) {
  		/* Mark BH routine as complete */
0fab6de09   Joe Perches   synclink drivers ...
734
735
  		info->bh_running = false;
  		info->bh_requested = false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
736
  	}
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
737

3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
738
  	spin_unlock_irqrestore(&info->lock, flags);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
739

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
740
741
  	return rc;
  }
c4028958b   David Howells   WorkStruct: make ...
742
  static void bh_handler(struct work_struct *work)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
743
  {
c4028958b   David Howells   WorkStruct: make ...
744
  	MGSLPC_INFO *info = container_of(work, MGSLPC_INFO, task);
eeb461343   Alan Cox   synclink_cs: Conv...
745
  	struct tty_struct *tty;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
746
  	int action;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
747
  	if (debug_level >= DEBUG_LEVEL_BH)
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
748
749
  		printk("%s(%d):bh_handler(%s) entry
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
750
  			__FILE__,__LINE__,info->device_name);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
751

0fab6de09   Joe Perches   synclink drivers ...
752
  	info->bh_running = true;
eeb461343   Alan Cox   synclink_cs: Conv...
753
  	tty = tty_port_tty_get(&info->port);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
754
755
  
  	while((action = bh_action(info)) != 0) {
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
756

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
757
  		/* Process work item */
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
758
759
760
  		if (debug_level >= DEBUG_LEVEL_BH)
  			printk("%s(%d):bh_handler() work item action=%d
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
761
762
763
  				__FILE__,__LINE__,action);
  
  		switch (action) {
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
764

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
765
  		case BH_RECEIVE:
eeb461343   Alan Cox   synclink_cs: Conv...
766
  			while(rx_get_frame(info, tty));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
767
768
  			break;
  		case BH_TRANSMIT:
eeb461343   Alan Cox   synclink_cs: Conv...
769
  			bh_transmit(info, tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
770
771
772
773
774
775
776
777
778
779
780
  			break;
  		case BH_STATUS:
  			bh_status(info);
  			break;
  		default:
  			/* unknown work item ID */
  			printk("Unknown work item ID=%08X!
  ", action);
  			break;
  		}
  	}
eeb461343   Alan Cox   synclink_cs: Conv...
781
  	tty_kref_put(tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
782
  	if (debug_level >= DEBUG_LEVEL_BH)
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
783
784
  		printk("%s(%d):bh_handler(%s) exit
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
785
786
  			__FILE__,__LINE__,info->device_name);
  }
eeb461343   Alan Cox   synclink_cs: Conv...
787
  static void bh_transmit(MGSLPC_INFO *info, struct tty_struct *tty)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
788
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
789
790
791
  	if (debug_level >= DEBUG_LEVEL_BH)
  		printk("bh_transmit() entry on %s
  ", info->device_name);
b963a8441   Jiri Slaby   [PATCH] Char: tty...
792
  	if (tty)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
793
  		tty_wakeup(tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
794
  }
cdaad343b   Peter Hagervall   [PATCH] Sparse fi...
795
  static void bh_status(MGSLPC_INFO *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
796
797
798
799
800
801
  {
  	info->ri_chkcount = 0;
  	info->dsr_chkcount = 0;
  	info->dcd_chkcount = 0;
  	info->cts_chkcount = 0;
  }
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
802
  /* eom: non-zero = end of frame */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
803
804
805
806
807
808
809
  static void rx_ready_hdlc(MGSLPC_INFO *info, int eom)
  {
  	unsigned char data[2];
  	unsigned char fifo_count, read_count, i;
  	RXBUF *buf = (RXBUF*)(info->rx_buf + (info->rx_put * info->rx_buf_size));
  
  	if (debug_level >= DEBUG_LEVEL_ISR)
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
810
811
  		printk("%s(%d):rx_ready_hdlc(eom=%d)
  ", __FILE__, __LINE__, eom);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
812

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
813
814
815
816
817
818
819
  	if (!info->rx_enabled)
  		return;
  
  	if (info->rx_frame_count >= info->rx_buf_count) {
  		/* no more free buffers */
  		issue_command(info, CHA, CMD_RXRESET);
  		info->pending_bh |= BH_RECEIVE;
0fab6de09   Joe Perches   synclink drivers ...
820
  		info->rx_overflow = true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
821
822
823
824
825
  		info->icount.buf_overrun++;
  		return;
  	}
  
  	if (eom) {
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
826
  		/* end of frame, get FIFO count from RBCL register */
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
827
828
  		fifo_count = (unsigned char)(read_reg(info, CHA+RBCL) & 0x1f);
  		if (fifo_count == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
829
830
831
  			fifo_count = 32;
  	} else
  		fifo_count = 32;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
832

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
  	do {
  		if (fifo_count == 1) {
  			read_count = 1;
  			data[0] = read_reg(info, CHA + RXFIFO);
  		} else {
  			read_count = 2;
  			*((unsigned short *) data) = read_reg16(info, CHA + RXFIFO);
  		}
  		fifo_count -= read_count;
  		if (!fifo_count && eom)
  			buf->status = data[--read_count];
  
  		for (i = 0; i < read_count; i++) {
  			if (buf->count >= info->max_frame_size) {
  				/* frame too large, reset receiver and reset current buffer */
  				issue_command(info, CHA, CMD_RXRESET);
  				buf->count = 0;
  				return;
  			}
  			*(buf->data + buf->count) = data[i];
  			buf->count++;
  		}
  	} while (fifo_count);
  
  	if (eom) {
  		info->pending_bh |= BH_RECEIVE;
  		info->rx_frame_count++;
  		info->rx_put++;
  		if (info->rx_put >= info->rx_buf_count)
  			info->rx_put = 0;
  	}
  	issue_command(info, CHA, CMD_RXFIFO);
  }
2e124b4a3   Jiri Slaby   TTY: switch tty_f...
866
  static void rx_ready_async(MGSLPC_INFO *info, int tcd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
867
  {
227434f89   Jiri Slaby   TTY: switch tty_b...
868
  	struct tty_port *port = &info->port;
33f0f88f1   Alan Cox   [PATCH] TTY layer...
869
  	unsigned char data, status, flag;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
870
  	int fifo_count;
33f0f88f1   Alan Cox   [PATCH] TTY layer...
871
  	int work = 0;
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
872
  	struct mgsl_icount *icount = &info->icount;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
873
874
  
  	if (tcd) {
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
875
  		/* early termination, get FIFO count from RBCL register */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
876
877
878
879
880
881
882
883
884
  		fifo_count = (unsigned char)(read_reg(info, CHA+RBCL) & 0x1f);
  
  		/* Zero fifo count could mean 0 or 32 bytes available.
  		 * If BIT5 of STAR is set then at least 1 byte is available.
  		 */
  		if (!fifo_count && (read_reg(info,CHA+STAR) & BIT5))
  			fifo_count = 32;
  	} else
  		fifo_count = 32;
33f0f88f1   Alan Cox   [PATCH] TTY layer...
885

227434f89   Jiri Slaby   TTY: switch tty_b...
886
  	tty_buffer_request_room(port, fifo_count);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
887
  	/* Flush received async data to receive data buffer. */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
888
889
890
891
  	while (fifo_count) {
  		data   = read_reg(info, CHA + RXFIFO);
  		status = read_reg(info, CHA + RXFIFO);
  		fifo_count -= 2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
892
  		icount->rx++;
33f0f88f1   Alan Cox   [PATCH] TTY layer...
893
  		flag = TTY_NORMAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
894
895
896
897
898
899
  
  		// if no frameing/crc error then save data
  		// BIT7:parity error
  		// BIT6:framing error
  
  		if (status & (BIT7 + BIT6)) {
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
900
  			if (status & BIT7)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
901
902
903
904
905
906
907
  				icount->parity++;
  			else
  				icount->frame++;
  
  			/* discard char if tty control flags say so */
  			if (status & info->ignore_status_mask)
  				continue;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
908

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
909
910
911
  			status &= info->read_status_mask;
  
  			if (status & BIT7)
33f0f88f1   Alan Cox   [PATCH] TTY layer...
912
  				flag = TTY_PARITY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
913
  			else if (status & BIT6)
33f0f88f1   Alan Cox   [PATCH] TTY layer...
914
  				flag = TTY_FRAME;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
915
  		}
92a19f9ce   Jiri Slaby   TTY: switch tty_i...
916
  		work += tty_insert_flip_char(port, data, flag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
917
918
919
920
  	}
  	issue_command(info, CHA, CMD_RXFIFO);
  
  	if (debug_level >= DEBUG_LEVEL_ISR) {
33f0f88f1   Alan Cox   [PATCH] TTY layer...
921
922
  		printk("%s(%d):rx_ready_async",
  			__FILE__,__LINE__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
923
924
925
926
927
  		printk("%s(%d):rx=%d brk=%d parity=%d frame=%d overrun=%d
  ",
  			__FILE__,__LINE__,icount->rx,icount->brk,
  			icount->parity,icount->frame,icount->overrun);
  	}
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
928

33f0f88f1   Alan Cox   [PATCH] TTY layer...
929
  	if (work)
2e124b4a3   Jiri Slaby   TTY: switch tty_f...
930
  		tty_flip_buffer_push(port);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
931
  }
eeb461343   Alan Cox   synclink_cs: Conv...
932
  static void tx_done(MGSLPC_INFO *info, struct tty_struct *tty)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
933
934
935
  {
  	if (!info->tx_active)
  		return;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
936

0fab6de09   Joe Perches   synclink drivers ...
937
938
  	info->tx_active = false;
  	info->tx_aborting = false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
939
940
941
942
943
  
  	if (info->params.mode == MGSL_MODE_ASYNC)
  		return;
  
  	info->tx_count = info->tx_put = info->tx_get = 0;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
944
  	del_timer(&info->tx_timer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
945
946
947
948
949
950
  	if (info->drop_rts_on_tx_done) {
  		get_signals(info);
  		if (info->serial_signals & SerialSignal_RTS) {
  			info->serial_signals &= ~SerialSignal_RTS;
  			set_signals(info);
  		}
0fab6de09   Joe Perches   synclink drivers ...
951
  		info->drop_rts_on_tx_done = false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
952
  	}
af69c7f92   Paul Fulghum   [PATCH] generic H...
953
  #if SYNCLINK_GENERIC_HDLC
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
954
955
  	if (info->netcount)
  		hdlcdev_tx_done(info);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
956
  	else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
957
958
  #endif
  	{
221b7b579   Alexey Khoroshilov   pcmcia: synclink_...
959
  		if (tty && (tty->stopped || tty->hw_stopped)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
960
961
962
963
964
965
  			tx_stop(info);
  			return;
  		}
  		info->pending_bh |= BH_TRANSMIT;
  	}
  }
eeb461343   Alan Cox   synclink_cs: Conv...
966
  static void tx_ready(MGSLPC_INFO *info, struct tty_struct *tty)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
967
968
969
970
971
  {
  	unsigned char fifo_count = 32;
  	int c;
  
  	if (debug_level >= DEBUG_LEVEL_ISR)
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
972
973
  		printk("%s(%d):tx_ready(%s)
  ", __FILE__, __LINE__, info->device_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
974
975
976
977
978
  
  	if (info->params.mode == MGSL_MODE_HDLC) {
  		if (!info->tx_active)
  			return;
  	} else {
221b7b579   Alexey Khoroshilov   pcmcia: synclink_...
979
  		if (tty && (tty->stopped || tty->hw_stopped)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
980
981
982
983
  			tx_stop(info);
  			return;
  		}
  		if (!info->tx_count)
0fab6de09   Joe Perches   synclink drivers ...
984
  			info->tx_active = false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
985
986
987
988
989
990
991
  	}
  
  	if (!info->tx_count)
  		return;
  
  	while (info->tx_count && fifo_count) {
  		c = min(2, min_t(int, fifo_count, min(info->tx_count, TXBUFSIZE - info->tx_get)));
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
992

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
  		if (c == 1) {
  			write_reg(info, CHA + TXFIFO, *(info->tx_buf + info->tx_get));
  		} else {
  			write_reg16(info, CHA + TXFIFO,
  					  *((unsigned short*)(info->tx_buf + info->tx_get)));
  		}
  		info->tx_count -= c;
  		info->tx_get = (info->tx_get + c) & (TXBUFSIZE - 1);
  		fifo_count -= c;
  	}
  
  	if (info->params.mode == MGSL_MODE_ASYNC) {
  		if (info->tx_count < WAKEUP_CHARS)
  			info->pending_bh |= BH_TRANSMIT;
  		issue_command(info, CHA, CMD_TXFIFO);
  	} else {
  		if (info->tx_count)
  			issue_command(info, CHA, CMD_TXFIFO);
  		else
  			issue_command(info, CHA, CMD_TXFIFO + CMD_TXEOM);
  	}
  }
eeb461343   Alan Cox   synclink_cs: Conv...
1015
  static void cts_change(MGSLPC_INFO *info, struct tty_struct *tty)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
  {
  	get_signals(info);
  	if ((info->cts_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT)
  		irq_disable(info, CHB, IRQ_CTS);
  	info->icount.cts++;
  	if (info->serial_signals & SerialSignal_CTS)
  		info->input_signal_events.cts_up++;
  	else
  		info->input_signal_events.cts_down++;
  	wake_up_interruptible(&info->status_event_wait_q);
  	wake_up_interruptible(&info->event_wait_q);
3498d13b8   Linus Torvalds   Merge tag 'tty-3....
1027
  	if (tty && tty_port_cts_enabled(&info->port)) {
eeb461343   Alan Cox   synclink_cs: Conv...
1028
  		if (tty->hw_stopped) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1029
1030
1031
  			if (info->serial_signals & SerialSignal_CTS) {
  				if (debug_level >= DEBUG_LEVEL_ISR)
  					printk("CTS tx start...");
221b7b579   Alexey Khoroshilov   pcmcia: synclink_...
1032
  				tty->hw_stopped = 0;
eeb461343   Alan Cox   synclink_cs: Conv...
1033
  				tx_start(info, tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1034
1035
1036
1037
1038
1039
1040
  				info->pending_bh |= BH_TRANSMIT;
  				return;
  			}
  		} else {
  			if (!(info->serial_signals & SerialSignal_CTS)) {
  				if (debug_level >= DEBUG_LEVEL_ISR)
  					printk("CTS tx stop...");
221b7b579   Alexey Khoroshilov   pcmcia: synclink_...
1041
  				tty->hw_stopped = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1042
1043
1044
1045
1046
1047
  				tx_stop(info);
  			}
  		}
  	}
  	info->pending_bh |= BH_STATUS;
  }
eeb461343   Alan Cox   synclink_cs: Conv...
1048
  static void dcd_change(MGSLPC_INFO *info, struct tty_struct *tty)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
  {
  	get_signals(info);
  	if ((info->dcd_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT)
  		irq_disable(info, CHB, IRQ_DCD);
  	info->icount.dcd++;
  	if (info->serial_signals & SerialSignal_DCD) {
  		info->input_signal_events.dcd_up++;
  	}
  	else
  		info->input_signal_events.dcd_down++;
af69c7f92   Paul Fulghum   [PATCH] generic H...
1059
  #if SYNCLINK_GENERIC_HDLC
fbeff3c1d   Krzysztof Halasa   [WAN]: Converted ...
1060
1061
1062
1063
1064
1065
  	if (info->netcount) {
  		if (info->serial_signals & SerialSignal_DCD)
  			netif_carrier_on(info->netdev);
  		else
  			netif_carrier_off(info->netdev);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1066
1067
1068
  #endif
  	wake_up_interruptible(&info->status_event_wait_q);
  	wake_up_interruptible(&info->event_wait_q);
2d68655d1   Peter Hurley   tty: Replace ASYN...
1069
  	if (tty_port_check_carrier(&info->port)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1070
1071
1072
1073
  		if (debug_level >= DEBUG_LEVEL_ISR)
  			printk("%s CD now %s...", info->device_name,
  			       (info->serial_signals & SerialSignal_DCD) ? "on" : "off");
  		if (info->serial_signals & SerialSignal_DCD)
eeb461343   Alan Cox   synclink_cs: Conv...
1074
  			wake_up_interruptible(&info->port.open_wait);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1075
1076
1077
  		else {
  			if (debug_level >= DEBUG_LEVEL_ISR)
  				printk("doing serial hangup...");
eeb461343   Alan Cox   synclink_cs: Conv...
1078
1079
  			if (tty)
  				tty_hangup(tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
  		}
  	}
  	info->pending_bh |= BH_STATUS;
  }
  
  static void dsr_change(MGSLPC_INFO *info)
  {
  	get_signals(info);
  	if ((info->dsr_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT)
  		port_irq_disable(info, PVR_DSR);
  	info->icount.dsr++;
  	if (info->serial_signals & SerialSignal_DSR)
  		info->input_signal_events.dsr_up++;
  	else
  		info->input_signal_events.dsr_down++;
  	wake_up_interruptible(&info->status_event_wait_q);
  	wake_up_interruptible(&info->event_wait_q);
  	info->pending_bh |= BH_STATUS;
  }
  
  static void ri_change(MGSLPC_INFO *info)
  {
  	get_signals(info);
  	if ((info->ri_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT)
  		port_irq_disable(info, PVR_RI);
  	info->icount.rng++;
  	if (info->serial_signals & SerialSignal_RI)
  		info->input_signal_events.ri_up++;
  	else
  		info->input_signal_events.ri_down++;
  	wake_up_interruptible(&info->status_event_wait_q);
  	wake_up_interruptible(&info->event_wait_q);
  	info->pending_bh |= BH_STATUS;
  }
  
  /* Interrupt service routine entry point.
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1116
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1117
   * Arguments:
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1118
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1119
1120
   * irq     interrupt number that caused interrupt
   * dev_id  device ID supplied during interrupt registration
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1121
   */
a6f97b293   Jeff Garzik   drivers/char: min...
1122
  static irqreturn_t mgslpc_isr(int dummy, void *dev_id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1123
  {
a6f97b293   Jeff Garzik   drivers/char: min...
1124
  	MGSLPC_INFO *info = dev_id;
eeb461343   Alan Cox   synclink_cs: Conv...
1125
  	struct tty_struct *tty;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1126
1127
1128
  	unsigned short isr;
  	unsigned char gis, pis;
  	int count=0;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1129
  	if (debug_level >= DEBUG_LEVEL_ISR)
a6f97b293   Jeff Garzik   drivers/char: min...
1130
1131
  		printk("mgslpc_isr(%d) entry.
  ", info->irq_level);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1132

e2d409636   Dominik Brodowski   [PATCH] pcmcia: u...
1133
  	if (!(info->p_dev->_locked))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1134
  		return IRQ_HANDLED;
eeb461343   Alan Cox   synclink_cs: Conv...
1135
  	tty = tty_port_tty_get(&info->port);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1136
1137
1138
  	spin_lock(&info->lock);
  
  	while ((gis = read_reg(info, CHA + GIS))) {
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1139
  		if (debug_level >= DEBUG_LEVEL_ISR)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1140
1141
1142
1143
1144
1145
1146
1147
1148
  			printk("mgslpc_isr %s gis=%04X
  ", info->device_name,gis);
  
  		if ((gis & 0x70) || count > 1000) {
  			printk("synclink_cs:hardware failed or ejected
  ");
  			break;
  		}
  		count++;
ecda040ff   Alexandru Juncu   pcmcia: synclink_...
1149
  		if (gis & (BIT1 | BIT0)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1150
1151
  			isr = read_reg16(info, CHB + ISR);
  			if (isr & IRQ_DCD)
eeb461343   Alan Cox   synclink_cs: Conv...
1152
  				dcd_change(info, tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1153
  			if (isr & IRQ_CTS)
eeb461343   Alan Cox   synclink_cs: Conv...
1154
  				cts_change(info, tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1155
  		}
ecda040ff   Alexandru Juncu   pcmcia: synclink_...
1156
  		if (gis & (BIT3 | BIT2))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1157
1158
1159
  		{
  			isr = read_reg16(info, CHA + ISR);
  			if (isr & IRQ_TIMER) {
0fab6de09   Joe Perches   synclink drivers ...
1160
  				info->irq_occurred = true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1161
1162
  				irq_disable(info, CHA, IRQ_TIMER);
  			}
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1163
  			/* receive IRQs */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1164
1165
1166
1167
1168
1169
  			if (isr & IRQ_EXITHUNT) {
  				info->icount.exithunt++;
  				wake_up_interruptible(&info->event_wait_q);
  			}
  			if (isr & IRQ_BREAK_ON) {
  				info->icount.brk++;
eeb461343   Alan Cox   synclink_cs: Conv...
1170
1171
  				if (info->port.flags & ASYNC_SAK)
  					do_SAK(tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1172
1173
1174
1175
  			}
  			if (isr & IRQ_RXTIME) {
  				issue_command(info, CHA, CMD_RXFIFO_READ);
  			}
ecda040ff   Alexandru Juncu   pcmcia: synclink_...
1176
  			if (isr & (IRQ_RXEOM | IRQ_RXFIFO)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1177
  				if (info->params.mode == MGSL_MODE_HDLC)
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1178
  					rx_ready_hdlc(info, isr & IRQ_RXEOM);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1179
  				else
2e124b4a3   Jiri Slaby   TTY: switch tty_f...
1180
  					rx_ready_async(info, isr & IRQ_RXEOM);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1181
  			}
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1182
  			/* transmit IRQs */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1183
1184
1185
1186
1187
  			if (isr & IRQ_UNDERRUN) {
  				if (info->tx_aborting)
  					info->icount.txabort++;
  				else
  					info->icount.txunder++;
eeb461343   Alan Cox   synclink_cs: Conv...
1188
  				tx_done(info, tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1189
1190
1191
  			}
  			else if (isr & IRQ_ALLSENT) {
  				info->icount.txok++;
eeb461343   Alan Cox   synclink_cs: Conv...
1192
  				tx_done(info, tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1193
1194
  			}
  			else if (isr & IRQ_TXFIFO)
eeb461343   Alan Cox   synclink_cs: Conv...
1195
  				tx_ready(info, tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1196
1197
1198
1199
1200
1201
1202
1203
1204
  		}
  		if (gis & BIT7) {
  			pis = read_reg(info, CHA + PIS);
  			if (pis & BIT1)
  				dsr_change(info);
  			if (pis & BIT2)
  				ri_change(info);
  		}
  	}
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1205
1206
  
  	/* Request bottom half processing if there's something
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1207
1208
1209
1210
  	 * for it to do and the bh is not already running
  	 */
  
  	if (info->pending_bh && !info->bh_running && !info->bh_requested) {
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1211
  		if (debug_level >= DEBUG_LEVEL_ISR)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1212
1213
1214
1215
  			printk("%s(%d):%s queueing bh task.
  ",
  				__FILE__,__LINE__,info->device_name);
  		schedule_work(&info->task);
0fab6de09   Joe Perches   synclink drivers ...
1216
  		info->bh_requested = true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1217
1218
1219
  	}
  
  	spin_unlock(&info->lock);
eeb461343   Alan Cox   synclink_cs: Conv...
1220
  	tty_kref_put(tty);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1221
1222
  
  	if (debug_level >= DEBUG_LEVEL_ISR)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1223
1224
  		printk("%s(%d):mgslpc_isr(%d)exit.
  ",
a6f97b293   Jeff Garzik   drivers/char: min...
1225
  		       __FILE__, __LINE__, info->irq_level);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1226
1227
1228
1229
1230
1231
  
  	return IRQ_HANDLED;
  }
  
  /* Initialize and start device.
   */
eeb461343   Alan Cox   synclink_cs: Conv...
1232
  static int startup(MGSLPC_INFO * info, struct tty_struct *tty)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1233
1234
  {
  	int retval = 0;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1235

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1236
  	if (debug_level >= DEBUG_LEVEL_INFO)
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1237
1238
  		printk("%s(%d):startup(%s)
  ", __FILE__, __LINE__, info->device_name);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1239

d41861ca1   Peter Hurley   tty: Replace ASYN...
1240
  	if (tty_port_initialized(&info->port))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1241
  		return 0;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1242

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1243
1244
1245
1246
1247
1248
  	if (!info->tx_buf) {
  		/* allocate a page of memory for a transmit buffer */
  		info->tx_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
  		if (!info->tx_buf) {
  			printk(KERN_ERR"%s(%d):%s can't allocate transmit buffer
  ",
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1249
  				__FILE__, __LINE__, info->device_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1250
1251
1252
1253
1254
  			return -ENOMEM;
  		}
  	}
  
  	info->pending_bh = 0;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1255

a7482a2e7   Paul Fulghum   [PATCH] synclink_...
1256
  	memset(&info->icount, 0, sizeof(info->icount));
40565f196   Jiri Slaby   [PATCH] Char: tim...
1257
  	setup_timer(&info->tx_timer, tx_timeout, (unsigned long)info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1258
1259
1260
  
  	/* Allocate and claim adapter resources */
  	retval = claim_resources(info);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1261

25985edce   Lucas De Marchi   Fix common misspe...
1262
  	/* perform existence check and diagnostics */
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1263
  	if (!retval)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1264
  		retval = adapter_test(info);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1265

3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1266
1267
  	if (retval) {
  		if (capable(CAP_SYS_ADMIN) && tty)
eeb461343   Alan Cox   synclink_cs: Conv...
1268
  			set_bit(TTY_IO_ERROR, &tty->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1269
  		release_resources(info);
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1270
1271
  		return retval;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1272
1273
  
  	/* program hardware for current parameters */
eeb461343   Alan Cox   synclink_cs: Conv...
1274
  	mgslpc_change_params(info, tty);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1275

eeb461343   Alan Cox   synclink_cs: Conv...
1276
1277
  	if (tty)
  		clear_bit(TTY_IO_ERROR, &tty->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1278

d41861ca1   Peter Hurley   tty: Replace ASYN...
1279
  	tty_port_set_initialized(&info->port, 1);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1280

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1281
1282
1283
1284
1285
  	return 0;
  }
  
  /* Called by mgslpc_close() and mgslpc_hangup() to shutdown hardware
   */
eeb461343   Alan Cox   synclink_cs: Conv...
1286
  static void shutdown(MGSLPC_INFO * info, struct tty_struct *tty)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1287
1288
  {
  	unsigned long flags;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1289

d41861ca1   Peter Hurley   tty: Replace ASYN...
1290
  	if (!tty_port_initialized(&info->port))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1291
1292
1293
1294
1295
  		return;
  
  	if (debug_level >= DEBUG_LEVEL_INFO)
  		printk("%s(%d):mgslpc_shutdown(%s)
  ",
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1296
  			 __FILE__, __LINE__, info->device_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1297
1298
1299
1300
1301
  
  	/* clear status wait queue because status changes */
  	/* can't happen after shutting down the hardware */
  	wake_up_interruptible(&info->status_event_wait_q);
  	wake_up_interruptible(&info->event_wait_q);
40565f196   Jiri Slaby   [PATCH] Char: tim...
1302
  	del_timer_sync(&info->tx_timer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1303
1304
1305
1306
1307
  
  	if (info->tx_buf) {
  		free_page((unsigned long) info->tx_buf);
  		info->tx_buf = NULL;
  	}
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1308
  	spin_lock_irqsave(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1309
1310
1311
1312
1313
1314
  
  	rx_stop(info);
  	tx_stop(info);
  
  	/* TODO:disable interrupts instead of reset to preserve signal states */
  	reset_device(info);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1315

9db276f8f   Peter Hurley   tty: Use termios ...
1316
  	if (!tty || C_HUPCL(tty)) {
9fe8074b8   Joe Perches   TTY: synclink: Co...
1317
  		info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1318
1319
  		set_signals(info);
  	}
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1320

3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1321
  	spin_unlock_irqrestore(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1322

d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1323
  	release_resources(info);
eeb461343   Alan Cox   synclink_cs: Conv...
1324
1325
  	if (tty)
  		set_bit(TTY_IO_ERROR, &tty->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1326

d41861ca1   Peter Hurley   tty: Replace ASYN...
1327
  	tty_port_set_initialized(&info->port, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1328
  }
eeb461343   Alan Cox   synclink_cs: Conv...
1329
  static void mgslpc_program_hw(MGSLPC_INFO *info, struct tty_struct *tty)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1330
1331
  {
  	unsigned long flags;
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1332
  	spin_lock_irqsave(&info->lock, flags);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1333

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1334
1335
1336
  	rx_stop(info);
  	tx_stop(info);
  	info->tx_count = info->tx_put = info->tx_get = 0;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1337

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1338
1339
1340
1341
  	if (info->params.mode == MGSL_MODE_HDLC || info->netcount)
  		hdlc_mode(info);
  	else
  		async_mode(info);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1342

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1343
  	set_signals(info);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1344

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1345
1346
1347
1348
1349
1350
1351
1352
  	info->dcd_chkcount = 0;
  	info->cts_chkcount = 0;
  	info->ri_chkcount = 0;
  	info->dsr_chkcount = 0;
  
  	irq_enable(info, CHB, IRQ_DCD | IRQ_CTS);
  	port_irq_enable(info, (unsigned char) PVR_DSR | PVR_RI);
  	get_signals(info);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1353

9db276f8f   Peter Hurley   tty: Use termios ...
1354
  	if (info->netcount || (tty && C_CREAD(tty)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1355
  		rx_start(info);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1356

3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1357
  	spin_unlock_irqrestore(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1358
1359
1360
1361
  }
  
  /* Reconfigure adapter based on new parameters
   */
eeb461343   Alan Cox   synclink_cs: Conv...
1362
  static void mgslpc_change_params(MGSLPC_INFO *info, struct tty_struct *tty)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1363
1364
1365
  {
  	unsigned cflag;
  	int bits_per_char;
373f5aedb   Alan Cox   pcmcia,synclink_c...
1366
  	if (!tty)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1367
  		return;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1368

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1369
1370
1371
  	if (debug_level >= DEBUG_LEVEL_INFO)
  		printk("%s(%d):mgslpc_change_params(%s)
  ",
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1372
  			 __FILE__, __LINE__, info->device_name);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1373

373f5aedb   Alan Cox   pcmcia,synclink_c...
1374
  	cflag = tty->termios.c_cflag;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1375

9fe8074b8   Joe Perches   TTY: synclink: Co...
1376
1377
  	/* if B0 rate (hangup) specified then negate RTS and DTR */
  	/* otherwise assert RTS and DTR */
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1378
  	if (cflag & CBAUD)
9fe8074b8   Joe Perches   TTY: synclink: Co...
1379
  		info->serial_signals |= SerialSignal_RTS | SerialSignal_DTR;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1380
  	else
9fe8074b8   Joe Perches   TTY: synclink: Co...
1381
  		info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1382

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1383
  	/* byte size and parity */
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1384

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1385
1386
1387
1388
1389
1390
1391
  	switch (cflag & CSIZE) {
  	case CS5: info->params.data_bits = 5; break;
  	case CS6: info->params.data_bits = 6; break;
  	case CS7: info->params.data_bits = 7; break;
  	case CS8: info->params.data_bits = 8; break;
  	default:  info->params.data_bits = 7; break;
  	}
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1392

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
  	if (cflag & CSTOPB)
  		info->params.stop_bits = 2;
  	else
  		info->params.stop_bits = 1;
  
  	info->params.parity = ASYNC_PARITY_NONE;
  	if (cflag & PARENB) {
  		if (cflag & PARODD)
  			info->params.parity = ASYNC_PARITY_ODD;
  		else
  			info->params.parity = ASYNC_PARITY_EVEN;
  #ifdef CMSPAR
  		if (cflag & CMSPAR)
  			info->params.parity = ASYNC_PARITY_SPACE;
  #endif
  	}
  
  	/* calculate number of jiffies to transmit a full
  	 * FIFO (32 bytes) at specified data rate
  	 */
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1413
  	bits_per_char = info->params.data_bits +
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1414
1415
1416
1417
1418
1419
1420
  			info->params.stop_bits + 1;
  
  	/* if port data rate is set to 460800 or less then
  	 * allow tty settings to override, otherwise keep the
  	 * current data rate.
  	 */
  	if (info->params.data_rate <= 460800) {
eeb461343   Alan Cox   synclink_cs: Conv...
1421
  		info->params.data_rate = tty_get_baud_rate(tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1422
  	}
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1423

3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1424
  	if (info->params.data_rate) {
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1425
  		info->timeout = (32*HZ*bits_per_char) /
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1426
1427
1428
  				info->params.data_rate;
  	}
  	info->timeout += HZ/50;		/* Add .02 seconds of slop */
5604a98e2   Peter Hurley   tty: Replace ASYN...
1429
  	tty_port_set_cts_flow(&info->port, cflag & CRTSCTS);
2d68655d1   Peter Hurley   tty: Replace ASYN...
1430
  	tty_port_set_check_carrier(&info->port, ~cflag & CLOCAL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1431
1432
  
  	/* process tty input control flags */
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1433

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1434
  	info->read_status_mask = 0;
eeb461343   Alan Cox   synclink_cs: Conv...
1435
  	if (I_INPCK(tty))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1436
  		info->read_status_mask |= BIT7 | BIT6;
eeb461343   Alan Cox   synclink_cs: Conv...
1437
  	if (I_IGNPAR(tty))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1438
  		info->ignore_status_mask |= BIT7 | BIT6;
eeb461343   Alan Cox   synclink_cs: Conv...
1439
  	mgslpc_program_hw(info, tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1440
1441
1442
1443
  }
  
  /* Add a character to the transmit buffer
   */
d7e752e27   Alan Cox   pcmcia: serial to...
1444
  static int mgslpc_put_char(struct tty_struct *tty, unsigned char ch)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1445
1446
1447
1448
1449
  {
  	MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
  	unsigned long flags;
  
  	if (debug_level >= DEBUG_LEVEL_INFO) {
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1450
1451
1452
  		printk("%s(%d):mgslpc_put_char(%d) on %s
  ",
  			__FILE__, __LINE__, ch, info->device_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1453
1454
1455
  	}
  
  	if (mgslpc_paranoia_check(info, tty->name, "mgslpc_put_char"))
d7e752e27   Alan Cox   pcmcia: serial to...
1456
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1457

326f28e9e   Eric Sesterhenn   [PATCH] More !tty...
1458
  	if (!info->tx_buf)
d7e752e27   Alan Cox   pcmcia: serial to...
1459
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1460

3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1461
  	spin_lock_irqsave(&info->lock, flags);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1462

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1463
1464
1465
1466
1467
1468
1469
  	if (info->params.mode == MGSL_MODE_ASYNC || !info->tx_active) {
  		if (info->tx_count < TXBUFSIZE - 1) {
  			info->tx_buf[info->tx_put++] = ch;
  			info->tx_put &= TXBUFSIZE-1;
  			info->tx_count++;
  		}
  	}
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1470

3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1471
  	spin_unlock_irqrestore(&info->lock, flags);
d7e752e27   Alan Cox   pcmcia: serial to...
1472
  	return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1473
1474
1475
1476
1477
1478
1479
1480
1481
  }
  
  /* Enable transmitter so remaining characters in the
   * transmit buffer are sent.
   */
  static void mgslpc_flush_chars(struct tty_struct *tty)
  {
  	MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
  	unsigned long flags;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1482

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1483
  	if (debug_level >= DEBUG_LEVEL_INFO)
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1484
1485
1486
  		printk("%s(%d):mgslpc_flush_chars() entry on %s tx_count=%d
  ",
  			__FILE__, __LINE__, info->device_name, info->tx_count);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1487

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1488
1489
1490
1491
1492
1493
1494
1495
  	if (mgslpc_paranoia_check(info, tty->name, "mgslpc_flush_chars"))
  		return;
  
  	if (info->tx_count <= 0 || tty->stopped ||
  	    tty->hw_stopped || !info->tx_buf)
  		return;
  
  	if (debug_level >= DEBUG_LEVEL_INFO)
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1496
1497
1498
  		printk("%s(%d):mgslpc_flush_chars() entry on %s starting transmitter
  ",
  			__FILE__, __LINE__, info->device_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1499

3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1500
  	spin_lock_irqsave(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1501
  	if (!info->tx_active)
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1502
1503
  		tx_start(info, tty);
  	spin_unlock_irqrestore(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1504
1505
1506
  }
  
  /* Send a block of data
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1507
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1508
   * Arguments:
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1509
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1510
1511
1512
   * tty        pointer to tty information structure
   * buf	      pointer to buffer containing send data
   * count      size of send data in bytes
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1513
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1514
1515
1516
1517
1518
1519
1520
1521
   * Returns: number of characters written
   */
  static int mgslpc_write(struct tty_struct * tty,
  			const unsigned char *buf, int count)
  {
  	int c, ret = 0;
  	MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
  	unsigned long flags;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1522

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1523
  	if (debug_level >= DEBUG_LEVEL_INFO)
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1524
1525
1526
  		printk("%s(%d):mgslpc_write(%s) count=%d
  ",
  			__FILE__, __LINE__, info->device_name, count);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1527

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1528
  	if (mgslpc_paranoia_check(info, tty->name, "mgslpc_write") ||
326f28e9e   Eric Sesterhenn   [PATCH] More !tty...
1529
  		!info->tx_buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
  		goto cleanup;
  
  	if (info->params.mode == MGSL_MODE_HDLC) {
  		if (count > TXBUFSIZE) {
  			ret = -EIO;
  			goto cleanup;
  		}
  		if (info->tx_active)
  			goto cleanup;
  		else if (info->tx_count)
  			goto start;
  	}
  
  	for (;;) {
  		c = min(count,
  			min(TXBUFSIZE - info->tx_count - 1,
  			    TXBUFSIZE - info->tx_put));
  		if (c <= 0)
  			break;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1549

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1550
  		memcpy(info->tx_buf + info->tx_put, buf, c);
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1551
  		spin_lock_irqsave(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1552
1553
  		info->tx_put = (info->tx_put + c) & (TXBUFSIZE-1);
  		info->tx_count += c;
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1554
  		spin_unlock_irqrestore(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1555
1556
1557
1558
1559
1560
  
  		buf += c;
  		count -= c;
  		ret += c;
  	}
  start:
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1561
1562
  	if (info->tx_count && !tty->stopped && !tty->hw_stopped) {
  		spin_lock_irqsave(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1563
  		if (!info->tx_active)
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1564
1565
1566
  			tx_start(info, tty);
  		spin_unlock_irqrestore(&info->lock, flags);
  	}
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1567
  cleanup:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1568
  	if (debug_level >= DEBUG_LEVEL_INFO)
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1569
1570
1571
  		printk("%s(%d):mgslpc_write(%s) returning=%d
  ",
  			__FILE__, __LINE__, info->device_name, ret);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1572
1573
1574
1575
1576
1577
1578
1579
1580
  	return ret;
  }
  
  /* Return the count of free bytes in transmit buffer
   */
  static int mgslpc_write_room(struct tty_struct *tty)
  {
  	MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
  	int ret;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1581

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
  	if (mgslpc_paranoia_check(info, tty->name, "mgslpc_write_room"))
  		return 0;
  
  	if (info->params.mode == MGSL_MODE_HDLC) {
  		/* HDLC (frame oriented) mode */
  		if (info->tx_active)
  			return 0;
  		else
  			return HDLC_MAX_FRAME_SIZE;
  	} else {
  		ret = TXBUFSIZE - info->tx_count - 1;
  		if (ret < 0)
  			ret = 0;
  	}
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1596

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1597
1598
1599
  	if (debug_level >= DEBUG_LEVEL_INFO)
  		printk("%s(%d):mgslpc_write_room(%s)=%d
  ",
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1600
  			 __FILE__, __LINE__, info->device_name, ret);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1601
1602
1603
1604
1605
1606
1607
1608
1609
  	return ret;
  }
  
  /* Return the count of bytes in transmit buffer
   */
  static int mgslpc_chars_in_buffer(struct tty_struct *tty)
  {
  	MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
  	int rc;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1610

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1611
1612
1613
  	if (debug_level >= DEBUG_LEVEL_INFO)
  		printk("%s(%d):mgslpc_chars_in_buffer(%s)
  ",
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1614
  			 __FILE__, __LINE__, info->device_name);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1615

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1616
1617
  	if (mgslpc_paranoia_check(info, tty->name, "mgslpc_chars_in_buffer"))
  		return 0;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1618

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1619
1620
1621
1622
1623
1624
1625
1626
  	if (info->params.mode == MGSL_MODE_HDLC)
  		rc = info->tx_active ? info->max_frame_size : 0;
  	else
  		rc = info->tx_count;
  
  	if (debug_level >= DEBUG_LEVEL_INFO)
  		printk("%s(%d):mgslpc_chars_in_buffer(%s)=%d
  ",
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1627
  			 __FILE__, __LINE__, info->device_name, rc);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1628

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1629
1630
1631
1632
1633
1634
1635
1636
1637
  	return rc;
  }
  
  /* Discard all data in the send buffer
   */
  static void mgslpc_flush_buffer(struct tty_struct *tty)
  {
  	MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
  	unsigned long flags;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1638

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1639
1640
1641
  	if (debug_level >= DEBUG_LEVEL_INFO)
  		printk("%s(%d):mgslpc_flush_buffer(%s) entry
  ",
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1642
  			 __FILE__, __LINE__, info->device_name);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1643

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1644
1645
  	if (mgslpc_paranoia_check(info, tty->name, "mgslpc_flush_buffer"))
  		return;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1646

3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1647
  	spin_lock_irqsave(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1648
  	info->tx_count = info->tx_put = info->tx_get = 0;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1649
  	del_timer(&info->tx_timer);
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1650
  	spin_unlock_irqrestore(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
  
  	wake_up_interruptible(&tty->write_wait);
  	tty_wakeup(tty);
  }
  
  /* Send a high-priority XON/XOFF character
   */
  static void mgslpc_send_xchar(struct tty_struct *tty, char ch)
  {
  	MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
  	unsigned long flags;
  
  	if (debug_level >= DEBUG_LEVEL_INFO)
  		printk("%s(%d):mgslpc_send_xchar(%s,%d)
  ",
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1666
  			 __FILE__, __LINE__, info->device_name, ch);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1667

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1668
1669
1670
1671
1672
  	if (mgslpc_paranoia_check(info, tty->name, "mgslpc_send_xchar"))
  		return;
  
  	info->x_char = ch;
  	if (ch) {
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1673
  		spin_lock_irqsave(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1674
  		if (!info->tx_enabled)
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1675
1676
  			tx_start(info, tty);
  		spin_unlock_irqrestore(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1677
1678
1679
1680
1681
1682
1683
1684
1685
  	}
  }
  
  /* Signal remote device to throttle send data (our receive data)
   */
  static void mgslpc_throttle(struct tty_struct * tty)
  {
  	MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
  	unsigned long flags;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1686

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1687
1688
1689
  	if (debug_level >= DEBUG_LEVEL_INFO)
  		printk("%s(%d):mgslpc_throttle(%s) entry
  ",
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1690
  			 __FILE__, __LINE__, info->device_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1691
1692
1693
  
  	if (mgslpc_paranoia_check(info, tty->name, "mgslpc_throttle"))
  		return;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1694

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1695
1696
  	if (I_IXOFF(tty))
  		mgslpc_send_xchar(tty, STOP_CHAR(tty));
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1697

9db276f8f   Peter Hurley   tty: Use termios ...
1698
  	if (C_CRTSCTS(tty)) {
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1699
  		spin_lock_irqsave(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1700
  		info->serial_signals &= ~SerialSignal_RTS;
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1701
1702
  		set_signals(info);
  		spin_unlock_irqrestore(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1703
1704
1705
1706
1707
1708
1709
1710
1711
  	}
  }
  
  /* Signal remote device to stop throttling send data (our receive data)
   */
  static void mgslpc_unthrottle(struct tty_struct * tty)
  {
  	MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
  	unsigned long flags;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1712

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1713
1714
1715
  	if (debug_level >= DEBUG_LEVEL_INFO)
  		printk("%s(%d):mgslpc_unthrottle(%s) entry
  ",
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1716
  			 __FILE__, __LINE__, info->device_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1717
1718
1719
  
  	if (mgslpc_paranoia_check(info, tty->name, "mgslpc_unthrottle"))
  		return;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1720

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1721
1722
1723
1724
1725
1726
  	if (I_IXOFF(tty)) {
  		if (info->x_char)
  			info->x_char = 0;
  		else
  			mgslpc_send_xchar(tty, START_CHAR(tty));
  	}
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1727

9db276f8f   Peter Hurley   tty: Use termios ...
1728
  	if (C_CRTSCTS(tty)) {
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1729
  		spin_lock_irqsave(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1730
  		info->serial_signals |= SerialSignal_RTS;
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1731
1732
  		set_signals(info);
  		spin_unlock_irqrestore(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
  	}
  }
  
  /* get the current serial statistics
   */
  static int get_stats(MGSLPC_INFO * info, struct mgsl_icount __user *user_icount)
  {
  	int err;
  	if (debug_level >= DEBUG_LEVEL_INFO)
  		printk("get_params(%s)
  ", info->device_name);
a7482a2e7   Paul Fulghum   [PATCH] synclink_...
1744
1745
1746
1747
1748
1749
1750
  	if (!user_icount) {
  		memset(&info->icount, 0, sizeof(info->icount));
  	} else {
  		COPY_TO_USER(err, user_icount, &info->icount, sizeof(struct mgsl_icount));
  		if (err)
  			return -EFAULT;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
  	return 0;
  }
  
  /* get the current serial parameters
   */
  static int get_params(MGSLPC_INFO * info, MGSL_PARAMS __user *user_params)
  {
  	int err;
  	if (debug_level >= DEBUG_LEVEL_INFO)
  		printk("get_params(%s)
  ", info->device_name);
  	COPY_TO_USER(err,user_params, &info->params, sizeof(MGSL_PARAMS));
  	if (err)
  		return -EFAULT;
  	return 0;
  }
  
  /* set the serial parameters
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1769
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1770
   * Arguments:
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1771
   *
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1772
1773
   *	info		pointer to device instance data
   *	new_params	user buffer containing new serial params
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1774
1775
1776
   *
   * Returns:	0 if success, otherwise error code
   */
eeb461343   Alan Cox   synclink_cs: Conv...
1777
  static int set_params(MGSLPC_INFO * info, MGSL_PARAMS __user *new_params, struct tty_struct *tty)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1778
  {
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1779
  	unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1780
1781
  	MGSL_PARAMS tmp_params;
  	int err;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1782

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1783
1784
1785
  	if (debug_level >= DEBUG_LEVEL_INFO)
  		printk("%s(%d):set_params %s
  ", __FILE__,__LINE__,
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1786
  			info->device_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1787
1788
  	COPY_FROM_USER(err,&tmp_params, new_params, sizeof(MGSL_PARAMS));
  	if (err) {
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1789
1790
1791
1792
  		if (debug_level >= DEBUG_LEVEL_INFO)
  			printk("%s(%d):set_params(%s) user buffer copy failed
  ",
  				__FILE__, __LINE__, info->device_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1793
1794
  		return -EFAULT;
  	}
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1795

3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1796
  	spin_lock_irqsave(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1797
  	memcpy(&info->params,&tmp_params,sizeof(MGSL_PARAMS));
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1798
  	spin_unlock_irqrestore(&info->lock, flags);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1799

3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1800
  	mgslpc_change_params(info, tty);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1801

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
  	return 0;
  }
  
  static int get_txidle(MGSLPC_INFO * info, int __user *idle_mode)
  {
  	int err;
  	if (debug_level >= DEBUG_LEVEL_INFO)
  		printk("get_txidle(%s)=%d
  ", info->device_name, info->idle_mode);
  	COPY_TO_USER(err,idle_mode, &info->idle_mode, sizeof(int));
  	if (err)
  		return -EFAULT;
  	return 0;
  }
  
  static int set_txidle(MGSLPC_INFO * info, int idle_mode)
  {
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1819
  	unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1820
1821
1822
  	if (debug_level >= DEBUG_LEVEL_INFO)
  		printk("set_txidle(%s,%d)
  ", info->device_name, idle_mode);
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1823
  	spin_lock_irqsave(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1824
1825
  	info->idle_mode = idle_mode;
  	tx_set_idle(info);
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1826
  	spin_unlock_irqrestore(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
  	return 0;
  }
  
  static int get_interface(MGSLPC_INFO * info, int __user *if_mode)
  {
  	int err;
  	if (debug_level >= DEBUG_LEVEL_INFO)
  		printk("get_interface(%s)=%d
  ", info->device_name, info->if_mode);
  	COPY_TO_USER(err,if_mode, &info->if_mode, sizeof(int));
  	if (err)
  		return -EFAULT;
  	return 0;
  }
  
  static int set_interface(MGSLPC_INFO * info, int if_mode)
  {
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1844
  	unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1845
1846
1847
1848
  	unsigned char val;
  	if (debug_level >= DEBUG_LEVEL_INFO)
  		printk("set_interface(%s,%d)
  ", info->device_name, if_mode);
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1849
  	spin_lock_irqsave(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
  	info->if_mode = if_mode;
  
  	val = read_reg(info, PVR) & 0x0f;
  	switch (info->if_mode)
  	{
  	case MGSL_INTERFACE_RS232: val |= PVR_RS232; break;
  	case MGSL_INTERFACE_V35:   val |= PVR_V35;   break;
  	case MGSL_INTERFACE_RS422: val |= PVR_RS422; break;
  	}
  	write_reg(info, PVR, val);
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1860
  	spin_unlock_irqrestore(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1861
1862
  	return 0;
  }
eeb461343   Alan Cox   synclink_cs: Conv...
1863
  static int set_txenable(MGSLPC_INFO * info, int enable, struct tty_struct *tty)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1864
  {
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1865
  	unsigned long flags;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1866

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1867
1868
1869
  	if (debug_level >= DEBUG_LEVEL_INFO)
  		printk("set_txenable(%s,%d)
  ", info->device_name, enable);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1870

3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1871
  	spin_lock_irqsave(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1872
1873
  	if (enable) {
  		if (!info->tx_enabled)
eeb461343   Alan Cox   synclink_cs: Conv...
1874
  			tx_start(info, tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1875
1876
1877
1878
  	} else {
  		if (info->tx_enabled)
  			tx_stop(info);
  	}
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1879
  	spin_unlock_irqrestore(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1880
1881
1882
1883
1884
  	return 0;
  }
  
  static int tx_abort(MGSLPC_INFO * info)
  {
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1885
  	unsigned long flags;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1886

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1887
1888
1889
  	if (debug_level >= DEBUG_LEVEL_INFO)
  		printk("tx_abort(%s)
  ", info->device_name);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1890

3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1891
  	spin_lock_irqsave(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1892
1893
1894
1895
1896
1897
  	if (info->tx_active && info->tx_count &&
  	    info->params.mode == MGSL_MODE_HDLC) {
  		/* clear data count so FIFO is not filled on next IRQ.
  		 * This results in underrun and abort transmission.
  		 */
  		info->tx_count = info->tx_put = info->tx_get = 0;
0fab6de09   Joe Perches   synclink drivers ...
1898
  		info->tx_aborting = true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1899
  	}
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1900
  	spin_unlock_irqrestore(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1901
1902
1903
1904
1905
  	return 0;
  }
  
  static int set_rxenable(MGSLPC_INFO * info, int enable)
  {
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1906
  	unsigned long flags;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1907

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1908
1909
1910
  	if (debug_level >= DEBUG_LEVEL_INFO)
  		printk("set_rxenable(%s,%d)
  ", info->device_name, enable);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1911

3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1912
  	spin_lock_irqsave(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1913
1914
1915
1916
1917
1918
1919
  	if (enable) {
  		if (!info->rx_enabled)
  			rx_start(info);
  	} else {
  		if (info->rx_enabled)
  			rx_stop(info);
  	}
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1920
  	spin_unlock_irqrestore(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1921
1922
1923
1924
  	return 0;
  }
  
  /* wait for specified event to occur
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1925
   *
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1926
1927
1928
   * Arguments:		info	pointer to device instance data
   *			mask	pointer to bitmask of events to wait for
   * Return Value:	0	if successful and bit mask updated with
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1929
   *				of events triggerred,
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1930
   *			otherwise error code
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1931
1932
1933
   */
  static int wait_events(MGSLPC_INFO * info, int __user *mask_ptr)
  {
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1934
  	unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
  	int s;
  	int rc=0;
  	struct mgsl_icount cprev, cnow;
  	int events;
  	int mask;
  	struct	_input_signal_events oldsigs, newsigs;
  	DECLARE_WAITQUEUE(wait, current);
  
  	COPY_FROM_USER(rc,&mask, mask_ptr, sizeof(int));
  	if (rc)
  		return  -EFAULT;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1946

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1947
1948
1949
  	if (debug_level >= DEBUG_LEVEL_INFO)
  		printk("wait_events(%s,%d)
  ", info->device_name, mask);
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1950
  	spin_lock_irqsave(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1951
1952
1953
1954
1955
1956
  
  	/* return immediately if state matches requested events */
  	get_signals(info);
  	s = info->serial_signals;
  	events = mask &
  		( ((s & SerialSignal_DSR) ? MgslEvent_DsrActive:MgslEvent_DsrInactive) +
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1957
  		  ((s & SerialSignal_DCD) ? MgslEvent_DcdActive:MgslEvent_DcdInactive) +
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1958
1959
1960
  		  ((s & SerialSignal_CTS) ? MgslEvent_CtsActive:MgslEvent_CtsInactive) +
  		  ((s & SerialSignal_RI)  ? MgslEvent_RiActive :MgslEvent_RiInactive) );
  	if (events) {
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1961
  		spin_unlock_irqrestore(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1962
1963
1964
1965
1966
1967
  		goto exit;
  	}
  
  	/* save current irq counts */
  	cprev = info->icount;
  	oldsigs = info->input_signal_events;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1968

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1969
1970
1971
  	if ((info->params.mode == MGSL_MODE_HDLC) &&
  	    (mask & MgslEvent_ExitHuntMode))
  		irq_enable(info, CHA, IRQ_EXITHUNT);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1972

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1973
1974
  	set_current_state(TASK_INTERRUPTIBLE);
  	add_wait_queue(&info->event_wait_q, &wait);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1975

3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1976
  	spin_unlock_irqrestore(&info->lock, flags);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1977

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1978
1979
1980
1981
1982
1983
  	for(;;) {
  		schedule();
  		if (signal_pending(current)) {
  			rc = -ERESTARTSYS;
  			break;
  		}
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
1984

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1985
  		/* get current irq counts */
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1986
  		spin_lock_irqsave(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1987
1988
1989
  		cnow = info->icount;
  		newsigs = info->input_signal_events;
  		set_current_state(TASK_INTERRUPTIBLE);
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
1990
  		spin_unlock_irqrestore(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
  
  		/* if no change, wait aborted for some reason */
  		if (newsigs.dsr_up   == oldsigs.dsr_up   &&
  		    newsigs.dsr_down == oldsigs.dsr_down &&
  		    newsigs.dcd_up   == oldsigs.dcd_up   &&
  		    newsigs.dcd_down == oldsigs.dcd_down &&
  		    newsigs.cts_up   == oldsigs.cts_up   &&
  		    newsigs.cts_down == oldsigs.cts_down &&
  		    newsigs.ri_up    == oldsigs.ri_up    &&
  		    newsigs.ri_down  == oldsigs.ri_down  &&
  		    cnow.exithunt    == cprev.exithunt   &&
  		    cnow.rxidle      == cprev.rxidle) {
  			rc = -EIO;
  			break;
  		}
  
  		events = mask &
  			( (newsigs.dsr_up   != oldsigs.dsr_up   ? MgslEvent_DsrActive:0)   +
  			  (newsigs.dsr_down != oldsigs.dsr_down ? MgslEvent_DsrInactive:0) +
  			  (newsigs.dcd_up   != oldsigs.dcd_up   ? MgslEvent_DcdActive:0)   +
  			  (newsigs.dcd_down != oldsigs.dcd_down ? MgslEvent_DcdInactive:0) +
  			  (newsigs.cts_up   != oldsigs.cts_up   ? MgslEvent_CtsActive:0)   +
  			  (newsigs.cts_down != oldsigs.cts_down ? MgslEvent_CtsInactive:0) +
  			  (newsigs.ri_up    != oldsigs.ri_up    ? MgslEvent_RiActive:0)    +
  			  (newsigs.ri_down  != oldsigs.ri_down  ? MgslEvent_RiInactive:0)  +
  			  (cnow.exithunt    != cprev.exithunt   ? MgslEvent_ExitHuntMode:0) +
  			  (cnow.rxidle      != cprev.rxidle     ? MgslEvent_IdleReceived:0) );
  		if (events)
  			break;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2020

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2021
2022
2023
  		cprev = cnow;
  		oldsigs = newsigs;
  	}
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2024

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2025
2026
2027
2028
  	remove_wait_queue(&info->event_wait_q, &wait);
  	set_current_state(TASK_RUNNING);
  
  	if (mask & MgslEvent_ExitHuntMode) {
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2029
  		spin_lock_irqsave(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2030
2031
  		if (!waitqueue_active(&info->event_wait_q))
  			irq_disable(info, CHA, IRQ_EXITHUNT);
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2032
  		spin_unlock_irqrestore(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2033
2034
2035
2036
2037
2038
2039
2040
2041
  	}
  exit:
  	if (rc == 0)
  		PUT_USER(rc, events, mask_ptr);
  	return rc;
  }
  
  static int modem_input_wait(MGSLPC_INFO *info,int arg)
  {
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2042
  	unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2043
2044
2045
2046
2047
  	int rc;
  	struct mgsl_icount cprev, cnow;
  	DECLARE_WAITQUEUE(wait, current);
  
  	/* save current irq counts */
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2048
  	spin_lock_irqsave(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2049
2050
2051
  	cprev = info->icount;
  	add_wait_queue(&info->status_event_wait_q, &wait);
  	set_current_state(TASK_INTERRUPTIBLE);
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2052
  	spin_unlock_irqrestore(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2053
2054
2055
2056
2057
2058
2059
2060
2061
  
  	for(;;) {
  		schedule();
  		if (signal_pending(current)) {
  			rc = -ERESTARTSYS;
  			break;
  		}
  
  		/* get new irq counts */
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2062
  		spin_lock_irqsave(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2063
2064
  		cnow = info->icount;
  		set_current_state(TASK_INTERRUPTIBLE);
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2065
  		spin_unlock_irqrestore(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
  
  		/* if no change, wait aborted for some reason */
  		if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
  		    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) {
  			rc = -EIO;
  			break;
  		}
  
  		/* check for change in caller specified modem input */
  		if ((arg & TIOCM_RNG && cnow.rng != cprev.rng) ||
  		    (arg & TIOCM_DSR && cnow.dsr != cprev.dsr) ||
  		    (arg & TIOCM_CD  && cnow.dcd != cprev.dcd) ||
  		    (arg & TIOCM_CTS && cnow.cts != cprev.cts)) {
  			rc = 0;
  			break;
  		}
  
  		cprev = cnow;
  	}
  	remove_wait_queue(&info->status_event_wait_q, &wait);
  	set_current_state(TASK_RUNNING);
  	return rc;
  }
  
  /* return the state of the serial control and status signals
   */
60b33c133   Alan Cox   tiocmget: kill of...
2092
  static int tiocmget(struct tty_struct *tty)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2093
2094
2095
  {
  	MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
  	unsigned int result;
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2096
  	unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2097

3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2098
2099
2100
  	spin_lock_irqsave(&info->lock, flags);
  	get_signals(info);
  	spin_unlock_irqrestore(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
  
  	result = ((info->serial_signals & SerialSignal_RTS) ? TIOCM_RTS:0) +
  		((info->serial_signals & SerialSignal_DTR) ? TIOCM_DTR:0) +
  		((info->serial_signals & SerialSignal_DCD) ? TIOCM_CAR:0) +
  		((info->serial_signals & SerialSignal_RI)  ? TIOCM_RNG:0) +
  		((info->serial_signals & SerialSignal_DSR) ? TIOCM_DSR:0) +
  		((info->serial_signals & SerialSignal_CTS) ? TIOCM_CTS:0);
  
  	if (debug_level >= DEBUG_LEVEL_INFO)
  		printk("%s(%d):%s tiocmget() value=%08X
  ",
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2112
  			 __FILE__, __LINE__, info->device_name, result);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2113
2114
2115
2116
2117
  	return result;
  }
  
  /* set modem control signals (DTR/RTS)
   */
20b9d1771   Alan Cox   tiocmset: kill th...
2118
  static int tiocmset(struct tty_struct *tty,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2119
2120
2121
  		    unsigned int set, unsigned int clear)
  {
  	MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2122
  	unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2123
2124
2125
2126
  
  	if (debug_level >= DEBUG_LEVEL_INFO)
  		printk("%s(%d):%s tiocmset(%x,%x)
  ",
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2127
  			__FILE__, __LINE__, info->device_name, set, clear);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2128
2129
2130
2131
2132
2133
2134
2135
2136
  
  	if (set & TIOCM_RTS)
  		info->serial_signals |= SerialSignal_RTS;
  	if (set & TIOCM_DTR)
  		info->serial_signals |= SerialSignal_DTR;
  	if (clear & TIOCM_RTS)
  		info->serial_signals &= ~SerialSignal_RTS;
  	if (clear & TIOCM_DTR)
  		info->serial_signals &= ~SerialSignal_DTR;
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2137
2138
2139
  	spin_lock_irqsave(&info->lock, flags);
  	set_signals(info);
  	spin_unlock_irqrestore(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2140
2141
2142
2143
2144
2145
2146
2147
2148
  
  	return 0;
  }
  
  /* Set or clear transmit break condition
   *
   * Arguments:		tty		pointer to tty instance data
   *			break_state	-1=set break condition, 0=clear
   */
9e98966c7   Alan Cox   tty: rework break...
2149
  static int mgslpc_break(struct tty_struct *tty, int break_state)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2150
2151
2152
  {
  	MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data;
  	unsigned long flags;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2153

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2154
2155
2156
  	if (debug_level >= DEBUG_LEVEL_INFO)
  		printk("%s(%d):mgslpc_break(%s,%d)
  ",
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2157
  			 __FILE__, __LINE__, info->device_name, break_state);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2158

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2159
  	if (mgslpc_paranoia_check(info, tty->name, "mgslpc_break"))
9e98966c7   Alan Cox   tty: rework break...
2160
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2161

3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2162
2163
  	spin_lock_irqsave(&info->lock, flags);
  	if (break_state == -1)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2164
  		set_reg_bits(info, CHA+DAFO, BIT6);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2165
  	else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2166
  		clear_reg_bits(info, CHA+DAFO, BIT6);
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2167
  	spin_unlock_irqrestore(&info->lock, flags);
9e98966c7   Alan Cox   tty: rework break...
2168
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2169
  }
0587102cf   Alan Cox   tty: icount chang...
2170
2171
2172
2173
2174
2175
  static int mgslpc_get_icount(struct tty_struct *tty,
  				struct serial_icounter_struct *icount)
  {
  	MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data;
  	struct mgsl_icount cnow;	/* kernel counter temps */
  	unsigned long flags;
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2176
  	spin_lock_irqsave(&info->lock, flags);
0587102cf   Alan Cox   tty: icount chang...
2177
  	cnow = info->icount;
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2178
  	spin_unlock_irqrestore(&info->lock, flags);
0587102cf   Alan Cox   tty: icount chang...
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
  
  	icount->cts = cnow.cts;
  	icount->dsr = cnow.dsr;
  	icount->rng = cnow.rng;
  	icount->dcd = cnow.dcd;
  	icount->rx = cnow.rx;
  	icount->tx = cnow.tx;
  	icount->frame = cnow.frame;
  	icount->overrun = cnow.overrun;
  	icount->parity = cnow.parity;
  	icount->brk = cnow.brk;
  	icount->buf_overrun = cnow.buf_overrun;
  
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2194
  /* Service an IOCTL request
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2195
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2196
   * Arguments:
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2197
   *
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2198
2199
2200
   *	tty	pointer to tty instance data
   *	cmd	IOCTL command code
   *	arg	command argument/context
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2201
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2202
2203
   * Return Value:	0 if success, otherwise error code
   */
751b3840d   Axel Lin   pcmcia: synclink_...
2204
  static int mgslpc_ioctl(struct tty_struct *tty,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2205
2206
2207
  			unsigned int cmd, unsigned long arg)
  {
  	MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data;
eeb461343   Alan Cox   synclink_cs: Conv...
2208
  	void __user *argp = (void __user *)arg;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2209

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2210
  	if (debug_level >= DEBUG_LEVEL_INFO)
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2211
2212
2213
  		printk("%s(%d):mgslpc_ioctl %s cmd=%08X
  ", __FILE__, __LINE__,
  			info->device_name, cmd);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2214

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2215
2216
2217
2218
  	if (mgslpc_paranoia_check(info, tty->name, "mgslpc_ioctl"))
  		return -ENODEV;
  
  	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
0587102cf   Alan Cox   tty: icount chang...
2219
  	    (cmd != TIOCMIWAIT)) {
18900ca65   Peter Hurley   tty: Replace TTY_...
2220
  		if (tty_io_error(tty))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2221
2222
  		    return -EIO;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2223
2224
2225
2226
  	switch (cmd) {
  	case MGSL_IOCGPARAMS:
  		return get_params(info, argp);
  	case MGSL_IOCSPARAMS:
eeb461343   Alan Cox   synclink_cs: Conv...
2227
  		return set_params(info, argp, tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2228
2229
2230
2231
2232
2233
2234
2235
2236
  	case MGSL_IOCGTXIDLE:
  		return get_txidle(info, argp);
  	case MGSL_IOCSTXIDLE:
  		return set_txidle(info, (int)arg);
  	case MGSL_IOCGIF:
  		return get_interface(info, argp);
  	case MGSL_IOCSIF:
  		return set_interface(info,(int)arg);
  	case MGSL_IOCTXENABLE:
eeb461343   Alan Cox   synclink_cs: Conv...
2237
  		return set_txenable(info,(int)arg, tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
  	case MGSL_IOCRXENABLE:
  		return set_rxenable(info,(int)arg);
  	case MGSL_IOCTXABORT:
  		return tx_abort(info);
  	case MGSL_IOCGSTATS:
  		return get_stats(info, argp);
  	case MGSL_IOCWAITEVENT:
  		return wait_events(info, argp);
  	case TIOCMIWAIT:
  		return modem_input_wait(info,(int)arg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2248
2249
2250
2251
2252
2253
2254
  	default:
  		return -ENOIOCTLCMD;
  	}
  	return 0;
  }
  
  /* Set new termios settings
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2255
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2256
   * Arguments:
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2257
   *
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2258
2259
   *	tty		pointer to tty structure
   *	termios		pointer to buffer to hold returned old termios
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2260
   */
606d099cd   Alan Cox   [PATCH] tty: swit...
2261
  static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2262
2263
2264
  {
  	MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
  	unsigned long flags;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2265

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2266
  	if (debug_level >= DEBUG_LEVEL_INFO)
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2267
2268
2269
  		printk("%s(%d):mgslpc_set_termios %s
  ", __FILE__, __LINE__,
  			tty->driver->name);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2270

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2271
  	/* just return if nothing has changed */
373f5aedb   Alan Cox   pcmcia,synclink_c...
2272
2273
  	if ((tty->termios.c_cflag == old_termios->c_cflag)
  	    && (RELEVANT_IFLAG(tty->termios.c_iflag)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2274
2275
  		== RELEVANT_IFLAG(old_termios->c_iflag)))
  	  return;
eeb461343   Alan Cox   synclink_cs: Conv...
2276
  	mgslpc_change_params(info, tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2277
2278
  
  	/* Handle transition to B0 status */
9db276f8f   Peter Hurley   tty: Use termios ...
2279
  	if ((old_termios->c_cflag & CBAUD) && !C_BAUD(tty)) {
9fe8074b8   Joe Perches   TTY: synclink: Co...
2280
  		info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR);
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2281
2282
2283
  		spin_lock_irqsave(&info->lock, flags);
  		set_signals(info);
  		spin_unlock_irqrestore(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2284
  	}
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2285

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2286
  	/* Handle transition away from B0 status */
9db276f8f   Peter Hurley   tty: Use termios ...
2287
  	if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2288
  		info->serial_signals |= SerialSignal_DTR;
97ef38b82   Peter Hurley   tty: Replace TTY_...
2289
  		if (!C_CRTSCTS(tty) || !tty_throttled(tty))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2290
  			info->serial_signals |= SerialSignal_RTS;
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2291
2292
2293
  		spin_lock_irqsave(&info->lock, flags);
  		set_signals(info);
  		spin_unlock_irqrestore(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2294
  	}
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2295

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2296
  	/* Handle turning off CRTSCTS */
9db276f8f   Peter Hurley   tty: Use termios ...
2297
  	if (old_termios->c_cflag & CRTSCTS && !C_CRTSCTS(tty)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2298
2299
2300
2301
2302
2303
2304
2305
  		tty->hw_stopped = 0;
  		tx_release(tty);
  	}
  }
  
  static void mgslpc_close(struct tty_struct *tty, struct file * filp)
  {
  	MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data;
eeb461343   Alan Cox   synclink_cs: Conv...
2306
  	struct tty_port *port = &info->port;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2307
2308
2309
  
  	if (mgslpc_paranoia_check(info, tty->name, "mgslpc_close"))
  		return;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2310

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2311
2312
2313
  	if (debug_level >= DEBUG_LEVEL_INFO)
  		printk("%s(%d):mgslpc_close(%s) entry, count=%d
  ",
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2314
  			 __FILE__, __LINE__, info->device_name, port->count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2315

eeb461343   Alan Cox   synclink_cs: Conv...
2316
  	if (tty_port_close_start(port, tty, filp) == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2317
  		goto cleanup;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2318

d41861ca1   Peter Hurley   tty: Replace ASYN...
2319
  	if (tty_port_initialized(port))
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2320
  		mgslpc_wait_until_sent(tty, info->timeout);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2321

978e595f8   Alan Cox   tty/serial: lay t...
2322
  	mgslpc_flush_buffer(tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2323

978e595f8   Alan Cox   tty/serial: lay t...
2324
  	tty_ldisc_flush(tty);
eeb461343   Alan Cox   synclink_cs: Conv...
2325
2326
2327
2328
  	shutdown(info, tty);
  	
  	tty_port_close_end(port, tty);
  	tty_port_tty_set(port, NULL);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2329
  cleanup:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2330
  	if (debug_level >= DEBUG_LEVEL_INFO)
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2331
2332
  		printk("%s(%d):mgslpc_close(%s) exit, count=%d
  ", __FILE__, __LINE__,
eeb461343   Alan Cox   synclink_cs: Conv...
2333
  			tty->driver->name, port->count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2334
2335
2336
2337
2338
2339
2340
2341
  }
  
  /* Wait until the transmitter is empty.
   */
  static void mgslpc_wait_until_sent(struct tty_struct *tty, int timeout)
  {
  	MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data;
  	unsigned long orig_jiffies, char_time;
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2342
  	if (!info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2343
2344
2345
2346
2347
  		return;
  
  	if (debug_level >= DEBUG_LEVEL_INFO)
  		printk("%s(%d):mgslpc_wait_until_sent(%s) entry
  ",
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2348
  			 __FILE__, __LINE__, info->device_name);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2349

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2350
2351
  	if (mgslpc_paranoia_check(info, tty->name, "mgslpc_wait_until_sent"))
  		return;
d41861ca1   Peter Hurley   tty: Replace ASYN...
2352
  	if (!tty_port_initialized(&info->port))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2353
  		goto exit;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2354

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2355
  	orig_jiffies = jiffies;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2356

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2357
2358
2359
2360
  	/* Set check interval to 1/5 of estimated time to
  	 * send a character, and make it at least 1. The check
  	 * interval should also be less than the timeout.
  	 * Note: use tight timings here to satisfy the NIST-PCTS.
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2361
  	 */
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2362
2363
  	if (info->params.data_rate) {
  	     	char_time = info->timeout/(32 * 5);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2364
2365
2366
2367
  		if (!char_time)
  			char_time++;
  	} else
  		char_time = 1;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2368

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2369
2370
  	if (timeout)
  		char_time = min_t(unsigned long, char_time, timeout);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2371

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
  	if (info->params.mode == MGSL_MODE_HDLC) {
  		while (info->tx_active) {
  			msleep_interruptible(jiffies_to_msecs(char_time));
  			if (signal_pending(current))
  				break;
  			if (timeout && time_after(jiffies, orig_jiffies + timeout))
  				break;
  		}
  	} else {
  		while ((info->tx_count || info->tx_active) &&
  			info->tx_enabled) {
  			msleep_interruptible(jiffies_to_msecs(char_time));
  			if (signal_pending(current))
  				break;
  			if (timeout && time_after(jiffies, orig_jiffies + timeout))
  				break;
  		}
  	}
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2390

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2391
2392
2393
2394
  exit:
  	if (debug_level >= DEBUG_LEVEL_INFO)
  		printk("%s(%d):mgslpc_wait_until_sent(%s) exit
  ",
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2395
  			 __FILE__, __LINE__, info->device_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2396
2397
2398
2399
2400
2401
2402
2403
  }
  
  /* Called by tty_hangup() when a hangup is signaled.
   * This is the same as closing all open files for the port.
   */
  static void mgslpc_hangup(struct tty_struct *tty)
  {
  	MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2404

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2405
2406
2407
  	if (debug_level >= DEBUG_LEVEL_INFO)
  		printk("%s(%d):mgslpc_hangup(%s)
  ",
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2408
  			 __FILE__, __LINE__, info->device_name);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2409

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2410
2411
2412
2413
  	if (mgslpc_paranoia_check(info, tty->name, "mgslpc_hangup"))
  		return;
  
  	mgslpc_flush_buffer(tty);
eeb461343   Alan Cox   synclink_cs: Conv...
2414
2415
  	shutdown(info, tty);
  	tty_port_hangup(&info->port);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2416
  }
eeb461343   Alan Cox   synclink_cs: Conv...
2417
  static int carrier_raised(struct tty_port *port)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2418
  {
eeb461343   Alan Cox   synclink_cs: Conv...
2419
2420
  	MGSLPC_INFO *info = container_of(port, MGSLPC_INFO, port);
  	unsigned long flags;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2421

3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2422
2423
2424
  	spin_lock_irqsave(&info->lock, flags);
  	get_signals(info);
  	spin_unlock_irqrestore(&info->lock, flags);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2425

eeb461343   Alan Cox   synclink_cs: Conv...
2426
2427
2428
2429
  	if (info->serial_signals & SerialSignal_DCD)
  		return 1;
  	return 0;
  }
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2430

fcc8ac182   Alan Cox   tty: Add carrier ...
2431
  static void dtr_rts(struct tty_port *port, int onoff)
eeb461343   Alan Cox   synclink_cs: Conv...
2432
2433
2434
  {
  	MGSLPC_INFO *info = container_of(port, MGSLPC_INFO, port);
  	unsigned long flags;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2435

3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2436
  	spin_lock_irqsave(&info->lock, flags);
fcc8ac182   Alan Cox   tty: Add carrier ...
2437
  	if (onoff)
9fe8074b8   Joe Perches   TTY: synclink: Co...
2438
  		info->serial_signals |= SerialSignal_RTS | SerialSignal_DTR;
fcc8ac182   Alan Cox   tty: Add carrier ...
2439
  	else
9fe8074b8   Joe Perches   TTY: synclink: Co...
2440
  		info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR);
eeb461343   Alan Cox   synclink_cs: Conv...
2441
  	set_signals(info);
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2442
  	spin_unlock_irqrestore(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2443
  }
eeb461343   Alan Cox   synclink_cs: Conv...
2444

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2445
2446
2447
  static int mgslpc_open(struct tty_struct *tty, struct file * filp)
  {
  	MGSLPC_INFO	*info;
eeb461343   Alan Cox   synclink_cs: Conv...
2448
  	struct tty_port *port;
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2449
2450
  	int		retval, line;
  	unsigned long	flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2451

d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2452
  	/* verify range of specified line number */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2453
  	line = tty->index;
410235fd4   Jiri Slaby   TTY: remove unnee...
2454
  	if (line >= mgslpc_device_count) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2455
2456
  		printk("%s(%d):mgslpc_open with invalid line #%d.
  ",
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2457
  			__FILE__, __LINE__, line);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2458
2459
2460
2461
2462
2463
2464
2465
2466
  		return -ENODEV;
  	}
  
  	/* find the info structure for the specified line */
  	info = mgslpc_device_list;
  	while(info && info->line != line)
  		info = info->next_device;
  	if (mgslpc_paranoia_check(info, tty->name, "mgslpc_open"))
  		return -ENODEV;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2467

eeb461343   Alan Cox   synclink_cs: Conv...
2468
  	port = &info->port;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2469
  	tty->driver_data = info;
eeb461343   Alan Cox   synclink_cs: Conv...
2470
  	tty_port_tty_set(port, tty);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2471

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2472
2473
2474
  	if (debug_level >= DEBUG_LEVEL_INFO)
  		printk("%s(%d):mgslpc_open(%s), old ref count = %d
  ",
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2475
  			 __FILE__, __LINE__, tty->driver->name, port->count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2476

d6c53c0e9   Jiri Slaby   TTY: move low_lat...
2477
  	port->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2478
2479
2480
2481
2482
2483
2484
  
  	spin_lock_irqsave(&info->netlock, flags);
  	if (info->netcount) {
  		retval = -EBUSY;
  		spin_unlock_irqrestore(&info->netlock, flags);
  		goto cleanup;
  	}
eeb461343   Alan Cox   synclink_cs: Conv...
2485
2486
2487
  	spin_lock(&port->lock);
  	port->count++;
  	spin_unlock(&port->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2488
  	spin_unlock_irqrestore(&info->netlock, flags);
eeb461343   Alan Cox   synclink_cs: Conv...
2489
  	if (port->count == 1) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2490
  		/* 1st open on this device, init hardware */
eeb461343   Alan Cox   synclink_cs: Conv...
2491
  		retval = startup(info, tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2492
2493
2494
  		if (retval < 0)
  			goto cleanup;
  	}
eeb461343   Alan Cox   synclink_cs: Conv...
2495
  	retval = tty_port_block_til_ready(&info->port, tty, filp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2496
2497
2498
2499
  	if (retval) {
  		if (debug_level >= DEBUG_LEVEL_INFO)
  			printk("%s(%d):block_til_ready(%s) returned %d
  ",
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2500
  				 __FILE__, __LINE__, info->device_name, retval);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2501
2502
2503
2504
2505
2506
  		goto cleanup;
  	}
  
  	if (debug_level >= DEBUG_LEVEL_INFO)
  		printk("%s(%d):mgslpc_open(%s) success
  ",
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2507
  			 __FILE__, __LINE__, info->device_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2508
  	retval = 0;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2509
2510
  
  cleanup:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2511
2512
2513
2514
2515
2516
  	return retval;
  }
  
  /*
   * /proc fs routines....
   */
87687144b   Alexey Dobriyan   proc tty: switch ...
2517
  static inline void line_info(struct seq_file *m, MGSLPC_INFO *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2518
2519
  {
  	char	stat_buf[30];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2520
  	unsigned long flags;
87687144b   Alexey Dobriyan   proc tty: switch ...
2521
  	seq_printf(m, "%s:io:%04X irq:%d",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2522
2523
2524
  		      info->device_name, info->io_base, info->irq_level);
  
  	/* output current serial signal states */
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2525
2526
2527
  	spin_lock_irqsave(&info->lock, flags);
  	get_signals(info);
  	spin_unlock_irqrestore(&info->lock, flags);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2528

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
  	stat_buf[0] = 0;
  	stat_buf[1] = 0;
  	if (info->serial_signals & SerialSignal_RTS)
  		strcat(stat_buf, "|RTS");
  	if (info->serial_signals & SerialSignal_CTS)
  		strcat(stat_buf, "|CTS");
  	if (info->serial_signals & SerialSignal_DTR)
  		strcat(stat_buf, "|DTR");
  	if (info->serial_signals & SerialSignal_DSR)
  		strcat(stat_buf, "|DSR");
  	if (info->serial_signals & SerialSignal_DCD)
  		strcat(stat_buf, "|CD");
  	if (info->serial_signals & SerialSignal_RI)
  		strcat(stat_buf, "|RI");
  
  	if (info->params.mode == MGSL_MODE_HDLC) {
87687144b   Alexey Dobriyan   proc tty: switch ...
2545
  		seq_printf(m, " HDLC txok:%d rxok:%d",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2546
2547
  			      info->icount.txok, info->icount.rxok);
  		if (info->icount.txunder)
87687144b   Alexey Dobriyan   proc tty: switch ...
2548
  			seq_printf(m, " txunder:%d", info->icount.txunder);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2549
  		if (info->icount.txabort)
87687144b   Alexey Dobriyan   proc tty: switch ...
2550
  			seq_printf(m, " txabort:%d", info->icount.txabort);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2551
  		if (info->icount.rxshort)
87687144b   Alexey Dobriyan   proc tty: switch ...
2552
  			seq_printf(m, " rxshort:%d", info->icount.rxshort);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2553
  		if (info->icount.rxlong)
87687144b   Alexey Dobriyan   proc tty: switch ...
2554
  			seq_printf(m, " rxlong:%d", info->icount.rxlong);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2555
  		if (info->icount.rxover)
87687144b   Alexey Dobriyan   proc tty: switch ...
2556
  			seq_printf(m, " rxover:%d", info->icount.rxover);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2557
  		if (info->icount.rxcrc)
87687144b   Alexey Dobriyan   proc tty: switch ...
2558
  			seq_printf(m, " rxcrc:%d", info->icount.rxcrc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2559
  	} else {
87687144b   Alexey Dobriyan   proc tty: switch ...
2560
  		seq_printf(m, " ASYNC tx:%d rx:%d",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2561
2562
  			      info->icount.tx, info->icount.rx);
  		if (info->icount.frame)
87687144b   Alexey Dobriyan   proc tty: switch ...
2563
  			seq_printf(m, " fe:%d", info->icount.frame);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2564
  		if (info->icount.parity)
87687144b   Alexey Dobriyan   proc tty: switch ...
2565
  			seq_printf(m, " pe:%d", info->icount.parity);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2566
  		if (info->icount.brk)
87687144b   Alexey Dobriyan   proc tty: switch ...
2567
  			seq_printf(m, " brk:%d", info->icount.brk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2568
  		if (info->icount.overrun)
87687144b   Alexey Dobriyan   proc tty: switch ...
2569
  			seq_printf(m, " oe:%d", info->icount.overrun);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2570
  	}
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2571

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2572
  	/* Append serial signal status to end */
87687144b   Alexey Dobriyan   proc tty: switch ...
2573
2574
  	seq_printf(m, " %s
  ", stat_buf+1);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2575

87687144b   Alexey Dobriyan   proc tty: switch ...
2576
2577
  	seq_printf(m, "txactive=%d bh_req=%d bh_run=%d pending_bh=%x
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2578
2579
  		       info->tx_active,info->bh_requested,info->bh_running,
  		       info->pending_bh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2580
2581
2582
2583
  }
  
  /* Called to print information about devices
   */
87687144b   Alexey Dobriyan   proc tty: switch ...
2584
  static int mgslpc_proc_show(struct seq_file *m, void *v)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2585
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2586
  	MGSLPC_INFO *info;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2587

87687144b   Alexey Dobriyan   proc tty: switch ...
2588
2589
  	seq_printf(m, "synclink driver:%s
  ", driver_version);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2590

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2591
  	info = mgslpc_device_list;
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2592
  	while (info) {
87687144b   Alexey Dobriyan   proc tty: switch ...
2593
  		line_info(m, info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2594
2595
  		info = info->next_device;
  	}
87687144b   Alexey Dobriyan   proc tty: switch ...
2596
2597
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2598

87687144b   Alexey Dobriyan   proc tty: switch ...
2599
2600
2601
  static int mgslpc_proc_open(struct inode *inode, struct file *file)
  {
  	return single_open(file, mgslpc_proc_show, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2602
  }
87687144b   Alexey Dobriyan   proc tty: switch ...
2603
2604
2605
2606
2607
2608
2609
  static const struct file_operations mgslpc_proc_fops = {
  	.owner		= THIS_MODULE,
  	.open		= mgslpc_proc_open,
  	.read		= seq_read,
  	.llseek		= seq_lseek,
  	.release	= single_release,
  };
cdaad343b   Peter Hagervall   [PATCH] Sparse fi...
2610
  static int rx_alloc_buffers(MGSLPC_INFO *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
  {
  	/* each buffer has header and data */
  	info->rx_buf_size = sizeof(RXBUF) + info->max_frame_size;
  
  	/* calculate total allocation size for 8 buffers */
  	info->rx_buf_total_size = info->rx_buf_size * 8;
  
  	/* limit total allocated memory */
  	if (info->rx_buf_total_size > 0x10000)
  		info->rx_buf_total_size = 0x10000;
  
  	/* calculate number of buffers */
  	info->rx_buf_count = info->rx_buf_total_size / info->rx_buf_size;
  
  	info->rx_buf = kmalloc(info->rx_buf_total_size, GFP_KERNEL);
  	if (info->rx_buf == NULL)
  		return -ENOMEM;
a6b68a69f   Paul Fulghum   synclink fix ldis...
2628
2629
2630
2631
2632
2633
2634
2635
  	/* unused flag buffer to satisfy receive_buf calling interface */
  	info->flag_buf = kzalloc(info->max_frame_size, GFP_KERNEL);
  	if (!info->flag_buf) {
  		kfree(info->rx_buf);
  		info->rx_buf = NULL;
  		return -ENOMEM;
  	}
  	
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2636
2637
2638
  	rx_reset_buffers(info);
  	return 0;
  }
cdaad343b   Peter Hagervall   [PATCH] Sparse fi...
2639
  static void rx_free_buffers(MGSLPC_INFO *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2640
  {
735d5661d   Jesper Juhl   [PATCH] kfree cle...
2641
  	kfree(info->rx_buf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2642
  	info->rx_buf = NULL;
a6b68a69f   Paul Fulghum   synclink fix ldis...
2643
2644
  	kfree(info->flag_buf);
  	info->flag_buf = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2645
  }
cdaad343b   Peter Hagervall   [PATCH] Sparse fi...
2646
  static int claim_resources(MGSLPC_INFO *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2647
  {
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2648
2649
2650
  	if (rx_alloc_buffers(info) < 0) {
  		printk("Can't allocate rx buffer %s
  ", info->device_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2651
2652
  		release_resources(info);
  		return -ENODEV;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2653
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2654
2655
  	return 0;
  }
cdaad343b   Peter Hagervall   [PATCH] Sparse fi...
2656
  static void release_resources(MGSLPC_INFO *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2657
2658
2659
2660
2661
2662
2663
2664
2665
  {
  	if (debug_level >= DEBUG_LEVEL_INFO)
  		printk("release_resources(%s)
  ", info->device_name);
  	rx_free_buffers(info);
  }
  
  /* Add the specified device instance data structure to the
   * global linked list of devices and increment the device count.
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2666
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2667
2668
   * Arguments:		info	pointer to device instance data
   */
d34138d05   Alexey Khoroshilov   pcmcia: synclink_...
2669
  static int mgslpc_add_device(MGSLPC_INFO *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2670
  {
d34138d05   Alexey Khoroshilov   pcmcia: synclink_...
2671
2672
2673
  	MGSLPC_INFO *current_dev = NULL;
  	struct device *tty_dev;
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2674
2675
2676
  	info->next_device = NULL;
  	info->line = mgslpc_device_count;
  	sprintf(info->device_name,"ttySLP%d",info->line);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2677

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2678
2679
2680
  	if (info->line < MAX_DEVICE_COUNT) {
  		if (maxframe[info->line])
  			info->max_frame_size = maxframe[info->line];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2681
2682
2683
  	}
  
  	mgslpc_device_count++;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2684

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2685
2686
  	if (!mgslpc_device_list)
  		mgslpc_device_list = info;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2687
  	else {
d34138d05   Alexey Khoroshilov   pcmcia: synclink_...
2688
  		current_dev = mgslpc_device_list;
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2689
  		while (current_dev->next_device)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2690
2691
2692
  			current_dev = current_dev->next_device;
  		current_dev->next_device = info;
  	}
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2693

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2694
2695
2696
2697
  	if (info->max_frame_size < 4096)
  		info->max_frame_size = 4096;
  	else if (info->max_frame_size > 65535)
  		info->max_frame_size = 65535;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2698

3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
2699
2700
  	printk("SyncLink PC Card %s:IO=%04X IRQ=%d
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2701
  		info->device_name, info->io_base, info->irq_level);
af69c7f92   Paul Fulghum   [PATCH] generic H...
2702
  #if SYNCLINK_GENERIC_HDLC
d34138d05   Alexey Khoroshilov   pcmcia: synclink_...
2703
2704
2705
  	ret = hdlcdev_init(info);
  	if (ret != 0)
  		goto failed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2706
  #endif
d34138d05   Alexey Khoroshilov   pcmcia: synclink_...
2707
2708
  
  	tty_dev = tty_port_register_device(&info->port, serial_driver, info->line,
a33ba8274   Jiri Slaby   TTY: synclink_cs,...
2709
  			&info->p_dev->dev);
d34138d05   Alexey Khoroshilov   pcmcia: synclink_...
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
  	if (IS_ERR(tty_dev)) {
  		ret = PTR_ERR(tty_dev);
  #if SYNCLINK_GENERIC_HDLC
  		hdlcdev_exit(info);
  #endif
  		goto failed;
  	}
  
  	return 0;
  
  failed:
  	if (current_dev)
  		current_dev->next_device = NULL;
  	else
  		mgslpc_device_list = NULL;
  	mgslpc_device_count--;
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2727
  }
cdaad343b   Peter Hagervall   [PATCH] Sparse fi...
2728
  static void mgslpc_remove_device(MGSLPC_INFO *remove_info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
  {
  	MGSLPC_INFO *info = mgslpc_device_list;
  	MGSLPC_INFO *last = NULL;
  
  	while(info) {
  		if (info == remove_info) {
  			if (last)
  				last->next_device = info->next_device;
  			else
  				mgslpc_device_list = info->next_device;
16a1065f2   Jiri Slaby   TTY: synclink_cs,...
2739
  			tty_unregister_device(serial_driver, info->line);
af69c7f92   Paul Fulghum   [PATCH] generic H...
2740
  #if SYNCLINK_GENERIC_HDLC
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2741
2742
2743
  			hdlcdev_exit(info);
  #endif
  			release_resources(info);
191c5f102   Jiri Slaby   TTY: call tty_por...
2744
  			tty_port_destroy(&info->port);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2745
2746
2747
2748
2749
2750
2751
2752
  			kfree(info);
  			mgslpc_device_count--;
  			return;
  		}
  		last = info;
  		info = info->next_device;
  	}
  }
25f8f54f6   Joe Perches   pcmcia: Convert p...
2753
  static const struct pcmcia_device_id mgslpc_ids[] = {
4af48c8c1   Dominik Brodowski   [PATCH] pcmcia: i...
2754
2755
2756
2757
  	PCMCIA_DEVICE_MANF_CARD(0x02c5, 0x0050),
  	PCMCIA_DEVICE_NULL
  };
  MODULE_DEVICE_TABLE(pcmcia, mgslpc_ids);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2758
2759
  static struct pcmcia_driver mgslpc_driver = {
  	.owner		= THIS_MODULE,
2e9b981a7   Dominik Brodowski   pcmcia: move driv...
2760
  	.name		= "synclink_cs",
15b99ac17   Dominik Brodowski   [PATCH] pcmcia: a...
2761
  	.probe		= mgslpc_probe,
cc3b4866b   Dominik Brodowski   [PATCH] pcmcia: u...
2762
  	.remove		= mgslpc_detach,
4af48c8c1   Dominik Brodowski   [PATCH] pcmcia: i...
2763
  	.id_table	= mgslpc_ids,
98e4c28b7   Dominik Brodowski   [PATCH] pcmcia: n...
2764
2765
  	.suspend	= mgslpc_suspend,
  	.resume		= mgslpc_resume,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2766
  };
b68e31d0e   Jeff Dike   [PATCH] const str...
2767
  static const struct tty_operations mgslpc_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
  	.open = mgslpc_open,
  	.close = mgslpc_close,
  	.write = mgslpc_write,
  	.put_char = mgslpc_put_char,
  	.flush_chars = mgslpc_flush_chars,
  	.write_room = mgslpc_write_room,
  	.chars_in_buffer = mgslpc_chars_in_buffer,
  	.flush_buffer = mgslpc_flush_buffer,
  	.ioctl = mgslpc_ioctl,
  	.throttle = mgslpc_throttle,
  	.unthrottle = mgslpc_unthrottle,
  	.send_xchar = mgslpc_send_xchar,
  	.break_ctl = mgslpc_break,
  	.wait_until_sent = mgslpc_wait_until_sent,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2782
2783
2784
2785
2786
2787
  	.set_termios = mgslpc_set_termios,
  	.stop = tx_pause,
  	.start = tx_release,
  	.hangup = mgslpc_hangup,
  	.tiocmget = tiocmget,
  	.tiocmset = tiocmset,
dc98d9650   Andres Salomon   tty: fix warning ...
2788
  	.get_icount = mgslpc_get_icount,
87687144b   Alexey Dobriyan   proc tty: switch ...
2789
  	.proc_fops = &mgslpc_proc_fops,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2790
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2791
  static int __init synclink_cs_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2792
2793
  {
  	int rc;
cc93441ee   Jiri Slaby   TTY: synclink_cs,...
2794
2795
2796
  	if (break_on_load) {
  		mgslpc_get_text_ptr();
  		BREAKPOINT();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2797
  	}
cc93441ee   Jiri Slaby   TTY: synclink_cs,...
2798
2799
2800
  	serial_driver = tty_alloc_driver(MAX_DEVICE_COUNT,
  			TTY_DRIVER_REAL_RAW |
  			TTY_DRIVER_DYNAMIC_DEV);
c3a6344ae   Dan Carpenter   TTY: tty_alloc_dr...
2801
2802
  	if (IS_ERR(serial_driver)) {
  		rc = PTR_ERR(serial_driver);
cc93441ee   Jiri Slaby   TTY: synclink_cs,...
2803
2804
  		goto err;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2805

cc93441ee   Jiri Slaby   TTY: synclink_cs,...
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
  	/* Initialize the tty_driver structure */
  	serial_driver->driver_name = "synclink_cs";
  	serial_driver->name = "ttySLP";
  	serial_driver->major = ttymajor;
  	serial_driver->minor_start = 64;
  	serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
  	serial_driver->subtype = SERIAL_TYPE_NORMAL;
  	serial_driver->init_termios = tty_std_termios;
  	serial_driver->init_termios.c_cflag =
  	B9600 | CS8 | CREAD | HUPCL | CLOCAL;
  	tty_set_operations(serial_driver, &mgslpc_ops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2817

cc93441ee   Jiri Slaby   TTY: synclink_cs,...
2818
2819
2820
2821
2822
2823
2824
  	rc = tty_register_driver(serial_driver);
  	if (rc < 0) {
  		printk(KERN_ERR "%s(%d):Couldn't register serial driver
  ",
  				__FILE__, __LINE__);
  		goto err_put_tty;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2825

16a1065f2   Jiri Slaby   TTY: synclink_cs,...
2826
2827
2828
  	rc = pcmcia_register_driver(&mgslpc_driver);
  	if (rc < 0)
  		goto err_unreg_tty;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2829

cc93441ee   Jiri Slaby   TTY: synclink_cs,...
2830
2831
2832
  	printk(KERN_INFO "%s %s, tty major#%d
  ", driver_name, driver_version,
  			serial_driver->major);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2833

737586fe5   Jiri Slaby   TTY: synclink_cs,...
2834
  	return 0;
16a1065f2   Jiri Slaby   TTY: synclink_cs,...
2835
2836
  err_unreg_tty:
  	tty_unregister_driver(serial_driver);
737586fe5   Jiri Slaby   TTY: synclink_cs,...
2837
2838
  err_put_tty:
  	put_tty_driver(serial_driver);
16a1065f2   Jiri Slaby   TTY: synclink_cs,...
2839
  err:
737586fe5   Jiri Slaby   TTY: synclink_cs,...
2840
  	return rc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2841
  }
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2842
  static void __exit synclink_cs_exit(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2843
  {
16a1065f2   Jiri Slaby   TTY: synclink_cs,...
2844
  	pcmcia_unregister_driver(&mgslpc_driver);
737586fe5   Jiri Slaby   TTY: synclink_cs,...
2845
2846
  	tty_unregister_driver(serial_driver);
  	put_tty_driver(serial_driver);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2847
2848
2849
2850
2851
2852
2853
2854
2855
  }
  
  module_init(synclink_cs_init);
  module_exit(synclink_cs_exit);
  
  static void mgslpc_set_rate(MGSLPC_INFO *info, unsigned char channel, unsigned int rate)
  {
  	unsigned int M, N;
  	unsigned char val;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2856
2857
  	/* note:standard BRG mode is broken in V3.2 chip
  	 * so enhanced mode is always used
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
  	 */
  
  	if (rate) {
  		N = 3686400 / rate;
  		if (!N)
  			N = 1;
  		N >>= 1;
  		for (M = 1; N > 64 && M < 16; M++)
  			N >>= 1;
  		N--;
  
  		/* BGR[5..0] = N
  		 * BGR[9..6] = M
  		 * BGR[7..0] contained in BGR register
  		 * BGR[9..8] contained in CCR2[7..6]
  		 * divisor = (N+1)*2^M
  		 *
  		 * Note: M *must* not be zero (causes asymetric duty cycle)
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2876
  		 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
  		write_reg(info, (unsigned char) (channel + BGR),
  				  (unsigned char) ((M << 6) + N));
  		val = read_reg(info, (unsigned char) (channel + CCR2)) & 0x3f;
  		val |= ((M << 4) & 0xc0);
  		write_reg(info, (unsigned char) (channel + CCR2), val);
  	}
  }
  
  /* Enabled the AUX clock output at the specified frequency.
   */
  static void enable_auxclk(MGSLPC_INFO *info)
  {
  	unsigned char val;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2890

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
  	/* MODE
  	 *
  	 * 07..06  MDS[1..0] 10 = transparent HDLC mode
  	 * 05      ADM Address Mode, 0 = no addr recognition
  	 * 04      TMD Timer Mode, 0 = external
  	 * 03      RAC Receiver Active, 0 = inactive
  	 * 02      RTS 0=RTS active during xmit, 1=RTS always active
  	 * 01      TRS Timer Resolution, 1=512
  	 * 00      TLP Test Loop, 0 = no loop
  	 *
  	 * 1000 0010
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2902
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2903
  	val = 0x82;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2904
2905
  
  	/* channel B RTS is used to enable AUXCLK driver on SP505 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2906
2907
2908
  	if (info->params.mode == MGSL_MODE_HDLC && info->params.clock_speed)
  		val |= BIT2;
  	write_reg(info, CHB + MODE, val);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2909

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2910
2911
2912
2913
2914
2915
2916
2917
2918
  	/* CCR0
  	 *
  	 * 07      PU Power Up, 1=active, 0=power down
  	 * 06      MCE Master Clock Enable, 1=enabled
  	 * 05      Reserved, 0
  	 * 04..02  SC[2..0] Encoding
  	 * 01..00  SM[1..0] Serial Mode, 00=HDLC
  	 *
  	 * 11000000
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2919
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2920
  	write_reg(info, CHB + CCR0, 0xc0);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2921

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
  	/* CCR1
  	 *
  	 * 07      SFLG Shared Flag, 0 = disable shared flags
  	 * 06      GALP Go Active On Loop, 0 = not used
  	 * 05      GLP Go On Loop, 0 = not used
  	 * 04      ODS Output Driver Select, 1=TxD is push-pull output
  	 * 03      ITF Interframe Time Fill, 0=mark, 1=flag
  	 * 02..00  CM[2..0] Clock Mode
  	 *
  	 * 0001 0111
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2932
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2933
  	write_reg(info, CHB + CCR1, 0x17);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2934

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
  	/* CCR2 (Channel B)
  	 *
  	 * 07..06  BGR[9..8] Baud rate bits 9..8
  	 * 05      BDF Baud rate divisor factor, 0=1, 1=BGR value
  	 * 04      SSEL Clock source select, 1=submode b
  	 * 03      TOE 0=TxCLK is input, 1=TxCLK is output
  	 * 02      RWX Read/Write Exchange 0=disabled
  	 * 01      C32, CRC select, 0=CRC-16, 1=CRC-32
  	 * 00      DIV, data inversion 0=disabled, 1=enabled
  	 *
  	 * 0011 1000
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2946
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2947
2948
2949
2950
  	if (info->params.mode == MGSL_MODE_HDLC && info->params.clock_speed)
  		write_reg(info, CHB + CCR2, 0x38);
  	else
  		write_reg(info, CHB + CCR2, 0x30);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2951

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
  	/* CCR4
  	 *
  	 * 07      MCK4 Master Clock Divide by 4, 1=enabled
  	 * 06      EBRG Enhanced Baud Rate Generator Mode, 1=enabled
  	 * 05      TST1 Test Pin, 0=normal operation
  	 * 04      ICD Ivert Carrier Detect, 1=enabled (active low)
  	 * 03..02  Reserved, must be 0
  	 * 01..00  RFT[1..0] RxFIFO Threshold 00=32 bytes
  	 *
  	 * 0101 0000
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2962
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2963
  	write_reg(info, CHB + CCR4, 0x50);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2964

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2965
2966
  	/* if auxclk not enabled, set internal BRG so
  	 * CTS transitions can be detected (requires TxC)
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2967
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2968
2969
2970
2971
2972
  	if (info->params.mode == MGSL_MODE_HDLC && info->params.clock_speed)
  		mgslpc_set_rate(info, CHB, info->params.clock_speed);
  	else
  		mgslpc_set_rate(info, CHB, 921600);
  }
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2973
  static void loopback_enable(MGSLPC_INFO *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2974
2975
  {
  	unsigned char val;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2976
2977
  
  	/* CCR1:02..00  CM[2..0] Clock Mode = 111 (clock mode 7) */
ecda040ff   Alexandru Juncu   pcmcia: synclink_...
2978
  	val = read_reg(info, CHA + CCR1) | (BIT2 | BIT1 | BIT0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2979
  	write_reg(info, CHA + CCR1, val);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2980
2981
  
  	/* CCR2:04 SSEL Clock source select, 1=submode b */
ecda040ff   Alexandru Juncu   pcmcia: synclink_...
2982
  	val = read_reg(info, CHA + CCR2) | (BIT4 | BIT5);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2983
  	write_reg(info, CHA + CCR2, val);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2984
2985
  
  	/* set LinkSpeed if available, otherwise default to 2Mbps */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2986
2987
2988
2989
  	if (info->params.clock_speed)
  		mgslpc_set_rate(info, CHA, info->params.clock_speed);
  	else
  		mgslpc_set_rate(info, CHA, 1843200);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2990
2991
  
  	/* MODE:00 TLP Test Loop, 1=loopback enabled */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2992
2993
2994
  	val = read_reg(info, CHA + MODE) | BIT0;
  	write_reg(info, CHA + MODE, val);
  }
cdaad343b   Peter Hagervall   [PATCH] Sparse fi...
2995
  static void hdlc_mode(MGSLPC_INFO *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2996
2997
2998
  {
  	unsigned char val;
  	unsigned char clkmode, clksubmode;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
2999
  	/* disable all interrupts */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3000
3001
3002
  	irq_disable(info, CHA, 0xffff);
  	irq_disable(info, CHB, 0xffff);
  	port_irq_disable(info, 0xff);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3003
3004
  
  	/* assume clock mode 0a, rcv=RxC xmt=TxC */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3005
3006
3007
  	clkmode = clksubmode = 0;
  	if (info->params.flags & HDLC_FLAG_RXC_DPLL
  	    && info->params.flags & HDLC_FLAG_TXC_DPLL) {
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3008
  		/* clock mode 7a, rcv = DPLL, xmt = DPLL */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3009
3010
3011
  		clkmode = 7;
  	} else if (info->params.flags & HDLC_FLAG_RXC_BRG
  		 && info->params.flags & HDLC_FLAG_TXC_BRG) {
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3012
  		/* clock mode 7b, rcv = BRG, xmt = BRG */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3013
3014
3015
3016
  		clkmode = 7;
  		clksubmode = 1;
  	} else if (info->params.flags & HDLC_FLAG_RXC_DPLL) {
  		if (info->params.flags & HDLC_FLAG_TXC_BRG) {
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3017
  			/* clock mode 6b, rcv = DPLL, xmt = BRG/16 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3018
3019
3020
  			clkmode = 6;
  			clksubmode = 1;
  		} else {
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3021
  			/* clock mode 6a, rcv = DPLL, xmt = TxC */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3022
3023
3024
  			clkmode = 6;
  		}
  	} else if (info->params.flags & HDLC_FLAG_TXC_BRG) {
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3025
  		/* clock mode 0b, rcv = RxC, xmt = BRG */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3026
3027
  		clksubmode = 1;
  	}
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3028

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
  	/* MODE
  	 *
  	 * 07..06  MDS[1..0] 10 = transparent HDLC mode
  	 * 05      ADM Address Mode, 0 = no addr recognition
  	 * 04      TMD Timer Mode, 0 = external
  	 * 03      RAC Receiver Active, 0 = inactive
  	 * 02      RTS 0=RTS active during xmit, 1=RTS always active
  	 * 01      TRS Timer Resolution, 1=512
  	 * 00      TLP Test Loop, 0 = no loop
  	 *
  	 * 1000 0010
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3040
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3041
3042
3043
  	val = 0x82;
  	if (info->params.loopback)
  		val |= BIT0;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3044
3045
  
  	/* preserve RTS state */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3046
3047
3048
  	if (info->serial_signals & SerialSignal_RTS)
  		val |= BIT2;
  	write_reg(info, CHA + MODE, val);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3049

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3050
3051
3052
3053
3054
3055
3056
3057
3058
  	/* CCR0
  	 *
  	 * 07      PU Power Up, 1=active, 0=power down
  	 * 06      MCE Master Clock Enable, 1=enabled
  	 * 05      Reserved, 0
  	 * 04..02  SC[2..0] Encoding
  	 * 01..00  SM[1..0] Serial Mode, 00=HDLC
  	 *
  	 * 11000000
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3059
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
  	val = 0xc0;
  	switch (info->params.encoding)
  	{
  	case HDLC_ENCODING_NRZI:
  		val |= BIT3;
  		break;
  	case HDLC_ENCODING_BIPHASE_SPACE:
  		val |= BIT4;
  		break;		// FM0
  	case HDLC_ENCODING_BIPHASE_MARK:
ecda040ff   Alexandru Juncu   pcmcia: synclink_...
3070
  		val |= BIT4 | BIT2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3071
3072
  		break;		// FM1
  	case HDLC_ENCODING_BIPHASE_LEVEL:
ecda040ff   Alexandru Juncu   pcmcia: synclink_...
3073
  		val |= BIT4 | BIT3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3074
3075
3076
  		break;		// Manchester
  	}
  	write_reg(info, CHA + CCR0, val);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3077

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
  	/* CCR1
  	 *
  	 * 07      SFLG Shared Flag, 0 = disable shared flags
  	 * 06      GALP Go Active On Loop, 0 = not used
  	 * 05      GLP Go On Loop, 0 = not used
  	 * 04      ODS Output Driver Select, 1=TxD is push-pull output
  	 * 03      ITF Interframe Time Fill, 0=mark, 1=flag
  	 * 02..00  CM[2..0] Clock Mode
  	 *
  	 * 0001 0000
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3088
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3089
3090
  	val = 0x10 + clkmode;
  	write_reg(info, CHA + CCR1, val);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3091

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
  	/* CCR2
  	 *
  	 * 07..06  BGR[9..8] Baud rate bits 9..8
  	 * 05      BDF Baud rate divisor factor, 0=1, 1=BGR value
  	 * 04      SSEL Clock source select, 1=submode b
  	 * 03      TOE 0=TxCLK is input, 0=TxCLK is input
  	 * 02      RWX Read/Write Exchange 0=disabled
  	 * 01      C32, CRC select, 0=CRC-16, 1=CRC-32
  	 * 00      DIV, data inversion 0=disabled, 1=enabled
  	 *
  	 * 0000 0000
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3103
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
  	val = 0x00;
  	if (clkmode == 2 || clkmode == 3 || clkmode == 6
  	    || clkmode == 7 || (clkmode == 0 && clksubmode == 1))
  		val |= BIT5;
  	if (clksubmode)
  		val |= BIT4;
  	if (info->params.crc_type == HDLC_CRC_32_CCITT)
  		val |= BIT1;
  	if (info->params.encoding == HDLC_ENCODING_NRZB)
  		val |= BIT0;
  	write_reg(info, CHA + CCR2, val);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3115

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
  	/* CCR3
  	 *
  	 * 07..06  PRE[1..0] Preamble count 00=1, 01=2, 10=4, 11=8
  	 * 05      EPT Enable preamble transmission, 1=enabled
  	 * 04      RADD Receive address pushed to FIFO, 0=disabled
  	 * 03      CRL CRC Reset Level, 0=FFFF
  	 * 02      RCRC Rx CRC 0=On 1=Off
  	 * 01      TCRC Tx CRC 0=On 1=Off
  	 * 00      PSD DPLL Phase Shift Disable
  	 *
  	 * 0000 0000
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3127
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3128
3129
  	val = 0x00;
  	if (info->params.crc_type == HDLC_CRC_NONE)
ecda040ff   Alexandru Juncu   pcmcia: synclink_...
3130
  		val |= BIT2 | BIT1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
  	if (info->params.preamble != HDLC_PREAMBLE_PATTERN_NONE)
  		val |= BIT5;
  	switch (info->params.preamble_length)
  	{
  	case HDLC_PREAMBLE_LENGTH_16BITS:
  		val |= BIT6;
  		break;
  	case HDLC_PREAMBLE_LENGTH_32BITS:
  		val |= BIT6;
  		break;
  	case HDLC_PREAMBLE_LENGTH_64BITS:
ecda040ff   Alexandru Juncu   pcmcia: synclink_...
3142
  		val |= BIT7 | BIT6;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3143
3144
3145
  		break;
  	}
  	write_reg(info, CHA + CCR3, val);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3146
3147
  
  	/* PRE - Preamble pattern */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3148
3149
3150
3151
3152
3153
3154
3155
3156
  	val = 0;
  	switch (info->params.preamble)
  	{
  	case HDLC_PREAMBLE_PATTERN_FLAGS: val = 0x7e; break;
  	case HDLC_PREAMBLE_PATTERN_10:    val = 0xaa; break;
  	case HDLC_PREAMBLE_PATTERN_01:    val = 0x55; break;
  	case HDLC_PREAMBLE_PATTERN_ONES:  val = 0xff; break;
  	}
  	write_reg(info, CHA + PRE, val);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3157

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
  	/* CCR4
  	 *
  	 * 07      MCK4 Master Clock Divide by 4, 1=enabled
  	 * 06      EBRG Enhanced Baud Rate Generator Mode, 1=enabled
  	 * 05      TST1 Test Pin, 0=normal operation
  	 * 04      ICD Ivert Carrier Detect, 1=enabled (active low)
  	 * 03..02  Reserved, must be 0
  	 * 01..00  RFT[1..0] RxFIFO Threshold 00=32 bytes
  	 *
  	 * 0101 0000
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3168
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3169
3170
3171
3172
3173
3174
  	val = 0x50;
  	write_reg(info, CHA + CCR4, val);
  	if (info->params.flags & HDLC_FLAG_RXC_DPLL)
  		mgslpc_set_rate(info, CHA, info->params.clock_speed * 16);
  	else
  		mgslpc_set_rate(info, CHA, info->params.clock_speed);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3175

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3176
3177
3178
3179
  	/* RLCR Receive length check register
  	 *
  	 * 7     1=enable receive length check
  	 * 6..0  Max frame length = (RL + 1) * 32
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3180
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3181
  	write_reg(info, CHA + RLCR, 0);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3182

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3183
3184
3185
3186
3187
3188
3189
3190
3191
  	/* XBCH Transmit Byte Count High
  	 *
  	 * 07      DMA mode, 0 = interrupt driven
  	 * 06      NRM, 0=ABM (ignored)
  	 * 05      CAS Carrier Auto Start
  	 * 04      XC Transmit Continuously (ignored)
  	 * 03..00  XBC[10..8] Transmit byte count bits 10..8
  	 *
  	 * 0000 0000
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3192
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
  	val = 0x00;
  	if (info->params.flags & HDLC_FLAG_AUTO_DCD)
  		val |= BIT5;
  	write_reg(info, CHA + XBCH, val);
  	enable_auxclk(info);
  	if (info->params.loopback || info->testing_irq)
  		loopback_enable(info);
  	if (info->params.flags & HDLC_FLAG_AUTO_CTS)
  	{
  		irq_enable(info, CHB, IRQ_CTS);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3203
  		/* PVR[3] 1=AUTO CTS active */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3204
3205
3206
3207
3208
  		set_reg_bits(info, CHA + PVR, BIT3);
  	} else
  		clear_reg_bits(info, CHA + PVR, BIT3);
  
  	irq_enable(info, CHA,
ecda040ff   Alexandru Juncu   pcmcia: synclink_...
3209
3210
  			 IRQ_RXEOM | IRQ_RXFIFO | IRQ_ALLSENT |
  			 IRQ_UNDERRUN | IRQ_TXFIFO);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3211
3212
3213
  	issue_command(info, CHA, CMD_TXRESET + CMD_RXRESET);
  	wait_command_complete(info, CHA);
  	read_reg16(info, CHA + ISR);	/* clear pending IRQs */
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3214

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3215
3216
3217
3218
3219
3220
3221
3222
3223
  	/* Master clock mode enabled above to allow reset commands
  	 * to complete even if no data clocks are present.
  	 *
  	 * Disable master clock mode for normal communications because
  	 * V3.2 of the ESCC2 has a bug that prevents the transmit all sent
  	 * IRQ when in master clock mode.
  	 *
  	 * Leave master clock mode enabled for IRQ test because the
  	 * timer IRQ used by the test can only happen in master clock mode.
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3224
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3225
3226
3227
3228
3229
3230
3231
3232
  	if (!info->testing_irq)
  		clear_reg_bits(info, CHA + CCR0, BIT6);
  
  	tx_set_idle(info);
  
  	tx_stop(info);
  	rx_stop(info);
  }
cdaad343b   Peter Hagervall   [PATCH] Sparse fi...
3233
  static void rx_stop(MGSLPC_INFO *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3234
3235
3236
3237
  {
  	if (debug_level >= DEBUG_LEVEL_ISR)
  		printk("%s(%d):rx_stop(%s)
  ",
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
3238
  			 __FILE__, __LINE__, info->device_name);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3239
3240
  
  	/* MODE:03 RAC Receiver Active, 0=inactive */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3241
  	clear_reg_bits(info, CHA + MODE, BIT3);
0fab6de09   Joe Perches   synclink drivers ...
3242
3243
  	info->rx_enabled = false;
  	info->rx_overflow = false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3244
  }
cdaad343b   Peter Hagervall   [PATCH] Sparse fi...
3245
  static void rx_start(MGSLPC_INFO *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3246
3247
3248
3249
  {
  	if (debug_level >= DEBUG_LEVEL_ISR)
  		printk("%s(%d):rx_start(%s)
  ",
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
3250
  			 __FILE__, __LINE__, info->device_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3251
3252
  
  	rx_reset_buffers(info);
0fab6de09   Joe Perches   synclink drivers ...
3253
3254
  	info->rx_enabled = false;
  	info->rx_overflow = false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3255

d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3256
  	/* MODE:03 RAC Receiver Active, 1=active */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3257
  	set_reg_bits(info, CHA + MODE, BIT3);
0fab6de09   Joe Perches   synclink drivers ...
3258
  	info->rx_enabled = true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3259
  }
eeb461343   Alan Cox   synclink_cs: Conv...
3260
  static void tx_start(MGSLPC_INFO *info, struct tty_struct *tty)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3261
3262
3263
3264
  {
  	if (debug_level >= DEBUG_LEVEL_ISR)
  		printk("%s(%d):tx_start(%s)
  ",
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
3265
  			 __FILE__, __LINE__, info->device_name);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3266

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3267
3268
3269
3270
  	if (info->tx_count) {
  		/* If auto RTS enabled and RTS is inactive, then assert */
  		/* RTS and set a flag indicating that the driver should */
  		/* negate RTS when the transmission completes. */
0fab6de09   Joe Perches   synclink drivers ...
3271
  		info->drop_rts_on_tx_done = false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3272
3273
3274
3275
3276
3277
  
  		if (info->params.flags & HDLC_FLAG_AUTO_RTS) {
  			get_signals(info);
  			if (!(info->serial_signals & SerialSignal_RTS)) {
  				info->serial_signals |= SerialSignal_RTS;
  				set_signals(info);
0fab6de09   Joe Perches   synclink drivers ...
3278
  				info->drop_rts_on_tx_done = true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3279
3280
3281
3282
3283
  			}
  		}
  
  		if (info->params.mode == MGSL_MODE_ASYNC) {
  			if (!info->tx_active) {
0fab6de09   Joe Perches   synclink drivers ...
3284
  				info->tx_active = true;
eeb461343   Alan Cox   synclink_cs: Conv...
3285
  				tx_ready(info, tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3286
3287
  			}
  		} else {
0fab6de09   Joe Perches   synclink drivers ...
3288
  			info->tx_active = true;
eeb461343   Alan Cox   synclink_cs: Conv...
3289
  			tx_ready(info, tty);
40565f196   Jiri Slaby   [PATCH] Char: tim...
3290
3291
  			mod_timer(&info->tx_timer, jiffies +
  					msecs_to_jiffies(5000));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3292
3293
3294
3295
  		}
  	}
  
  	if (!info->tx_enabled)
0fab6de09   Joe Perches   synclink drivers ...
3296
  		info->tx_enabled = true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3297
  }
cdaad343b   Peter Hagervall   [PATCH] Sparse fi...
3298
  static void tx_stop(MGSLPC_INFO *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3299
3300
3301
3302
  {
  	if (debug_level >= DEBUG_LEVEL_ISR)
  		printk("%s(%d):tx_stop(%s)
  ",
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
3303
  			 __FILE__, __LINE__, info->device_name);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3304
3305
  
  	del_timer(&info->tx_timer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3306

0fab6de09   Joe Perches   synclink drivers ...
3307
3308
  	info->tx_enabled = false;
  	info->tx_active = false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3309
3310
3311
3312
  }
  
  /* Reset the adapter to a known state and prepare it for further use.
   */
cdaad343b   Peter Hagervall   [PATCH] Sparse fi...
3313
  static void reset_device(MGSLPC_INFO *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3314
  {
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3315
  	/* power up both channels (set BIT7) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3316
3317
3318
3319
  	write_reg(info, CHA + CCR0, 0x80);
  	write_reg(info, CHB + CCR0, 0x80);
  	write_reg(info, CHA + MODE, 0);
  	write_reg(info, CHB + MODE, 0);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3320
3321
  
  	/* disable all interrupts */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3322
3323
3324
  	irq_disable(info, CHA, 0xffff);
  	irq_disable(info, CHB, 0xffff);
  	port_irq_disable(info, 0xff);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3325

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3326
3327
3328
3329
3330
3331
3332
3333
3334
  	/* PCR Port Configuration Register
  	 *
  	 * 07..04  DEC[3..0] Serial I/F select outputs
  	 * 03      output, 1=AUTO CTS control enabled
  	 * 02      RI Ring Indicator input 0=active
  	 * 01      DSR input 0=active
  	 * 00      DTR output 0=active
  	 *
  	 * 0000 0110
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3335
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3336
  	write_reg(info, PCR, 0x06);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3337

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
  	/* PVR Port Value Register
  	 *
  	 * 07..04  DEC[3..0] Serial I/F select (0000=disabled)
  	 * 03      AUTO CTS output 1=enabled
  	 * 02      RI Ring Indicator input
  	 * 01      DSR input
  	 * 00      DTR output (1=inactive)
  	 *
  	 * 0000 0001
  	 */
  //	write_reg(info, PVR, PVR_DTR);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3349

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3350
3351
3352
3353
3354
3355
3356
3357
3358
  	/* IPC Interrupt Port Configuration
  	 *
  	 * 07      VIS 1=Masked interrupts visible
  	 * 06..05  Reserved, 0
  	 * 04..03  SLA Slave address, 00 ignored
  	 * 02      CASM Cascading Mode, 1=daisy chain
  	 * 01..00  IC[1..0] Interrupt Config, 01=push-pull output, active low
  	 *
  	 * 0000 0101
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3359
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3360
3361
  	write_reg(info, IPC, 0x05);
  }
cdaad343b   Peter Hagervall   [PATCH] Sparse fi...
3362
  static void async_mode(MGSLPC_INFO *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3363
3364
  {
  	unsigned char val;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3365
  	/* disable all interrupts */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3366
3367
3368
  	irq_disable(info, CHA, 0xffff);
  	irq_disable(info, CHB, 0xffff);
  	port_irq_disable(info, 0xff);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3369

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
  	/* MODE
  	 *
  	 * 07      Reserved, 0
  	 * 06      FRTS RTS State, 0=active
  	 * 05      FCTS Flow Control on CTS
  	 * 04      FLON Flow Control Enable
  	 * 03      RAC Receiver Active, 0 = inactive
  	 * 02      RTS 0=Auto RTS, 1=manual RTS
  	 * 01      TRS Timer Resolution, 1=512
  	 * 00      TLP Test Loop, 0 = no loop
  	 *
  	 * 0000 0110
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3382
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3383
3384
3385
  	val = 0x06;
  	if (info->params.loopback)
  		val |= BIT0;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3386
3387
  
  	/* preserve RTS state */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3388
3389
3390
  	if (!(info->serial_signals & SerialSignal_RTS))
  		val |= BIT6;
  	write_reg(info, CHA + MODE, val);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3391

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3392
3393
3394
3395
3396
3397
3398
3399
3400
  	/* CCR0
  	 *
  	 * 07      PU Power Up, 1=active, 0=power down
  	 * 06      MCE Master Clock Enable, 1=enabled
  	 * 05      Reserved, 0
  	 * 04..02  SC[2..0] Encoding, 000=NRZ
  	 * 01..00  SM[1..0] Serial Mode, 11=Async
  	 *
  	 * 1000 0011
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3401
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3402
  	write_reg(info, CHA + CCR0, 0x83);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3403

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3404
3405
3406
3407
3408
3409
3410
3411
  	/* CCR1
  	 *
  	 * 07..05  Reserved, 0
  	 * 04      ODS Output Driver Select, 1=TxD is push-pull output
  	 * 03      BCR Bit Clock Rate, 1=16x
  	 * 02..00  CM[2..0] Clock Mode, 111=BRG
  	 *
  	 * 0001 1111
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3412
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3413
  	write_reg(info, CHA + CCR1, 0x1f);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3414

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
  	/* CCR2 (channel A)
  	 *
  	 * 07..06  BGR[9..8] Baud rate bits 9..8
  	 * 05      BDF Baud rate divisor factor, 0=1, 1=BGR value
  	 * 04      SSEL Clock source select, 1=submode b
  	 * 03      TOE 0=TxCLK is input, 0=TxCLK is input
  	 * 02      RWX Read/Write Exchange 0=disabled
  	 * 01      Reserved, 0
  	 * 00      DIV, data inversion 0=disabled, 1=enabled
  	 *
  	 * 0001 0000
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3426
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3427
  	write_reg(info, CHA + CCR2, 0x10);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3428

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3429
3430
3431
3432
3433
3434
  	/* CCR3
  	 *
  	 * 07..01  Reserved, 0
  	 * 00      PSD DPLL Phase Shift Disable
  	 *
  	 * 0000 0000
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3435
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3436
  	write_reg(info, CHA + CCR3, 0);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3437

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3438
3439
3440
3441
3442
3443
3444
3445
3446
  	/* CCR4
  	 *
  	 * 07      MCK4 Master Clock Divide by 4, 1=enabled
  	 * 06      EBRG Enhanced Baud Rate Generator Mode, 1=enabled
  	 * 05      TST1 Test Pin, 0=normal operation
  	 * 04      ICD Ivert Carrier Detect, 1=enabled (active low)
  	 * 03..00  Reserved, must be 0
  	 *
  	 * 0101 0000
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3447
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3448
3449
  	write_reg(info, CHA + CCR4, 0x50);
  	mgslpc_set_rate(info, CHA, info->params.data_rate * 16);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3450

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3451
3452
3453
3454
3455
3456
3457
3458
3459
  	/* DAFO Data Format
  	 *
  	 * 07      Reserved, 0
  	 * 06      XBRK transmit break, 0=normal operation
  	 * 05      Stop bits (0=1, 1=2)
  	 * 04..03  PAR[1..0] Parity (01=odd, 10=even)
  	 * 02      PAREN Parity Enable
  	 * 01..00  CHL[1..0] Character Length (00=8, 01=7)
  	 *
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3460
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
  	val = 0x00;
  	if (info->params.data_bits != 8)
  		val |= BIT0;	/* 7 bits */
  	if (info->params.stop_bits != 1)
  		val |= BIT5;
  	if (info->params.parity != ASYNC_PARITY_NONE)
  	{
  		val |= BIT2;	/* Parity enable */
  		if (info->params.parity == ASYNC_PARITY_ODD)
  			val |= BIT3;
  		else
  			val |= BIT4;
  	}
  	write_reg(info, CHA + DAFO, val);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3475

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
  	/* RFC Rx FIFO Control
  	 *
  	 * 07      Reserved, 0
  	 * 06      DPS, 1=parity bit not stored in data byte
  	 * 05      DXS, 0=all data stored in FIFO (including XON/XOFF)
  	 * 04      RFDF Rx FIFO Data Format, 1=status byte stored in FIFO
  	 * 03..02  RFTH[1..0], rx threshold, 11=16 status + 16 data byte
  	 * 01      Reserved, 0
  	 * 00      TCDE Terminate Char Detect Enable, 0=disabled
  	 *
  	 * 0101 1100
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3487
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3488
  	write_reg(info, CHA + RFC, 0x5c);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3489

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3490
3491
3492
  	/* RLCR Receive length check register
  	 *
  	 * Max frame length = (RL + 1) * 32
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3493
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3494
  	write_reg(info, CHA + RLCR, 0);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3495

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3496
3497
3498
3499
3500
3501
3502
3503
3504
  	/* XBCH Transmit Byte Count High
  	 *
  	 * 07      DMA mode, 0 = interrupt driven
  	 * 06      NRM, 0=ABM (ignored)
  	 * 05      CAS Carrier Auto Start
  	 * 04      XC Transmit Continuously (ignored)
  	 * 03..00  XBC[10..8] Transmit byte count bits 10..8
  	 *
  	 * 0000 0000
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3505
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3506
3507
3508
3509
3510
3511
  	val = 0x00;
  	if (info->params.flags & HDLC_FLAG_AUTO_DCD)
  		val |= BIT5;
  	write_reg(info, CHA + XBCH, val);
  	if (info->params.flags & HDLC_FLAG_AUTO_CTS)
  		irq_enable(info, CHA, IRQ_CTS);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3512
3513
  
  	/* MODE:03 RAC Receiver Active, 1=active */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3514
3515
3516
3517
  	set_reg_bits(info, CHA + MODE, BIT3);
  	enable_auxclk(info);
  	if (info->params.flags & HDLC_FLAG_AUTO_CTS) {
  		irq_enable(info, CHB, IRQ_CTS);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3518
  		/* PVR[3] 1=AUTO CTS active */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3519
3520
3521
3522
  		set_reg_bits(info, CHA + PVR, BIT3);
  	} else
  		clear_reg_bits(info, CHA + PVR, BIT3);
  	irq_enable(info, CHA,
ecda040ff   Alexandru Juncu   pcmcia: synclink_...
3523
3524
  			  IRQ_RXEOM | IRQ_RXFIFO | IRQ_BREAK_ON | IRQ_RXTIME |
  			  IRQ_ALLSENT | IRQ_TXFIFO);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3525
3526
3527
3528
3529
3530
3531
  	issue_command(info, CHA, CMD_TXRESET + CMD_RXRESET);
  	wait_command_complete(info, CHA);
  	read_reg16(info, CHA + ISR);	/* clear pending IRQs */
  }
  
  /* Set the HDLC idle mode for the transmitter.
   */
cdaad343b   Peter Hagervall   [PATCH] Sparse fi...
3532
  static void tx_set_idle(MGSLPC_INFO *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3533
  {
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3534
  	/* Note: ESCC2 only supports flags and one idle modes */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3535
3536
3537
3538
3539
3540
3541
3542
  	if (info->idle_mode == HDLC_TXIDLE_FLAGS)
  		set_reg_bits(info, CHA + CCR1, BIT3);
  	else
  		clear_reg_bits(info, CHA + CCR1, BIT3);
  }
  
  /* get state of the V24 status (input) signals.
   */
cdaad343b   Peter Hagervall   [PATCH] Sparse fi...
3543
  static void get_signals(MGSLPC_INFO *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3544
3545
  {
  	unsigned char status = 0;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3546

9fe8074b8   Joe Perches   TTY: synclink: Co...
3547
3548
  	/* preserve RTS and DTR */
  	info->serial_signals &= SerialSignal_RTS | SerialSignal_DTR;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
  
  	if (read_reg(info, CHB + VSTR) & BIT7)
  		info->serial_signals |= SerialSignal_DCD;
  	if (read_reg(info, CHB + STAR) & BIT1)
  		info->serial_signals |= SerialSignal_CTS;
  
  	status = read_reg(info, CHA + PVR);
  	if (!(status & PVR_RI))
  		info->serial_signals |= SerialSignal_RI;
  	if (!(status & PVR_DSR))
  		info->serial_signals |= SerialSignal_DSR;
  }
9fe8074b8   Joe Perches   TTY: synclink: Co...
3561
  /* Set the state of RTS and DTR based on contents of
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3562
3563
   * serial_signals member of device extension.
   */
cdaad343b   Peter Hagervall   [PATCH] Sparse fi...
3564
  static void set_signals(MGSLPC_INFO *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
  {
  	unsigned char val;
  
  	val = read_reg(info, CHA + MODE);
  	if (info->params.mode == MGSL_MODE_ASYNC) {
  		if (info->serial_signals & SerialSignal_RTS)
  			val &= ~BIT6;
  		else
  			val |= BIT6;
  	} else {
  		if (info->serial_signals & SerialSignal_RTS)
  			val |= BIT2;
  		else
  			val &= ~BIT2;
  	}
  	write_reg(info, CHA + MODE, val);
  
  	if (info->serial_signals & SerialSignal_DTR)
  		clear_reg_bits(info, CHA + PVR, PVR_DTR);
  	else
  		set_reg_bits(info, CHA + PVR, PVR_DTR);
  }
cdaad343b   Peter Hagervall   [PATCH] Sparse fi...
3587
  static void rx_reset_buffers(MGSLPC_INFO *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
  {
  	RXBUF *buf;
  	int i;
  
  	info->rx_put = 0;
  	info->rx_get = 0;
  	info->rx_frame_count = 0;
  	for (i=0 ; i < info->rx_buf_count ; i++) {
  		buf = (RXBUF*)(info->rx_buf + (i * info->rx_buf_size));
  		buf->status = buf->count = 0;
  	}
  }
  
  /* Attempt to return a received HDLC frame
   * Only frames received without errors are returned.
   *
0fab6de09   Joe Perches   synclink drivers ...
3604
   * Returns true if frame returned, otherwise false
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3605
   */
eeb461343   Alan Cox   synclink_cs: Conv...
3606
  static bool rx_get_frame(MGSLPC_INFO *info, struct tty_struct *tty)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3607
3608
3609
3610
3611
  {
  	unsigned short status;
  	RXBUF *buf;
  	unsigned int framesize = 0;
  	unsigned long flags;
0fab6de09   Joe Perches   synclink drivers ...
3612
  	bool return_frame = false;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3613

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3614
  	if (info->rx_frame_count == 0)
0fab6de09   Joe Perches   synclink drivers ...
3615
  		return false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
  
  	buf = (RXBUF*)(info->rx_buf + (info->rx_get * info->rx_buf_size));
  
  	status = buf->status;
  
  	/* 07  VFR  1=valid frame
  	 * 06  RDO  1=data overrun
  	 * 05  CRC  1=OK, 0=error
  	 * 04  RAB  1=frame aborted
  	 */
  	if ((status & 0xf0) != 0xA0) {
  		if (!(status & BIT7) || (status & BIT4))
  			info->icount.rxabort++;
  		else if (status & BIT6)
  			info->icount.rxover++;
  		else if (!(status & BIT5)) {
  			info->icount.rxcrc++;
  			if (info->params.crc_type & HDLC_CRC_RETURN_EX)
0fab6de09   Joe Perches   synclink drivers ...
3634
  				return_frame = true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3635
3636
  		}
  		framesize = 0;
af69c7f92   Paul Fulghum   [PATCH] generic H...
3637
  #if SYNCLINK_GENERIC_HDLC
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3638
  		{
198191c4a   Krzysztof Halasa   WAN: convert driv...
3639
3640
  			info->netdev->stats.rx_errors++;
  			info->netdev->stats.rx_frame_errors++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3641
3642
3643
  		}
  #endif
  	} else
0fab6de09   Joe Perches   synclink drivers ...
3644
  		return_frame = true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3645
3646
3647
3648
3649
3650
3651
  
  	if (return_frame)
  		framesize = buf->count;
  
  	if (debug_level >= DEBUG_LEVEL_BH)
  		printk("%s(%d):rx_get_frame(%s) status=%04X size=%d
  ",
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
3652
  			__FILE__, __LINE__, info->device_name, status, framesize);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3653

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3654
  	if (debug_level >= DEBUG_LEVEL_DATA)
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3655
  		trace_block(info, buf->data, framesize, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
  	if (framesize) {
  		if ((info->params.crc_type & HDLC_CRC_RETURN_EX &&
  		      framesize+1 > info->max_frame_size) ||
  		    framesize > info->max_frame_size)
  			info->icount.rxlong++;
  		else {
  			if (status & BIT5)
  				info->icount.rxok++;
  
  			if (info->params.crc_type & HDLC_CRC_RETURN_EX) {
  				*(buf->data + framesize) = status & BIT5 ? RX_OK:RX_CRC_ERROR;
  				++framesize;
  			}
af69c7f92   Paul Fulghum   [PATCH] generic H...
3669
  #if SYNCLINK_GENERIC_HDLC
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3670
3671
3672
3673
3674
3675
3676
  			if (info->netcount)
  				hdlcdev_rx(info, buf->data, framesize);
  			else
  #endif
  				ldisc_receive_buf(tty, buf->data, info->flag_buf, framesize);
  		}
  	}
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
3677
  	spin_lock_irqsave(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3678
3679
3680
3681
3682
  	buf->status = buf->count = 0;
  	info->rx_frame_count--;
  	info->rx_get++;
  	if (info->rx_get >= info->rx_buf_count)
  		info->rx_get = 0;
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
3683
  	spin_unlock_irqrestore(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3684

0fab6de09   Joe Perches   synclink drivers ...
3685
  	return true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3686
  }
0fab6de09   Joe Perches   synclink drivers ...
3687
  static bool register_test(MGSLPC_INFO *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3688
  {
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3689
  	static unsigned char patterns[] =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3690
  	    { 0x00, 0xff, 0xaa, 0x55, 0x69, 0x96, 0x0f };
fe971071a   Tobias Klauser   [PATCH] drivers/c...
3691
  	static unsigned int count = ARRAY_SIZE(patterns);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3692
  	unsigned int i;
0fab6de09   Joe Perches   synclink drivers ...
3693
  	bool rc = true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3694
  	unsigned long flags;
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
3695
  	spin_lock_irqsave(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3696
3697
3698
3699
3700
  	reset_device(info);
  
  	for (i = 0; i < count; i++) {
  		write_reg(info, XAD1, patterns[i]);
  		write_reg(info, XAD2, patterns[(i + 1) % count]);
fe971071a   Tobias Klauser   [PATCH] drivers/c...
3701
  		if ((read_reg(info, XAD1) != patterns[i]) ||
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3702
  		    (read_reg(info, XAD2) != patterns[(i + 1) % count])) {
0fab6de09   Joe Perches   synclink drivers ...
3703
  			rc = false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3704
3705
3706
  			break;
  		}
  	}
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
3707
  	spin_unlock_irqrestore(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3708
3709
  	return rc;
  }
0fab6de09   Joe Perches   synclink drivers ...
3710
  static bool irq_test(MGSLPC_INFO *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3711
3712
3713
  {
  	unsigned long end_time;
  	unsigned long flags;
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
3714
  	spin_lock_irqsave(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3715
  	reset_device(info);
0fab6de09   Joe Perches   synclink drivers ...
3716
  	info->testing_irq = true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3717
  	hdlc_mode(info);
0fab6de09   Joe Perches   synclink drivers ...
3718
  	info->irq_occurred = false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3719
3720
3721
3722
3723
3724
  
  	/* init hdlc mode */
  
  	irq_enable(info, CHA, IRQ_TIMER);
  	write_reg(info, CHA + TIMR, 0);	/* 512 cycles */
  	issue_command(info, CHA, CMD_START_TIMER);
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
3725
  	spin_unlock_irqrestore(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3726
3727
3728
3729
3730
  
  	end_time=100;
  	while(end_time-- && !info->irq_occurred) {
  		msleep_interruptible(10);
  	}
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3731

0fab6de09   Joe Perches   synclink drivers ...
3732
  	info->testing_irq = false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3733

3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
3734
  	spin_lock_irqsave(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3735
  	reset_device(info);
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
3736
  	spin_unlock_irqrestore(&info->lock, flags);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3737

0fab6de09   Joe Perches   synclink drivers ...
3738
  	return info->irq_occurred;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3739
  }
cdaad343b   Peter Hagervall   [PATCH] Sparse fi...
3740
  static int adapter_test(MGSLPC_INFO *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3741
3742
3743
  {
  	if (!register_test(info)) {
  		info->init_error = DiagStatus_AddressFailure;
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
3744
3745
3746
  		printk("%s(%d):Register test failure for device %s Addr=%04X
  ",
  			__FILE__, __LINE__, info->device_name, (unsigned short)(info->io_base));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3747
3748
3749
3750
3751
  		return -ENODEV;
  	}
  
  	if (!irq_test(info)) {
  		info->init_error = DiagStatus_IrqFailure;
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
3752
3753
3754
  		printk("%s(%d):Interrupt test failure for device %s IRQ=%d
  ",
  			__FILE__, __LINE__, info->device_name, (unsigned short)(info->irq_level));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3755
3756
3757
3758
3759
3760
  		return -ENODEV;
  	}
  
  	if (debug_level >= DEBUG_LEVEL_INFO)
  		printk("%s(%d):device %s passed diagnostics
  ",
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
3761
  			__FILE__, __LINE__, info->device_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3762
3763
  	return 0;
  }
cdaad343b   Peter Hagervall   [PATCH] Sparse fi...
3764
  static void trace_block(MGSLPC_INFO *info,const char* data, int count, int xmit)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3765
3766
3767
3768
  {
  	int i;
  	int linecount;
  	if (xmit)
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
3769
3770
  		printk("%s tx data:
  ", info->device_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3771
  	else
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
3772
3773
  		printk("%s rx data:
  ", info->device_name);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3774

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3775
3776
3777
3778
3779
  	while(count) {
  		if (count > 16)
  			linecount = 16;
  		else
  			linecount = count;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3780

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3781
  		for(i=0;i<linecount;i++)
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
3782
  			printk("%02X ", (unsigned char)data[i]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3783
3784
3785
3786
  		for(;i<17;i++)
  			printk("   ");
  		for(i=0;i<linecount;i++) {
  			if (data[i]>=040 && data[i]<=0176)
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
3787
  				printk("%c", data[i]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3788
3789
3790
3791
3792
  			else
  				printk(".");
  		}
  		printk("
  ");
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3793

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3794
3795
3796
3797
3798
3799
3800
3801
  		data  += linecount;
  		count -= linecount;
  	}
  }
  
  /* HDLC frame time out
   * update stats and do tx completion processing
   */
cdaad343b   Peter Hagervall   [PATCH] Sparse fi...
3802
  static void tx_timeout(unsigned long context)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3803
3804
3805
  {
  	MGSLPC_INFO *info = (MGSLPC_INFO*)context;
  	unsigned long flags;
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3806

3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
3807
3808
3809
3810
3811
3812
  	if (debug_level >= DEBUG_LEVEL_INFO)
  		printk("%s(%d):tx_timeout(%s)
  ",
  			__FILE__, __LINE__, info->device_name);
  	if (info->tx_active &&
  	    info->params.mode == MGSL_MODE_HDLC) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3813
3814
  		info->icount.txtimeout++;
  	}
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
3815
  	spin_lock_irqsave(&info->lock, flags);
0fab6de09   Joe Perches   synclink drivers ...
3816
  	info->tx_active = false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3817
  	info->tx_count = info->tx_put = info->tx_get = 0;
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
3818
  	spin_unlock_irqrestore(&info->lock, flags);
d12341f9f   Jeff Garzik   char/pcmcia/syncl...
3819

af69c7f92   Paul Fulghum   [PATCH] generic H...
3820
  #if SYNCLINK_GENERIC_HDLC
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3821
3822
3823
3824
  	if (info->netcount)
  		hdlcdev_tx_done(info);
  	else
  #endif
eeb461343   Alan Cox   synclink_cs: Conv...
3825
3826
3827
3828
3829
  	{
  		struct tty_struct *tty = tty_port_tty_get(&info->port);
  		bh_transmit(info, tty);
  		tty_kref_put(tty);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3830
  }
af69c7f92   Paul Fulghum   [PATCH] generic H...
3831
  #if SYNCLINK_GENERIC_HDLC
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3832
3833
3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
  
  /**
   * called by generic HDLC layer when protocol selected (PPP, frame relay, etc.)
   * set encoding and frame check sequence (FCS) options
   *
   * dev       pointer to network device structure
   * encoding  serial encoding setting
   * parity    FCS setting
   *
   * returns 0 if success, otherwise error code
   */
  static int hdlcdev_attach(struct net_device *dev, unsigned short encoding,
  			  unsigned short parity)
  {
  	MGSLPC_INFO *info = dev_to_port(dev);
eeb461343   Alan Cox   synclink_cs: Conv...
3847
  	struct tty_struct *tty;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3848
3849
3850
3851
  	unsigned char  new_encoding;
  	unsigned short new_crctype;
  
  	/* return error if TTY interface open */
eeb461343   Alan Cox   synclink_cs: Conv...
3852
  	if (info->port.count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
  		return -EBUSY;
  
  	switch (encoding)
  	{
  	case ENCODING_NRZ:        new_encoding = HDLC_ENCODING_NRZ; break;
  	case ENCODING_NRZI:       new_encoding = HDLC_ENCODING_NRZI_SPACE; break;
  	case ENCODING_FM_MARK:    new_encoding = HDLC_ENCODING_BIPHASE_MARK; break;
  	case ENCODING_FM_SPACE:   new_encoding = HDLC_ENCODING_BIPHASE_SPACE; break;
  	case ENCODING_MANCHESTER: new_encoding = HDLC_ENCODING_BIPHASE_LEVEL; break;
  	default: return -EINVAL;
  	}
  
  	switch (parity)
  	{
  	case PARITY_NONE:            new_crctype = HDLC_CRC_NONE; break;
  	case PARITY_CRC16_PR1_CCITT: new_crctype = HDLC_CRC_16_CCITT; break;
  	case PARITY_CRC32_PR1_CCITT: new_crctype = HDLC_CRC_32_CCITT; break;
  	default: return -EINVAL;
  	}
  
  	info->params.encoding = new_encoding;
53b3531bb   Alexey Dobriyan   [PATCH] s/;;/;/g
3874
  	info->params.crc_type = new_crctype;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3875
3876
  
  	/* if network interface up, reprogram hardware */
eeb461343   Alan Cox   synclink_cs: Conv...
3877
3878
3879
3880
3881
  	if (info->netcount) {
  		tty = tty_port_tty_get(&info->port);
  		mgslpc_program_hw(info, tty);
  		tty_kref_put(tty);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3882
3883
3884
3885
3886
3887
3888
3889
3890
  
  	return 0;
  }
  
  /**
   * called by generic HDLC layer to send frame
   *
   * skb  socket buffer containing HDLC frame
   * dev  pointer to network device structure
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3891
   */
4c5d502d8   Stephen Hemminger   hdlc: convert to ...
3892
3893
  static netdev_tx_t hdlcdev_xmit(struct sk_buff *skb,
  				      struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3894
3895
  {
  	MGSLPC_INFO *info = dev_to_port(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3896
3897
3898
  	unsigned long flags;
  
  	if (debug_level >= DEBUG_LEVEL_INFO)
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
3899
3900
  		printk(KERN_INFO "%s:hdlc_xmit(%s)
  ", __FILE__, dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3901
3902
3903
3904
3905
  
  	/* stop sending until this frame completes */
  	netif_stop_queue(dev);
  
  	/* copy data to device buffers */
d626f62b1   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
3906
  	skb_copy_from_linear_data(skb, info->tx_buf, skb->len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3907
3908
3909
3910
  	info->tx_get = 0;
  	info->tx_put = info->tx_count = skb->len;
  
  	/* update network statistics */
198191c4a   Krzysztof Halasa   WAN: convert driv...
3911
3912
  	dev->stats.tx_packets++;
  	dev->stats.tx_bytes += skb->len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3913
3914
3915
3916
3917
  
  	/* done with socket buffer, so free it */
  	dev_kfree_skb(skb);
  
  	/* save start time for transmit timeout detection */
860e9538a   Florian Westphal   treewide: replace...
3918
  	netif_trans_update(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3919
3920
  
  	/* start hardware transmitter if necessary */
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
3921
  	spin_lock_irqsave(&info->lock, flags);
eeb461343   Alan Cox   synclink_cs: Conv...
3922
3923
  	if (!info->tx_active) {
  		struct tty_struct *tty = tty_port_tty_get(&info->port);
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
3924
3925
  		tx_start(info, tty);
  		tty_kref_put(tty);
eeb461343   Alan Cox   synclink_cs: Conv...
3926
  	}
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
3927
  	spin_unlock_irqrestore(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3928

4c5d502d8   Stephen Hemminger   hdlc: convert to ...
3929
  	return NETDEV_TX_OK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
  }
  
  /**
   * called by network layer when interface enabled
   * claim resources and initialize hardware
   *
   * dev  pointer to network device structure
   *
   * returns 0 if success, otherwise error code
   */
  static int hdlcdev_open(struct net_device *dev)
  {
  	MGSLPC_INFO *info = dev_to_port(dev);
eeb461343   Alan Cox   synclink_cs: Conv...
3943
  	struct tty_struct *tty;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3944
3945
3946
3947
  	int rc;
  	unsigned long flags;
  
  	if (debug_level >= DEBUG_LEVEL_INFO)
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
3948
3949
  		printk("%s:hdlcdev_open(%s)
  ", __FILE__, dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3950
3951
  
  	/* generic HDLC layer open processing */
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
3952
3953
  	rc = hdlc_open(dev);
  	if (rc != 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3954
3955
3956
3957
  		return rc;
  
  	/* arbitrate between network and tty opens */
  	spin_lock_irqsave(&info->netlock, flags);
eeb461343   Alan Cox   synclink_cs: Conv...
3958
  	if (info->port.count != 0 || info->netcount != 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3959
3960
3961
3962
3963
3964
3965
  		printk(KERN_WARNING "%s: hdlc_open returning busy
  ", dev->name);
  		spin_unlock_irqrestore(&info->netlock, flags);
  		return -EBUSY;
  	}
  	info->netcount=1;
  	spin_unlock_irqrestore(&info->netlock, flags);
eeb461343   Alan Cox   synclink_cs: Conv...
3966
  	tty = tty_port_tty_get(&info->port);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3967
  	/* claim resources and init adapter */
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
3968
3969
  	rc = startup(info, tty);
  	if (rc != 0) {
eeb461343   Alan Cox   synclink_cs: Conv...
3970
  		tty_kref_put(tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3971
3972
3973
3974
3975
  		spin_lock_irqsave(&info->netlock, flags);
  		info->netcount=0;
  		spin_unlock_irqrestore(&info->netlock, flags);
  		return rc;
  	}
9fe8074b8   Joe Perches   TTY: synclink: Co...
3976
3977
  	/* assert RTS and DTR, apply hardware settings */
  	info->serial_signals |= SerialSignal_RTS | SerialSignal_DTR;
eeb461343   Alan Cox   synclink_cs: Conv...
3978
3979
  	mgslpc_program_hw(info, tty);
  	tty_kref_put(tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3980
3981
  
  	/* enable network layer transmit */
860e9538a   Florian Westphal   treewide: replace...
3982
  	netif_trans_update(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3983
3984
3985
3986
3987
3988
  	netif_start_queue(dev);
  
  	/* inform generic HDLC layer of current DCD status */
  	spin_lock_irqsave(&info->lock, flags);
  	get_signals(info);
  	spin_unlock_irqrestore(&info->lock, flags);
fbeff3c1d   Krzysztof Halasa   [WAN]: Converted ...
3989
3990
3991
3992
  	if (info->serial_signals & SerialSignal_DCD)
  		netif_carrier_on(dev);
  	else
  		netif_carrier_off(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3993
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
  	return 0;
  }
  
  /**
   * called by network layer when interface is disabled
   * shutdown hardware and release resources
   *
   * dev  pointer to network device structure
   *
   * returns 0 if success, otherwise error code
   */
  static int hdlcdev_close(struct net_device *dev)
  {
  	MGSLPC_INFO *info = dev_to_port(dev);
eeb461343   Alan Cox   synclink_cs: Conv...
4007
  	struct tty_struct *tty = tty_port_tty_get(&info->port);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4008
4009
4010
  	unsigned long flags;
  
  	if (debug_level >= DEBUG_LEVEL_INFO)
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
4011
4012
  		printk("%s:hdlcdev_close(%s)
  ", __FILE__, dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4013
4014
4015
4016
  
  	netif_stop_queue(dev);
  
  	/* shutdown adapter and release resources */
eeb461343   Alan Cox   synclink_cs: Conv...
4017
4018
  	shutdown(info, tty);
  	tty_kref_put(tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
  	hdlc_close(dev);
  
  	spin_lock_irqsave(&info->netlock, flags);
  	info->netcount=0;
  	spin_unlock_irqrestore(&info->netlock, flags);
  
  	return 0;
  }
  
  /**
   * called by network layer to process IOCTL call to network device
   *
   * dev  pointer to network device structure
   * ifr  pointer to network interface request structure
   * cmd  IOCTL command code
   *
   * returns 0 if success, otherwise error code
   */
  static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
  {
  	const size_t size = sizeof(sync_serial_settings);
  	sync_serial_settings new_line;
  	sync_serial_settings __user *line = ifr->ifr_settings.ifs_ifsu.sync;
  	MGSLPC_INFO *info = dev_to_port(dev);
  	unsigned int flags;
  
  	if (debug_level >= DEBUG_LEVEL_INFO)
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
4046
4047
  		printk("%s:hdlcdev_ioctl(%s)
  ", __FILE__, dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4048
4049
  
  	/* return error if TTY interface open */
eeb461343   Alan Cox   synclink_cs: Conv...
4050
  	if (info->port.count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4051
4052
4053
4054
  		return -EBUSY;
  
  	if (cmd != SIOCWANDEV)
  		return hdlc_ioctl(dev, ifr, cmd);
5b917a142   Vasiliy Kulikov   pcmcia: synclink_...
4055
  	memset(&new_line, 0, size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
  	switch(ifr->ifr_settings.type) {
  	case IF_GET_IFACE: /* return current sync_serial_settings */
  
  		ifr->ifr_settings.type = IF_IFACE_SYNC_SERIAL;
  		if (ifr->ifr_settings.size < size) {
  			ifr->ifr_settings.size = size; /* data size wanted */
  			return -ENOBUFS;
  		}
  
  		flags = info->params.flags & (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL |
  					      HDLC_FLAG_RXC_BRG    | HDLC_FLAG_RXC_TXCPIN |
  					      HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL |
  					      HDLC_FLAG_TXC_BRG    | HDLC_FLAG_TXC_RXCPIN);
  
  		switch (flags){
  		case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN): new_line.clock_type = CLOCK_EXT; break;
  		case (HDLC_FLAG_RXC_BRG    | HDLC_FLAG_TXC_BRG):    new_line.clock_type = CLOCK_INT; break;
  		case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG):    new_line.clock_type = CLOCK_TXINT; break;
  		case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN): new_line.clock_type = CLOCK_TXFROMRX; break;
  		default: new_line.clock_type = CLOCK_DEFAULT;
  		}
  
  		new_line.clock_rate = info->params.clock_speed;
  		new_line.loopback   = info->params.loopback ? 1:0;
  
  		if (copy_to_user(line, &new_line, size))
  			return -EFAULT;
  		return 0;
  
  	case IF_IFACE_SYNC_SERIAL: /* set sync_serial_settings */
  
  		if(!capable(CAP_NET_ADMIN))
  			return -EPERM;
  		if (copy_from_user(&new_line, line, size))
  			return -EFAULT;
  
  		switch (new_line.clock_type)
  		{
  		case CLOCK_EXT:      flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN; break;
  		case CLOCK_TXFROMRX: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN; break;
  		case CLOCK_INT:      flags = HDLC_FLAG_RXC_BRG    | HDLC_FLAG_TXC_BRG;    break;
  		case CLOCK_TXINT:    flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG;    break;
  		case CLOCK_DEFAULT:  flags = info->params.flags &
  					     (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL |
  					      HDLC_FLAG_RXC_BRG    | HDLC_FLAG_RXC_TXCPIN |
  					      HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL |
  					      HDLC_FLAG_TXC_BRG    | HDLC_FLAG_TXC_RXCPIN); break;
  		default: return -EINVAL;
  		}
  
  		if (new_line.loopback != 0 && new_line.loopback != 1)
  			return -EINVAL;
  
  		info->params.flags &= ~(HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL |
  					HDLC_FLAG_RXC_BRG    | HDLC_FLAG_RXC_TXCPIN |
  					HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL |
  					HDLC_FLAG_TXC_BRG    | HDLC_FLAG_TXC_RXCPIN);
  		info->params.flags |= flags;
  
  		info->params.loopback = new_line.loopback;
  
  		if (flags & (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG))
  			info->params.clock_speed = new_line.clock_rate;
  		else
  			info->params.clock_speed = 0;
  
  		/* if network interface up, reprogram hardware */
eeb461343   Alan Cox   synclink_cs: Conv...
4123
4124
4125
4126
4127
  		if (info->netcount) {
  			struct tty_struct *tty = tty_port_tty_get(&info->port);
  			mgslpc_program_hw(info, tty);
  			tty_kref_put(tty);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4128
4129
4130
4131
4132
4133
4134
4135
4136
4137
4138
4139
4140
4141
4142
  		return 0;
  
  	default:
  		return hdlc_ioctl(dev, ifr, cmd);
  	}
  }
  
  /**
   * called by network layer when transmit timeout is detected
   *
   * dev  pointer to network device structure
   */
  static void hdlcdev_tx_timeout(struct net_device *dev)
  {
  	MGSLPC_INFO *info = dev_to_port(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4143
4144
4145
  	unsigned long flags;
  
  	if (debug_level >= DEBUG_LEVEL_INFO)
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
4146
4147
  		printk("hdlcdev_tx_timeout(%s)
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4148

198191c4a   Krzysztof Halasa   WAN: convert driv...
4149
4150
  	dev->stats.tx_errors++;
  	dev->stats.tx_aborted_errors++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4151

3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
4152
  	spin_lock_irqsave(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4153
  	tx_stop(info);
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
4154
  	spin_unlock_irqrestore(&info->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
4167
4168
4169
4170
4171
4172
4173
4174
4175
4176
4177
4178
4179
4180
4181
4182
  
  	netif_wake_queue(dev);
  }
  
  /**
   * called by device driver when transmit completes
   * reenable network layer transmit if stopped
   *
   * info  pointer to device instance information
   */
  static void hdlcdev_tx_done(MGSLPC_INFO *info)
  {
  	if (netif_queue_stopped(info->netdev))
  		netif_wake_queue(info->netdev);
  }
  
  /**
   * called by device driver when frame received
   * pass frame to network layer
   *
   * info  pointer to device instance information
   * buf   pointer to buffer contianing frame data
   * size  count of data bytes in buf
   */
  static void hdlcdev_rx(MGSLPC_INFO *info, char *buf, int size)
  {
  	struct sk_buff *skb = dev_alloc_skb(size);
  	struct net_device *dev = info->netdev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4183
4184
  
  	if (debug_level >= DEBUG_LEVEL_INFO)
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
4185
4186
  		printk("hdlcdev_rx(%s)
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4187
4188
4189
4190
  
  	if (skb == NULL) {
  		printk(KERN_NOTICE "%s: can't alloc skb, dropping packet
  ", dev->name);
198191c4a   Krzysztof Halasa   WAN: convert driv...
4191
  		dev->stats.rx_dropped++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4192
4193
  		return;
  	}
198191c4a   Krzysztof Halasa   WAN: convert driv...
4194
  	memcpy(skb_put(skb, size), buf, size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4195

198191c4a   Krzysztof Halasa   WAN: convert driv...
4196
  	skb->protocol = hdlc_type_trans(skb, dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4197

198191c4a   Krzysztof Halasa   WAN: convert driv...
4198
4199
  	dev->stats.rx_packets++;
  	dev->stats.rx_bytes += size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4200
4201
  
  	netif_rx(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4202
  }
991990a12   Krzysztof Hałasa   WAN: Convert gene...
4203
4204
4205
4206
4207
4208
4209
4210
  static const struct net_device_ops hdlcdev_ops = {
  	.ndo_open       = hdlcdev_open,
  	.ndo_stop       = hdlcdev_close,
  	.ndo_change_mtu = hdlc_change_mtu,
  	.ndo_start_xmit = hdlc_start_xmit,
  	.ndo_do_ioctl   = hdlcdev_ioctl,
  	.ndo_tx_timeout = hdlcdev_tx_timeout,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4211
4212
4213
4214
4215
4216
4217
4218
4219
4220
4221
4222
4223
4224
4225
  /**
   * called by device driver when adding device instance
   * do generic HDLC initialization
   *
   * info  pointer to device instance information
   *
   * returns 0 if success, otherwise error code
   */
  static int hdlcdev_init(MGSLPC_INFO *info)
  {
  	int rc;
  	struct net_device *dev;
  	hdlc_device *hdlc;
  
  	/* allocate and initialize network and HDLC layer objects */
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
4226
4227
4228
4229
  	dev = alloc_hdlcdev(info);
  	if (dev == NULL) {
  		printk(KERN_ERR "%s:hdlc device allocation failure
  ", __FILE__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4230
4231
4232
4233
4234
4235
4236
4237
  		return -ENOMEM;
  	}
  
  	/* for network layer reporting purposes only */
  	dev->base_addr = info->io_base;
  	dev->irq       = info->irq_level;
  
  	/* network layer callbacks and settings */
991990a12   Krzysztof Hałasa   WAN: Convert gene...
4238
4239
  	dev->netdev_ops	    = &hdlcdev_ops;
  	dev->watchdog_timeo = 10 * HZ;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4240
4241
4242
4243
4244
4245
4246
4247
  	dev->tx_queue_len   = 50;
  
  	/* generic HDLC layer callbacks and settings */
  	hdlc         = dev_to_hdlc(dev);
  	hdlc->attach = hdlcdev_attach;
  	hdlc->xmit   = hdlcdev_xmit;
  
  	/* register objects with HDLC layer */
3d5539939   Alexey Khoroshilov   pcmcia: synclink_...
4248
4249
4250
4251
  	rc = register_hdlc_device(dev);
  	if (rc) {
  		printk(KERN_WARNING "%s:unable to register hdlc device
  ", __FILE__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4252
4253
4254
4255
4256
4257
4258
4259
4260
4261
4262
4263
4264
4265
4266
4267
4268
4269
4270
4271
4272
4273
  		free_netdev(dev);
  		return rc;
  	}
  
  	info->netdev = dev;
  	return 0;
  }
  
  /**
   * called by device driver when removing device instance
   * do generic HDLC cleanup
   *
   * info  pointer to device instance information
   */
  static void hdlcdev_exit(MGSLPC_INFO *info)
  {
  	unregister_hdlc_device(info->netdev);
  	free_netdev(info->netdev);
  	info->netdev = NULL;
  }
  
  #endif /* CONFIG_HDLC */