Blame view

drivers/tty/synclink_gt.c 132 KB
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1
  /*
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2
3
4
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
37
38
39
40
41
42
   * Device driver for Microgate SyncLink GT serial adapters.
   *
   * 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.
   */
  
  /*
   * DEBUG OUTPUT DEFINITIONS
   *
   * uncomment lines below to enable specific types of debug output
   *
   * DBGINFO   information - most verbose output
   * DBGERR    serious errors
   * DBGBH     bottom half service routine debugging
   * DBGISR    interrupt service routine debugging
   * DBGDATA   output receive and transmit data
   * DBGTBUF   output transmit DMA buffers and registers
   * DBGRBUF   output receive DMA buffers and registers
   */
  
  #define DBGINFO(fmt) if (debug_level >= DEBUG_LEVEL_INFO) printk fmt
  #define DBGERR(fmt) if (debug_level >= DEBUG_LEVEL_ERROR) printk fmt
  #define DBGBH(fmt) if (debug_level >= DEBUG_LEVEL_BH) printk fmt
  #define DBGISR(fmt) if (debug_level >= DEBUG_LEVEL_ISR) printk fmt
  #define DBGDATA(info, buf, size, label) if (debug_level >= DEBUG_LEVEL_DATA) trace_block((info), (buf), (size), (label))
f602501d9   Alan Cox   synclink: kill th...
43
44
  /*#define DBGTBUF(info) dump_tbufs(info)*/
  /*#define DBGRBUF(info) dump_rbufs(info)*/
705b6c7b3   Paul Fulghum   [PATCH] new drive...
45

705b6c7b3   Paul Fulghum   [PATCH] new drive...
46
  #include <linux/module.h>
705b6c7b3   Paul Fulghum   [PATCH] new drive...
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
  #include <linux/errno.h>
  #include <linux/signal.h>
  #include <linux/sched.h>
  #include <linux/timer.h>
  #include <linux/interrupt.h>
  #include <linux/pci.h>
  #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>
a18c56e5a   Alexey Dobriyan   proc tty: switch ...
62
  #include <linux/seq_file.h>
705b6c7b3   Paul Fulghum   [PATCH] new drive...
63
64
65
66
67
68
69
70
71
72
  #include <linux/slab.h>
  #include <linux/netdevice.h>
  #include <linux/vmalloc.h>
  #include <linux/init.h>
  #include <linux/delay.h>
  #include <linux/ioctl.h>
  #include <linux/termios.h>
  #include <linux/bitops.h>
  #include <linux/workqueue.h>
  #include <linux/hdlc.h>
3dd1247f4   Robert P. J. Day   synclink: standar...
73
  #include <linux/synclink.h>
705b6c7b3   Paul Fulghum   [PATCH] new drive...
74

705b6c7b3   Paul Fulghum   [PATCH] new drive...
75
76
77
78
79
80
  #include <asm/system.h>
  #include <asm/io.h>
  #include <asm/irq.h>
  #include <asm/dma.h>
  #include <asm/types.h>
  #include <asm/uaccess.h>
af69c7f92   Paul Fulghum   [PATCH] generic H...
81
82
83
84
  #if defined(CONFIG_HDLC) || (defined(CONFIG_HDLC_MODULE) && defined(CONFIG_SYNCLINK_GT_MODULE))
  #define SYNCLINK_GENERIC_HDLC 1
  #else
  #define SYNCLINK_GENERIC_HDLC 0
705b6c7b3   Paul Fulghum   [PATCH] new drive...
85
86
87
88
89
90
  #endif
  
  /*
   * module identification
   */
  static char *driver_name     = "SyncLink GT";
705b6c7b3   Paul Fulghum   [PATCH] new drive...
91
92
93
94
  static char *tty_driver_name = "synclink_gt";
  static char *tty_dev_prefix  = "ttySLG";
  MODULE_LICENSE("GPL");
  #define MGSL_MAGIC 0x5401
a077c1a07   Paul Fulghum   [PATCH] synclink_...
95
  #define MAX_DEVICES 32
705b6c7b3   Paul Fulghum   [PATCH] new drive...
96
97
98
  
  static struct pci_device_id pci_table[] = {
  	{PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
6f84be84b   Paul Fulghum   [PATCH] synclink_...
99
  	{PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT2_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
705b6c7b3   Paul Fulghum   [PATCH] new drive...
100
101
102
103
104
105
106
107
108
109
110
111
112
113
  	{PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT4_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
  	{PCI_VENDOR_ID_MICROGATE, SYNCLINK_AC_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
  	{0,}, /* terminate list */
  };
  MODULE_DEVICE_TABLE(pci, pci_table);
  
  static int  init_one(struct pci_dev *dev,const struct pci_device_id *ent);
  static void remove_one(struct pci_dev *dev);
  static struct pci_driver pci_driver = {
  	.name		= "synclink_gt",
  	.id_table	= pci_table,
  	.probe		= init_one,
  	.remove		= __devexit_p(remove_one),
  };
0fab6de09   Joe Perches   synclink drivers ...
114
  static bool pci_registered;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
115
116
117
118
119
120
121
122
123
124
  
  /*
   * module configuration and status
   */
  static struct slgt_info *slgt_device_list;
  static int slgt_device_count;
  
  static int ttymajor;
  static int debug_level;
  static int maxframe[MAX_DEVICES];
705b6c7b3   Paul Fulghum   [PATCH] new drive...
125
126
127
128
  
  module_param(ttymajor, int, 0);
  module_param(debug_level, int, 0);
  module_param_array(maxframe, int, NULL, 0);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
129
130
131
132
  
  MODULE_PARM_DESC(ttymajor, "TTY major device number override: 0=auto assigned");
  MODULE_PARM_DESC(debug_level, "Debug syslog output: 0=disabled, 1 to 5=increasing detail");
  MODULE_PARM_DESC(maxframe, "Maximum frame size used by device (4096 to 65535)");
705b6c7b3   Paul Fulghum   [PATCH] new drive...
133
134
135
136
  
  /*
   * tty support and callbacks
   */
705b6c7b3   Paul Fulghum   [PATCH] new drive...
137
138
139
140
141
  static struct tty_driver *serial_driver;
  
  static int  open(struct tty_struct *tty, struct file * filp);
  static void close(struct tty_struct *tty, struct file * filp);
  static void hangup(struct tty_struct *tty);
606d099cd   Alan Cox   [PATCH] tty: swit...
142
  static void set_termios(struct tty_struct *tty, struct ktermios *old_termios);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
143
144
  
  static int  write(struct tty_struct *tty, const unsigned char *buf, int count);
55da77899   Alan Cox   synclink series: ...
145
  static int put_char(struct tty_struct *tty, unsigned char ch);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
146
147
148
149
150
151
152
  static void send_xchar(struct tty_struct *tty, char ch);
  static void wait_until_sent(struct tty_struct *tty, int timeout);
  static int  write_room(struct tty_struct *tty);
  static void flush_chars(struct tty_struct *tty);
  static void flush_buffer(struct tty_struct *tty);
  static void tx_hold(struct tty_struct *tty);
  static void tx_release(struct tty_struct *tty);
6caa76b77   Alan Cox   tty: now phase ou...
153
  static int  ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
154
155
156
  static int  chars_in_buffer(struct tty_struct *tty);
  static void throttle(struct tty_struct * tty);
  static void unthrottle(struct tty_struct * tty);
9e98966c7   Alan Cox   tty: rework break...
157
  static int set_break(struct tty_struct *tty, int break_state);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
158
159
160
161
  
  /*
   * generic HDLC support and callbacks
   */
af69c7f92   Paul Fulghum   [PATCH] generic H...
162
  #if SYNCLINK_GENERIC_HDLC
705b6c7b3   Paul Fulghum   [PATCH] new drive...
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
  #define dev_to_port(D) (dev_to_hdlc(D)->priv)
  static void hdlcdev_tx_done(struct slgt_info *info);
  static void hdlcdev_rx(struct slgt_info *info, char *buf, int size);
  static int  hdlcdev_init(struct slgt_info *info);
  static void hdlcdev_exit(struct slgt_info *info);
  #endif
  
  
  /*
   * device specific structures, macros and functions
   */
  
  #define SLGT_MAX_PORTS 4
  #define SLGT_REG_SIZE  256
  
  /*
0080b7aae   Paul Fulghum   [PATCH] synclink_...
179
180
181
182
183
184
185
186
187
188
189
190
191
192
   * conditional wait facility
   */
  struct cond_wait {
  	struct cond_wait *next;
  	wait_queue_head_t q;
  	wait_queue_t wait;
  	unsigned int data;
  };
  static void init_cond_wait(struct cond_wait *w, unsigned int data);
  static void add_cond_wait(struct cond_wait **head, struct cond_wait *w);
  static void remove_cond_wait(struct cond_wait **head, struct cond_wait *w);
  static void flush_cond_wait(struct cond_wait **head);
  
  /*
705b6c7b3   Paul Fulghum   [PATCH] new drive...
193
194
195
196
   * DMA buffer descriptor and access macros
   */
  struct slgt_desc
  {
51ef9c57f   Al Viro   synclink_gt endia...
197
198
199
200
  	__le16 count;
  	__le16 status;
  	__le32 pbuf;  /* physical address of data buffer */
  	__le32 next;  /* physical address of next descriptor */
705b6c7b3   Paul Fulghum   [PATCH] new drive...
201
202
203
204
205
  
  	/* driver book keeping */
  	char *buf;          /* virtual  address of data buffer */
      	unsigned int pdesc; /* physical address of this descriptor */
  	dma_addr_t buf_dma_addr;
403214d0a   Paul Fulghum   synclink_gt: impr...
206
  	unsigned short buf_count;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
207
208
209
210
211
212
  };
  
  #define set_desc_buffer(a,b) (a).pbuf = cpu_to_le32((unsigned int)(b))
  #define set_desc_next(a,b) (a).next   = cpu_to_le32((unsigned int)(b))
  #define set_desc_count(a,b)(a).count  = cpu_to_le16((unsigned short)(b))
  #define set_desc_eof(a,b)  (a).status = cpu_to_le16((b) ? (le16_to_cpu((a).status) | BIT0) : (le16_to_cpu((a).status) & ~BIT0))
5ba5a5d21   Paul Fulghum   tty: synclink_gt ...
213
  #define set_desc_status(a, b) (a).status = cpu_to_le16((unsigned short)(b))
705b6c7b3   Paul Fulghum   [PATCH] new drive...
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
  #define desc_count(a)      (le16_to_cpu((a).count))
  #define desc_status(a)     (le16_to_cpu((a).status))
  #define desc_complete(a)   (le16_to_cpu((a).status) & BIT15)
  #define desc_eof(a)        (le16_to_cpu((a).status) & BIT2)
  #define desc_crc_error(a)  (le16_to_cpu((a).status) & BIT1)
  #define desc_abort(a)      (le16_to_cpu((a).status) & BIT0)
  #define desc_residue(a)    ((le16_to_cpu((a).status) & 0x38) >> 3)
  
  struct _input_signal_events {
  	int ri_up;
  	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
   */
  struct slgt_info {
  	void *if_ptr;		/* General purpose pointer (used by SPPP) */
8fb06c771   Alan Cox   synclink: use tty...
238
  	struct tty_port port;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
239
240
241
242
  
  	struct slgt_info *next_device;	/* device list link */
  
  	int magic;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
243
244
245
246
247
248
249
250
251
252
  
  	char device_name[25];
  	struct pci_dev *pdev;
  
  	int port_count;  /* count of ports on adapter */
  	int adapter_num; /* adapter instance number */
  	int port_num;    /* port instance number */
  
  	/* array of pointers to port contexts on this adapter */
  	struct slgt_info *port_array[SLGT_MAX_PORTS];
705b6c7b3   Paul Fulghum   [PATCH] new drive...
253
  	int			line;		/* tty line instance number */
705b6c7b3   Paul Fulghum   [PATCH] new drive...
254
255
  
  	struct mgsl_icount	icount;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
256
257
  	int			timeout;
  	int			x_char;		/* xon/xoff character */
705b6c7b3   Paul Fulghum   [PATCH] new drive...
258
259
  	unsigned int		read_status_mask;
  	unsigned int 		ignore_status_mask;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
260
261
262
263
  	wait_queue_head_t	status_event_wait_q;
  	wait_queue_head_t	event_wait_q;
  	struct timer_list	tx_timer;
  	struct timer_list	rx_timer;
0080b7aae   Paul Fulghum   [PATCH] synclink_...
264
265
  	unsigned int            gpio_present;
  	struct cond_wait        *gpio_wait_q;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
266
267
268
269
  	spinlock_t lock;	/* spinlock for synchronizing with ISR */
  
  	struct work_struct task;
  	u32 pending_bh;
0fab6de09   Joe Perches   synclink drivers ...
270
271
  	bool bh_requested;
  	bool bh_running;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
272
273
  
  	int isr_overflow;
0fab6de09   Joe Perches   synclink drivers ...
274
275
  	bool irq_requested;	/* true if IRQ requested */
  	bool irq_occurred;	/* for diagnostics use */
705b6c7b3   Paul Fulghum   [PATCH] new drive...
276
277
278
279
280
281
282
283
284
  
  	/* device configuration */
  
  	unsigned int bus_type;
  	unsigned int irq_level;
  	unsigned long irq_flags;
  
  	unsigned char __iomem * reg_addr;  /* memory mapped registers address */
  	u32 phys_reg_addr;
0fab6de09   Joe Perches   synclink drivers ...
285
  	bool reg_addr_requested;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
286
287
288
289
  
  	MGSL_PARAMS params;       /* communications parameters */
  	u32 idle_mode;
  	u32 max_frame_size;       /* as set by device config */
814dae031   Paul Fulghum   synclink_gt: add ...
290
  	unsigned int rbuf_fill_level;
5ba5a5d21   Paul Fulghum   tty: synclink_gt ...
291
  	unsigned int rx_pio;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
292
  	unsigned int if_mode;
1f80769ff   Paul Fulghum   synclink_gt: add ...
293
  	unsigned int base_clock;
9807224f1   Paul Fulghum   drivers/char/sync...
294
295
  	unsigned int xsync;
  	unsigned int xctrl;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
296
297
  
  	/* device status */
0fab6de09   Joe Perches   synclink drivers ...
298
299
  	bool rx_enabled;
  	bool rx_restart;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
300

0fab6de09   Joe Perches   synclink drivers ...
301
302
  	bool tx_enabled;
  	bool tx_active;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
303
304
  
  	unsigned char signals;    /* serial signal states */
2641dfd98   Darren Jenkins   [PATCH] synclink_...
305
  	int init_error;  /* initialization error */
705b6c7b3   Paul Fulghum   [PATCH] new drive...
306
307
308
309
310
311
  
  	unsigned char *tx_buf;
  	int tx_count;
  
  	char flag_buf[MAX_ASYNC_BUFFER_SIZE];
  	char char_buf[MAX_ASYNC_BUFFER_SIZE];
0fab6de09   Joe Perches   synclink drivers ...
312
  	bool drop_rts_on_tx_done;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
313
314
315
316
317
318
319
320
321
322
323
324
325
326
  	struct	_input_signal_events	input_signal_events;
  
  	int dcd_chkcount;	/* check counts to prevent */
  	int cts_chkcount;	/* too many IRQs if a signal */
  	int dsr_chkcount;	/* is floating */
  	int ri_chkcount;
  
  	char *bufs;		/* virtual address of DMA buffer lists */
  	dma_addr_t bufs_dma_addr; /* physical address of buffer descriptors */
  
  	unsigned int rbuf_count;
  	struct slgt_desc *rbufs;
  	unsigned int rbuf_current;
  	unsigned int rbuf_index;
5ba5a5d21   Paul Fulghum   tty: synclink_gt ...
327
328
  	unsigned int rbuf_fill_index;
  	unsigned short rbuf_fill_count;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
329
330
331
332
333
334
335
336
337
338
339
340
  
  	unsigned int tbuf_count;
  	struct slgt_desc *tbufs;
  	unsigned int tbuf_current;
  	unsigned int tbuf_start;
  
  	unsigned char *tmp_rbuf;
  	unsigned int tmp_rbuf_count;
  
  	/* SPPP/Cisco HDLC device parts */
  
  	int netcount;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
341
  	spinlock_t netlock;
af69c7f92   Paul Fulghum   [PATCH] generic H...
342
  #if SYNCLINK_GENERIC_HDLC
705b6c7b3   Paul Fulghum   [PATCH] new drive...
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
  	struct net_device *netdev;
  #endif
  
  };
  
  static MGSL_PARAMS default_params = {
  	.mode            = MGSL_MODE_HDLC,
  	.loopback        = 0,
  	.flags           = HDLC_FLAG_UNDERRUN_ABORT15,
  	.encoding        = HDLC_ENCODING_NRZI_SPACE,
  	.clock_speed     = 0,
  	.addr_filter     = 0xff,
  	.crc_type        = HDLC_CRC_16_CCITT,
  	.preamble_length = HDLC_PREAMBLE_LENGTH_8BITS,
  	.preamble        = HDLC_PREAMBLE_PATTERN_NONE,
  	.data_rate       = 9600,
  	.data_bits       = 8,
  	.stop_bits       = 1,
  	.parity          = ASYNC_PARITY_NONE
  };
  
  
  #define BH_RECEIVE  1
  #define BH_TRANSMIT 2
  #define BH_STATUS   4
  #define IO_PIN_SHUTDOWN_LIMIT 100
  
  #define DMABUFSIZE 256
  #define DESC_LIST_SIZE 4096
  
  #define MASK_PARITY  BIT1
202af6d50   Paul Fulghum   [PATCH] synclink_...
374
375
  #define MASK_FRAMING BIT0
  #define MASK_BREAK   BIT14
705b6c7b3   Paul Fulghum   [PATCH] new drive...
376
377
378
  #define MASK_OVERRUN BIT4
  
  #define GSR   0x00 /* global status */
0080b7aae   Paul Fulghum   [PATCH] synclink_...
379
380
381
382
383
  #define JCR   0x04 /* JTAG control */
  #define IODR  0x08 /* GPIO direction */
  #define IOER  0x0c /* GPIO interrupt enable */
  #define IOVR  0x10 /* GPIO value */
  #define IOSR  0x14 /* GPIO interrupt status */
705b6c7b3   Paul Fulghum   [PATCH] new drive...
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
  #define TDR   0x80 /* tx data */
  #define RDR   0x80 /* rx data */
  #define TCR   0x82 /* tx control */
  #define TIR   0x84 /* tx idle */
  #define TPR   0x85 /* tx preamble */
  #define RCR   0x86 /* rx control */
  #define VCR   0x88 /* V.24 control */
  #define CCR   0x89 /* clock control */
  #define BDR   0x8a /* baud divisor */
  #define SCR   0x8c /* serial control */
  #define SSR   0x8e /* serial status */
  #define RDCSR 0x90 /* rx DMA control/status */
  #define TDCSR 0x94 /* tx DMA control/status */
  #define RDDAR 0x98 /* rx DMA descriptor address */
  #define TDDAR 0x9c /* tx DMA descriptor address */
9807224f1   Paul Fulghum   drivers/char/sync...
399
400
  #define XSR   0x40 /* extended sync pattern */
  #define XCR   0x44 /* extended control */
705b6c7b3   Paul Fulghum   [PATCH] new drive...
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
  
  #define RXIDLE      BIT14
  #define RXBREAK     BIT14
  #define IRQ_TXDATA  BIT13
  #define IRQ_TXIDLE  BIT12
  #define IRQ_TXUNDER BIT11 /* HDLC */
  #define IRQ_RXDATA  BIT10
  #define IRQ_RXIDLE  BIT9  /* HDLC */
  #define IRQ_RXBREAK BIT9  /* async */
  #define IRQ_RXOVER  BIT8
  #define IRQ_DSR     BIT7
  #define IRQ_CTS     BIT6
  #define IRQ_DCD     BIT5
  #define IRQ_RI      BIT4
  #define IRQ_ALL     0x3ff0
  #define IRQ_MASTER  BIT0
  
  #define slgt_irq_on(info, mask) \
  	wr_reg16((info), SCR, (unsigned short)(rd_reg16((info), SCR) | (mask)))
  #define slgt_irq_off(info, mask) \
  	wr_reg16((info), SCR, (unsigned short)(rd_reg16((info), SCR) & ~(mask)))
  
  static __u8  rd_reg8(struct slgt_info *info, unsigned int addr);
  static void  wr_reg8(struct slgt_info *info, unsigned int addr, __u8 value);
  static __u16 rd_reg16(struct slgt_info *info, unsigned int addr);
  static void  wr_reg16(struct slgt_info *info, unsigned int addr, __u16 value);
  static __u32 rd_reg32(struct slgt_info *info, unsigned int addr);
  static void  wr_reg32(struct slgt_info *info, unsigned int addr, __u32 value);
  
  static void  msc_set_vcr(struct slgt_info *info);
  
  static int  startup(struct slgt_info *info);
  static int  block_til_ready(struct tty_struct *tty, struct file * filp,struct slgt_info *info);
  static void shutdown(struct slgt_info *info);
  static void program_hw(struct slgt_info *info);
  static void change_params(struct slgt_info *info);
  
  static int  register_test(struct slgt_info *info);
  static int  irq_test(struct slgt_info *info);
  static int  loopback_test(struct slgt_info *info);
  static int  adapter_test(struct slgt_info *info);
  
  static void reset_adapter(struct slgt_info *info);
  static void reset_port(struct slgt_info *info);
  static void async_mode(struct slgt_info *info);
cb10dc9ac   Paul Fulghum   [PATCH] synclink_...
446
  static void sync_mode(struct slgt_info *info);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
447
448
449
450
451
452
  
  static void rx_stop(struct slgt_info *info);
  static void rx_start(struct slgt_info *info);
  static void reset_rbufs(struct slgt_info *info);
  static void free_rbufs(struct slgt_info *info, unsigned int first, unsigned int last);
  static void rdma_reset(struct slgt_info *info);
0fab6de09   Joe Perches   synclink drivers ...
453
454
  static bool rx_get_frame(struct slgt_info *info);
  static bool rx_get_buf(struct slgt_info *info);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
455
456
457
458
459
  
  static void tx_start(struct slgt_info *info);
  static void tx_stop(struct slgt_info *info);
  static void tx_set_idle(struct slgt_info *info);
  static unsigned int free_tbuf_count(struct slgt_info *info);
403214d0a   Paul Fulghum   synclink_gt: impr...
460
  static unsigned int tbuf_bytes(struct slgt_info *info);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
461
462
  static void reset_tbufs(struct slgt_info *info);
  static void tdma_reset(struct slgt_info *info);
de538eb34   Paul Fulghum   serial: synclink_...
463
  static bool tx_load(struct slgt_info *info, const char *buf, unsigned int count);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
464
465
466
467
468
469
470
  
  static void get_signals(struct slgt_info *info);
  static void set_signals(struct slgt_info *info);
  static void enable_loopback(struct slgt_info *info);
  static void set_rate(struct slgt_info *info, u32 data_rate);
  
  static int  bh_action(struct slgt_info *info);
c4028958b   David Howells   WorkStruct: make ...
471
  static void bh_handler(struct work_struct *work);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
472
473
474
475
476
  static void bh_transmit(struct slgt_info *info);
  static void isr_serial(struct slgt_info *info);
  static void isr_rdma(struct slgt_info *info);
  static void isr_txeom(struct slgt_info *info, unsigned short status);
  static void isr_tdma(struct slgt_info *info);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
  
  static int  alloc_dma_bufs(struct slgt_info *info);
  static void free_dma_bufs(struct slgt_info *info);
  static int  alloc_desc(struct slgt_info *info);
  static void free_desc(struct slgt_info *info);
  static int  alloc_bufs(struct slgt_info *info, struct slgt_desc *bufs, int count);
  static void free_bufs(struct slgt_info *info, struct slgt_desc *bufs, int count);
  
  static int  alloc_tmp_rbuf(struct slgt_info *info);
  static void free_tmp_rbuf(struct slgt_info *info);
  
  static void tx_timeout(unsigned long context);
  static void rx_timeout(unsigned long context);
  
  /*
   * ioctl handlers
   */
  static int  get_stats(struct slgt_info *info, struct mgsl_icount __user *user_icount);
  static int  get_params(struct slgt_info *info, MGSL_PARAMS __user *params);
  static int  set_params(struct slgt_info *info, MGSL_PARAMS __user *params);
  static int  get_txidle(struct slgt_info *info, int __user *idle_mode);
  static int  set_txidle(struct slgt_info *info, int idle_mode);
  static int  tx_enable(struct slgt_info *info, int enable);
  static int  tx_abort(struct slgt_info *info);
  static int  rx_enable(struct slgt_info *info, int enable);
  static int  modem_input_wait(struct slgt_info *info,int arg);
  static int  wait_mgsl_event(struct slgt_info *info, int __user *mask_ptr);
60b33c133   Alan Cox   tiocmget: kill of...
504
  static int  tiocmget(struct tty_struct *tty);
20b9d1771   Alan Cox   tiocmset: kill th...
505
506
  static int  tiocmset(struct tty_struct *tty,
  				unsigned int set, unsigned int clear);
9e98966c7   Alan Cox   tty: rework break...
507
  static int set_break(struct tty_struct *tty, int break_state);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
508
509
  static int  get_interface(struct slgt_info *info, int __user *if_mode);
  static int  set_interface(struct slgt_info *info, int if_mode);
0080b7aae   Paul Fulghum   [PATCH] synclink_...
510
511
512
  static int  set_gpio(struct slgt_info *info, struct gpio_desc __user *gpio);
  static int  get_gpio(struct slgt_info *info, struct gpio_desc __user *gpio);
  static int  wait_gpio(struct slgt_info *info, struct gpio_desc __user *gpio);
9807224f1   Paul Fulghum   drivers/char/sync...
513
514
515
516
  static int  get_xsync(struct slgt_info *info, int __user *if_mode);
  static int  set_xsync(struct slgt_info *info, int if_mode);
  static int  get_xctrl(struct slgt_info *info, int __user *if_mode);
  static int  set_xctrl(struct slgt_info *info, int if_mode);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
  
  /*
   * driver functions
   */
  static void add_device(struct slgt_info *info);
  static void device_init(int adapter_num, struct pci_dev *pdev);
  static int  claim_resources(struct slgt_info *info);
  static void release_resources(struct slgt_info *info);
  
  /*
   * DEBUG OUTPUT CODE
   */
  #ifndef DBGINFO
  #define DBGINFO(fmt)
  #endif
  #ifndef DBGERR
  #define DBGERR(fmt)
  #endif
  #ifndef DBGBH
  #define DBGBH(fmt)
  #endif
  #ifndef DBGISR
  #define DBGISR(fmt)
  #endif
  
  #ifdef DBGDATA
  static void trace_block(struct slgt_info *info, const char *data, int count, const char *label)
  {
  	int i;
  	int linecount;
  	printk("%s %s data:
  ",info->device_name, label);
  	while(count) {
  		linecount = (count > 16) ? 16 : count;
  		for(i=0; i < linecount; i++)
  			printk("%02X ",(unsigned char)data[i]);
  		for(;i<17;i++)
  			printk("   ");
  		for(i=0;i<linecount;i++) {
  			if (data[i]>=040 && data[i]<=0176)
  				printk("%c",data[i]);
  			else
  				printk(".");
  		}
  		printk("
  ");
  		data  += linecount;
  		count -= linecount;
  	}
  }
  #else
  #define DBGDATA(info, buf, size, label)
  #endif
  
  #ifdef DBGTBUF
  static void dump_tbufs(struct slgt_info *info)
  {
  	int i;
  	printk("tbuf_current=%d
  ", info->tbuf_current);
  	for (i=0 ; i < info->tbuf_count ; i++) {
  		printk("%d: count=%04X status=%04X
  ",
  			i, le16_to_cpu(info->tbufs[i].count), le16_to_cpu(info->tbufs[i].status));
  	}
  }
  #else
  #define DBGTBUF(info)
  #endif
  
  #ifdef DBGRBUF
  static void dump_rbufs(struct slgt_info *info)
  {
  	int i;
  	printk("rbuf_current=%d
  ", info->rbuf_current);
  	for (i=0 ; i < info->rbuf_count ; i++) {
  		printk("%d: count=%04X status=%04X
  ",
  			i, le16_to_cpu(info->rbufs[i].count), le16_to_cpu(info->rbufs[i].status));
  	}
  }
  #else
  #define DBGRBUF(info)
  #endif
  
  static inline int sanity_check(struct slgt_info *info, char *devname, const char *name)
  {
  #ifdef SANITY_CHECK
  	if (!info) {
  		printk("null struct slgt_info for (%s) in %s
  ", devname, name);
  		return 1;
  	}
  	if (info->magic != MGSL_MAGIC) {
  		printk("bad magic number struct slgt_info (%s) in %s
  ", devname, name);
  		return 1;
  	}
  #else
  	if (!info)
  		return 1;
  #endif
  	return 0;
  }
  
  /**
   * line discipline callback wrappers
   *
   * The wrappers maintain line discipline references
   * while calling into the line discipline.
   *
   * ldisc_receive_buf  - pass receive data to line discipline
   */
  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
639
640
  		if (ld->ops->receive_buf)
  			ld->ops->receive_buf(tty, data, flags, count);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
  		tty_ldisc_deref(ld);
  	}
  }
  
  /* tty callbacks */
  
  static int open(struct tty_struct *tty, struct file *filp)
  {
  	struct slgt_info *info;
  	int retval, line;
  	unsigned long flags;
  
  	line = tty->index;
  	if ((line < 0) || (line >= slgt_device_count)) {
  		DBGERR(("%s: open with invalid line #%d.
  ", driver_name, line));
  		return -ENODEV;
  	}
  
  	info = slgt_device_list;
  	while(info && info->line != line)
  		info = info->next_device;
  	if (sanity_check(info, tty->name, "open"))
  		return -ENODEV;
  	if (info->init_error) {
  		DBGERR(("%s init error=%d
  ", info->device_name, info->init_error));
  		return -ENODEV;
  	}
  
  	tty->driver_data = info;
8fb06c771   Alan Cox   synclink: use tty...
672
  	info->port.tty = tty;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
673

8fb06c771   Alan Cox   synclink: use tty...
674
675
  	DBGINFO(("%s open, old ref count = %d
  ", info->device_name, info->port.count));
705b6c7b3   Paul Fulghum   [PATCH] new drive...
676
677
  
  	/* If port is closing, signal caller to try again */
8fb06c771   Alan Cox   synclink: use tty...
678
679
680
681
  	if (tty_hung_up_p(filp) || info->port.flags & ASYNC_CLOSING){
  		if (info->port.flags & ASYNC_CLOSING)
  			interruptible_sleep_on(&info->port.close_wait);
  		retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ?
705b6c7b3   Paul Fulghum   [PATCH] new drive...
682
683
684
  			-EAGAIN : -ERESTARTSYS);
  		goto cleanup;
  	}
a360fae67   Alan Cox   synclink: reworki...
685
  	mutex_lock(&info->port.mutex);
8fb06c771   Alan Cox   synclink: use tty...
686
  	info->port.tty->low_latency = (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
687
688
689
690
691
  
  	spin_lock_irqsave(&info->netlock, flags);
  	if (info->netcount) {
  		retval = -EBUSY;
  		spin_unlock_irqrestore(&info->netlock, flags);
a360fae67   Alan Cox   synclink: reworki...
692
  		mutex_unlock(&info->port.mutex);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
693
694
  		goto cleanup;
  	}
8fb06c771   Alan Cox   synclink: use tty...
695
  	info->port.count++;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
696
  	spin_unlock_irqrestore(&info->netlock, flags);
8fb06c771   Alan Cox   synclink: use tty...
697
  	if (info->port.count == 1) {
705b6c7b3   Paul Fulghum   [PATCH] new drive...
698
699
  		/* 1st open on this device, init hardware */
  		retval = startup(info);
80d04f22b   Dan Carpenter   synclink: add mut...
700
701
  		if (retval < 0) {
  			mutex_unlock(&info->port.mutex);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
702
  			goto cleanup;
80d04f22b   Dan Carpenter   synclink: add mut...
703
  		}
705b6c7b3   Paul Fulghum   [PATCH] new drive...
704
  	}
a360fae67   Alan Cox   synclink: reworki...
705
  	mutex_unlock(&info->port.mutex);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
706
707
708
709
710
711
712
713
714
715
716
717
  	retval = block_til_ready(tty, filp, info);
  	if (retval) {
  		DBGINFO(("%s block_til_ready rc=%d
  ", info->device_name, retval));
  		goto cleanup;
  	}
  
  	retval = 0;
  
  cleanup:
  	if (retval) {
  		if (tty->count == 1)
8fb06c771   Alan Cox   synclink: use tty...
718
719
720
  			info->port.tty = NULL; /* tty layer will release tty struct */
  		if(info->port.count)
  			info->port.count--;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
721
722
723
724
725
726
727
728
729
730
731
732
733
  	}
  
  	DBGINFO(("%s open rc=%d
  ", info->device_name, retval));
  	return retval;
  }
  
  static void close(struct tty_struct *tty, struct file *filp)
  {
  	struct slgt_info *info = tty->driver_data;
  
  	if (sanity_check(info, tty->name, "close"))
  		return;
8fb06c771   Alan Cox   synclink: use tty...
734
735
  	DBGINFO(("%s close entry, count=%d
  ", info->device_name, info->port.count));
705b6c7b3   Paul Fulghum   [PATCH] new drive...
736

a6614999e   Alan Cox   tty: Introduce so...
737
  	if (tty_port_close_start(&info->port, tty, filp) == 0)
705b6c7b3   Paul Fulghum   [PATCH] new drive...
738
  		goto cleanup;
a360fae67   Alan Cox   synclink: reworki...
739
  	mutex_lock(&info->port.mutex);
8fb06c771   Alan Cox   synclink: use tty...
740
   	if (info->port.flags & ASYNC_INITIALIZED)
705b6c7b3   Paul Fulghum   [PATCH] new drive...
741
   		wait_until_sent(tty, info->timeout);
978e595f8   Alan Cox   tty/serial: lay t...
742
  	flush_buffer(tty);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
743
744
745
  	tty_ldisc_flush(tty);
  
  	shutdown(info);
a360fae67   Alan Cox   synclink: reworki...
746
  	mutex_unlock(&info->port.mutex);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
747

a6614999e   Alan Cox   tty: Introduce so...
748
  	tty_port_close_end(&info->port, tty);
8fb06c771   Alan Cox   synclink: use tty...
749
  	info->port.tty = NULL;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
750
  cleanup:
8fb06c771   Alan Cox   synclink: use tty...
751
752
  	DBGINFO(("%s close exit, count=%d
  ", tty->driver->name, info->port.count));
705b6c7b3   Paul Fulghum   [PATCH] new drive...
753
754
755
756
757
  }
  
  static void hangup(struct tty_struct *tty)
  {
  	struct slgt_info *info = tty->driver_data;
a360fae67   Alan Cox   synclink: reworki...
758
  	unsigned long flags;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
759
760
761
762
763
764
765
  
  	if (sanity_check(info, tty->name, "hangup"))
  		return;
  	DBGINFO(("%s hangup
  ", info->device_name));
  
  	flush_buffer(tty);
a360fae67   Alan Cox   synclink: reworki...
766
767
  
  	mutex_lock(&info->port.mutex);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
768
  	shutdown(info);
a360fae67   Alan Cox   synclink: reworki...
769
  	spin_lock_irqsave(&info->port.lock, flags);
8fb06c771   Alan Cox   synclink: use tty...
770
771
772
  	info->port.count = 0;
  	info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
  	info->port.tty = NULL;
a360fae67   Alan Cox   synclink: reworki...
773
774
  	spin_unlock_irqrestore(&info->port.lock, flags);
  	mutex_unlock(&info->port.mutex);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
775

8fb06c771   Alan Cox   synclink: use tty...
776
  	wake_up_interruptible(&info->port.open_wait);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
777
  }
606d099cd   Alan Cox   [PATCH] tty: swit...
778
  static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
705b6c7b3   Paul Fulghum   [PATCH] new drive...
779
780
781
782
783
784
  {
  	struct slgt_info *info = tty->driver_data;
  	unsigned long flags;
  
  	DBGINFO(("%s set_termios
  ", tty->driver->name));
705b6c7b3   Paul Fulghum   [PATCH] new drive...
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
  	change_params(info);
  
  	/* Handle transition to B0 status */
  	if (old_termios->c_cflag & CBAUD &&
  	    !(tty->termios->c_cflag & CBAUD)) {
  		info->signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
  		spin_lock_irqsave(&info->lock,flags);
  		set_signals(info);
  		spin_unlock_irqrestore(&info->lock,flags);
  	}
  
  	/* Handle transition away from B0 status */
  	if (!(old_termios->c_cflag & CBAUD) &&
  	    tty->termios->c_cflag & CBAUD) {
  		info->signals |= SerialSignal_DTR;
   		if (!(tty->termios->c_cflag & CRTSCTS) ||
   		    !test_bit(TTY_THROTTLED, &tty->flags)) {
  			info->signals |= SerialSignal_RTS;
   		}
  		spin_lock_irqsave(&info->lock,flags);
  	 	set_signals(info);
  		spin_unlock_irqrestore(&info->lock,flags);
  	}
  
  	/* Handle turning off CRTSCTS */
  	if (old_termios->c_cflag & CRTSCTS &&
  	    !(tty->termios->c_cflag & CRTSCTS)) {
  		tty->hw_stopped = 0;
  		tx_release(tty);
  	}
  }
ce89294c0   Paul Fulghum   synclink_gt: fix ...
816
817
818
819
820
821
822
823
824
825
826
  static void update_tx_timer(struct slgt_info *info)
  {
  	/*
  	 * use worst case speed of 1200bps to calculate transmit timeout
  	 * based on data in buffers (tbuf_bytes) and FIFO (128 bytes)
  	 */
  	if (info->params.mode == MGSL_MODE_HDLC) {
  		int timeout  = (tbuf_bytes(info) * 7) + 1000;
  		mod_timer(&info->tx_timer, jiffies + msecs_to_jiffies(timeout));
  	}
  }
705b6c7b3   Paul Fulghum   [PATCH] new drive...
827
828
829
830
831
832
833
834
  static int write(struct tty_struct *tty,
  		 const unsigned char *buf, int count)
  {
  	int ret = 0;
  	struct slgt_info *info = tty->driver_data;
  	unsigned long flags;
  
  	if (sanity_check(info, tty->name, "write"))
de538eb34   Paul Fulghum   serial: synclink_...
835
  		return -EIO;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
836
837
  	DBGINFO(("%s write count=%d
  ", info->device_name, count));
de538eb34   Paul Fulghum   serial: synclink_...
838
839
  	if (!info->tx_buf || (count > info->max_frame_size))
  		return -EIO;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
840

de538eb34   Paul Fulghum   serial: synclink_...
841
842
  	if (!count || tty->stopped || tty->hw_stopped)
  		return 0;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
843

de538eb34   Paul Fulghum   serial: synclink_...
844
  	spin_lock_irqsave(&info->lock, flags);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
845

de538eb34   Paul Fulghum   serial: synclink_...
846
  	if (info->tx_count) {
8a38c2851   Paul Fulghum   synclink_gt: impr...
847
  		/* send accumulated data from send_char() */
de538eb34   Paul Fulghum   serial: synclink_...
848
849
850
  		if (!tx_load(info, info->tx_buf, info->tx_count))
  			goto cleanup;
  		info->tx_count = 0;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
851
  	}
de538eb34   Paul Fulghum   serial: synclink_...
852
853
  	if (tx_load(info, buf, count))
  		ret = count;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
854
855
  
  cleanup:
de538eb34   Paul Fulghum   serial: synclink_...
856
  	spin_unlock_irqrestore(&info->lock, flags);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
857
858
859
860
  	DBGINFO(("%s write rc=%d
  ", info->device_name, ret));
  	return ret;
  }
55da77899   Alan Cox   synclink series: ...
861
  static int put_char(struct tty_struct *tty, unsigned char ch)
705b6c7b3   Paul Fulghum   [PATCH] new drive...
862
863
864
  {
  	struct slgt_info *info = tty->driver_data;
  	unsigned long flags;
6c82c4150   Andrew Morton   drivers/char/sync...
865
  	int ret = 0;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
866
867
  
  	if (sanity_check(info, tty->name, "put_char"))
55da77899   Alan Cox   synclink series: ...
868
  		return 0;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
869
870
  	DBGINFO(("%s put_char(%d)
  ", info->device_name, ch));
326f28e9e   Eric Sesterhenn   [PATCH] More !tty...
871
  	if (!info->tx_buf)
55da77899   Alan Cox   synclink series: ...
872
  		return 0;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
873
  	spin_lock_irqsave(&info->lock,flags);
de538eb34   Paul Fulghum   serial: synclink_...
874
  	if (info->tx_count < info->max_frame_size) {
705b6c7b3   Paul Fulghum   [PATCH] new drive...
875
  		info->tx_buf[info->tx_count++] = ch;
55da77899   Alan Cox   synclink series: ...
876
877
  		ret = 1;
  	}
705b6c7b3   Paul Fulghum   [PATCH] new drive...
878
  	spin_unlock_irqrestore(&info->lock,flags);
55da77899   Alan Cox   synclink series: ...
879
  	return ret;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
  }
  
  static void send_xchar(struct tty_struct *tty, char ch)
  {
  	struct slgt_info *info = tty->driver_data;
  	unsigned long flags;
  
  	if (sanity_check(info, tty->name, "send_xchar"))
  		return;
  	DBGINFO(("%s send_xchar(%d)
  ", info->device_name, ch));
  	info->x_char = ch;
  	if (ch) {
  		spin_lock_irqsave(&info->lock,flags);
  		if (!info->tx_enabled)
  		 	tx_start(info);
  		spin_unlock_irqrestore(&info->lock,flags);
  	}
  }
  
  static void wait_until_sent(struct tty_struct *tty, int timeout)
  {
  	struct slgt_info *info = tty->driver_data;
  	unsigned long orig_jiffies, char_time;
  
  	if (!info )
  		return;
  	if (sanity_check(info, tty->name, "wait_until_sent"))
  		return;
  	DBGINFO(("%s wait_until_sent entry
  ", info->device_name));
8fb06c771   Alan Cox   synclink: use tty...
911
  	if (!(info->port.flags & ASYNC_INITIALIZED))
705b6c7b3   Paul Fulghum   [PATCH] new drive...
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
  		goto exit;
  
  	orig_jiffies = jiffies;
  
  	/* 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.
  	 */
  
  	if (info->params.data_rate) {
  	       	char_time = info->timeout/(32 * 5);
  		if (!char_time)
  			char_time++;
  	} else
  		char_time = 1;
  
  	if (timeout)
  		char_time = min_t(unsigned long, char_time, timeout);
  
  	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;
  	}
705b6c7b3   Paul Fulghum   [PATCH] new drive...
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
  exit:
  	DBGINFO(("%s wait_until_sent exit
  ", info->device_name));
  }
  
  static int write_room(struct tty_struct *tty)
  {
  	struct slgt_info *info = tty->driver_data;
  	int ret;
  
  	if (sanity_check(info, tty->name, "write_room"))
  		return 0;
  	ret = (info->tx_active) ? 0 : HDLC_MAX_FRAME_SIZE;
  	DBGINFO(("%s write_room=%d
  ", info->device_name, ret));
  	return ret;
  }
  
  static void flush_chars(struct tty_struct *tty)
  {
  	struct slgt_info *info = tty->driver_data;
  	unsigned long flags;
  
  	if (sanity_check(info, tty->name, "flush_chars"))
  		return;
  	DBGINFO(("%s flush_chars entry tx_count=%d
  ", info->device_name, info->tx_count));
  
  	if (info->tx_count <= 0 || tty->stopped ||
  	    tty->hw_stopped || !info->tx_buf)
  		return;
  
  	DBGINFO(("%s flush_chars start transmit
  ", info->device_name));
  
  	spin_lock_irqsave(&info->lock,flags);
de538eb34   Paul Fulghum   serial: synclink_...
975
976
  	if (info->tx_count && tx_load(info, info->tx_buf, info->tx_count))
  		info->tx_count = 0;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
977
978
979
980
981
982
983
984
985
986
987
988
  	spin_unlock_irqrestore(&info->lock,flags);
  }
  
  static void flush_buffer(struct tty_struct *tty)
  {
  	struct slgt_info *info = tty->driver_data;
  	unsigned long flags;
  
  	if (sanity_check(info, tty->name, "flush_buffer"))
  		return;
  	DBGINFO(("%s flush_buffer
  ", info->device_name));
de538eb34   Paul Fulghum   serial: synclink_...
989
990
991
  	spin_lock_irqsave(&info->lock, flags);
  	info->tx_count = 0;
  	spin_unlock_irqrestore(&info->lock, flags);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
992

705b6c7b3   Paul Fulghum   [PATCH] new drive...
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
  	tty_wakeup(tty);
  }
  
  /*
   * throttle (stop) transmitter
   */
  static void tx_hold(struct tty_struct *tty)
  {
  	struct slgt_info *info = tty->driver_data;
  	unsigned long flags;
  
  	if (sanity_check(info, tty->name, "tx_hold"))
  		return;
  	DBGINFO(("%s tx_hold
  ", info->device_name));
  	spin_lock_irqsave(&info->lock,flags);
  	if (info->tx_enabled && info->params.mode == MGSL_MODE_ASYNC)
  	 	tx_stop(info);
  	spin_unlock_irqrestore(&info->lock,flags);
  }
  
  /*
   * release (start) transmitter
   */
  static void tx_release(struct tty_struct *tty)
  {
  	struct slgt_info *info = tty->driver_data;
  	unsigned long flags;
  
  	if (sanity_check(info, tty->name, "tx_release"))
  		return;
  	DBGINFO(("%s tx_release
  ", info->device_name));
de538eb34   Paul Fulghum   serial: synclink_...
1026
1027
1028
1029
  	spin_lock_irqsave(&info->lock, flags);
  	if (info->tx_count && tx_load(info, info->tx_buf, info->tx_count))
  		info->tx_count = 0;
  	spin_unlock_irqrestore(&info->lock, flags);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1030
1031
1032
1033
1034
1035
1036
1037
  }
  
  /*
   * Service an IOCTL request
   *
   * Arguments
   *
   * 	tty	pointer to tty instance data
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1038
1039
1040
1041
1042
   * 	cmd	IOCTL command code
   * 	arg	command argument/context
   *
   * Return 0 if success, otherwise error code
   */
6caa76b77   Alan Cox   tty: now phase ou...
1043
  static int ioctl(struct tty_struct *tty,
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1044
1045
1046
  		 unsigned int cmd, unsigned long arg)
  {
  	struct slgt_info *info = tty->driver_data;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1047
  	void __user *argp = (void __user *)arg;
1f8cabb70   Alan Cox   synclink series: ...
1048
  	int ret;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1049
1050
1051
1052
1053
1054
1055
  
  	if (sanity_check(info, tty->name, "ioctl"))
  		return -ENODEV;
  	DBGINFO(("%s ioctl() cmd=%08X
  ", info->device_name, cmd));
  
  	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
0587102cf   Alan Cox   tty: icount chang...
1056
  	    (cmd != TIOCMIWAIT)) {
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1057
1058
1059
  		if (tty->flags & (1 << TTY_IO_ERROR))
  		    return -EIO;
  	}
f602501d9   Alan Cox   synclink: kill th...
1060
1061
1062
1063
1064
  	switch (cmd) {
  	case MGSL_IOCWAITEVENT:
  		return wait_mgsl_event(info, argp);
  	case TIOCMIWAIT:
  		return modem_input_wait(info,(int)arg);
f602501d9   Alan Cox   synclink: kill th...
1065
1066
1067
1068
1069
1070
  	case MGSL_IOCSGPIO:
  		return set_gpio(info, argp);
  	case MGSL_IOCGGPIO:
  		return get_gpio(info, argp);
  	case MGSL_IOCWAITGPIO:
  		return wait_gpio(info, argp);
9807224f1   Paul Fulghum   drivers/char/sync...
1071
1072
1073
1074
1075
1076
1077
1078
  	case MGSL_IOCGXSYNC:
  		return get_xsync(info, argp);
  	case MGSL_IOCSXSYNC:
  		return set_xsync(info, (int)arg);
  	case MGSL_IOCGXCTRL:
  		return get_xctrl(info, argp);
  	case MGSL_IOCSXCTRL:
  		return set_xctrl(info, (int)arg);
f602501d9   Alan Cox   synclink: kill th...
1079
1080
  	}
  	mutex_lock(&info->port.mutex);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1081
1082
  	switch (cmd) {
  	case MGSL_IOCGPARAMS:
1f8cabb70   Alan Cox   synclink series: ...
1083
1084
  		ret = get_params(info, argp);
  		break;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1085
  	case MGSL_IOCSPARAMS:
1f8cabb70   Alan Cox   synclink series: ...
1086
1087
  		ret = set_params(info, argp);
  		break;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1088
  	case MGSL_IOCGTXIDLE:
1f8cabb70   Alan Cox   synclink series: ...
1089
1090
  		ret = get_txidle(info, argp);
  		break;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1091
  	case MGSL_IOCSTXIDLE:
1f8cabb70   Alan Cox   synclink series: ...
1092
1093
  		ret = set_txidle(info, (int)arg);
  		break;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1094
  	case MGSL_IOCTXENABLE:
1f8cabb70   Alan Cox   synclink series: ...
1095
1096
  		ret = tx_enable(info, (int)arg);
  		break;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1097
  	case MGSL_IOCRXENABLE:
1f8cabb70   Alan Cox   synclink series: ...
1098
1099
  		ret = rx_enable(info, (int)arg);
  		break;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1100
  	case MGSL_IOCTXABORT:
1f8cabb70   Alan Cox   synclink series: ...
1101
1102
  		ret = tx_abort(info);
  		break;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1103
  	case MGSL_IOCGSTATS:
1f8cabb70   Alan Cox   synclink series: ...
1104
1105
  		ret = get_stats(info, argp);
  		break;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1106
  	case MGSL_IOCGIF:
1f8cabb70   Alan Cox   synclink series: ...
1107
1108
  		ret = get_interface(info, argp);
  		break;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1109
  	case MGSL_IOCSIF:
1f8cabb70   Alan Cox   synclink series: ...
1110
1111
  		ret = set_interface(info,(int)arg);
  		break;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1112
  	default:
1f8cabb70   Alan Cox   synclink series: ...
1113
  		ret = -ENOIOCTLCMD;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1114
  	}
f602501d9   Alan Cox   synclink: kill th...
1115
  	mutex_unlock(&info->port.mutex);
1f8cabb70   Alan Cox   synclink series: ...
1116
  	return ret;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1117
  }
0587102cf   Alan Cox   tty: icount chang...
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
  static int get_icount(struct tty_struct *tty,
  				struct serial_icounter_struct *icount)
  
  {
  	struct slgt_info *info = tty->driver_data;
  	struct mgsl_icount cnow;	/* kernel counter temps */
  	unsigned long flags;
  
  	spin_lock_irqsave(&info->lock,flags);
  	cnow = info->icount;
  	spin_unlock_irqrestore(&info->lock,flags);
  
  	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;
  }
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1144
  /*
2acdb1694   Paul Fulghum   synclink_gt: add ...
1145
1146
1147
1148
1149
1150
1151
1152
1153
   * support for 32 bit ioctl calls on 64 bit systems
   */
  #ifdef CONFIG_COMPAT
  static long get_params32(struct slgt_info *info, struct MGSL_PARAMS32 __user *user_params)
  {
  	struct MGSL_PARAMS32 tmp_params;
  
  	DBGINFO(("%s get_params32
  ", info->device_name));
ed77ed611   Vasiliy Kulikov   drivers/char/sync...
1154
  	memset(&tmp_params, 0, sizeof(tmp_params));
2acdb1694   Paul Fulghum   synclink_gt: add ...
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
  	tmp_params.mode            = (compat_ulong_t)info->params.mode;
  	tmp_params.loopback        = info->params.loopback;
  	tmp_params.flags           = info->params.flags;
  	tmp_params.encoding        = info->params.encoding;
  	tmp_params.clock_speed     = (compat_ulong_t)info->params.clock_speed;
  	tmp_params.addr_filter     = info->params.addr_filter;
  	tmp_params.crc_type        = info->params.crc_type;
  	tmp_params.preamble_length = info->params.preamble_length;
  	tmp_params.preamble        = info->params.preamble;
  	tmp_params.data_rate       = (compat_ulong_t)info->params.data_rate;
  	tmp_params.data_bits       = info->params.data_bits;
  	tmp_params.stop_bits       = info->params.stop_bits;
  	tmp_params.parity          = info->params.parity;
  	if (copy_to_user(user_params, &tmp_params, sizeof(struct MGSL_PARAMS32)))
  		return -EFAULT;
  	return 0;
  }
  
  static long set_params32(struct slgt_info *info, struct MGSL_PARAMS32 __user *new_params)
  {
  	struct MGSL_PARAMS32 tmp_params;
  
  	DBGINFO(("%s set_params32
  ", info->device_name));
  	if (copy_from_user(&tmp_params, new_params, sizeof(struct MGSL_PARAMS32)))
  		return -EFAULT;
  
  	spin_lock(&info->lock);
1f80769ff   Paul Fulghum   synclink_gt: add ...
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
  	if (tmp_params.mode == MGSL_MODE_BASE_CLOCK) {
  		info->base_clock = tmp_params.clock_speed;
  	} else {
  		info->params.mode            = tmp_params.mode;
  		info->params.loopback        = tmp_params.loopback;
  		info->params.flags           = tmp_params.flags;
  		info->params.encoding        = tmp_params.encoding;
  		info->params.clock_speed     = tmp_params.clock_speed;
  		info->params.addr_filter     = tmp_params.addr_filter;
  		info->params.crc_type        = tmp_params.crc_type;
  		info->params.preamble_length = tmp_params.preamble_length;
  		info->params.preamble        = tmp_params.preamble;
  		info->params.data_rate       = tmp_params.data_rate;
  		info->params.data_bits       = tmp_params.data_bits;
  		info->params.stop_bits       = tmp_params.stop_bits;
  		info->params.parity          = tmp_params.parity;
  	}
2acdb1694   Paul Fulghum   synclink_gt: add ...
1200
  	spin_unlock(&info->lock);
1f80769ff   Paul Fulghum   synclink_gt: add ...
1201
  	program_hw(info);
2acdb1694   Paul Fulghum   synclink_gt: add ...
1202
1203
1204
  
  	return 0;
  }
6caa76b77   Alan Cox   tty: now phase ou...
1205
  static long slgt_compat_ioctl(struct tty_struct *tty,
2acdb1694   Paul Fulghum   synclink_gt: add ...
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
  			 unsigned int cmd, unsigned long arg)
  {
  	struct slgt_info *info = tty->driver_data;
  	int rc = -ENOIOCTLCMD;
  
  	if (sanity_check(info, tty->name, "compat_ioctl"))
  		return -ENODEV;
  	DBGINFO(("%s compat_ioctl() cmd=%08X
  ", info->device_name, cmd));
  
  	switch (cmd) {
  
  	case MGSL_IOCSPARAMS32:
  		rc = set_params32(info, compat_ptr(arg));
  		break;
  
  	case MGSL_IOCGPARAMS32:
  		rc = get_params32(info, compat_ptr(arg));
  		break;
  
  	case MGSL_IOCGPARAMS:
  	case MGSL_IOCSPARAMS:
  	case MGSL_IOCGTXIDLE:
  	case MGSL_IOCGSTATS:
  	case MGSL_IOCWAITEVENT:
  	case MGSL_IOCGIF:
  	case MGSL_IOCSGPIO:
  	case MGSL_IOCGGPIO:
  	case MGSL_IOCWAITGPIO:
9807224f1   Paul Fulghum   drivers/char/sync...
1235
1236
  	case MGSL_IOCGXSYNC:
  	case MGSL_IOCGXCTRL:
2acdb1694   Paul Fulghum   synclink_gt: add ...
1237
1238
1239
1240
1241
1242
  	case MGSL_IOCSTXIDLE:
  	case MGSL_IOCTXENABLE:
  	case MGSL_IOCRXENABLE:
  	case MGSL_IOCTXABORT:
  	case TIOCMIWAIT:
  	case MGSL_IOCSIF:
9807224f1   Paul Fulghum   drivers/char/sync...
1243
1244
  	case MGSL_IOCSXSYNC:
  	case MGSL_IOCSXCTRL:
6caa76b77   Alan Cox   tty: now phase ou...
1245
  		rc = ioctl(tty, cmd, arg);
2acdb1694   Paul Fulghum   synclink_gt: add ...
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
  		break;
  	}
  
  	DBGINFO(("%s compat_ioctl() cmd=%08X rc=%d
  ", info->device_name, cmd, rc));
  	return rc;
  }
  #else
  #define slgt_compat_ioctl NULL
  #endif /* ifdef CONFIG_COMPAT */
  
  /*
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1258
1259
   * proc fs support
   */
a18c56e5a   Alexey Dobriyan   proc tty: switch ...
1260
  static inline void line_info(struct seq_file *m, struct slgt_info *info)
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1261
1262
  {
  	char stat_buf[30];
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1263
  	unsigned long flags;
a18c56e5a   Alexey Dobriyan   proc tty: switch ...
1264
1265
  	seq_printf(m, "%s: IO=%08X IRQ=%d MaxFrameSize=%u
  ",
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
  		      info->device_name, info->phys_reg_addr,
  		      info->irq_level, info->max_frame_size);
  
  	/* output current serial signal states */
  	spin_lock_irqsave(&info->lock,flags);
  	get_signals(info);
  	spin_unlock_irqrestore(&info->lock,flags);
  
  	stat_buf[0] = 0;
  	stat_buf[1] = 0;
  	if (info->signals & SerialSignal_RTS)
  		strcat(stat_buf, "|RTS");
  	if (info->signals & SerialSignal_CTS)
  		strcat(stat_buf, "|CTS");
  	if (info->signals & SerialSignal_DTR)
  		strcat(stat_buf, "|DTR");
  	if (info->signals & SerialSignal_DSR)
  		strcat(stat_buf, "|DSR");
  	if (info->signals & SerialSignal_DCD)
  		strcat(stat_buf, "|CD");
  	if (info->signals & SerialSignal_RI)
  		strcat(stat_buf, "|RI");
  
  	if (info->params.mode != MGSL_MODE_ASYNC) {
a18c56e5a   Alexey Dobriyan   proc tty: switch ...
1290
  		seq_printf(m, "\tHDLC txok:%d rxok:%d",
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1291
1292
  			       info->icount.txok, info->icount.rxok);
  		if (info->icount.txunder)
a18c56e5a   Alexey Dobriyan   proc tty: switch ...
1293
  			seq_printf(m, " txunder:%d", info->icount.txunder);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1294
  		if (info->icount.txabort)
a18c56e5a   Alexey Dobriyan   proc tty: switch ...
1295
  			seq_printf(m, " txabort:%d", info->icount.txabort);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1296
  		if (info->icount.rxshort)
a18c56e5a   Alexey Dobriyan   proc tty: switch ...
1297
  			seq_printf(m, " rxshort:%d", info->icount.rxshort);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1298
  		if (info->icount.rxlong)
a18c56e5a   Alexey Dobriyan   proc tty: switch ...
1299
  			seq_printf(m, " rxlong:%d", info->icount.rxlong);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1300
  		if (info->icount.rxover)
a18c56e5a   Alexey Dobriyan   proc tty: switch ...
1301
  			seq_printf(m, " rxover:%d", info->icount.rxover);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1302
  		if (info->icount.rxcrc)
a18c56e5a   Alexey Dobriyan   proc tty: switch ...
1303
  			seq_printf(m, " rxcrc:%d", info->icount.rxcrc);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1304
  	} else {
a18c56e5a   Alexey Dobriyan   proc tty: switch ...
1305
  		seq_printf(m, "\tASYNC tx:%d rx:%d",
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1306
1307
  			       info->icount.tx, info->icount.rx);
  		if (info->icount.frame)
a18c56e5a   Alexey Dobriyan   proc tty: switch ...
1308
  			seq_printf(m, " fe:%d", info->icount.frame);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1309
  		if (info->icount.parity)
a18c56e5a   Alexey Dobriyan   proc tty: switch ...
1310
  			seq_printf(m, " pe:%d", info->icount.parity);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1311
  		if (info->icount.brk)
a18c56e5a   Alexey Dobriyan   proc tty: switch ...
1312
  			seq_printf(m, " brk:%d", info->icount.brk);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1313
  		if (info->icount.overrun)
a18c56e5a   Alexey Dobriyan   proc tty: switch ...
1314
  			seq_printf(m, " oe:%d", info->icount.overrun);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1315
1316
1317
  	}
  
  	/* Append serial signal status to end */
a18c56e5a   Alexey Dobriyan   proc tty: switch ...
1318
1319
  	seq_printf(m, " %s
  ", stat_buf+1);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1320

a18c56e5a   Alexey Dobriyan   proc tty: switch ...
1321
1322
  	seq_printf(m, "\ttxactive=%d bh_req=%d bh_run=%d pending_bh=%x
  ",
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1323
1324
  		       info->tx_active,info->bh_requested,info->bh_running,
  		       info->pending_bh);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1325
1326
1327
1328
  }
  
  /* Called to print information about devices
   */
a18c56e5a   Alexey Dobriyan   proc tty: switch ...
1329
  static int synclink_gt_proc_show(struct seq_file *m, void *v)
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1330
  {
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1331
  	struct slgt_info *info;
a18c56e5a   Alexey Dobriyan   proc tty: switch ...
1332
1333
  	seq_puts(m, "synclink_gt driver
  ");
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1334
1335
1336
  
  	info = slgt_device_list;
  	while( info ) {
a18c56e5a   Alexey Dobriyan   proc tty: switch ...
1337
  		line_info(m, info);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1338
1339
  		info = info->next_device;
  	}
a18c56e5a   Alexey Dobriyan   proc tty: switch ...
1340
1341
  	return 0;
  }
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1342

a18c56e5a   Alexey Dobriyan   proc tty: switch ...
1343
1344
1345
  static int synclink_gt_proc_open(struct inode *inode, struct file *file)
  {
  	return single_open(file, synclink_gt_proc_show, NULL);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1346
  }
a18c56e5a   Alexey Dobriyan   proc tty: switch ...
1347
1348
1349
1350
1351
1352
1353
  static const struct file_operations synclink_gt_proc_fops = {
  	.owner		= THIS_MODULE,
  	.open		= synclink_gt_proc_open,
  	.read		= seq_read,
  	.llseek		= seq_lseek,
  	.release	= single_release,
  };
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1354
1355
1356
1357
1358
1359
  /*
   * return count of bytes in transmit buffer
   */
  static int chars_in_buffer(struct tty_struct *tty)
  {
  	struct slgt_info *info = tty->driver_data;
403214d0a   Paul Fulghum   synclink_gt: impr...
1360
  	int count;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1361
1362
  	if (sanity_check(info, tty->name, "chars_in_buffer"))
  		return 0;
403214d0a   Paul Fulghum   synclink_gt: impr...
1363
1364
1365
1366
  	count = tbuf_bytes(info);
  	DBGINFO(("%s chars_in_buffer()=%d
  ", info->device_name, count));
  	return count;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
  }
  
  /*
   * signal remote device to throttle send data (our receive data)
   */
  static void throttle(struct tty_struct * tty)
  {
  	struct slgt_info *info = tty->driver_data;
  	unsigned long flags;
  
  	if (sanity_check(info, tty->name, "throttle"))
  		return;
  	DBGINFO(("%s throttle
  ", info->device_name));
  	if (I_IXOFF(tty))
  		send_xchar(tty, STOP_CHAR(tty));
   	if (tty->termios->c_cflag & CRTSCTS) {
  		spin_lock_irqsave(&info->lock,flags);
  		info->signals &= ~SerialSignal_RTS;
  	 	set_signals(info);
  		spin_unlock_irqrestore(&info->lock,flags);
  	}
  }
  
  /*
   * signal remote device to stop throttling send data (our receive data)
   */
  static void unthrottle(struct tty_struct * tty)
  {
  	struct slgt_info *info = tty->driver_data;
  	unsigned long flags;
  
  	if (sanity_check(info, tty->name, "unthrottle"))
  		return;
  	DBGINFO(("%s unthrottle
  ", info->device_name));
  	if (I_IXOFF(tty)) {
  		if (info->x_char)
  			info->x_char = 0;
  		else
  			send_xchar(tty, START_CHAR(tty));
  	}
   	if (tty->termios->c_cflag & CRTSCTS) {
  		spin_lock_irqsave(&info->lock,flags);
  		info->signals |= SerialSignal_RTS;
  	 	set_signals(info);
  		spin_unlock_irqrestore(&info->lock,flags);
  	}
  }
  
  /*
   * set or clear transmit break condition
   * break_state	-1=set break condition, 0=clear
   */
9e98966c7   Alan Cox   tty: rework break...
1421
  static int set_break(struct tty_struct *tty, int break_state)
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1422
1423
1424
1425
1426
1427
  {
  	struct slgt_info *info = tty->driver_data;
  	unsigned short value;
  	unsigned long flags;
  
  	if (sanity_check(info, tty->name, "set_break"))
9e98966c7   Alan Cox   tty: rework break...
1428
  		return -EINVAL;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
  	DBGINFO(("%s set_break(%d)
  ", info->device_name, break_state));
  
  	spin_lock_irqsave(&info->lock,flags);
  	value = rd_reg16(info, TCR);
   	if (break_state == -1)
  		value |= BIT6;
  	else
  		value &= ~BIT6;
  	wr_reg16(info, TCR, value);
  	spin_unlock_irqrestore(&info->lock,flags);
9e98966c7   Alan Cox   tty: rework break...
1440
  	return 0;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1441
  }
af69c7f92   Paul Fulghum   [PATCH] generic H...
1442
  #if SYNCLINK_GENERIC_HDLC
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
  
  /**
   * 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)
  {
  	struct slgt_info *info = dev_to_port(dev);
  	unsigned char  new_encoding;
  	unsigned short new_crctype;
  
  	/* return error if TTY interface open */
8fb06c771   Alan Cox   synclink: use tty...
1462
  	if (info->port.count)
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
  		return -EBUSY;
  
  	DBGINFO(("%s hdlcdev_attach
  ", info->device_name));
  
  	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
1487
  	info->params.crc_type = new_crctype;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
  
  	/* if network interface up, reprogram hardware */
  	if (info->netcount)
  		program_hw(info);
  
  	return 0;
  }
  
  /**
   * called by generic HDLC layer to send frame
   *
   * skb  socket buffer containing HDLC frame
   * dev  pointer to network device structure
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1501
   */
4c5d502d8   Stephen Hemminger   hdlc: convert to ...
1502
1503
  static netdev_tx_t hdlcdev_xmit(struct sk_buff *skb,
  				      struct net_device *dev)
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1504
1505
  {
  	struct slgt_info *info = dev_to_port(dev);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1506
1507
1508
1509
  	unsigned long flags;
  
  	DBGINFO(("%s hdlc_xmit
  ", dev->name));
de538eb34   Paul Fulghum   serial: synclink_...
1510
1511
  	if (!skb->len)
  		return NETDEV_TX_OK;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1512
1513
  	/* stop sending until this frame completes */
  	netif_stop_queue(dev);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1514
  	/* update network statistics */
198191c4a   Krzysztof Halasa   WAN: convert driv...
1515
1516
  	dev->stats.tx_packets++;
  	dev->stats.tx_bytes += skb->len;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1517

705b6c7b3   Paul Fulghum   [PATCH] new drive...
1518
1519
  	/* save start time for transmit timeout detection */
  	dev->trans_start = jiffies;
de538eb34   Paul Fulghum   serial: synclink_...
1520
1521
1522
1523
1524
1525
  	spin_lock_irqsave(&info->lock, flags);
  	tx_load(info, skb->data, skb->len);
  	spin_unlock_irqrestore(&info->lock, flags);
  
  	/* done with socket buffer, so free it */
  	dev_kfree_skb(skb);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1526

4c5d502d8   Stephen Hemminger   hdlc: convert to ...
1527
  	return NETDEV_TX_OK;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
  }
  
  /**
   * 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)
  {
  	struct slgt_info *info = dev_to_port(dev);
  	int rc;
  	unsigned long flags;
d4c63b7c7   Paul Fulghum   synclink_gt fix m...
1543
1544
  	if (!try_module_get(THIS_MODULE))
  		return -EBUSY;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1545
1546
1547
1548
1549
1550
1551
1552
1553
  	DBGINFO(("%s hdlcdev_open
  ", dev->name));
  
  	/* generic HDLC layer open processing */
  	if ((rc = hdlc_open(dev)))
  		return rc;
  
  	/* arbitrate between network and tty opens */
  	spin_lock_irqsave(&info->netlock, flags);
8fb06c771   Alan Cox   synclink: use tty...
1554
  	if (info->port.count != 0 || info->netcount != 0) {
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
  		DBGINFO(("%s hdlc_open busy
  ", dev->name));
  		spin_unlock_irqrestore(&info->netlock, flags);
  		return -EBUSY;
  	}
  	info->netcount=1;
  	spin_unlock_irqrestore(&info->netlock, flags);
  
  	/* claim resources and init adapter */
  	if ((rc = startup(info)) != 0) {
  		spin_lock_irqsave(&info->netlock, flags);
  		info->netcount=0;
  		spin_unlock_irqrestore(&info->netlock, flags);
  		return rc;
  	}
  
  	/* assert DTR and RTS, apply hardware settings */
  	info->signals |= SerialSignal_RTS + SerialSignal_DTR;
  	program_hw(info);
  
  	/* enable network layer transmit */
  	dev->trans_start = jiffies;
  	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 ...
1583
1584
1585
1586
  	if (info->signals & SerialSignal_DCD)
  		netif_carrier_on(dev);
  	else
  		netif_carrier_off(dev);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
  	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)
  {
  	struct slgt_info *info = dev_to_port(dev);
  	unsigned long flags;
  
  	DBGINFO(("%s hdlcdev_close
  ", dev->name));
  
  	netif_stop_queue(dev);
  
  	/* shutdown adapter and release resources */
  	shutdown(info);
  
  	hdlc_close(dev);
  
  	spin_lock_irqsave(&info->netlock, flags);
  	info->netcount=0;
  	spin_unlock_irqrestore(&info->netlock, flags);
d4c63b7c7   Paul Fulghum   synclink_gt fix m...
1616
  	module_put(THIS_MODULE);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
  	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;
  	struct slgt_info *info = dev_to_port(dev);
  	unsigned int flags;
  
  	DBGINFO(("%s hdlcdev_ioctl
  ", dev->name));
  
  	/* return error if TTY interface open */
8fb06c771   Alan Cox   synclink: use tty...
1641
  	if (info->port.count)
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1642
1643
1644
1645
  		return -EBUSY;
  
  	if (cmd != SIOCWANDEV)
  		return hdlc_ioctl(dev, ifr, cmd);
ed77ed611   Vasiliy Kulikov   drivers/char/sync...
1646
  	memset(&new_line, 0, sizeof(new_line));
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
  	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 */
  		if (info->netcount)
  			program_hw(info);
  		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)
  {
  	struct slgt_info *info = dev_to_port(dev);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1731
1732
1733
1734
  	unsigned long flags;
  
  	DBGINFO(("%s hdlcdev_tx_timeout
  ", dev->name));
198191c4a   Krzysztof Halasa   WAN: convert driv...
1735
1736
  	dev->stats.tx_errors++;
  	dev->stats.tx_aborted_errors++;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
  
  	spin_lock_irqsave(&info->lock,flags);
  	tx_stop(info);
  	spin_unlock_irqrestore(&info->lock,flags);
  
  	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(struct slgt_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(struct slgt_info *info, char *buf, int size)
  {
  	struct sk_buff *skb = dev_alloc_skb(size);
  	struct net_device *dev = info->netdev;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1769
1770
1771
1772
1773
1774
1775
  
  	DBGINFO(("%s hdlcdev_rx
  ", dev->name));
  
  	if (skb == NULL) {
  		DBGERR(("%s: can't alloc skb, drop packet
  ", dev->name));
198191c4a   Krzysztof Halasa   WAN: convert driv...
1776
  		dev->stats.rx_dropped++;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1777
1778
  		return;
  	}
198191c4a   Krzysztof Halasa   WAN: convert driv...
1779
  	memcpy(skb_put(skb, size), buf, size);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1780

198191c4a   Krzysztof Halasa   WAN: convert driv...
1781
  	skb->protocol = hdlc_type_trans(skb, dev);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1782

198191c4a   Krzysztof Halasa   WAN: convert driv...
1783
1784
  	dev->stats.rx_packets++;
  	dev->stats.rx_bytes += size;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1785
1786
  
  	netif_rx(skb);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1787
  }
991990a12   Krzysztof HaÅ‚asa   WAN: Convert gene...
1788
1789
1790
1791
1792
1793
1794
1795
  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,
  };
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
  /**
   * 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(struct slgt_info *info)
  {
  	int rc;
  	struct net_device *dev;
  	hdlc_device *hdlc;
  
  	/* allocate and initialize network and HDLC layer objects */
  
  	if (!(dev = alloc_hdlcdev(info))) {
  		printk(KERN_ERR "%s hdlc device alloc failure
  ", info->device_name);
  		return -ENOMEM;
  	}
  
  	/* for network layer reporting purposes only */
  	dev->mem_start = info->phys_reg_addr;
  	dev->mem_end   = info->phys_reg_addr + SLGT_REG_SIZE - 1;
  	dev->irq       = info->irq_level;
  
  	/* network layer callbacks and settings */
991990a12   Krzysztof HaÅ‚asa   WAN: Convert gene...
1824
1825
  	dev->netdev_ops	    = &hdlcdev_ops;
  	dev->watchdog_timeo = 10 * HZ;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
  	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 */
  	if ((rc = register_hdlc_device(dev))) {
  		printk(KERN_WARNING "%s:unable to register hdlc device
  ",__FILE__);
  		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(struct slgt_info *info)
  {
  	unregister_hdlc_device(info->netdev);
  	free_netdev(info->netdev);
  	info->netdev = NULL;
  }
  
  #endif /* ifdef CONFIG_HDLC */
  
  /*
   * get async data from rx DMA buffers
   */
  static void rx_async(struct slgt_info *info)
  {
8fb06c771   Alan Cox   synclink: use tty...
1865
   	struct tty_struct *tty = info->port.tty;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1866
1867
1868
1869
1870
1871
   	struct mgsl_icount *icount = &info->icount;
  	unsigned int start, end;
  	unsigned char *p;
  	unsigned char status;
  	struct slgt_desc *bufs = info->rbufs;
  	int i, count;
33f0f88f1   Alan Cox   [PATCH] TTY layer...
1872
1873
1874
  	int chars = 0;
  	int stat;
  	unsigned char ch;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
  
  	start = end = info->rbuf_current;
  
  	while(desc_complete(bufs[end])) {
  		count = desc_count(bufs[end]) - info->rbuf_index;
  		p     = bufs[end].buf + info->rbuf_index;
  
  		DBGISR(("%s rx_async count=%d
  ", info->device_name, count));
  		DBGDATA(info, p, count, "rx");
  
  		for(i=0 ; i < count; i+=2, p+=2) {
33f0f88f1   Alan Cox   [PATCH] TTY layer...
1887
  			ch = *p;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1888
  			icount->rx++;
33f0f88f1   Alan Cox   [PATCH] TTY layer...
1889
  			stat = 0;
202af6d50   Paul Fulghum   [PATCH] synclink_...
1890
1891
  			if ((status = *(p+1) & (BIT1 + BIT0))) {
  				if (status & BIT1)
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1892
  					icount->parity++;
202af6d50   Paul Fulghum   [PATCH] synclink_...
1893
  				else if (status & BIT0)
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1894
1895
1896
1897
  					icount->frame++;
  				/* discard char if tty control flags say so */
  				if (status & info->ignore_status_mask)
  					continue;
202af6d50   Paul Fulghum   [PATCH] synclink_...
1898
  				if (status & BIT1)
33f0f88f1   Alan Cox   [PATCH] TTY layer...
1899
  					stat = TTY_PARITY;
202af6d50   Paul Fulghum   [PATCH] synclink_...
1900
  				else if (status & BIT0)
33f0f88f1   Alan Cox   [PATCH] TTY layer...
1901
  					stat = TTY_FRAME;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1902
1903
  			}
  			if (tty) {
33f0f88f1   Alan Cox   [PATCH] TTY layer...
1904
1905
  				tty_insert_flip_char(tty, ch, stat);
  				chars++;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1906
1907
1908
1909
1910
1911
  			}
  		}
  
  		if (i < count) {
  			/* receive buffer not completed */
  			info->rbuf_index += i;
40565f196   Jiri Slaby   [PATCH] Char: tim...
1912
  			mod_timer(&info->rx_timer, jiffies + 1);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
  			break;
  		}
  
  		info->rbuf_index = 0;
  		free_rbufs(info, end, end);
  
  		if (++end == info->rbuf_count)
  			end = 0;
  
  		/* if entire list searched then no frame available */
  		if (end == start)
  			break;
  	}
33f0f88f1   Alan Cox   [PATCH] TTY layer...
1926
  	if (tty && chars)
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
  		tty_flip_buffer_push(tty);
  }
  
  /*
   * return next bottom half action to perform
   */
  static int bh_action(struct slgt_info *info)
  {
  	unsigned long flags;
  	int rc;
  
  	spin_lock_irqsave(&info->lock,flags);
  
  	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;
  	} else {
  		/* Mark BH routine as complete */
0fab6de09   Joe Perches   synclink drivers ...
1951
1952
  		info->bh_running = false;
  		info->bh_requested = false;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
  		rc = 0;
  	}
  
  	spin_unlock_irqrestore(&info->lock,flags);
  
  	return rc;
  }
  
  /*
   * perform bottom half processing
   */
c4028958b   David Howells   WorkStruct: make ...
1964
  static void bh_handler(struct work_struct *work)
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1965
  {
c4028958b   David Howells   WorkStruct: make ...
1966
  	struct slgt_info *info = container_of(work, struct slgt_info, task);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1967
1968
1969
1970
  	int action;
  
  	if (!info)
  		return;
0fab6de09   Joe Perches   synclink drivers ...
1971
  	info->bh_running = true;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
  
  	while((action = bh_action(info))) {
  		switch (action) {
  		case BH_RECEIVE:
  			DBGBH(("%s bh receive
  ", info->device_name));
  			switch(info->params.mode) {
  			case MGSL_MODE_ASYNC:
  				rx_async(info);
  				break;
  			case MGSL_MODE_HDLC:
  				while(rx_get_frame(info));
  				break;
  			case MGSL_MODE_RAW:
cb10dc9ac   Paul Fulghum   [PATCH] synclink_...
1986
1987
  			case MGSL_MODE_MONOSYNC:
  			case MGSL_MODE_BISYNC:
9807224f1   Paul Fulghum   drivers/char/sync...
1988
  			case MGSL_MODE_XSYNC:
705b6c7b3   Paul Fulghum   [PATCH] new drive...
1989
1990
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
  				while(rx_get_buf(info));
  				break;
  			}
  			/* restart receiver if rx DMA buffers exhausted */
  			if (info->rx_restart)
  				rx_start(info);
  			break;
  		case BH_TRANSMIT:
  			bh_transmit(info);
  			break;
  		case BH_STATUS:
  			DBGBH(("%s bh status
  ", info->device_name));
  			info->ri_chkcount = 0;
  			info->dsr_chkcount = 0;
  			info->dcd_chkcount = 0;
  			info->cts_chkcount = 0;
  			break;
  		default:
  			DBGBH(("%s unknown action
  ", info->device_name));
  			break;
  		}
  	}
  	DBGBH(("%s bh_handler exit
  ", info->device_name));
  }
  
  static void bh_transmit(struct slgt_info *info)
  {
8fb06c771   Alan Cox   synclink: use tty...
2019
  	struct tty_struct *tty = info->port.tty;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2020
2021
2022
  
  	DBGBH(("%s bh_transmit
  ", info->device_name));
b963a8441   Jiri Slaby   [PATCH] Char: tty...
2023
  	if (tty)
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2024
  		tty_wakeup(tty);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2025
  }
ed8485fb3   Paul Fulghum   synclink_gt fix m...
2026
  static void dsr_change(struct slgt_info *info, unsigned short status)
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2027
  {
ed8485fb3   Paul Fulghum   synclink_gt fix m...
2028
2029
2030
2031
2032
2033
2034
  	if (status & BIT3) {
  		info->signals |= SerialSignal_DSR;
  		info->input_signal_events.dsr_up++;
  	} else {
  		info->signals &= ~SerialSignal_DSR;
  		info->input_signal_events.dsr_down++;
  	}
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2035
2036
2037
2038
2039
2040
2041
  	DBGISR(("dsr_change %s signals=%04X
  ", info->device_name, info->signals));
  	if ((info->dsr_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) {
  		slgt_irq_off(info, IRQ_DSR);
  		return;
  	}
  	info->icount.dsr++;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2042
2043
2044
2045
  	wake_up_interruptible(&info->status_event_wait_q);
  	wake_up_interruptible(&info->event_wait_q);
  	info->pending_bh |= BH_STATUS;
  }
ed8485fb3   Paul Fulghum   synclink_gt fix m...
2046
  static void cts_change(struct slgt_info *info, unsigned short status)
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2047
  {
ed8485fb3   Paul Fulghum   synclink_gt fix m...
2048
2049
2050
2051
2052
2053
2054
  	if (status & BIT2) {
  		info->signals |= SerialSignal_CTS;
  		info->input_signal_events.cts_up++;
  	} else {
  		info->signals &= ~SerialSignal_CTS;
  		info->input_signal_events.cts_down++;
  	}
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2055
2056
2057
2058
2059
2060
2061
  	DBGISR(("cts_change %s signals=%04X
  ", info->device_name, info->signals));
  	if ((info->cts_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) {
  		slgt_irq_off(info, IRQ_CTS);
  		return;
  	}
  	info->icount.cts++;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2062
2063
2064
  	wake_up_interruptible(&info->status_event_wait_q);
  	wake_up_interruptible(&info->event_wait_q);
  	info->pending_bh |= BH_STATUS;
8fb06c771   Alan Cox   synclink: use tty...
2065
2066
2067
  	if (info->port.flags & ASYNC_CTS_FLOW) {
  		if (info->port.tty) {
  			if (info->port.tty->hw_stopped) {
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2068
  				if (info->signals & SerialSignal_CTS) {
8fb06c771   Alan Cox   synclink: use tty...
2069
  		 			info->port.tty->hw_stopped = 0;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2070
2071
2072
2073
2074
  					info->pending_bh |= BH_TRANSMIT;
  					return;
  				}
  			} else {
  				if (!(info->signals & SerialSignal_CTS))
8fb06c771   Alan Cox   synclink: use tty...
2075
  		 			info->port.tty->hw_stopped = 1;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2076
2077
2078
2079
  			}
  		}
  	}
  }
ed8485fb3   Paul Fulghum   synclink_gt fix m...
2080
  static void dcd_change(struct slgt_info *info, unsigned short status)
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2081
  {
ed8485fb3   Paul Fulghum   synclink_gt fix m...
2082
2083
2084
2085
2086
2087
2088
  	if (status & BIT1) {
  		info->signals |= SerialSignal_DCD;
  		info->input_signal_events.dcd_up++;
  	} else {
  		info->signals &= ~SerialSignal_DCD;
  		info->input_signal_events.dcd_down++;
  	}
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2089
2090
2091
2092
2093
2094
2095
  	DBGISR(("dcd_change %s signals=%04X
  ", info->device_name, info->signals));
  	if ((info->dcd_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) {
  		slgt_irq_off(info, IRQ_DCD);
  		return;
  	}
  	info->icount.dcd++;
af69c7f92   Paul Fulghum   [PATCH] generic H...
2096
  #if SYNCLINK_GENERIC_HDLC
fbeff3c1d   Krzysztof Halasa   [WAN]: Converted ...
2097
2098
2099
2100
2101
2102
  	if (info->netcount) {
  		if (info->signals & SerialSignal_DCD)
  			netif_carrier_on(info->netdev);
  		else
  			netif_carrier_off(info->netdev);
  	}
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2103
2104
2105
2106
  #endif
  	wake_up_interruptible(&info->status_event_wait_q);
  	wake_up_interruptible(&info->event_wait_q);
  	info->pending_bh |= BH_STATUS;
8fb06c771   Alan Cox   synclink: use tty...
2107
  	if (info->port.flags & ASYNC_CHECK_CD) {
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2108
  		if (info->signals & SerialSignal_DCD)
8fb06c771   Alan Cox   synclink: use tty...
2109
  			wake_up_interruptible(&info->port.open_wait);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2110
  		else {
8fb06c771   Alan Cox   synclink: use tty...
2111
2112
  			if (info->port.tty)
  				tty_hangup(info->port.tty);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2113
2114
2115
  		}
  	}
  }
ed8485fb3   Paul Fulghum   synclink_gt fix m...
2116
  static void ri_change(struct slgt_info *info, unsigned short status)
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2117
  {
ed8485fb3   Paul Fulghum   synclink_gt fix m...
2118
2119
2120
2121
2122
2123
2124
  	if (status & BIT0) {
  		info->signals |= SerialSignal_RI;
  		info->input_signal_events.ri_up++;
  	} else {
  		info->signals &= ~SerialSignal_RI;
  		info->input_signal_events.ri_down++;
  	}
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2125
2126
2127
2128
2129
2130
  	DBGISR(("ri_change %s signals=%04X
  ", info->device_name, info->signals));
  	if ((info->ri_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) {
  		slgt_irq_off(info, IRQ_RI);
  		return;
  	}
ed8485fb3   Paul Fulghum   synclink_gt fix m...
2131
  	info->icount.rng++;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2132
2133
2134
2135
  	wake_up_interruptible(&info->status_event_wait_q);
  	wake_up_interruptible(&info->event_wait_q);
  	info->pending_bh |= BH_STATUS;
  }
5ba5a5d21   Paul Fulghum   tty: synclink_gt ...
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
  static void isr_rxdata(struct slgt_info *info)
  {
  	unsigned int count = info->rbuf_fill_count;
  	unsigned int i = info->rbuf_fill_index;
  	unsigned short reg;
  
  	while (rd_reg16(info, SSR) & IRQ_RXDATA) {
  		reg = rd_reg16(info, RDR);
  		DBGISR(("isr_rxdata %s RDR=%04X
  ", info->device_name, reg));
  		if (desc_complete(info->rbufs[i])) {
  			/* all buffers full */
  			rx_stop(info);
  			info->rx_restart = 1;
  			continue;
  		}
  		info->rbufs[i].buf[count++] = (unsigned char)reg;
  		/* async mode saves status byte to buffer for each data byte */
  		if (info->params.mode == MGSL_MODE_ASYNC)
  			info->rbufs[i].buf[count++] = (unsigned char)(reg >> 8);
  		if (count == info->rbuf_fill_level || (reg & BIT10)) {
  			/* buffer full or end of frame */
  			set_desc_count(info->rbufs[i], count);
  			set_desc_status(info->rbufs[i], BIT15 | (reg >> 8));
  			info->rbuf_fill_count = count = 0;
  			if (++i == info->rbuf_count)
  				i = 0;
  			info->pending_bh |= BH_RECEIVE;
  		}
  	}
  
  	info->rbuf_fill_index = i;
  	info->rbuf_fill_count = count;
  }
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2170
2171
2172
2173
2174
2175
2176
2177
  static void isr_serial(struct slgt_info *info)
  {
  	unsigned short status = rd_reg16(info, SSR);
  
  	DBGISR(("%s isr_serial status=%04X
  ", info->device_name, status));
  
  	wr_reg16(info, SSR, status); /* clear pending */
0fab6de09   Joe Perches   synclink drivers ...
2178
  	info->irq_occurred = true;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2179
2180
2181
  
  	if (info->params.mode == MGSL_MODE_ASYNC) {
  		if (status & IRQ_TXIDLE) {
de538eb34   Paul Fulghum   serial: synclink_...
2182
  			if (info->tx_active)
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2183
2184
  				isr_txeom(info, status);
  		}
5ba5a5d21   Paul Fulghum   tty: synclink_gt ...
2185
2186
  		if (info->rx_pio && (status & IRQ_RXDATA))
  			isr_rxdata(info);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2187
2188
2189
  		if ((status & IRQ_RXBREAK) && (status & RXBREAK)) {
  			info->icount.brk++;
  			/* process break detection if tty control allows */
8fb06c771   Alan Cox   synclink: use tty...
2190
  			if (info->port.tty) {
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2191
2192
  				if (!(status & info->ignore_status_mask)) {
  					if (info->read_status_mask & MASK_BREAK) {
8fb06c771   Alan Cox   synclink: use tty...
2193
2194
2195
  						tty_insert_flip_char(info->port.tty, 0, TTY_BREAK);
  						if (info->port.flags & ASYNC_SAK)
  							do_SAK(info->port.tty);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2196
2197
2198
2199
2200
2201
2202
  					}
  				}
  			}
  		}
  	} else {
  		if (status & (IRQ_TXIDLE + IRQ_TXUNDER))
  			isr_txeom(info, status);
5ba5a5d21   Paul Fulghum   tty: synclink_gt ...
2203
2204
  		if (info->rx_pio && (status & IRQ_RXDATA))
  			isr_rxdata(info);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
  		if (status & IRQ_RXIDLE) {
  			if (status & RXIDLE)
  				info->icount.rxidle++;
  			else
  				info->icount.exithunt++;
  			wake_up_interruptible(&info->event_wait_q);
  		}
  
  		if (status & IRQ_RXOVER)
  			rx_start(info);
  	}
  
  	if (status & IRQ_DSR)
ed8485fb3   Paul Fulghum   synclink_gt fix m...
2218
  		dsr_change(info, status);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2219
  	if (status & IRQ_CTS)
ed8485fb3   Paul Fulghum   synclink_gt fix m...
2220
  		cts_change(info, status);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2221
  	if (status & IRQ_DCD)
ed8485fb3   Paul Fulghum   synclink_gt fix m...
2222
  		dcd_change(info, status);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2223
  	if (status & IRQ_RI)
ed8485fb3   Paul Fulghum   synclink_gt fix m...
2224
  		ri_change(info, status);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
  }
  
  static void isr_rdma(struct slgt_info *info)
  {
  	unsigned int status = rd_reg32(info, RDCSR);
  
  	DBGISR(("%s isr_rdma status=%08x
  ", info->device_name, status));
  
  	/* RDCSR (rx DMA control/status)
  	 *
  	 * 31..07  reserved
  	 * 06      save status byte to DMA buffer
  	 * 05      error
  	 * 04      eol (end of list)
  	 * 03      eob (end of buffer)
  	 * 02      IRQ enable
  	 * 01      reset
  	 * 00      enable
  	 */
  	wr_reg32(info, RDCSR, status);	/* clear pending */
  
  	if (status & (BIT5 + BIT4)) {
  		DBGISR(("%s isr_rdma rx_restart=1
  ", info->device_name));
0fab6de09   Joe Perches   synclink drivers ...
2250
  		info->rx_restart = true;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
  	}
  	info->pending_bh |= BH_RECEIVE;
  }
  
  static void isr_tdma(struct slgt_info *info)
  {
  	unsigned int status = rd_reg32(info, TDCSR);
  
  	DBGISR(("%s isr_tdma status=%08x
  ", info->device_name, status));
  
  	/* TDCSR (tx DMA control/status)
  	 *
  	 * 31..06  reserved
  	 * 05      error
  	 * 04      eol (end of list)
  	 * 03      eob (end of buffer)
  	 * 02      IRQ enable
  	 * 01      reset
  	 * 00      enable
  	 */
  	wr_reg32(info, TDCSR, status);	/* clear pending */
  
  	if (status & (BIT5 + BIT4 + BIT3)) {
  		// another transmit buffer has completed
  		// run bottom half to get more send data from user
  		info->pending_bh |= BH_TRANSMIT;
  	}
  }
de538eb34   Paul Fulghum   serial: synclink_...
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
  /*
   * return true if there are unsent tx DMA buffers, otherwise false
   *
   * if there are unsent buffers then info->tbuf_start
   * is set to index of first unsent buffer
   */
  static bool unsent_tbufs(struct slgt_info *info)
  {
  	unsigned int i = info->tbuf_current;
  	bool rc = false;
  
  	/*
  	 * search backwards from last loaded buffer (precedes tbuf_current)
  	 * for first unsent buffer (desc_count > 0)
  	 */
  
  	do {
  		if (i)
  			i--;
  		else
  			i = info->tbuf_count - 1;
  		if (!desc_count(info->tbufs[i]))
  			break;
  		info->tbuf_start = i;
  		rc = true;
  	} while (i != info->tbuf_current);
  
  	return rc;
  }
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2309
2310
2311
2312
2313
2314
2315
  static void isr_txeom(struct slgt_info *info, unsigned short status)
  {
  	DBGISR(("%s txeom status=%04x
  ", info->device_name, status));
  
  	slgt_irq_off(info, IRQ_TXDATA + IRQ_TXIDLE + IRQ_TXUNDER);
  	tdma_reset(info);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
  	if (status & IRQ_TXUNDER) {
  		unsigned short val = rd_reg16(info, TCR);
  		wr_reg16(info, TCR, (unsigned short)(val | BIT2)); /* set reset bit */
  		wr_reg16(info, TCR, val); /* clear reset bit */
  	}
  
  	if (info->tx_active) {
  		if (info->params.mode != MGSL_MODE_ASYNC) {
  			if (status & IRQ_TXUNDER)
  				info->icount.txunder++;
  			else if (status & IRQ_TXIDLE)
  				info->icount.txok++;
  		}
de538eb34   Paul Fulghum   serial: synclink_...
2329
2330
2331
2332
2333
  		if (unsent_tbufs(info)) {
  			tx_start(info);
  			update_tx_timer(info);
  			return;
  		}
0fab6de09   Joe Perches   synclink drivers ...
2334
  		info->tx_active = false;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2335
2336
2337
2338
2339
  
  		del_timer(&info->tx_timer);
  
  		if (info->params.mode != MGSL_MODE_ASYNC && info->drop_rts_on_tx_done) {
  			info->signals &= ~SerialSignal_RTS;
0fab6de09   Joe Perches   synclink drivers ...
2340
  			info->drop_rts_on_tx_done = false;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2341
2342
  			set_signals(info);
  		}
af69c7f92   Paul Fulghum   [PATCH] generic H...
2343
  #if SYNCLINK_GENERIC_HDLC
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2344
2345
2346
2347
2348
  		if (info->netcount)
  			hdlcdev_tx_done(info);
  		else
  #endif
  		{
8fb06c771   Alan Cox   synclink: use tty...
2349
  			if (info->port.tty && (info->port.tty->stopped || info->port.tty->hw_stopped)) {
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2350
2351
2352
2353
2354
2355
2356
  				tx_stop(info);
  				return;
  			}
  			info->pending_bh |= BH_TRANSMIT;
  		}
  	}
  }
0080b7aae   Paul Fulghum   [PATCH] synclink_...
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
  static void isr_gpio(struct slgt_info *info, unsigned int changed, unsigned int state)
  {
  	struct cond_wait *w, *prev;
  
  	/* wake processes waiting for specific transitions */
  	for (w = info->gpio_wait_q, prev = NULL ; w != NULL ; w = w->next) {
  		if (w->data & changed) {
  			w->data = state;
  			wake_up_interruptible(&w->q);
  			if (prev != NULL)
  				prev->next = w->next;
  			else
  				info->gpio_wait_q = w->next;
  		} else
  			prev = w;
  	}
  }
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2374
2375
2376
2377
  /* interrupt service routine
   *
   * 	irq	interrupt number
   * 	dev_id	device ID supplied during interrupt registration
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2378
   */
a6f97b293   Jeff Garzik   drivers/char: min...
2379
  static irqreturn_t slgt_interrupt(int dummy, void *dev_id)
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2380
  {
a6f97b293   Jeff Garzik   drivers/char: min...
2381
  	struct slgt_info *info = dev_id;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2382
2383
  	unsigned int gsr;
  	unsigned int i;
a6f97b293   Jeff Garzik   drivers/char: min...
2384
2385
  	DBGISR(("slgt_interrupt irq=%d entry
  ", info->irq_level));
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2386

705b6c7b3   Paul Fulghum   [PATCH] new drive...
2387
2388
2389
  	while((gsr = rd_reg32(info, GSR) & 0xffffff00)) {
  		DBGISR(("%s gsr=%08x
  ", info->device_name, gsr));
0fab6de09   Joe Perches   synclink drivers ...
2390
  		info->irq_occurred = true;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2391
2392
2393
  		for(i=0; i < info->port_count ; i++) {
  			if (info->port_array[i] == NULL)
  				continue;
ffd7d6baa   Paul Fulghum   synclink_gt: fix ...
2394
  			spin_lock(&info->port_array[i]->lock);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2395
2396
2397
2398
2399
2400
  			if (gsr & (BIT8 << i))
  				isr_serial(info->port_array[i]);
  			if (gsr & (BIT16 << (i*2)))
  				isr_rdma(info->port_array[i]);
  			if (gsr & (BIT17 << (i*2)))
  				isr_tdma(info->port_array[i]);
ffd7d6baa   Paul Fulghum   synclink_gt: fix ...
2401
  			spin_unlock(&info->port_array[i]->lock);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2402
2403
  		}
  	}
0080b7aae   Paul Fulghum   [PATCH] synclink_...
2404
2405
2406
  	if (info->gpio_present) {
  		unsigned int state;
  		unsigned int changed;
ffd7d6baa   Paul Fulghum   synclink_gt: fix ...
2407
  		spin_lock(&info->lock);
0080b7aae   Paul Fulghum   [PATCH] synclink_...
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
  		while ((changed = rd_reg32(info, IOSR)) != 0) {
  			DBGISR(("%s iosr=%08x
  ", info->device_name, changed));
  			/* read latched state of GPIO signals */
  			state = rd_reg32(info, IOVR);
  			/* clear pending GPIO interrupt bits */
  			wr_reg32(info, IOSR, changed);
  			for (i=0 ; i < info->port_count ; i++) {
  				if (info->port_array[i] != NULL)
  					isr_gpio(info->port_array[i], changed, state);
  			}
  		}
ffd7d6baa   Paul Fulghum   synclink_gt: fix ...
2420
  		spin_unlock(&info->lock);
0080b7aae   Paul Fulghum   [PATCH] synclink_...
2421
  	}
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2422
2423
  	for(i=0; i < info->port_count ; i++) {
  		struct slgt_info *port = info->port_array[i];
ffd7d6baa   Paul Fulghum   synclink_gt: fix ...
2424
2425
2426
2427
  		if (port == NULL)
  			continue;
  		spin_lock(&port->lock);
  		if ((port->port.count || port->netcount) &&
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2428
2429
2430
2431
2432
  		    port->pending_bh && !port->bh_running &&
  		    !port->bh_requested) {
  			DBGISR(("%s bh queued
  ", port->device_name));
  			schedule_work(&port->task);
0fab6de09   Joe Perches   synclink drivers ...
2433
  			port->bh_requested = true;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2434
  		}
ffd7d6baa   Paul Fulghum   synclink_gt: fix ...
2435
  		spin_unlock(&port->lock);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2436
  	}
a6f97b293   Jeff Garzik   drivers/char: min...
2437
2438
  	DBGISR(("slgt_interrupt irq=%d exit
  ", info->irq_level));
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2439
2440
2441
2442
2443
2444
2445
  	return IRQ_HANDLED;
  }
  
  static int startup(struct slgt_info *info)
  {
  	DBGINFO(("%s startup
  ", info->device_name));
8fb06c771   Alan Cox   synclink: use tty...
2446
  	if (info->port.flags & ASYNC_INITIALIZED)
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
  		return 0;
  
  	if (!info->tx_buf) {
  		info->tx_buf = kmalloc(info->max_frame_size, GFP_KERNEL);
  		if (!info->tx_buf) {
  			DBGERR(("%s can't allocate tx buffer
  ", info->device_name));
  			return -ENOMEM;
  		}
  	}
  
  	info->pending_bh = 0;
  
  	memset(&info->icount, 0, sizeof(info->icount));
  
  	/* program hardware for current parameters */
  	change_params(info);
8fb06c771   Alan Cox   synclink: use tty...
2464
2465
  	if (info->port.tty)
  		clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2466

8fb06c771   Alan Cox   synclink: use tty...
2467
  	info->port.flags |= ASYNC_INITIALIZED;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
  
  	return 0;
  }
  
  /*
   *  called by close() and hangup() to shutdown hardware
   */
  static void shutdown(struct slgt_info *info)
  {
  	unsigned long flags;
8fb06c771   Alan Cox   synclink: use tty...
2478
  	if (!(info->port.flags & ASYNC_INITIALIZED))
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
  		return;
  
  	DBGINFO(("%s shutdown
  ", info->device_name));
  
  	/* 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);
  
  	del_timer_sync(&info->tx_timer);
  	del_timer_sync(&info->rx_timer);
  
  	kfree(info->tx_buf);
  	info->tx_buf = NULL;
  
  	spin_lock_irqsave(&info->lock,flags);
  
  	tx_stop(info);
  	rx_stop(info);
  
  	slgt_irq_off(info, IRQ_ALL | IRQ_MASTER);
8fb06c771   Alan Cox   synclink: use tty...
2501
   	if (!info->port.tty || info->port.tty->termios->c_cflag & HUPCL) {
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2502
2503
2504
   		info->signals &= ~(SerialSignal_DTR + SerialSignal_RTS);
  		set_signals(info);
  	}
0080b7aae   Paul Fulghum   [PATCH] synclink_...
2505
  	flush_cond_wait(&info->gpio_wait_q);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2506
  	spin_unlock_irqrestore(&info->lock,flags);
8fb06c771   Alan Cox   synclink: use tty...
2507
2508
  	if (info->port.tty)
  		set_bit(TTY_IO_ERROR, &info->port.tty->flags);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2509

8fb06c771   Alan Cox   synclink: use tty...
2510
  	info->port.flags &= ~ASYNC_INITIALIZED;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
  }
  
  static void program_hw(struct slgt_info *info)
  {
  	unsigned long flags;
  
  	spin_lock_irqsave(&info->lock,flags);
  
  	rx_stop(info);
  	tx_stop(info);
cb10dc9ac   Paul Fulghum   [PATCH] synclink_...
2521
  	if (info->params.mode != MGSL_MODE_ASYNC ||
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2522
  	    info->netcount)
cb10dc9ac   Paul Fulghum   [PATCH] synclink_...
2523
  		sync_mode(info);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2524
2525
2526
2527
2528
2529
2530
2531
2532
  	else
  		async_mode(info);
  
  	set_signals(info);
  
  	info->dcd_chkcount = 0;
  	info->cts_chkcount = 0;
  	info->ri_chkcount = 0;
  	info->dsr_chkcount = 0;
a6b2f87be   Paul Fulghum   synclink_gt: enab...
2533
  	slgt_irq_on(info, IRQ_DCD | IRQ_CTS | IRQ_DSR | IRQ_RI);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2534
2535
2536
  	get_signals(info);
  
  	if (info->netcount ||
8fb06c771   Alan Cox   synclink: use tty...
2537
  	    (info->port.tty && info->port.tty->termios->c_cflag & CREAD))
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
  		rx_start(info);
  
  	spin_unlock_irqrestore(&info->lock,flags);
  }
  
  /*
   * reconfigure adapter based on new parameters
   */
  static void change_params(struct slgt_info *info)
  {
  	unsigned cflag;
  	int bits_per_char;
8fb06c771   Alan Cox   synclink: use tty...
2550
  	if (!info->port.tty || !info->port.tty->termios)
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2551
2552
2553
  		return;
  	DBGINFO(("%s change_params
  ", info->device_name));
8fb06c771   Alan Cox   synclink: use tty...
2554
  	cflag = info->port.tty->termios->c_cflag;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
  
  	/* if B0 rate (hangup) specified then negate DTR and RTS */
  	/* otherwise assert DTR and RTS */
   	if (cflag & CBAUD)
  		info->signals |= SerialSignal_RTS + SerialSignal_DTR;
  	else
  		info->signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
  
  	/* byte size and parity */
  
  	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;
  	}
  
  	info->params.stop_bits = (cflag & CSTOPB) ? 2 : 1;
  
  	if (cflag & PARENB)
  		info->params.parity = (cflag & PARODD) ? ASYNC_PARITY_ODD : ASYNC_PARITY_EVEN;
  	else
  		info->params.parity = ASYNC_PARITY_NONE;
  
  	/* calculate number of jiffies to transmit a full
  	 * FIFO (32 bytes) at specified data rate
  	 */
  	bits_per_char = info->params.data_bits +
  			info->params.stop_bits + 1;
8fb06c771   Alan Cox   synclink: use tty...
2585
  	info->params.data_rate = tty_get_baud_rate(info->port.tty);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2586
2587
2588
2589
2590
2591
2592
2593
  
  	if (info->params.data_rate) {
  		info->timeout = (32*HZ*bits_per_char) /
  				info->params.data_rate;
  	}
  	info->timeout += HZ/50;		/* Add .02 seconds of slop */
  
  	if (cflag & CRTSCTS)
8fb06c771   Alan Cox   synclink: use tty...
2594
  		info->port.flags |= ASYNC_CTS_FLOW;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2595
  	else
8fb06c771   Alan Cox   synclink: use tty...
2596
  		info->port.flags &= ~ASYNC_CTS_FLOW;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2597
2598
  
  	if (cflag & CLOCAL)
8fb06c771   Alan Cox   synclink: use tty...
2599
  		info->port.flags &= ~ASYNC_CHECK_CD;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2600
  	else
8fb06c771   Alan Cox   synclink: use tty...
2601
  		info->port.flags |= ASYNC_CHECK_CD;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2602
2603
2604
2605
  
  	/* process tty input control flags */
  
  	info->read_status_mask = IRQ_RXOVER;
8fb06c771   Alan Cox   synclink: use tty...
2606
  	if (I_INPCK(info->port.tty))
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2607
  		info->read_status_mask |= MASK_PARITY | MASK_FRAMING;
8fb06c771   Alan Cox   synclink: use tty...
2608
   	if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty))
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2609
   		info->read_status_mask |= MASK_BREAK;
8fb06c771   Alan Cox   synclink: use tty...
2610
  	if (I_IGNPAR(info->port.tty))
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2611
  		info->ignore_status_mask |= MASK_PARITY | MASK_FRAMING;
8fb06c771   Alan Cox   synclink: use tty...
2612
  	if (I_IGNBRK(info->port.tty)) {
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2613
2614
2615
2616
  		info->ignore_status_mask |= MASK_BREAK;
  		/* If ignoring parity and break indicators, ignore
  		 * overruns too.  (For real raw support).
  		 */
8fb06c771   Alan Cox   synclink: use tty...
2617
  		if (I_IGNPAR(info->port.tty))
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
  			info->ignore_status_mask |= MASK_OVERRUN;
  	}
  
  	program_hw(info);
  }
  
  static int get_stats(struct slgt_info *info, struct mgsl_icount __user *user_icount)
  {
  	DBGINFO(("%s get_stats
  ",  info->device_name));
  	if (!user_icount) {
  		memset(&info->icount, 0, sizeof(info->icount));
  	} else {
  		if (copy_to_user(user_icount, &info->icount, sizeof(struct mgsl_icount)))
  			return -EFAULT;
  	}
  	return 0;
  }
  
  static int get_params(struct slgt_info *info, MGSL_PARAMS __user *user_params)
  {
  	DBGINFO(("%s get_params
  ", info->device_name));
  	if (copy_to_user(user_params, &info->params, sizeof(MGSL_PARAMS)))
  		return -EFAULT;
  	return 0;
  }
  
  static int set_params(struct slgt_info *info, MGSL_PARAMS __user *new_params)
  {
   	unsigned long flags;
  	MGSL_PARAMS tmp_params;
  
  	DBGINFO(("%s set_params
  ", info->device_name));
  	if (copy_from_user(&tmp_params, new_params, sizeof(MGSL_PARAMS)))
  		return -EFAULT;
  
  	spin_lock_irqsave(&info->lock, flags);
1f80769ff   Paul Fulghum   synclink_gt: add ...
2657
2658
2659
2660
  	if (tmp_params.mode == MGSL_MODE_BASE_CLOCK)
  		info->base_clock = tmp_params.clock_speed;
  	else
  		memcpy(&info->params, &tmp_params, sizeof(MGSL_PARAMS));
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2661
  	spin_unlock_irqrestore(&info->lock, flags);
1f80769ff   Paul Fulghum   synclink_gt: add ...
2662
  	program_hw(info);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
  
  	return 0;
  }
  
  static int get_txidle(struct slgt_info *info, int __user *idle_mode)
  {
  	DBGINFO(("%s get_txidle=%d
  ", info->device_name, info->idle_mode));
  	if (put_user(info->idle_mode, idle_mode))
  		return -EFAULT;
  	return 0;
  }
  
  static int set_txidle(struct slgt_info *info, int idle_mode)
  {
   	unsigned long flags;
  	DBGINFO(("%s set_txidle(%d)
  ", info->device_name, idle_mode));
  	spin_lock_irqsave(&info->lock,flags);
  	info->idle_mode = idle_mode;
643f3319b   Paul Fulghum   [PATCH] add syncl...
2683
2684
  	if (info->params.mode != MGSL_MODE_ASYNC)
  		tx_set_idle(info);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
  	spin_unlock_irqrestore(&info->lock,flags);
  	return 0;
  }
  
  static int tx_enable(struct slgt_info *info, int enable)
  {
   	unsigned long flags;
  	DBGINFO(("%s tx_enable(%d)
  ", info->device_name, enable));
  	spin_lock_irqsave(&info->lock,flags);
  	if (enable) {
  		if (!info->tx_enabled)
  			tx_start(info);
  	} else {
  		if (info->tx_enabled)
  			tx_stop(info);
  	}
  	spin_unlock_irqrestore(&info->lock,flags);
  	return 0;
  }
  
  /*
   * abort transmit HDLC frame
   */
  static int tx_abort(struct slgt_info *info)
  {
   	unsigned long flags;
  	DBGINFO(("%s tx_abort
  ", info->device_name));
  	spin_lock_irqsave(&info->lock,flags);
  	tdma_reset(info);
  	spin_unlock_irqrestore(&info->lock,flags);
  	return 0;
  }
  
  static int rx_enable(struct slgt_info *info, int enable)
  {
   	unsigned long flags;
814dae031   Paul Fulghum   synclink_gt: add ...
2723
2724
2725
  	unsigned int rbuf_fill_level;
  	DBGINFO(("%s rx_enable(%08x)
  ", info->device_name, enable));
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2726
  	spin_lock_irqsave(&info->lock,flags);
814dae031   Paul Fulghum   synclink_gt: add ...
2727
2728
2729
2730
2731
2732
2733
  	/*
  	 * enable[31..16] = receive DMA buffer fill level
  	 * 0 = noop (leave fill level unchanged)
  	 * fill level must be multiple of 4 and <= buffer size
  	 */
  	rbuf_fill_level = ((unsigned int)enable) >> 16;
  	if (rbuf_fill_level) {
c68a99cda   Paul Fulghum   synclink_gt fix l...
2734
2735
  		if ((rbuf_fill_level > DMABUFSIZE) || (rbuf_fill_level % 4)) {
  			spin_unlock_irqrestore(&info->lock, flags);
814dae031   Paul Fulghum   synclink_gt: add ...
2736
  			return -EINVAL;
c68a99cda   Paul Fulghum   synclink_gt fix l...
2737
  		}
814dae031   Paul Fulghum   synclink_gt: add ...
2738
  		info->rbuf_fill_level = rbuf_fill_level;
5ba5a5d21   Paul Fulghum   tty: synclink_gt ...
2739
2740
2741
2742
  		if (rbuf_fill_level < 128)
  			info->rx_pio = 1; /* PIO mode */
  		else
  			info->rx_pio = 0; /* DMA mode */
814dae031   Paul Fulghum   synclink_gt: add ...
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
  		rx_stop(info); /* restart receiver to use new fill level */
  	}
  
  	/*
  	 * enable[1..0] = receiver enable command
  	 * 0 = disable
  	 * 1 = enable
  	 * 2 = enable or force hunt mode if already enabled
  	 */
  	enable &= 3;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2753
2754
2755
  	if (enable) {
  		if (!info->rx_enabled)
  			rx_start(info);
cb10dc9ac   Paul Fulghum   [PATCH] synclink_...
2756
2757
2758
2759
  		else if (enable == 2) {
  			/* force hunt mode (write 1 to RCR[3]) */
  			wr_reg16(info, RCR, rd_reg16(info, RCR) | BIT3);
  		}
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
  	} else {
  		if (info->rx_enabled)
  			rx_stop(info);
  	}
  	spin_unlock_irqrestore(&info->lock,flags);
  	return 0;
  }
  
  /*
   *  wait for specified event to occur
   */
  static int wait_mgsl_event(struct slgt_info *info, int __user *mask_ptr)
  {
   	unsigned long flags;
  	int s;
  	int rc=0;
  	struct mgsl_icount cprev, cnow;
  	int events;
  	int mask;
  	struct	_input_signal_events oldsigs, newsigs;
  	DECLARE_WAITQUEUE(wait, current);
  
  	if (get_user(mask, mask_ptr))
  		return -EFAULT;
  
  	DBGINFO(("%s wait_mgsl_event(%d)
  ", info->device_name, mask));
  
  	spin_lock_irqsave(&info->lock,flags);
  
  	/* return immediately if state matches requested events */
  	get_signals(info);
  	s = info->signals;
  
  	events = mask &
  		( ((s & SerialSignal_DSR) ? MgslEvent_DsrActive:MgslEvent_DsrInactive) +
   		  ((s & SerialSignal_DCD) ? MgslEvent_DcdActive:MgslEvent_DcdInactive) +
  		  ((s & SerialSignal_CTS) ? MgslEvent_CtsActive:MgslEvent_CtsInactive) +
  		  ((s & SerialSignal_RI)  ? MgslEvent_RiActive :MgslEvent_RiInactive) );
  	if (events) {
  		spin_unlock_irqrestore(&info->lock,flags);
  		goto exit;
  	}
  
  	/* save current irq counts */
  	cprev = info->icount;
  	oldsigs = info->input_signal_events;
  
  	/* enable hunt and idle irqs if needed */
  	if (mask & (MgslEvent_ExitHuntMode+MgslEvent_IdleReceived)) {
  		unsigned short val = rd_reg16(info, SCR);
  		if (!(val & IRQ_RXIDLE))
  			wr_reg16(info, SCR, (unsigned short)(val | IRQ_RXIDLE));
  	}
  
  	set_current_state(TASK_INTERRUPTIBLE);
  	add_wait_queue(&info->event_wait_q, &wait);
  
  	spin_unlock_irqrestore(&info->lock,flags);
  
  	for(;;) {
  		schedule();
  		if (signal_pending(current)) {
  			rc = -ERESTARTSYS;
  			break;
  		}
  
  		/* get current irq counts */
  		spin_lock_irqsave(&info->lock,flags);
  		cnow = info->icount;
  		newsigs = info->input_signal_events;
  		set_current_state(TASK_INTERRUPTIBLE);
  		spin_unlock_irqrestore(&info->lock,flags);
  
  		/* 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;
  
  		cprev = cnow;
  		oldsigs = newsigs;
  	}
  
  	remove_wait_queue(&info->event_wait_q, &wait);
  	set_current_state(TASK_RUNNING);
  
  
  	if (mask & (MgslEvent_ExitHuntMode + MgslEvent_IdleReceived)) {
  		spin_lock_irqsave(&info->lock,flags);
  		if (!waitqueue_active(&info->event_wait_q)) {
  			/* disable enable exit hunt mode/idle rcvd IRQs */
  			wr_reg16(info, SCR,
  				(unsigned short)(rd_reg16(info, SCR) & ~IRQ_RXIDLE));
  		}
  		spin_unlock_irqrestore(&info->lock,flags);
  	}
  exit:
  	if (rc == 0)
  		rc = put_user(events, mask_ptr);
  	return rc;
  }
  
  static int get_interface(struct slgt_info *info, int __user *if_mode)
  {
  	DBGINFO(("%s get_interface=%x
  ", info->device_name, info->if_mode));
  	if (put_user(info->if_mode, if_mode))
  		return -EFAULT;
  	return 0;
  }
  
  static int set_interface(struct slgt_info *info, int if_mode)
  {
   	unsigned long flags;
35fbd397f   Paul Fulghum   [PATCH] synclink_...
2898
  	unsigned short val;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
  
  	DBGINFO(("%s set_interface=%x)
  ", info->device_name, if_mode));
  	spin_lock_irqsave(&info->lock,flags);
  	info->if_mode = if_mode;
  
  	msc_set_vcr(info);
  
  	/* TCR (tx control) 07  1=RTS driver control */
  	val = rd_reg16(info, TCR);
  	if (info->if_mode & MGSL_INTERFACE_RTS_EN)
  		val |= BIT7;
  	else
  		val &= ~BIT7;
  	wr_reg16(info, TCR, val);
  
  	spin_unlock_irqrestore(&info->lock,flags);
  	return 0;
  }
9807224f1   Paul Fulghum   drivers/char/sync...
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
  static int get_xsync(struct slgt_info *info, int __user *xsync)
  {
  	DBGINFO(("%s get_xsync=%x
  ", info->device_name, info->xsync));
  	if (put_user(info->xsync, xsync))
  		return -EFAULT;
  	return 0;
  }
  
  /*
   * set extended sync pattern (1 to 4 bytes) for extended sync mode
   *
   * sync pattern is contained in least significant bytes of value
   * most significant byte of sync pattern is oldest (1st sent/detected)
   */
  static int set_xsync(struct slgt_info *info, int xsync)
  {
  	unsigned long flags;
  
  	DBGINFO(("%s set_xsync=%x)
  ", info->device_name, xsync));
  	spin_lock_irqsave(&info->lock, flags);
  	info->xsync = xsync;
  	wr_reg32(info, XSR, xsync);
  	spin_unlock_irqrestore(&info->lock, flags);
  	return 0;
  }
  
  static int get_xctrl(struct slgt_info *info, int __user *xctrl)
  {
  	DBGINFO(("%s get_xctrl=%x
  ", info->device_name, info->xctrl));
  	if (put_user(info->xctrl, xctrl))
  		return -EFAULT;
  	return 0;
  }
  
  /*
   * set extended control options
   *
   * xctrl[31:19] reserved, must be zero
   * xctrl[18:17] extended sync pattern length in bytes
   *              00 = 1 byte  in xsr[7:0]
   *              01 = 2 bytes in xsr[15:0]
   *              10 = 3 bytes in xsr[23:0]
   *              11 = 4 bytes in xsr[31:0]
   * xctrl[16]    1 = enable terminal count, 0=disabled
   * xctrl[15:0]  receive terminal count for fixed length packets
   *              value is count minus one (0 = 1 byte packet)
   *              when terminal count is reached, receiver
   *              automatically returns to hunt mode and receive
   *              FIFO contents are flushed to DMA buffers with
   *              end of frame (EOF) status
   */
  static int set_xctrl(struct slgt_info *info, int xctrl)
  {
  	unsigned long flags;
  
  	DBGINFO(("%s set_xctrl=%x)
  ", info->device_name, xctrl));
  	spin_lock_irqsave(&info->lock, flags);
  	info->xctrl = xctrl;
  	wr_reg32(info, XCR, xctrl);
  	spin_unlock_irqrestore(&info->lock, flags);
  	return 0;
  }
0080b7aae   Paul Fulghum   [PATCH] synclink_...
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
  /*
   * set general purpose IO pin state and direction
   *
   * user_gpio fields:
   * state   each bit indicates a pin state
   * smask   set bit indicates pin state to set
   * dir     each bit indicates a pin direction (0=input, 1=output)
   * dmask   set bit indicates pin direction to set
   */
  static int set_gpio(struct slgt_info *info, struct gpio_desc __user *user_gpio)
  {
   	unsigned long flags;
  	struct gpio_desc gpio;
  	__u32 data;
  
  	if (!info->gpio_present)
  		return -EINVAL;
  	if (copy_from_user(&gpio, user_gpio, sizeof(gpio)))
  		return -EFAULT;
  	DBGINFO(("%s set_gpio state=%08x smask=%08x dir=%08x dmask=%08x
  ",
  		 info->device_name, gpio.state, gpio.smask,
  		 gpio.dir, gpio.dmask));
ffd7d6baa   Paul Fulghum   synclink_gt: fix ...
3007
  	spin_lock_irqsave(&info->port_array[0]->lock, flags);
0080b7aae   Paul Fulghum   [PATCH] synclink_...
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
  	if (gpio.dmask) {
  		data = rd_reg32(info, IODR);
  		data |= gpio.dmask & gpio.dir;
  		data &= ~(gpio.dmask & ~gpio.dir);
  		wr_reg32(info, IODR, data);
  	}
  	if (gpio.smask) {
  		data = rd_reg32(info, IOVR);
  		data |= gpio.smask & gpio.state;
  		data &= ~(gpio.smask & ~gpio.state);
  		wr_reg32(info, IOVR, data);
  	}
ffd7d6baa   Paul Fulghum   synclink_gt: fix ...
3020
  	spin_unlock_irqrestore(&info->port_array[0]->lock, flags);
0080b7aae   Paul Fulghum   [PATCH] synclink_...
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
  
  	return 0;
  }
  
  /*
   * get general purpose IO pin state and direction
   */
  static int get_gpio(struct slgt_info *info, struct gpio_desc __user *user_gpio)
  {
  	struct gpio_desc gpio;
  	if (!info->gpio_present)
  		return -EINVAL;
  	gpio.state = rd_reg32(info, IOVR);
  	gpio.smask = 0xffffffff;
  	gpio.dir   = rd_reg32(info, IODR);
  	gpio.dmask = 0xffffffff;
  	if (copy_to_user(user_gpio, &gpio, sizeof(gpio)))
  		return -EFAULT;
  	DBGINFO(("%s get_gpio state=%08x dir=%08x
  ",
  		 info->device_name, gpio.state, gpio.dir));
  	return 0;
  }
  
  /*
   * conditional wait facility
   */
  static void init_cond_wait(struct cond_wait *w, unsigned int data)
  {
  	init_waitqueue_head(&w->q);
  	init_waitqueue_entry(&w->wait, current);
  	w->data = data;
  }
  
  static void add_cond_wait(struct cond_wait **head, struct cond_wait *w)
  {
  	set_current_state(TASK_INTERRUPTIBLE);
  	add_wait_queue(&w->q, &w->wait);
  	w->next = *head;
  	*head = w;
  }
  
  static void remove_cond_wait(struct cond_wait **head, struct cond_wait *cw)
  {
  	struct cond_wait *w, *prev;
  	remove_wait_queue(&cw->q, &cw->wait);
  	set_current_state(TASK_RUNNING);
  	for (w = *head, prev = NULL ; w != NULL ; prev = w, w = w->next) {
  		if (w == cw) {
  			if (prev != NULL)
  				prev->next = w->next;
  			else
  				*head = w->next;
  			break;
  		}
  	}
  }
  
  static void flush_cond_wait(struct cond_wait **head)
  {
  	while (*head != NULL) {
  		wake_up_interruptible(&(*head)->q);
  		*head = (*head)->next;
  	}
  }
  
  /*
   * wait for general purpose I/O pin(s) to enter specified state
   *
   * user_gpio fields:
   * state - bit indicates target pin state
   * smask - set bit indicates watched pin
   *
   * The wait ends when at least one watched pin enters the specified
   * state. When 0 (no error) is returned, user_gpio->state is set to the
   * state of all GPIO pins when the wait ends.
   *
   * Note: Each pin may be a dedicated input, dedicated output, or
   * configurable input/output. The number and configuration of pins
   * varies with the specific adapter model. Only input pins (dedicated
   * or configured) can be monitored with this function.
   */
  static int wait_gpio(struct slgt_info *info, struct gpio_desc __user *user_gpio)
  {
   	unsigned long flags;
  	int rc = 0;
  	struct gpio_desc gpio;
  	struct cond_wait wait;
  	u32 state;
  
  	if (!info->gpio_present)
  		return -EINVAL;
  	if (copy_from_user(&gpio, user_gpio, sizeof(gpio)))
  		return -EFAULT;
  	DBGINFO(("%s wait_gpio() state=%08x smask=%08x
  ",
  		 info->device_name, gpio.state, gpio.smask));
  	/* ignore output pins identified by set IODR bit */
  	if ((gpio.smask &= ~rd_reg32(info, IODR)) == 0)
  		return -EINVAL;
  	init_cond_wait(&wait, gpio.smask);
ffd7d6baa   Paul Fulghum   synclink_gt: fix ...
3122
  	spin_lock_irqsave(&info->port_array[0]->lock, flags);
0080b7aae   Paul Fulghum   [PATCH] synclink_...
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
  	/* enable interrupts for watched pins */
  	wr_reg32(info, IOER, rd_reg32(info, IOER) | gpio.smask);
  	/* get current pin states */
  	state = rd_reg32(info, IOVR);
  
  	if (gpio.smask & ~(state ^ gpio.state)) {
  		/* already in target state */
  		gpio.state = state;
  	} else {
  		/* wait for target state */
  		add_cond_wait(&info->gpio_wait_q, &wait);
ffd7d6baa   Paul Fulghum   synclink_gt: fix ...
3134
  		spin_unlock_irqrestore(&info->port_array[0]->lock, flags);
0080b7aae   Paul Fulghum   [PATCH] synclink_...
3135
3136
3137
3138
3139
  		schedule();
  		if (signal_pending(current))
  			rc = -ERESTARTSYS;
  		else
  			gpio.state = wait.data;
ffd7d6baa   Paul Fulghum   synclink_gt: fix ...
3140
  		spin_lock_irqsave(&info->port_array[0]->lock, flags);
0080b7aae   Paul Fulghum   [PATCH] synclink_...
3141
3142
3143
3144
3145
3146
  		remove_cond_wait(&info->gpio_wait_q, &wait);
  	}
  
  	/* disable all GPIO interrupts if no waiting processes */
  	if (info->gpio_wait_q == NULL)
  		wr_reg32(info, IOER, 0);
ffd7d6baa   Paul Fulghum   synclink_gt: fix ...
3147
  	spin_unlock_irqrestore(&info->port_array[0]->lock, flags);
0080b7aae   Paul Fulghum   [PATCH] synclink_...
3148
3149
3150
3151
3152
  
  	if ((rc == 0) && copy_to_user(user_gpio, &gpio, sizeof(gpio)))
  		rc = -EFAULT;
  	return rc;
  }
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
  static int modem_input_wait(struct slgt_info *info,int arg)
  {
   	unsigned long flags;
  	int rc;
  	struct mgsl_icount cprev, cnow;
  	DECLARE_WAITQUEUE(wait, current);
  
  	/* save current irq counts */
  	spin_lock_irqsave(&info->lock,flags);
  	cprev = info->icount;
  	add_wait_queue(&info->status_event_wait_q, &wait);
  	set_current_state(TASK_INTERRUPTIBLE);
  	spin_unlock_irqrestore(&info->lock,flags);
  
  	for(;;) {
  		schedule();
  		if (signal_pending(current)) {
  			rc = -ERESTARTSYS;
  			break;
  		}
  
  		/* get new irq counts */
  		spin_lock_irqsave(&info->lock,flags);
  		cnow = info->icount;
  		set_current_state(TASK_INTERRUPTIBLE);
  		spin_unlock_irqrestore(&info->lock,flags);
  
  		/* 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 state of serial control and status signals
   */
60b33c133   Alan Cox   tiocmget: kill of...
3206
  static int tiocmget(struct tty_struct *tty)
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
  {
  	struct slgt_info *info = tty->driver_data;
  	unsigned int result;
   	unsigned long flags;
  
  	spin_lock_irqsave(&info->lock,flags);
   	get_signals(info);
  	spin_unlock_irqrestore(&info->lock,flags);
  
  	result = ((info->signals & SerialSignal_RTS) ? TIOCM_RTS:0) +
  		((info->signals & SerialSignal_DTR) ? TIOCM_DTR:0) +
  		((info->signals & SerialSignal_DCD) ? TIOCM_CAR:0) +
  		((info->signals & SerialSignal_RI)  ? TIOCM_RNG:0) +
  		((info->signals & SerialSignal_DSR) ? TIOCM_DSR:0) +
  		((info->signals & SerialSignal_CTS) ? TIOCM_CTS:0);
  
  	DBGINFO(("%s tiocmget value=%08X
  ", info->device_name, result));
  	return result;
  }
  
  /*
   * set modem control signals (DTR/RTS)
   *
   * 	cmd	signal command: TIOCMBIS = set bit TIOCMBIC = clear bit
   *		TIOCMSET = set/clear signal values
   * 	value	bit mask for command
   */
20b9d1771   Alan Cox   tiocmset: kill th...
3235
  static int tiocmset(struct tty_struct *tty,
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
  		    unsigned int set, unsigned int clear)
  {
  	struct slgt_info *info = tty->driver_data;
   	unsigned long flags;
  
  	DBGINFO(("%s tiocmset(%x,%x)
  ", info->device_name, set, clear));
  
  	if (set & TIOCM_RTS)
  		info->signals |= SerialSignal_RTS;
  	if (set & TIOCM_DTR)
  		info->signals |= SerialSignal_DTR;
  	if (clear & TIOCM_RTS)
  		info->signals &= ~SerialSignal_RTS;
  	if (clear & TIOCM_DTR)
  		info->signals &= ~SerialSignal_DTR;
  
  	spin_lock_irqsave(&info->lock,flags);
   	set_signals(info);
  	spin_unlock_irqrestore(&info->lock,flags);
  	return 0;
  }
31f35939d   Alan Cox   tty_port: Add a p...
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
  static int carrier_raised(struct tty_port *port)
  {
  	unsigned long flags;
  	struct slgt_info *info = container_of(port, struct slgt_info, port);
  
  	spin_lock_irqsave(&info->lock,flags);
   	get_signals(info);
  	spin_unlock_irqrestore(&info->lock,flags);
  	return (info->signals & SerialSignal_DCD) ? 1 : 0;
  }
fcc8ac182   Alan Cox   tty: Add carrier ...
3268
  static void dtr_rts(struct tty_port *port, int on)
5d951fb45   Alan Cox   tty: Pull the dtr...
3269
3270
3271
3272
3273
  {
  	unsigned long flags;
  	struct slgt_info *info = container_of(port, struct slgt_info, port);
  
  	spin_lock_irqsave(&info->lock,flags);
fcc8ac182   Alan Cox   tty: Add carrier ...
3274
3275
3276
3277
  	if (on)
  		info->signals |= SerialSignal_RTS + SerialSignal_DTR;
  	else
  		info->signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
5d951fb45   Alan Cox   tty: Pull the dtr...
3278
3279
3280
   	set_signals(info);
  	spin_unlock_irqrestore(&info->lock,flags);
  }
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3281
3282
3283
3284
3285
3286
3287
3288
  /*
   *  block current process until the device is ready to open
   */
  static int block_til_ready(struct tty_struct *tty, struct file *filp,
  			   struct slgt_info *info)
  {
  	DECLARE_WAITQUEUE(wait, current);
  	int		retval;
0fab6de09   Joe Perches   synclink drivers ...
3289
3290
  	bool		do_clocal = false;
  	bool		extra_count = false;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3291
  	unsigned long	flags;
31f35939d   Alan Cox   tty_port: Add a p...
3292
3293
  	int		cd;
  	struct tty_port *port = &info->port;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3294
3295
3296
3297
3298
3299
  
  	DBGINFO(("%s block_til_ready
  ", tty->driver->name));
  
  	if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){
  		/* nonblock mode is set or port is not enabled */
31f35939d   Alan Cox   tty_port: Add a p...
3300
  		port->flags |= ASYNC_NORMAL_ACTIVE;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3301
3302
3303
3304
  		return 0;
  	}
  
  	if (tty->termios->c_cflag & CLOCAL)
0fab6de09   Joe Perches   synclink drivers ...
3305
  		do_clocal = true;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3306
3307
3308
  
  	/* Wait for carrier detect and the line to become
  	 * free (i.e., not in use by the callout).  While we are in
31f35939d   Alan Cox   tty_port: Add a p...
3309
  	 * this loop, port->count is dropped by one, so that
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3310
3311
3312
3313
3314
  	 * close() knows when to free things.  We restore it upon
  	 * exit, either normal or abnormal.
  	 */
  
  	retval = 0;
31f35939d   Alan Cox   tty_port: Add a p...
3315
  	add_wait_queue(&port->open_wait, &wait);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3316
3317
3318
  
  	spin_lock_irqsave(&info->lock, flags);
  	if (!tty_hung_up_p(filp)) {
0fab6de09   Joe Perches   synclink drivers ...
3319
  		extra_count = true;
31f35939d   Alan Cox   tty_port: Add a p...
3320
  		port->count--;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3321
3322
  	}
  	spin_unlock_irqrestore(&info->lock, flags);
31f35939d   Alan Cox   tty_port: Add a p...
3323
  	port->blocked_open++;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3324
3325
  
  	while (1) {
5d951fb45   Alan Cox   tty: Pull the dtr...
3326
3327
  		if ((tty->termios->c_cflag & CBAUD))
  			tty_port_raise_dtr_rts(port);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3328
3329
  
  		set_current_state(TASK_INTERRUPTIBLE);
31f35939d   Alan Cox   tty_port: Add a p...
3330
3331
  		if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)){
  			retval = (port->flags & ASYNC_HUP_NOTIFY) ?
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3332
3333
3334
  					-EAGAIN : -ERESTARTSYS;
  			break;
  		}
31f35939d   Alan Cox   tty_port: Add a p...
3335
  		cd = tty_port_carrier_raised(port);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3336

31f35939d   Alan Cox   tty_port: Add a p...
3337
   		if (!(port->flags & ASYNC_CLOSING) && (do_clocal || cd ))
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3338
   			break;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3339
3340
3341
3342
3343
3344
3345
3346
  
  		if (signal_pending(current)) {
  			retval = -ERESTARTSYS;
  			break;
  		}
  
  		DBGINFO(("%s block_til_ready wait
  ", tty->driver->name));
e142a31da   Arnd Bergmann   tty: release BTM ...
3347
  		tty_unlock();
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3348
  		schedule();
e142a31da   Arnd Bergmann   tty: release BTM ...
3349
  		tty_lock();
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3350
3351
3352
  	}
  
  	set_current_state(TASK_RUNNING);
31f35939d   Alan Cox   tty_port: Add a p...
3353
  	remove_wait_queue(&port->open_wait, &wait);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3354
3355
  
  	if (extra_count)
31f35939d   Alan Cox   tty_port: Add a p...
3356
3357
  		port->count++;
  	port->blocked_open--;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3358
3359
  
  	if (!retval)
31f35939d   Alan Cox   tty_port: Add a p...
3360
  		port->flags |= ASYNC_NORMAL_ACTIVE;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3361
3362
3363
3364
3365
3366
3367
3368
  
  	DBGINFO(("%s block_til_ready ready, rc=%d
  ", tty->driver->name, retval));
  	return retval;
  }
  
  static int alloc_tmp_rbuf(struct slgt_info *info)
  {
04b374d0f   Paul Fulghum   [PATCH] add syncl...
3369
  	info->tmp_rbuf = kmalloc(info->max_frame_size + 5, GFP_KERNEL);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
  	if (info->tmp_rbuf == NULL)
  		return -ENOMEM;
  	return 0;
  }
  
  static void free_tmp_rbuf(struct slgt_info *info)
  {
  	kfree(info->tmp_rbuf);
  	info->tmp_rbuf = NULL;
  }
  
  /*
   * allocate DMA descriptor lists.
   */
  static int alloc_desc(struct slgt_info *info)
  {
  	unsigned int i;
  	unsigned int pbufs;
  
  	/* allocate memory to hold descriptor lists */
  	info->bufs = pci_alloc_consistent(info->pdev, DESC_LIST_SIZE, &info->bufs_dma_addr);
  	if (info->bufs == NULL)
  		return -ENOMEM;
  
  	memset(info->bufs, 0, DESC_LIST_SIZE);
  
  	info->rbufs = (struct slgt_desc*)info->bufs;
  	info->tbufs = ((struct slgt_desc*)info->bufs) + info->rbuf_count;
  
  	pbufs = (unsigned int)info->bufs_dma_addr;
  
  	/*
  	 * Build circular lists of descriptors
  	 */
  
  	for (i=0; i < info->rbuf_count; i++) {
  		/* physical address of this descriptor */
  		info->rbufs[i].pdesc = pbufs + (i * sizeof(struct slgt_desc));
  
  		/* physical address of next descriptor */
  		if (i == info->rbuf_count - 1)
  			info->rbufs[i].next = cpu_to_le32(pbufs);
  		else
  			info->rbufs[i].next = cpu_to_le32(pbufs + ((i+1) * sizeof(struct slgt_desc)));
  		set_desc_count(info->rbufs[i], DMABUFSIZE);
  	}
  
  	for (i=0; i < info->tbuf_count; i++) {
  		/* physical address of this descriptor */
  		info->tbufs[i].pdesc = pbufs + ((info->rbuf_count + i) * sizeof(struct slgt_desc));
  
  		/* physical address of next descriptor */
  		if (i == info->tbuf_count - 1)
  			info->tbufs[i].next = cpu_to_le32(pbufs + info->rbuf_count * sizeof(struct slgt_desc));
  		else
  			info->tbufs[i].next = cpu_to_le32(pbufs + ((info->rbuf_count + i + 1) * sizeof(struct slgt_desc)));
  	}
  
  	return 0;
  }
  
  static void free_desc(struct slgt_info *info)
  {
  	if (info->bufs != NULL) {
  		pci_free_consistent(info->pdev, DESC_LIST_SIZE, info->bufs, info->bufs_dma_addr);
  		info->bufs  = NULL;
  		info->rbufs = NULL;
  		info->tbufs = NULL;
  	}
  }
  
  static int alloc_bufs(struct slgt_info *info, struct slgt_desc *bufs, int count)
  {
  	int i;
  	for (i=0; i < count; i++) {
  		if ((bufs[i].buf = pci_alloc_consistent(info->pdev, DMABUFSIZE, &bufs[i].buf_dma_addr)) == NULL)
  			return -ENOMEM;
  		bufs[i].pbuf  = cpu_to_le32((unsigned int)bufs[i].buf_dma_addr);
  	}
  	return 0;
  }
  
  static void free_bufs(struct slgt_info *info, struct slgt_desc *bufs, int count)
  {
  	int i;
  	for (i=0; i < count; i++) {
  		if (bufs[i].buf == NULL)
  			continue;
  		pci_free_consistent(info->pdev, DMABUFSIZE, bufs[i].buf, bufs[i].buf_dma_addr);
  		bufs[i].buf = NULL;
  	}
  }
  
  static int alloc_dma_bufs(struct slgt_info *info)
  {
  	info->rbuf_count = 32;
  	info->tbuf_count = 32;
  
  	if (alloc_desc(info) < 0 ||
  	    alloc_bufs(info, info->rbufs, info->rbuf_count) < 0 ||
  	    alloc_bufs(info, info->tbufs, info->tbuf_count) < 0 ||
  	    alloc_tmp_rbuf(info) < 0) {
  		DBGERR(("%s DMA buffer alloc fail
  ", info->device_name));
  		return -ENOMEM;
  	}
  	reset_rbufs(info);
  	return 0;
  }
  
  static void free_dma_bufs(struct slgt_info *info)
  {
  	if (info->bufs) {
  		free_bufs(info, info->rbufs, info->rbuf_count);
  		free_bufs(info, info->tbufs, info->tbuf_count);
  		free_desc(info);
  	}
  	free_tmp_rbuf(info);
  }
  
  static int claim_resources(struct slgt_info *info)
  {
  	if (request_mem_region(info->phys_reg_addr, SLGT_REG_SIZE, "synclink_gt") == NULL) {
  		DBGERR(("%s reg addr conflict, addr=%08X
  ",
  			info->device_name, info->phys_reg_addr));
  		info->init_error = DiagStatus_AddressConflict;
  		goto errout;
  	}
  	else
0fab6de09   Joe Perches   synclink drivers ...
3500
  		info->reg_addr_requested = true;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3501

24cb23352   Alan Cox   char serial: swit...
3502
  	info->reg_addr = ioremap_nocache(info->phys_reg_addr, SLGT_REG_SIZE);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3503
  	if (!info->reg_addr) {
25985edce   Lucas De Marchi   Fix common misspe...
3504
3505
  		DBGERR(("%s can't map device registers, addr=%08X
  ",
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3506
3507
3508
3509
  			info->device_name, info->phys_reg_addr));
  		info->init_error = DiagStatus_CantAssignPciResources;
  		goto errout;
  	}
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
  	return 0;
  
  errout:
  	release_resources(info);
  	return -ENODEV;
  }
  
  static void release_resources(struct slgt_info *info)
  {
  	if (info->irq_requested) {
  		free_irq(info->irq_level, info);
0fab6de09   Joe Perches   synclink drivers ...
3521
  		info->irq_requested = false;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3522
3523
3524
3525
  	}
  
  	if (info->reg_addr_requested) {
  		release_mem_region(info->phys_reg_addr, SLGT_REG_SIZE);
0fab6de09   Joe Perches   synclink drivers ...
3526
  		info->reg_addr_requested = false;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3527
3528
3529
  	}
  
  	if (info->reg_addr) {
0c8365ecc   Paul Fulghum   [PATCH] synclink_...
3530
  		iounmap(info->reg_addr);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
  		info->reg_addr = NULL;
  	}
  }
  
  /* Add the specified device instance data structure to the
   * global linked list of devices and increment the device count.
   */
  static void add_device(struct slgt_info *info)
  {
  	char *devstr;
  
  	info->next_device = NULL;
  	info->line = slgt_device_count;
  	sprintf(info->device_name, "%s%d", tty_dev_prefix, info->line);
  
  	if (info->line < MAX_DEVICES) {
  		if (maxframe[info->line])
  			info->max_frame_size = maxframe[info->line];
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
  	}
  
  	slgt_device_count++;
  
  	if (!slgt_device_list)
  		slgt_device_list = info;
  	else {
  		struct slgt_info *current_dev = slgt_device_list;
  		while(current_dev->next_device)
  			current_dev = current_dev->next_device;
  		current_dev->next_device = info;
  	}
  
  	if (info->max_frame_size < 4096)
  		info->max_frame_size = 4096;
  	else if (info->max_frame_size > 65535)
  		info->max_frame_size = 65535;
  
  	switch(info->pdev->device) {
  	case SYNCLINK_GT_DEVICE_ID:
  		devstr = "GT";
  		break;
6f84be84b   Paul Fulghum   [PATCH] synclink_...
3571
3572
3573
  	case SYNCLINK_GT2_DEVICE_ID:
  		devstr = "GT2";
  		break;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
  	case SYNCLINK_GT4_DEVICE_ID:
  		devstr = "GT4";
  		break;
  	case SYNCLINK_AC_DEVICE_ID:
  		devstr = "AC";
  		info->params.mode = MGSL_MODE_ASYNC;
  		break;
  	default:
  		devstr = "(unknown model)";
  	}
  	printk("SyncLink %s %s IO=%08x IRQ=%d MaxFrameSize=%u
  ",
  		devstr, info->device_name, info->phys_reg_addr,
  		info->irq_level, info->max_frame_size);
af69c7f92   Paul Fulghum   [PATCH] generic H...
3588
  #if SYNCLINK_GENERIC_HDLC
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3589
3590
3591
  	hdlcdev_init(info);
  #endif
  }
31f35939d   Alan Cox   tty_port: Add a p...
3592
3593
  static const struct tty_port_operations slgt_port_ops = {
  	.carrier_raised = carrier_raised,
fcc8ac182   Alan Cox   tty: Add carrier ...
3594
  	.dtr_rts = dtr_rts,
31f35939d   Alan Cox   tty_port: Add a p...
3595
  };
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3596
3597
3598
3599
3600
3601
  /*
   *  allocate device instance structure, return NULL on failure
   */
  static struct slgt_info *alloc_dev(int adapter_num, int port_num, struct pci_dev *pdev)
  {
  	struct slgt_info *info;
dd00cc486   Yoann Padioleau   some kmalloc/mems...
3602
  	info = kzalloc(sizeof(struct slgt_info), GFP_KERNEL);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3603
3604
3605
3606
3607
3608
  
  	if (!info) {
  		DBGERR(("%s device alloc failed adapter=%d port=%d
  ",
  			driver_name, adapter_num, port_num));
  	} else {
44b7d1b37   Alan Cox   tty: add more tty...
3609
  		tty_port_init(&info->port);
31f35939d   Alan Cox   tty_port: Add a p...
3610
  		info->port.ops = &slgt_port_ops;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3611
  		info->magic = MGSL_MAGIC;
c4028958b   David Howells   WorkStruct: make ...
3612
  		INIT_WORK(&info->task, bh_handler);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3613
  		info->max_frame_size = 4096;
1f80769ff   Paul Fulghum   synclink_gt: add ...
3614
  		info->base_clock = 14745600;
814dae031   Paul Fulghum   synclink_gt: add ...
3615
  		info->rbuf_fill_level = DMABUFSIZE;
44b7d1b37   Alan Cox   tty: add more tty...
3616
3617
  		info->port.close_delay = 5*HZ/10;
  		info->port.closing_wait = 30*HZ;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3618
3619
3620
3621
3622
3623
3624
  		init_waitqueue_head(&info->status_event_wait_q);
  		init_waitqueue_head(&info->event_wait_q);
  		spin_lock_init(&info->netlock);
  		memcpy(&info->params,&default_params,sizeof(MGSL_PARAMS));
  		info->idle_mode = HDLC_TXIDLE_FLAGS;
  		info->adapter_num = adapter_num;
  		info->port_num = port_num;
40565f196   Jiri Slaby   [PATCH] Char: tim...
3625
3626
  		setup_timer(&info->tx_timer, tx_timeout, (unsigned long)info);
  		setup_timer(&info->rx_timer, rx_timeout, (unsigned long)info);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3627
3628
3629
3630
3631
  
  		/* Copy configuration info to device instance data */
  		info->pdev = pdev;
  		info->irq_level = pdev->irq;
  		info->phys_reg_addr = pci_resource_start(pdev,0);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3632
  		info->bus_type = MGSL_BUS_TYPE_PCI;
0f2ed4c6b   Thomas Gleixner   [PATCH] irq-flags...
3633
  		info->irq_flags = IRQF_SHARED;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
  
  		info->init_error = -1; /* assume error, set to 0 on successful init */
  	}
  
  	return info;
  }
  
  static void device_init(int adapter_num, struct pci_dev *pdev)
  {
  	struct slgt_info *port_array[SLGT_MAX_PORTS];
  	int i;
  	int port_count = 1;
6f84be84b   Paul Fulghum   [PATCH] synclink_...
3646
3647
3648
  	if (pdev->device == SYNCLINK_GT2_DEVICE_ID)
  		port_count = 2;
  	else if (pdev->device == SYNCLINK_GT4_DEVICE_ID)
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
  		port_count = 4;
  
  	/* allocate device instances for all ports */
  	for (i=0; i < port_count; ++i) {
  		port_array[i] = alloc_dev(adapter_num, i, pdev);
  		if (port_array[i] == NULL) {
  			for (--i; i >= 0; --i)
  				kfree(port_array[i]);
  			return;
  		}
  	}
  
  	/* give copy of port_array to all ports and add to device list  */
  	for (i=0; i < port_count; ++i) {
  		memcpy(port_array[i]->port_array, port_array, sizeof(port_array));
  		add_device(port_array[i]);
  		port_array[i]->port_count = port_count;
  		spin_lock_init(&port_array[i]->lock);
  	}
  
  	/* Allocate and claim adapter resources */
  	if (!claim_resources(port_array[0])) {
  
  		alloc_dma_bufs(port_array[0]);
  
  		/* copy resource information from first port to others */
  		for (i = 1; i < port_count; ++i) {
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
3687
3688
3689
3690
  			port_array[i]->irq_level = port_array[0]->irq_level;
  			port_array[i]->reg_addr  = port_array[0]->reg_addr;
  			alloc_dma_bufs(port_array[i]);
  		}
  
  		if (request_irq(port_array[0]->irq_level,
  					slgt_interrupt,
  					port_array[0]->irq_flags,
  					port_array[0]->device_name,
  					port_array[0]) < 0) {
  			DBGERR(("%s request_irq failed IRQ=%d
  ",
  				port_array[0]->device_name,
  				port_array[0]->irq_level));
  		} else {
0fab6de09   Joe Perches   synclink drivers ...
3691
  			port_array[0]->irq_requested = true;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3692
  			adapter_test(port_array[0]);
0080b7aae   Paul Fulghum   [PATCH] synclink_...
3693
  			for (i=1 ; i < port_count ; i++) {
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3694
  				port_array[i]->init_error = port_array[0]->init_error;
0080b7aae   Paul Fulghum   [PATCH] synclink_...
3695
3696
  				port_array[i]->gpio_present = port_array[0]->gpio_present;
  			}
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3697
3698
  		}
  	}
62eb5b1f3   Paul Fulghum   synclink_gt use d...
3699
3700
3701
  
  	for (i=0; i < port_count; ++i)
  		tty_register_device(serial_driver, port_array[i]->line, &(port_array[i]->pdev->dev));
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
  }
  
  static int __devinit init_one(struct pci_dev *dev,
  			      const struct pci_device_id *ent)
  {
  	if (pci_enable_device(dev)) {
  		printk("error enabling pci device %p
  ", dev);
  		return -EIO;
  	}
  	pci_set_master(dev);
  	device_init(slgt_device_count, dev);
  	return 0;
  }
  
  static void __devexit remove_one(struct pci_dev *dev)
  {
  }
b68e31d0e   Jeff Dike   [PATCH] const str...
3720
  static const struct tty_operations ops = {
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3721
3722
3723
3724
3725
3726
3727
3728
3729
  	.open = open,
  	.close = close,
  	.write = write,
  	.put_char = put_char,
  	.flush_chars = flush_chars,
  	.write_room = write_room,
  	.chars_in_buffer = chars_in_buffer,
  	.flush_buffer = flush_buffer,
  	.ioctl = ioctl,
2acdb1694   Paul Fulghum   synclink_gt: add ...
3730
  	.compat_ioctl = slgt_compat_ioctl,
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3731
3732
3733
3734
3735
  	.throttle = throttle,
  	.unthrottle = unthrottle,
  	.send_xchar = send_xchar,
  	.break_ctl = set_break,
  	.wait_until_sent = wait_until_sent,
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3736
3737
3738
3739
3740
3741
  	.set_termios = set_termios,
  	.stop = tx_hold,
  	.start = tx_release,
  	.hangup = hangup,
  	.tiocmget = tiocmget,
  	.tiocmset = tiocmset,
0587102cf   Alan Cox   tty: icount chang...
3742
  	.get_icount = get_icount,
a18c56e5a   Alexey Dobriyan   proc tty: switch ...
3743
  	.proc_fops = &synclink_gt_proc_fops,
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3744
3745
3746
3747
3748
3749
3750
  };
  
  static void slgt_cleanup(void)
  {
  	int rc;
  	struct slgt_info *info;
  	struct slgt_info *tmp;
a6b2f87be   Paul Fulghum   synclink_gt: enab...
3751
3752
  	printk(KERN_INFO "unload %s
  ", driver_name);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3753
3754
  
  	if (serial_driver) {
62eb5b1f3   Paul Fulghum   synclink_gt use d...
3755
3756
  		for (info=slgt_device_list ; info != NULL ; info=info->next_device)
  			tty_unregister_device(serial_driver, info->line);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
  		if ((rc = tty_unregister_driver(serial_driver)))
  			DBGERR(("tty_unregister_driver error=%d
  ", rc));
  		put_tty_driver(serial_driver);
  	}
  
  	/* reset devices */
  	info = slgt_device_list;
  	while(info) {
  		reset_port(info);
  		info = info->next_device;
  	}
  
  	/* release devices */
  	info = slgt_device_list;
  	while(info) {
af69c7f92   Paul Fulghum   [PATCH] generic H...
3773
  #if SYNCLINK_GENERIC_HDLC
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
  		hdlcdev_exit(info);
  #endif
  		free_dma_bufs(info);
  		free_tmp_rbuf(info);
  		if (info->port_num == 0)
  			release_resources(info);
  		tmp = info;
  		info = info->next_device;
  		kfree(tmp);
  	}
  
  	if (pci_registered)
  		pci_unregister_driver(&pci_driver);
  }
  
  /*
   *  Driver initialization entry point.
   */
  static int __init slgt_init(void)
  {
  	int rc;
a6b2f87be   Paul Fulghum   synclink_gt: enab...
3795
3796
  	printk(KERN_INFO "%s
  ", driver_name);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3797

705b6c7b3   Paul Fulghum   [PATCH] new drive...
3798
3799
  	serial_driver = alloc_tty_driver(MAX_DEVICES);
  	if (!serial_driver) {
62eb5b1f3   Paul Fulghum   synclink_gt use d...
3800
3801
3802
  		printk("%s can't allocate tty driver
  ", driver_name);
  		return -ENOMEM;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
  	}
  
  	/* Initialize the tty_driver structure */
  
  	serial_driver->owner = THIS_MODULE;
  	serial_driver->driver_name = tty_driver_name;
  	serial_driver->name = tty_dev_prefix;
  	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;
606d099cd   Alan Cox   [PATCH] tty: swit...
3817
3818
  	serial_driver->init_termios.c_ispeed = 9600;
  	serial_driver->init_termios.c_ospeed = 9600;
62eb5b1f3   Paul Fulghum   synclink_gt use d...
3819
  	serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3820
3821
3822
3823
3824
3825
3826
3827
  	tty_set_operations(serial_driver, &ops);
  	if ((rc = tty_register_driver(serial_driver)) < 0) {
  		DBGERR(("%s can't register serial driver
  ", driver_name));
  		put_tty_driver(serial_driver);
  		serial_driver = NULL;
  		goto error;
  	}
a6b2f87be   Paul Fulghum   synclink_gt: enab...
3828
3829
3830
  	printk(KERN_INFO "%s, tty major#%d
  ",
  	       driver_name, serial_driver->major);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3831

62eb5b1f3   Paul Fulghum   synclink_gt use d...
3832
3833
3834
3835
3836
3837
  	slgt_device_count = 0;
  	if ((rc = pci_register_driver(&pci_driver)) < 0) {
  		printk("%s pci_register_driver error=%d
  ", driver_name, rc);
  		goto error;
  	}
0fab6de09   Joe Perches   synclink drivers ...
3838
  	pci_registered = true;
62eb5b1f3   Paul Fulghum   synclink_gt use d...
3839
3840
3841
3842
  
  	if (!slgt_device_list)
  		printk("%s no devices found
  ",driver_name);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
  	return 0;
  
  error:
  	slgt_cleanup();
  	return rc;
  }
  
  static void __exit slgt_exit(void)
  {
  	slgt_cleanup();
  }
  
  module_init(slgt_init);
  module_exit(slgt_exit);
  
  /*
   * register access routines
   */
  
  #define CALC_REGADDR() \
  	unsigned long reg_addr = ((unsigned long)info->reg_addr) + addr; \
  	if (addr >= 0x80) \
9807224f1   Paul Fulghum   drivers/char/sync...
3865
3866
3867
  		reg_addr += (info->port_num) * 32; \
  	else if (addr >= 0x40)	\
  		reg_addr += (info->port_num) * 16;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
  
  static __u8 rd_reg8(struct slgt_info *info, unsigned int addr)
  {
  	CALC_REGADDR();
  	return readb((void __iomem *)reg_addr);
  }
  
  static void wr_reg8(struct slgt_info *info, unsigned int addr, __u8 value)
  {
  	CALC_REGADDR();
  	writeb(value, (void __iomem *)reg_addr);
  }
  
  static __u16 rd_reg16(struct slgt_info *info, unsigned int addr)
  {
  	CALC_REGADDR();
  	return readw((void __iomem *)reg_addr);
  }
  
  static void wr_reg16(struct slgt_info *info, unsigned int addr, __u16 value)
  {
  	CALC_REGADDR();
  	writew(value, (void __iomem *)reg_addr);
  }
  
  static __u32 rd_reg32(struct slgt_info *info, unsigned int addr)
  {
  	CALC_REGADDR();
  	return readl((void __iomem *)reg_addr);
  }
  
  static void wr_reg32(struct slgt_info *info, unsigned int addr, __u32 value)
  {
  	CALC_REGADDR();
  	writel(value, (void __iomem *)reg_addr);
  }
  
  static void rdma_reset(struct slgt_info *info)
  {
  	unsigned int i;
  
  	/* set reset bit */
  	wr_reg32(info, RDCSR, BIT1);
  
  	/* wait for enable bit cleared */
  	for(i=0 ; i < 1000 ; i++)
  		if (!(rd_reg32(info, RDCSR) & BIT0))
  			break;
  }
  
  static void tdma_reset(struct slgt_info *info)
  {
  	unsigned int i;
  
  	/* set reset bit */
  	wr_reg32(info, TDCSR, BIT1);
  
  	/* wait for enable bit cleared */
  	for(i=0 ; i < 1000 ; i++)
  		if (!(rd_reg32(info, TDCSR) & BIT0))
  			break;
  }
  
  /*
   * enable internal loopback
   * TxCLK and RxCLK are generated from BRG
   * and TxD is looped back to RxD internally.
   */
  static void enable_loopback(struct slgt_info *info)
  {
  	/* SCR (serial control) BIT2=looopback enable */
  	wr_reg16(info, SCR, (unsigned short)(rd_reg16(info, SCR) | BIT2));
  
  	if (info->params.mode != MGSL_MODE_ASYNC) {
  		/* CCR (clock control)
  		 * 07..05  tx clock source (010 = BRG)
  		 * 04..02  rx clock source (010 = BRG)
  		 * 01      auxclk enable   (0 = disable)
  		 * 00      BRG enable      (1 = enable)
  		 *
  		 * 0100 1001
  		 */
  		wr_reg8(info, CCR, 0x49);
  
  		/* set speed if available, otherwise use default */
  		if (info->params.clock_speed)
  			set_rate(info, info->params.clock_speed);
  		else
  			set_rate(info, 3686400);
  	}
  }
  
  /*
   *  set baud rate generator to specified rate
   */
  static void set_rate(struct slgt_info *info, u32 rate)
  {
  	unsigned int div;
1f80769ff   Paul Fulghum   synclink_gt: add ...
3966
  	unsigned int osc = info->base_clock;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
  
  	/* div = osc/rate - 1
  	 *
  	 * Round div up if osc/rate is not integer to
  	 * force to next slowest rate.
  	 */
  
  	if (rate) {
  		div = osc/rate;
  		if (!(osc % rate) && div)
  			div--;
  		wr_reg16(info, BDR, (unsigned short)div);
  	}
  }
  
  static void rx_stop(struct slgt_info *info)
  {
  	unsigned short val;
  
  	/* disable and reset receiver */
  	val = rd_reg16(info, RCR) & ~BIT1;          /* clear enable bit */
  	wr_reg16(info, RCR, (unsigned short)(val | BIT2)); /* set reset bit */
  	wr_reg16(info, RCR, val);                  /* clear reset bit */
  
  	slgt_irq_off(info, IRQ_RXOVER + IRQ_RXDATA + IRQ_RXIDLE);
  
  	/* clear pending rx interrupts */
  	wr_reg16(info, SSR, IRQ_RXIDLE + IRQ_RXOVER);
  
  	rdma_reset(info);
0fab6de09   Joe Perches   synclink drivers ...
3997
3998
  	info->rx_enabled = false;
  	info->rx_restart = false;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
  }
  
  static void rx_start(struct slgt_info *info)
  {
  	unsigned short val;
  
  	slgt_irq_off(info, IRQ_RXOVER + IRQ_RXDATA);
  
  	/* clear pending rx overrun IRQ */
  	wr_reg16(info, SSR, IRQ_RXOVER);
  
  	/* reset and disable receiver */
  	val = rd_reg16(info, RCR) & ~BIT1; /* clear enable bit */
  	wr_reg16(info, RCR, (unsigned short)(val | BIT2)); /* set reset bit */
  	wr_reg16(info, RCR, val);                  /* clear reset bit */
  
  	rdma_reset(info);
  	reset_rbufs(info);
5ba5a5d21   Paul Fulghum   tty: synclink_gt ...
4017
4018
4019
4020
4021
4022
4023
4024
  	if (info->rx_pio) {
  		/* rx request when rx FIFO not empty */
  		wr_reg16(info, SCR, (unsigned short)(rd_reg16(info, SCR) & ~BIT14));
  		slgt_irq_on(info, IRQ_RXDATA);
  		if (info->params.mode == MGSL_MODE_ASYNC) {
  			/* enable saving of rx status */
  			wr_reg32(info, RDCSR, BIT6);
  		}
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4025
  	} else {
5ba5a5d21   Paul Fulghum   tty: synclink_gt ...
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037
  		/* rx request when rx FIFO half full */
  		wr_reg16(info, SCR, (unsigned short)(rd_reg16(info, SCR) | BIT14));
  		/* set 1st descriptor address */
  		wr_reg32(info, RDDAR, info->rbufs[0].pdesc);
  
  		if (info->params.mode != MGSL_MODE_ASYNC) {
  			/* enable rx DMA and DMA interrupt */
  			wr_reg32(info, RDCSR, (BIT2 + BIT0));
  		} else {
  			/* enable saving of rx status, rx DMA and DMA interrupt */
  			wr_reg32(info, RDCSR, (BIT6 + BIT2 + BIT0));
  		}
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4038
4039
4040
4041
4042
4043
  	}
  
  	slgt_irq_on(info, IRQ_RXOVER);
  
  	/* enable receiver */
  	wr_reg16(info, RCR, (unsigned short)(rd_reg16(info, RCR) | BIT1));
0fab6de09   Joe Perches   synclink drivers ...
4044
4045
  	info->rx_restart = false;
  	info->rx_enabled = true;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4046
4047
4048
4049
4050
4051
  }
  
  static void tx_start(struct slgt_info *info)
  {
  	if (!info->tx_enabled) {
  		wr_reg16(info, TCR,
cb10dc9ac   Paul Fulghum   [PATCH] synclink_...
4052
  			 (unsigned short)((rd_reg16(info, TCR) | BIT1) & ~BIT2));
0fab6de09   Joe Perches   synclink drivers ...
4053
  		info->tx_enabled = true;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4054
  	}
de538eb34   Paul Fulghum   serial: synclink_...
4055
  	if (desc_count(info->tbufs[info->tbuf_start])) {
0fab6de09   Joe Perches   synclink drivers ...
4056
  		info->drop_rts_on_tx_done = false;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4057
4058
4059
4060
4061
4062
4063
  
  		if (info->params.mode != MGSL_MODE_ASYNC) {
  			if (info->params.flags & HDLC_FLAG_AUTO_RTS) {
  				get_signals(info);
  				if (!(info->signals & SerialSignal_RTS)) {
  					info->signals |= SerialSignal_RTS;
  					set_signals(info);
0fab6de09   Joe Perches   synclink drivers ...
4064
  					info->drop_rts_on_tx_done = true;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4065
4066
4067
4068
4069
4070
4071
  				}
  			}
  
  			slgt_irq_off(info, IRQ_TXDATA);
  			slgt_irq_on(info, IRQ_TXUNDER + IRQ_TXIDLE);
  			/* clear tx idle and underrun status bits */
  			wr_reg16(info, SSR, (unsigned short)(IRQ_TXIDLE + IRQ_TXUNDER));
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4072
  		} else {
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4073
4074
4075
4076
  			slgt_irq_off(info, IRQ_TXDATA);
  			slgt_irq_on(info, IRQ_TXIDLE);
  			/* clear tx idle status bit */
  			wr_reg16(info, SSR, IRQ_TXIDLE);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4077
  		}
ce89294c0   Paul Fulghum   synclink_gt: fix ...
4078
4079
4080
  		/* set 1st descriptor address and start DMA */
  		wr_reg32(info, TDDAR, info->tbufs[info->tbuf_start].pdesc);
  		wr_reg32(info, TDCSR, BIT2 + BIT0);
0fab6de09   Joe Perches   synclink drivers ...
4081
  		info->tx_active = true;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
  	}
  }
  
  static void tx_stop(struct slgt_info *info)
  {
  	unsigned short val;
  
  	del_timer(&info->tx_timer);
  
  	tdma_reset(info);
  
  	/* reset and disable transmitter */
  	val = rd_reg16(info, TCR) & ~BIT1;          /* clear enable bit */
  	wr_reg16(info, TCR, (unsigned short)(val | BIT2)); /* set reset bit */
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4096
4097
4098
4099
4100
4101
4102
  
  	slgt_irq_off(info, IRQ_TXDATA + IRQ_TXIDLE + IRQ_TXUNDER);
  
  	/* clear tx idle and underrun status bit */
  	wr_reg16(info, SSR, (unsigned short)(IRQ_TXIDLE + IRQ_TXUNDER));
  
  	reset_tbufs(info);
0fab6de09   Joe Perches   synclink drivers ...
4103
4104
  	info->tx_enabled = false;
  	info->tx_active = false;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
4124
4125
4126
4127
4128
4129
4130
4131
4132
4133
4134
4135
4136
4137
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152
4153
4154
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
4183
4184
4185
4186
4187
4188
4189
4190
4191
4192
4193
4194
4195
4196
4197
4198
4199
4200
4201
4202
4203
4204
4205
4206
4207
4208
4209
4210
4211
4212
4213
4214
4215
4216
4217
4218
4219
4220
4221
4222
4223
4224
4225
4226
4227
4228
4229
4230
  }
  
  static void reset_port(struct slgt_info *info)
  {
  	if (!info->reg_addr)
  		return;
  
  	tx_stop(info);
  	rx_stop(info);
  
  	info->signals &= ~(SerialSignal_DTR + SerialSignal_RTS);
  	set_signals(info);
  
  	slgt_irq_off(info, IRQ_ALL | IRQ_MASTER);
  }
  
  static void reset_adapter(struct slgt_info *info)
  {
  	int i;
  	for (i=0; i < info->port_count; ++i) {
  		if (info->port_array[i])
  			reset_port(info->port_array[i]);
  	}
  }
  
  static void async_mode(struct slgt_info *info)
  {
    	unsigned short val;
  
  	slgt_irq_off(info, IRQ_ALL | IRQ_MASTER);
  	tx_stop(info);
  	rx_stop(info);
  
  	/* TCR (tx control)
  	 *
  	 * 15..13  mode, 010=async
  	 * 12..10  encoding, 000=NRZ
  	 * 09      parity enable
  	 * 08      1=odd parity, 0=even parity
  	 * 07      1=RTS driver control
  	 * 06      1=break enable
  	 * 05..04  character length
  	 *         00=5 bits
  	 *         01=6 bits
  	 *         10=7 bits
  	 *         11=8 bits
  	 * 03      0=1 stop bit, 1=2 stop bits
  	 * 02      reset
  	 * 01      enable
  	 * 00      auto-CTS enable
  	 */
  	val = 0x4000;
  
  	if (info->if_mode & MGSL_INTERFACE_RTS_EN)
  		val |= BIT7;
  
  	if (info->params.parity != ASYNC_PARITY_NONE) {
  		val |= BIT9;
  		if (info->params.parity == ASYNC_PARITY_ODD)
  			val |= BIT8;
  	}
  
  	switch (info->params.data_bits)
  	{
  	case 6: val |= BIT4; break;
  	case 7: val |= BIT5; break;
  	case 8: val |= BIT5 + BIT4; break;
  	}
  
  	if (info->params.stop_bits != 1)
  		val |= BIT3;
  
  	if (info->params.flags & HDLC_FLAG_AUTO_CTS)
  		val |= BIT0;
  
  	wr_reg16(info, TCR, val);
  
  	/* RCR (rx control)
  	 *
  	 * 15..13  mode, 010=async
  	 * 12..10  encoding, 000=NRZ
  	 * 09      parity enable
  	 * 08      1=odd parity, 0=even parity
  	 * 07..06  reserved, must be 0
  	 * 05..04  character length
  	 *         00=5 bits
  	 *         01=6 bits
  	 *         10=7 bits
  	 *         11=8 bits
  	 * 03      reserved, must be zero
  	 * 02      reset
  	 * 01      enable
  	 * 00      auto-DCD enable
  	 */
  	val = 0x4000;
  
  	if (info->params.parity != ASYNC_PARITY_NONE) {
  		val |= BIT9;
  		if (info->params.parity == ASYNC_PARITY_ODD)
  			val |= BIT8;
  	}
  
  	switch (info->params.data_bits)
  	{
  	case 6: val |= BIT4; break;
  	case 7: val |= BIT5; break;
  	case 8: val |= BIT5 + BIT4; break;
  	}
  
  	if (info->params.flags & HDLC_FLAG_AUTO_DCD)
  		val |= BIT0;
  
  	wr_reg16(info, RCR, val);
  
  	/* CCR (clock control)
  	 *
  	 * 07..05  011 = tx clock source is BRG/16
  	 * 04..02  010 = rx clock source is BRG
  	 * 01      0 = auxclk disabled
  	 * 00      1 = BRG enabled
  	 *
  	 * 0110 1001
  	 */
  	wr_reg8(info, CCR, 0x69);
  
  	msc_set_vcr(info);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4231
4232
4233
4234
4235
4236
4237
4238
4239
4240
4241
4242
4243
4244
  	/* SCR (serial control)
  	 *
  	 * 15  1=tx req on FIFO half empty
  	 * 14  1=rx req on FIFO half full
  	 * 13  tx data  IRQ enable
  	 * 12  tx idle  IRQ enable
  	 * 11  rx break on IRQ enable
  	 * 10  rx data  IRQ enable
  	 * 09  rx break off IRQ enable
  	 * 08  overrun  IRQ enable
  	 * 07  DSR      IRQ enable
  	 * 06  CTS      IRQ enable
  	 * 05  DCD      IRQ enable
  	 * 04  RI       IRQ enable
1f80769ff   Paul Fulghum   synclink_gt: add ...
4245
  	 * 03  0=16x sampling, 1=8x sampling
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4246
4247
4248
4249
4250
  	 * 02  1=txd->rxd internal loopback enable
  	 * 01  reserved, must be zero
  	 * 00  1=master IRQ enable
  	 */
  	val = BIT15 + BIT14 + BIT0;
1f80769ff   Paul Fulghum   synclink_gt: add ...
4251
4252
4253
4254
4255
4256
4257
4258
4259
4260
4261
  	/* JCR[8] : 1 = x8 async mode feature available */
  	if ((rd_reg32(info, JCR) & BIT8) && info->params.data_rate &&
  	    ((info->base_clock < (info->params.data_rate * 16)) ||
  	     (info->base_clock % (info->params.data_rate * 16)))) {
  		/* use 8x sampling */
  		val |= BIT3;
  		set_rate(info, info->params.data_rate * 8);
  	} else {
  		/* use 16x sampling */
  		set_rate(info, info->params.data_rate * 16);
  	}
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4262
4263
4264
  	wr_reg16(info, SCR, val);
  
  	slgt_irq_on(info, IRQ_RXBREAK | IRQ_RXOVER);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4265
4266
4267
  	if (info->params.loopback)
  		enable_loopback(info);
  }
cb10dc9ac   Paul Fulghum   [PATCH] synclink_...
4268
  static void sync_mode(struct slgt_info *info)
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4269
4270
4271
4272
4273
4274
4275
4276
4277
  {
  	unsigned short val;
  
  	slgt_irq_off(info, IRQ_ALL | IRQ_MASTER);
  	tx_stop(info);
  	rx_stop(info);
  
  	/* TCR (tx control)
  	 *
9807224f1   Paul Fulghum   drivers/char/sync...
4278
4279
4280
4281
4282
4283
4284
  	 * 15..13  mode
  	 *         000=HDLC/SDLC
  	 *         001=raw bit synchronous
  	 *         010=asynchronous/isochronous
  	 *         011=monosync byte synchronous
  	 *         100=bisync byte synchronous
  	 *         101=xsync byte synchronous
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4285
4286
4287
4288
4289
4290
4291
4292
4293
4294
4295
  	 * 12..10  encoding
  	 * 09      CRC enable
  	 * 08      CRC32
  	 * 07      1=RTS driver control
  	 * 06      preamble enable
  	 * 05..04  preamble length
  	 * 03      share open/close flag
  	 * 02      reset
  	 * 01      enable
  	 * 00      auto-CTS enable
  	 */
993456cdc   Paul Fulghum   synclink_gt: leav...
4296
  	val = BIT2;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4297

cb10dc9ac   Paul Fulghum   [PATCH] synclink_...
4298
  	switch(info->params.mode) {
9807224f1   Paul Fulghum   drivers/char/sync...
4299
4300
4301
  	case MGSL_MODE_XSYNC:
  		val |= BIT15 + BIT13;
  		break;
cb10dc9ac   Paul Fulghum   [PATCH] synclink_...
4302
4303
4304
4305
  	case MGSL_MODE_MONOSYNC: val |= BIT14 + BIT13; break;
  	case MGSL_MODE_BISYNC:   val |= BIT15; break;
  	case MGSL_MODE_RAW:      val |= BIT13; break;
  	}
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4306
4307
4308
4309
4310
4311
4312
4313
4314
4315
4316
4317
4318
  	if (info->if_mode & MGSL_INTERFACE_RTS_EN)
  		val |= BIT7;
  
  	switch(info->params.encoding)
  	{
  	case HDLC_ENCODING_NRZB:          val |= BIT10; break;
  	case HDLC_ENCODING_NRZI_MARK:     val |= BIT11; break;
  	case HDLC_ENCODING_NRZI:          val |= BIT11 + BIT10; break;
  	case HDLC_ENCODING_BIPHASE_MARK:  val |= BIT12; break;
  	case HDLC_ENCODING_BIPHASE_SPACE: val |= BIT12 + BIT10; break;
  	case HDLC_ENCODING_BIPHASE_LEVEL: val |= BIT12 + BIT11; break;
  	case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: val |= BIT12 + BIT11 + BIT10; break;
  	}
04b374d0f   Paul Fulghum   [PATCH] add syncl...
4319
  	switch (info->params.crc_type & HDLC_CRC_MASK)
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4320
4321
4322
4323
4324
4325
4326
4327
4328
4329
4330
4331
4332
4333
4334
4335
4336
4337
4338
4339
4340
4341
4342
4343
4344
4345
4346
4347
4348
4349
4350
4351
4352
4353
4354
  	{
  	case HDLC_CRC_16_CCITT: val |= BIT9; break;
  	case HDLC_CRC_32_CCITT: val |= BIT9 + BIT8; break;
  	}
  
  	if (info->params.preamble != HDLC_PREAMBLE_PATTERN_NONE)
  		val |= BIT6;
  
  	switch (info->params.preamble_length)
  	{
  	case HDLC_PREAMBLE_LENGTH_16BITS: val |= BIT5; break;
  	case HDLC_PREAMBLE_LENGTH_32BITS: val |= BIT4; break;
  	case HDLC_PREAMBLE_LENGTH_64BITS: val |= BIT5 + BIT4; break;
  	}
  
  	if (info->params.flags & HDLC_FLAG_AUTO_CTS)
  		val |= BIT0;
  
  	wr_reg16(info, TCR, val);
  
  	/* TPR (transmit preamble) */
  
  	switch (info->params.preamble)
  	{
  	case HDLC_PREAMBLE_PATTERN_FLAGS: val = 0x7e; break;
  	case HDLC_PREAMBLE_PATTERN_ONES:  val = 0xff; break;
  	case HDLC_PREAMBLE_PATTERN_ZEROS: val = 0x00; break;
  	case HDLC_PREAMBLE_PATTERN_10:    val = 0x55; break;
  	case HDLC_PREAMBLE_PATTERN_01:    val = 0xaa; break;
  	default:                          val = 0x7e; break;
  	}
  	wr_reg8(info, TPR, (unsigned char)val);
  
  	/* RCR (rx control)
  	 *
9807224f1   Paul Fulghum   drivers/char/sync...
4355
4356
4357
4358
4359
4360
4361
  	 * 15..13  mode
  	 *         000=HDLC/SDLC
  	 *         001=raw bit synchronous
  	 *         010=asynchronous/isochronous
  	 *         011=monosync byte synchronous
  	 *         100=bisync byte synchronous
  	 *         101=xsync byte synchronous
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4362
4363
4364
4365
4366
4367
4368
4369
4370
  	 * 12..10  encoding
  	 * 09      CRC enable
  	 * 08      CRC32
  	 * 07..03  reserved, must be 0
  	 * 02      reset
  	 * 01      enable
  	 * 00      auto-DCD enable
  	 */
  	val = 0;
cb10dc9ac   Paul Fulghum   [PATCH] synclink_...
4371
  	switch(info->params.mode) {
9807224f1   Paul Fulghum   drivers/char/sync...
4372
4373
4374
  	case MGSL_MODE_XSYNC:
  		val |= BIT15 + BIT13;
  		break;
cb10dc9ac   Paul Fulghum   [PATCH] synclink_...
4375
4376
4377
4378
  	case MGSL_MODE_MONOSYNC: val |= BIT14 + BIT13; break;
  	case MGSL_MODE_BISYNC:   val |= BIT15; break;
  	case MGSL_MODE_RAW:      val |= BIT13; break;
  	}
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4379
4380
4381
4382
4383
4384
4385
4386
4387
4388
4389
  
  	switch(info->params.encoding)
  	{
  	case HDLC_ENCODING_NRZB:          val |= BIT10; break;
  	case HDLC_ENCODING_NRZI_MARK:     val |= BIT11; break;
  	case HDLC_ENCODING_NRZI:          val |= BIT11 + BIT10; break;
  	case HDLC_ENCODING_BIPHASE_MARK:  val |= BIT12; break;
  	case HDLC_ENCODING_BIPHASE_SPACE: val |= BIT12 + BIT10; break;
  	case HDLC_ENCODING_BIPHASE_LEVEL: val |= BIT12 + BIT11; break;
  	case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: val |= BIT12 + BIT11 + BIT10; break;
  	}
04b374d0f   Paul Fulghum   [PATCH] add syncl...
4390
  	switch (info->params.crc_type & HDLC_CRC_MASK)
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4391
4392
4393
4394
4395
4396
4397
4398
4399
4400
4401
4402
4403
4404
4405
4406
4407
4408
4409
4410
4411
4412
4413
4414
4415
4416
4417
4418
4419
4420
4421
4422
4423
4424
4425
4426
4427
4428
4429
4430
4431
4432
4433
4434
4435
4436
4437
4438
4439
4440
4441
4442
4443
4444
4445
4446
4447
4448
4449
4450
4451
4452
4453
4454
4455
4456
4457
4458
4459
4460
4461
4462
4463
4464
4465
4466
4467
4468
4469
4470
4471
4472
4473
4474
4475
4476
4477
4478
4479
4480
4481
4482
4483
4484
4485
4486
4487
4488
4489
4490
4491
  	{
  	case HDLC_CRC_16_CCITT: val |= BIT9; break;
  	case HDLC_CRC_32_CCITT: val |= BIT9 + BIT8; break;
  	}
  
  	if (info->params.flags & HDLC_FLAG_AUTO_DCD)
  		val |= BIT0;
  
  	wr_reg16(info, RCR, val);
  
  	/* CCR (clock control)
  	 *
  	 * 07..05  tx clock source
  	 * 04..02  rx clock source
  	 * 01      auxclk enable
  	 * 00      BRG enable
  	 */
  	val = 0;
  
  	if (info->params.flags & HDLC_FLAG_TXC_BRG)
  	{
  		// when RxC source is DPLL, BRG generates 16X DPLL
  		// reference clock, so take TxC from BRG/16 to get
  		// transmit clock at actual data rate
  		if (info->params.flags & HDLC_FLAG_RXC_DPLL)
  			val |= BIT6 + BIT5;	/* 011, txclk = BRG/16 */
  		else
  			val |= BIT6;	/* 010, txclk = BRG */
  	}
  	else if (info->params.flags & HDLC_FLAG_TXC_DPLL)
  		val |= BIT7;	/* 100, txclk = DPLL Input */
  	else if (info->params.flags & HDLC_FLAG_TXC_RXCPIN)
  		val |= BIT5;	/* 001, txclk = RXC Input */
  
  	if (info->params.flags & HDLC_FLAG_RXC_BRG)
  		val |= BIT3;	/* 010, rxclk = BRG */
  	else if (info->params.flags & HDLC_FLAG_RXC_DPLL)
  		val |= BIT4;	/* 100, rxclk = DPLL */
  	else if (info->params.flags & HDLC_FLAG_RXC_TXCPIN)
  		val |= BIT2;	/* 001, rxclk = TXC Input */
  
  	if (info->params.clock_speed)
  		val |= BIT1 + BIT0;
  
  	wr_reg8(info, CCR, (unsigned char)val);
  
  	if (info->params.flags & (HDLC_FLAG_TXC_DPLL + HDLC_FLAG_RXC_DPLL))
  	{
  		// program DPLL mode
  		switch(info->params.encoding)
  		{
  		case HDLC_ENCODING_BIPHASE_MARK:
  		case HDLC_ENCODING_BIPHASE_SPACE:
  			val = BIT7; break;
  		case HDLC_ENCODING_BIPHASE_LEVEL:
  		case HDLC_ENCODING_DIFF_BIPHASE_LEVEL:
  			val = BIT7 + BIT6; break;
  		default: val = BIT6;	// NRZ encodings
  		}
  		wr_reg16(info, RCR, (unsigned short)(rd_reg16(info, RCR) | val));
  
  		// DPLL requires a 16X reference clock from BRG
  		set_rate(info, info->params.clock_speed * 16);
  	}
  	else
  		set_rate(info, info->params.clock_speed);
  
  	tx_set_idle(info);
  
  	msc_set_vcr(info);
  
  	/* SCR (serial control)
  	 *
  	 * 15  1=tx req on FIFO half empty
  	 * 14  1=rx req on FIFO half full
  	 * 13  tx data  IRQ enable
  	 * 12  tx idle  IRQ enable
  	 * 11  underrun IRQ enable
  	 * 10  rx data  IRQ enable
  	 * 09  rx idle  IRQ enable
  	 * 08  overrun  IRQ enable
  	 * 07  DSR      IRQ enable
  	 * 06  CTS      IRQ enable
  	 * 05  DCD      IRQ enable
  	 * 04  RI       IRQ enable
  	 * 03  reserved, must be zero
  	 * 02  1=txd->rxd internal loopback enable
  	 * 01  reserved, must be zero
  	 * 00  1=master IRQ enable
  	 */
  	wr_reg16(info, SCR, BIT15 + BIT14 + BIT0);
  
  	if (info->params.loopback)
  		enable_loopback(info);
  }
  
  /*
   *  set transmit idle mode
   */
  static void tx_set_idle(struct slgt_info *info)
  {
643f3319b   Paul Fulghum   [PATCH] add syncl...
4492
4493
  	unsigned char val;
  	unsigned short tcr;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4494

643f3319b   Paul Fulghum   [PATCH] add syncl...
4495
4496
4497
4498
4499
4500
4501
4502
4503
4504
4505
4506
4507
4508
4509
4510
4511
4512
4513
4514
4515
4516
4517
4518
4519
4520
4521
4522
4523
  	/* if preamble enabled (tcr[6] == 1) then tx idle size = 8 bits
  	 * else tcr[5:4] = tx idle size: 00 = 8 bits, 01 = 16 bits
  	 */
  	tcr = rd_reg16(info, TCR);
  	if (info->idle_mode & HDLC_TXIDLE_CUSTOM_16) {
  		/* disable preamble, set idle size to 16 bits */
  		tcr = (tcr & ~(BIT6 + BIT5)) | BIT4;
  		/* MSB of 16 bit idle specified in tx preamble register (TPR) */
  		wr_reg8(info, TPR, (unsigned char)((info->idle_mode >> 8) & 0xff));
  	} else if (!(tcr & BIT6)) {
  		/* preamble is disabled, set idle size to 8 bits */
  		tcr &= ~(BIT5 + BIT4);
  	}
  	wr_reg16(info, TCR, tcr);
  
  	if (info->idle_mode & (HDLC_TXIDLE_CUSTOM_8 | HDLC_TXIDLE_CUSTOM_16)) {
  		/* LSB of custom tx idle specified in tx idle register */
  		val = (unsigned char)(info->idle_mode & 0xff);
  	} else {
  		/* standard 8 bit idle patterns */
  		switch(info->idle_mode)
  		{
  		case HDLC_TXIDLE_FLAGS:          val = 0x7e; break;
  		case HDLC_TXIDLE_ALT_ZEROS_ONES:
  		case HDLC_TXIDLE_ALT_MARK_SPACE: val = 0xaa; break;
  		case HDLC_TXIDLE_ZEROS:
  		case HDLC_TXIDLE_SPACE:          val = 0x00; break;
  		default:                         val = 0xff;
  		}
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4524
4525
4526
4527
4528
4529
4530
4531
4532
4533
4534
4535
4536
4537
4538
4539
4540
4541
4542
4543
4544
4545
4546
4547
4548
4549
4550
4551
4552
4553
4554
4555
4556
4557
4558
4559
4560
4561
4562
4563
4564
4565
4566
4567
4568
4569
4570
4571
4572
4573
4574
4575
4576
  	}
  
  	wr_reg8(info, TIR, val);
  }
  
  /*
   * get state of V24 status (input) signals
   */
  static void get_signals(struct slgt_info *info)
  {
  	unsigned short status = rd_reg16(info, SSR);
  
  	/* clear all serial signals except DTR and RTS */
  	info->signals &= SerialSignal_DTR + SerialSignal_RTS;
  
  	if (status & BIT3)
  		info->signals |= SerialSignal_DSR;
  	if (status & BIT2)
  		info->signals |= SerialSignal_CTS;
  	if (status & BIT1)
  		info->signals |= SerialSignal_DCD;
  	if (status & BIT0)
  		info->signals |= SerialSignal_RI;
  }
  
  /*
   * set V.24 Control Register based on current configuration
   */
  static void msc_set_vcr(struct slgt_info *info)
  {
  	unsigned char val = 0;
  
  	/* VCR (V.24 control)
  	 *
  	 * 07..04  serial IF select
  	 * 03      DTR
  	 * 02      RTS
  	 * 01      LL
  	 * 00      RL
  	 */
  
  	switch(info->if_mode & MGSL_INTERFACE_MASK)
  	{
  	case MGSL_INTERFACE_RS232:
  		val |= BIT5; /* 0010 */
  		break;
  	case MGSL_INTERFACE_V35:
  		val |= BIT7 + BIT6 + BIT5; /* 1110 */
  		break;
  	case MGSL_INTERFACE_RS422:
  		val |= BIT6; /* 0100 */
  		break;
  	}
e5590717a   Paul Fulghum   synclink_gt: add ...
4577
4578
  	if (info->if_mode & MGSL_INTERFACE_MSB_FIRST)
  		val |= BIT4;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4579
4580
4581
4582
4583
4584
4585
4586
4587
4588
4589
4590
4591
4592
4593
4594
4595
4596
4597
4598
4599
4600
4601
4602
4603
4604
4605
4606
4607
4608
4609
4610
4611
4612
4613
4614
4615
4616
  	if (info->signals & SerialSignal_DTR)
  		val |= BIT3;
  	if (info->signals & SerialSignal_RTS)
  		val |= BIT2;
  	if (info->if_mode & MGSL_INTERFACE_LL)
  		val |= BIT1;
  	if (info->if_mode & MGSL_INTERFACE_RL)
  		val |= BIT0;
  	wr_reg8(info, VCR, val);
  }
  
  /*
   * set state of V24 control (output) signals
   */
  static void set_signals(struct slgt_info *info)
  {
  	unsigned char val = rd_reg8(info, VCR);
  	if (info->signals & SerialSignal_DTR)
  		val |= BIT3;
  	else
  		val &= ~BIT3;
  	if (info->signals & SerialSignal_RTS)
  		val |= BIT2;
  	else
  		val &= ~BIT2;
  	wr_reg8(info, VCR, val);
  }
  
  /*
   * free range of receive DMA buffers (i to last)
   */
  static void free_rbufs(struct slgt_info *info, unsigned int i, unsigned int last)
  {
  	int done = 0;
  
  	while(!done) {
  		/* reset current buffer for reuse */
  		info->rbufs[i].status = 0;
814dae031   Paul Fulghum   synclink_gt: add ...
4617
  		set_desc_count(info->rbufs[i], info->rbuf_fill_level);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4618
4619
4620
4621
4622
4623
4624
4625
4626
4627
4628
4629
4630
4631
  		if (i == last)
  			done = 1;
  		if (++i == info->rbuf_count)
  			i = 0;
  	}
  	info->rbuf_current = i;
  }
  
  /*
   * mark all receive DMA buffers as free
   */
  static void reset_rbufs(struct slgt_info *info)
  {
  	free_rbufs(info, 0, info->rbuf_count - 1);
5ba5a5d21   Paul Fulghum   tty: synclink_gt ...
4632
4633
  	info->rbuf_fill_index = 0;
  	info->rbuf_fill_count = 0;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4634
4635
4636
4637
4638
  }
  
  /*
   * pass receive HDLC frame to upper layer
   *
0fab6de09   Joe Perches   synclink drivers ...
4639
   * return true if frame available, otherwise false
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4640
   */
0fab6de09   Joe Perches   synclink drivers ...
4641
  static bool rx_get_frame(struct slgt_info *info)
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4642
4643
4644
4645
  {
  	unsigned int start, end;
  	unsigned short status;
  	unsigned int framesize = 0;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4646
  	unsigned long flags;
8fb06c771   Alan Cox   synclink: use tty...
4647
  	struct tty_struct *tty = info->port.tty;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4648
  	unsigned char addr_field = 0xff;
04b374d0f   Paul Fulghum   [PATCH] add syncl...
4649
4650
4651
4652
4653
4654
  	unsigned int crc_size = 0;
  
  	switch (info->params.crc_type & HDLC_CRC_MASK) {
  	case HDLC_CRC_16_CCITT: crc_size = 2; break;
  	case HDLC_CRC_32_CCITT: crc_size = 4; break;
  	}
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4655
4656
4657
4658
4659
4660
4661
4662
4663
4664
4665
4666
4667
4668
4669
4670
4671
4672
4673
4674
4675
4676
4677
4678
4679
4680
4681
4682
4683
4684
4685
4686
4687
4688
4689
4690
4691
4692
4693
4694
4695
4696
4697
4698
  
  check_again:
  
  	framesize = 0;
  	addr_field = 0xff;
  	start = end = info->rbuf_current;
  
  	for (;;) {
  		if (!desc_complete(info->rbufs[end]))
  			goto cleanup;
  
  		if (framesize == 0 && info->params.addr_filter != 0xff)
  			addr_field = info->rbufs[end].buf[0];
  
  		framesize += desc_count(info->rbufs[end]);
  
  		if (desc_eof(info->rbufs[end]))
  			break;
  
  		if (++end == info->rbuf_count)
  			end = 0;
  
  		if (end == info->rbuf_current) {
  			if (info->rx_enabled){
  				spin_lock_irqsave(&info->lock,flags);
  				rx_start(info);
  				spin_unlock_irqrestore(&info->lock,flags);
  			}
  			goto cleanup;
  		}
  	}
  
  	/* status
  	 *
  	 * 15      buffer complete
  	 * 14..06  reserved
  	 * 05..04  residue
  	 * 02      eof (end of frame)
  	 * 01      CRC error
  	 * 00      abort
  	 */
  	status = desc_status(info->rbufs[end]);
  
  	/* ignore CRC bit if not using CRC (bit is undefined) */
04b374d0f   Paul Fulghum   [PATCH] add syncl...
4699
  	if ((info->params.crc_type & HDLC_CRC_MASK) == HDLC_CRC_NONE)
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4700
4701
4702
4703
4704
4705
4706
  		status &= ~BIT1;
  
  	if (framesize == 0 ||
  		 (addr_field != 0xff && addr_field != info->params.addr_filter)) {
  		free_rbufs(info, start, end);
  		goto check_again;
  	}
04b374d0f   Paul Fulghum   [PATCH] add syncl...
4707
4708
  	if (framesize < (2 + crc_size) || status & BIT0) {
  		info->icount.rxshort++;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4709
  		framesize = 0;
04b374d0f   Paul Fulghum   [PATCH] add syncl...
4710
4711
4712
4713
4714
  	} else if (status & BIT1) {
  		info->icount.rxcrc++;
  		if (!(info->params.crc_type & HDLC_CRC_RETURN_EX))
  			framesize = 0;
  	}
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4715

af69c7f92   Paul Fulghum   [PATCH] generic H...
4716
  #if SYNCLINK_GENERIC_HDLC
04b374d0f   Paul Fulghum   [PATCH] add syncl...
4717
  	if (framesize == 0) {
198191c4a   Krzysztof Halasa   WAN: convert driv...
4718
4719
  		info->netdev->stats.rx_errors++;
  		info->netdev->stats.rx_frame_errors++;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4720
  	}
04b374d0f   Paul Fulghum   [PATCH] add syncl...
4721
  #endif
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4722
4723
4724
4725
  
  	DBGBH(("%s rx frame status=%04X size=%d
  ",
  		info->device_name, status, framesize));
814dae031   Paul Fulghum   synclink_gt: add ...
4726
  	DBGDATA(info, info->rbufs[start].buf, min_t(int, framesize, info->rbuf_fill_level), "rx");
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4727
4728
  
  	if (framesize) {
04b374d0f   Paul Fulghum   [PATCH] add syncl...
4729
4730
4731
4732
4733
4734
  		if (!(info->params.crc_type & HDLC_CRC_RETURN_EX)) {
  			framesize -= crc_size;
  			crc_size = 0;
  		}
  
  		if (framesize > info->max_frame_size + crc_size)
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4735
4736
4737
4738
4739
4740
4741
4742
4743
4744
4745
  			info->icount.rxlong++;
  		else {
  			/* copy dma buffer(s) to contiguous temp buffer */
  			int copy_count = framesize;
  			int i = start;
  			unsigned char *p = info->tmp_rbuf;
  			info->tmp_rbuf_count = framesize;
  
  			info->icount.rxok++;
  
  			while(copy_count) {
814dae031   Paul Fulghum   synclink_gt: add ...
4746
  				int partial_count = min_t(int, copy_count, info->rbuf_fill_level);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4747
4748
4749
4750
4751
4752
  				memcpy(p, info->rbufs[i].buf, partial_count);
  				p += partial_count;
  				copy_count -= partial_count;
  				if (++i == info->rbuf_count)
  					i = 0;
  			}
04b374d0f   Paul Fulghum   [PATCH] add syncl...
4753
4754
4755
4756
  			if (info->params.crc_type & HDLC_CRC_RETURN_EX) {
  				*p = (status & BIT1) ? RX_CRC_ERROR : RX_OK;
  				framesize++;
  			}
af69c7f92   Paul Fulghum   [PATCH] generic H...
4757
  #if SYNCLINK_GENERIC_HDLC
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4758
4759
4760
4761
4762
4763
4764
4765
  			if (info->netcount)
  				hdlcdev_rx(info,info->tmp_rbuf, framesize);
  			else
  #endif
  				ldisc_receive_buf(tty, info->tmp_rbuf, info->flag_buf, framesize);
  		}
  	}
  	free_rbufs(info, start, end);
0fab6de09   Joe Perches   synclink drivers ...
4766
  	return true;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4767
4768
  
  cleanup:
0fab6de09   Joe Perches   synclink drivers ...
4769
  	return false;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4770
4771
4772
4773
  }
  
  /*
   * pass receive buffer (RAW synchronous mode) to tty layer
0fab6de09   Joe Perches   synclink drivers ...
4774
   * return true if buffer available, otherwise false
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4775
   */
0fab6de09   Joe Perches   synclink drivers ...
4776
  static bool rx_get_buf(struct slgt_info *info)
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4777
4778
  {
  	unsigned int i = info->rbuf_current;
cb10dc9ac   Paul Fulghum   [PATCH] synclink_...
4779
  	unsigned int count;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4780
4781
  
  	if (!desc_complete(info->rbufs[i]))
0fab6de09   Joe Perches   synclink drivers ...
4782
  		return false;
cb10dc9ac   Paul Fulghum   [PATCH] synclink_...
4783
4784
4785
4786
  	count = desc_count(info->rbufs[i]);
  	switch(info->params.mode) {
  	case MGSL_MODE_MONOSYNC:
  	case MGSL_MODE_BISYNC:
9807224f1   Paul Fulghum   drivers/char/sync...
4787
  	case MGSL_MODE_XSYNC:
cb10dc9ac   Paul Fulghum   [PATCH] synclink_...
4788
4789
4790
4791
4792
4793
4794
4795
4796
  		/* ignore residue in byte synchronous modes */
  		if (desc_residue(info->rbufs[i]))
  			count--;
  		break;
  	}
  	DBGDATA(info, info->rbufs[i].buf, count, "rx");
  	DBGINFO(("rx_get_buf size=%d
  ", count));
  	if (count)
8fb06c771   Alan Cox   synclink: use tty...
4797
  		ldisc_receive_buf(info->port.tty, info->rbufs[i].buf,
cb10dc9ac   Paul Fulghum   [PATCH] synclink_...
4798
  				  info->flag_buf, count);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4799
  	free_rbufs(info, i, i);
0fab6de09   Joe Perches   synclink drivers ...
4800
  	return true;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4801
4802
4803
4804
4805
4806
4807
4808
4809
4810
4811
4812
4813
4814
4815
4816
4817
4818
4819
4820
4821
4822
4823
4824
4825
4826
4827
4828
  }
  
  static void reset_tbufs(struct slgt_info *info)
  {
  	unsigned int i;
  	info->tbuf_current = 0;
  	for (i=0 ; i < info->tbuf_count ; i++) {
  		info->tbufs[i].status = 0;
  		info->tbufs[i].count  = 0;
  	}
  }
  
  /*
   * return number of free transmit DMA buffers
   */
  static unsigned int free_tbuf_count(struct slgt_info *info)
  {
  	unsigned int count = 0;
  	unsigned int i = info->tbuf_current;
  
  	do
  	{
  		if (desc_count(info->tbufs[i]))
  			break; /* buffer in use */
  		++count;
  		if (++i == info->tbuf_count)
  			i=0;
  	} while (i != info->tbuf_current);
bb029c67e   Paul Fulghum   synclink_gt: fix ...
4829
4830
  	/* if tx DMA active, last zero count buffer is in use */
  	if (count && (rd_reg32(info, TDCSR) & BIT0))
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4831
4832
4833
4834
4835
4836
  		--count;
  
  	return count;
  }
  
  /*
403214d0a   Paul Fulghum   synclink_gt: impr...
4837
4838
4839
4840
4841
4842
4843
4844
4845
4846
4847
4848
4849
4850
4851
4852
4853
4854
4855
4856
4857
4858
4859
4860
4861
4862
4863
4864
4865
4866
4867
4868
4869
4870
4871
4872
4873
4874
4875
4876
4877
4878
4879
4880
4881
4882
4883
4884
4885
4886
   * return number of bytes in unsent transmit DMA buffers
   * and the serial controller tx FIFO
   */
  static unsigned int tbuf_bytes(struct slgt_info *info)
  {
  	unsigned int total_count = 0;
  	unsigned int i = info->tbuf_current;
  	unsigned int reg_value;
  	unsigned int count;
  	unsigned int active_buf_count = 0;
  
  	/*
  	 * Add descriptor counts for all tx DMA buffers.
  	 * If count is zero (cleared by DMA controller after read),
  	 * the buffer is complete or is actively being read from.
  	 *
  	 * Record buf_count of last buffer with zero count starting
  	 * from current ring position. buf_count is mirror
  	 * copy of count and is not cleared by serial controller.
  	 * If DMA controller is active, that buffer is actively
  	 * being read so add to total.
  	 */
  	do {
  		count = desc_count(info->tbufs[i]);
  		if (count)
  			total_count += count;
  		else if (!total_count)
  			active_buf_count = info->tbufs[i].buf_count;
  		if (++i == info->tbuf_count)
  			i = 0;
  	} while (i != info->tbuf_current);
  
  	/* read tx DMA status register */
  	reg_value = rd_reg32(info, TDCSR);
  
  	/* if tx DMA active, last zero count buffer is in use */
  	if (reg_value & BIT0)
  		total_count += active_buf_count;
  
  	/* add tx FIFO count = reg_value[15..8] */
  	total_count += (reg_value >> 8) & 0xff;
  
  	/* if transmitter active add one byte for shift register */
  	if (info->tx_active)
  		total_count++;
  
  	return total_count;
  }
  
  /*
de538eb34   Paul Fulghum   serial: synclink_...
4887
4888
   * load data into transmit DMA buffer ring and start transmitter if needed
   * return true if data accepted, otherwise false (buffers full)
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4889
   */
de538eb34   Paul Fulghum   serial: synclink_...
4890
  static bool tx_load(struct slgt_info *info, const char *buf, unsigned int size)
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4891
4892
4893
4894
  {
  	unsigned short count;
  	unsigned int i;
  	struct slgt_desc *d;
de538eb34   Paul Fulghum   serial: synclink_...
4895
4896
4897
  	/* check required buffer space */
  	if (DIV_ROUND_UP(size, DMABUFSIZE) > free_tbuf_count(info))
  		return false;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4898
4899
  
  	DBGDATA(info, buf, size, "tx");
de538eb34   Paul Fulghum   serial: synclink_...
4900
4901
4902
4903
4904
4905
4906
4907
4908
4909
  	/*
  	 * copy data to one or more DMA buffers in circular ring
  	 * tbuf_start   = first buffer for this data
  	 * tbuf_current = next free buffer
  	 *
  	 * Copy all data before making data visible to DMA controller by
  	 * setting descriptor count of the first buffer.
  	 * This prevents an active DMA controller from reading the first DMA
  	 * buffers of a frame and stopping before the final buffers are filled.
  	 */
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4910
4911
4912
4913
  	info->tbuf_start = i = info->tbuf_current;
  
  	while (size) {
  		d = &info->tbufs[i];
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4914
4915
4916
4917
4918
4919
  
  		count = (unsigned short)((size > DMABUFSIZE) ? DMABUFSIZE : size);
  		memcpy(d->buf, buf, count);
  
  		size -= count;
  		buf  += count;
cb10dc9ac   Paul Fulghum   [PATCH] synclink_...
4920
4921
4922
4923
4924
4925
4926
  		/*
  		 * set EOF bit for last buffer of HDLC frame or
  		 * for every buffer in raw mode
  		 */
  		if ((!size && info->params.mode == MGSL_MODE_HDLC) ||
  		    info->params.mode == MGSL_MODE_RAW)
  			set_desc_eof(*d, 1);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4927
4928
  		else
  			set_desc_eof(*d, 0);
de538eb34   Paul Fulghum   serial: synclink_...
4929
4930
4931
  		/* set descriptor count for all but first buffer */
  		if (i != info->tbuf_start)
  			set_desc_count(*d, count);
403214d0a   Paul Fulghum   synclink_gt: impr...
4932
  		d->buf_count = count;
de538eb34   Paul Fulghum   serial: synclink_...
4933
4934
4935
  
  		if (++i == info->tbuf_count)
  			i = 0;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4936
4937
4938
  	}
  
  	info->tbuf_current = i;
de538eb34   Paul Fulghum   serial: synclink_...
4939
4940
4941
4942
4943
4944
4945
4946
4947
4948
4949
  
  	/* set first buffer count to make new data visible to DMA controller */
  	d = &info->tbufs[info->tbuf_start];
  	set_desc_count(*d, d->buf_count);
  
  	/* start transmitter if needed and update transmit timeout */
  	if (!info->tx_active)
  		tx_start(info);
  	update_tx_timer(info);
  
  	return true;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4950
4951
4952
4953
4954
4955
  }
  
  static int register_test(struct slgt_info *info)
  {
  	static unsigned short patterns[] =
  		{0x0000, 0xffff, 0xaaaa, 0x5555, 0x6969, 0x9696};
7ea7c6d51   Kulikov Vasiliy   synclink: use ARR...
4956
  	static unsigned int count = ARRAY_SIZE(patterns);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4957
4958
4959
4960
4961
4962
4963
4964
4965
4966
4967
4968
  	unsigned int i;
  	int rc = 0;
  
  	for (i=0 ; i < count ; i++) {
  		wr_reg16(info, TIR, patterns[i]);
  		wr_reg16(info, BDR, patterns[(i+1)%count]);
  		if ((rd_reg16(info, TIR) != patterns[i]) ||
  		    (rd_reg16(info, BDR) != patterns[(i+1)%count])) {
  			rc = -ENODEV;
  			break;
  		}
  	}
0080b7aae   Paul Fulghum   [PATCH] synclink_...
4969
  	info->gpio_present = (rd_reg32(info, JCR) & BIT5) ? 1 : 0;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4970
4971
4972
4973
4974
4975
4976
4977
  	info->init_error = rc ? 0 : DiagStatus_AddressFailure;
  	return rc;
  }
  
  static int irq_test(struct slgt_info *info)
  {
  	unsigned long timeout;
  	unsigned long flags;
8fb06c771   Alan Cox   synclink: use tty...
4978
  	struct tty_struct *oldtty = info->port.tty;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4979
4980
4981
  	u32 speed = info->params.data_rate;
  
  	info->params.data_rate = 921600;
8fb06c771   Alan Cox   synclink: use tty...
4982
  	info->port.tty = NULL;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4983
4984
4985
4986
4987
4988
4989
4990
4991
4992
4993
4994
4995
4996
  
  	spin_lock_irqsave(&info->lock, flags);
  	async_mode(info);
  	slgt_irq_on(info, IRQ_TXIDLE);
  
  	/* enable transmitter */
  	wr_reg16(info, TCR,
  		(unsigned short)(rd_reg16(info, TCR) | BIT1));
  
  	/* write one byte and wait for tx idle */
  	wr_reg16(info, TDR, 0);
  
  	/* assume failure */
  	info->init_error = DiagStatus_IrqFailure;
0fab6de09   Joe Perches   synclink drivers ...
4997
  	info->irq_occurred = false;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
4998
4999
5000
5001
5002
5003
5004
5005
5006
5007
5008
5009
  
  	spin_unlock_irqrestore(&info->lock, flags);
  
  	timeout=100;
  	while(timeout-- && !info->irq_occurred)
  		msleep_interruptible(10);
  
  	spin_lock_irqsave(&info->lock,flags);
  	reset_port(info);
  	spin_unlock_irqrestore(&info->lock,flags);
  
  	info->params.data_rate = speed;
8fb06c771   Alan Cox   synclink: use tty...
5010
  	info->port.tty = oldtty;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
5011
5012
5013
5014
5015
5016
5017
5018
5019
5020
5021
5022
5023
5024
5025
5026
5027
5028
5029
5030
5031
5032
5033
5034
5035
5036
5037
5038
5039
5040
5041
5042
5043
5044
5045
5046
5047
5048
  
  	info->init_error = info->irq_occurred ? 0 : DiagStatus_IrqFailure;
  	return info->irq_occurred ? 0 : -ENODEV;
  }
  
  static int loopback_test_rx(struct slgt_info *info)
  {
  	unsigned char *src, *dest;
  	int count;
  
  	if (desc_complete(info->rbufs[0])) {
  		count = desc_count(info->rbufs[0]);
  		src   = info->rbufs[0].buf;
  		dest  = info->tmp_rbuf;
  
  		for( ; count ; count-=2, src+=2) {
  			/* src=data byte (src+1)=status byte */
  			if (!(*(src+1) & (BIT9 + BIT8))) {
  				*dest = *src;
  				dest++;
  				info->tmp_rbuf_count++;
  			}
  		}
  		DBGDATA(info, info->tmp_rbuf, info->tmp_rbuf_count, "rx");
  		return 1;
  	}
  	return 0;
  }
  
  static int loopback_test(struct slgt_info *info)
  {
  #define TESTFRAMESIZE 20
  
  	unsigned long timeout;
  	u16 count = TESTFRAMESIZE;
  	unsigned char buf[TESTFRAMESIZE];
  	int rc = -ENODEV;
  	unsigned long flags;
8fb06c771   Alan Cox   synclink: use tty...
5049
  	struct tty_struct *oldtty = info->port.tty;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
5050
5051
5052
5053
5054
5055
5056
  	MGSL_PARAMS params;
  
  	memcpy(&params, &info->params, sizeof(params));
  
  	info->params.mode = MGSL_MODE_ASYNC;
  	info->params.data_rate = 921600;
  	info->params.loopback = 1;
8fb06c771   Alan Cox   synclink: use tty...
5057
  	info->port.tty = NULL;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
5058
5059
5060
5061
5062
5063
5064
5065
5066
5067
5068
5069
  
  	/* build and send transmit frame */
  	for (count = 0; count < TESTFRAMESIZE; ++count)
  		buf[count] = (unsigned char)count;
  
  	info->tmp_rbuf_count = 0;
  	memset(info->tmp_rbuf, 0, TESTFRAMESIZE);
  
  	/* program hardware for HDLC and enabled receiver */
  	spin_lock_irqsave(&info->lock,flags);
  	async_mode(info);
  	rx_start(info);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
5070
  	tx_load(info, buf, count);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
5071
5072
5073
5074
5075
5076
5077
5078
5079
5080
5081
5082
5083
5084
5085
5086
5087
5088
5089
5090
5091
5092
  	spin_unlock_irqrestore(&info->lock, flags);
  
  	/* wait for receive complete */
  	for (timeout = 100; timeout; --timeout) {
  		msleep_interruptible(10);
  		if (loopback_test_rx(info)) {
  			rc = 0;
  			break;
  		}
  	}
  
  	/* verify received frame length and contents */
  	if (!rc && (info->tmp_rbuf_count != count ||
  		  memcmp(buf, info->tmp_rbuf, count))) {
  		rc = -ENODEV;
  	}
  
  	spin_lock_irqsave(&info->lock,flags);
  	reset_adapter(info);
  	spin_unlock_irqrestore(&info->lock,flags);
  
  	memcpy(&info->params, &params, sizeof(info->params));
8fb06c771   Alan Cox   synclink: use tty...
5093
  	info->port.tty = oldtty;
705b6c7b3   Paul Fulghum   [PATCH] new drive...
5094
5095
5096
5097
5098
5099
5100
5101
5102
  
  	info->init_error = rc ? DiagStatus_DmaFailure : 0;
  	return rc;
  }
  
  static int adapter_test(struct slgt_info *info)
  {
  	DBGINFO(("testing %s
  ", info->device_name));
294dad053   Paul Fulghum   [PATCH] fix syncl...
5103
  	if (register_test(info) < 0) {
705b6c7b3   Paul Fulghum   [PATCH] new drive...
5104
5105
5106
  		printk("register test failure %s addr=%08X
  ",
  			info->device_name, info->phys_reg_addr);
294dad053   Paul Fulghum   [PATCH] fix syncl...
5107
  	} else if (irq_test(info) < 0) {
705b6c7b3   Paul Fulghum   [PATCH] new drive...
5108
5109
5110
  		printk("IRQ test failure %s IRQ=%d
  ",
  			info->device_name, info->irq_level);
294dad053   Paul Fulghum   [PATCH] fix syncl...
5111
  	} else if (loopback_test(info) < 0) {
705b6c7b3   Paul Fulghum   [PATCH] new drive...
5112
5113
5114
5115
5116
5117
5118
5119
5120
5121
5122
5123
5124
5125
5126
5127
5128
5129
5130
5131
  		printk("loopback test failure %s
  ", info->device_name);
  	}
  	return info->init_error;
  }
  
  /*
   * transmit timeout handler
   */
  static void tx_timeout(unsigned long context)
  {
  	struct slgt_info *info = (struct slgt_info*)context;
  	unsigned long flags;
  
  	DBGINFO(("%s tx_timeout
  ", info->device_name));
  	if(info->tx_active && info->params.mode == MGSL_MODE_HDLC) {
  		info->icount.txtimeout++;
  	}
  	spin_lock_irqsave(&info->lock,flags);
ce89294c0   Paul Fulghum   synclink_gt: fix ...
5132
  	tx_stop(info);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
5133
  	spin_unlock_irqrestore(&info->lock,flags);
af69c7f92   Paul Fulghum   [PATCH] generic H...
5134
  #if SYNCLINK_GENERIC_HDLC
705b6c7b3   Paul Fulghum   [PATCH] new drive...
5135
5136
5137
5138
5139
5140
5141
5142
5143
5144
5145
5146
5147
5148
5149
5150
5151
5152
5153
5154
  	if (info->netcount)
  		hdlcdev_tx_done(info);
  	else
  #endif
  		bh_transmit(info);
  }
  
  /*
   * receive buffer polling timer
   */
  static void rx_timeout(unsigned long context)
  {
  	struct slgt_info *info = (struct slgt_info*)context;
  	unsigned long flags;
  
  	DBGINFO(("%s rx_timeout
  ", info->device_name));
  	spin_lock_irqsave(&info->lock, flags);
  	info->pending_bh |= BH_RECEIVE;
  	spin_unlock_irqrestore(&info->lock, flags);
c4028958b   David Howells   WorkStruct: make ...
5155
  	bh_handler(&info->task);
705b6c7b3   Paul Fulghum   [PATCH] new drive...
5156
  }