Blame view

drivers/tty/moxa.c 52 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
  /*****************************************************************************/
  /*
   *           moxa.c  -- MOXA Intellio family multiport serial driver.
   *
b9705b603   Jiri Slaby   Char: moxa, updat...
5
6
   *      Copyright (C) 1999-2000  Moxa Technologies (support@moxa.com).
   *      Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
8
9
10
11
12
13
14
   *
   *      This code is loosely based on the Linux serial driver, written by
   *      Linus Torvalds, Theodore T'so and others.
   *
   *      This program is free software; you can redistribute it and/or modify
   *      it under the terms of the GNU General Public License as published by
   *      the Free Software Foundation; either version 2 of the License, or
   *      (at your option) any later version.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
16
17
18
19
20
21
22
   */
  
  /*
   *    MOXA Intellio Series Driver
   *      for             : LINUX
   *      date            : 1999/1/7
   *      version         : 5.1
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
25
26
27
  #include <linux/module.h>
  #include <linux/types.h>
  #include <linux/mm.h>
  #include <linux/ioport.h>
  #include <linux/errno.h>
037182346   Jiri Slaby   Char: moxa, add f...
28
  #include <linux/firmware.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
  #include <linux/signal.h>
  #include <linux/sched.h>
  #include <linux/timer.h>
  #include <linux/interrupt.h>
  #include <linux/tty.h>
  #include <linux/tty_flip.h>
  #include <linux/major.h>
  #include <linux/string.h>
  #include <linux/fcntl.h>
  #include <linux/ptrace.h>
  #include <linux/serial.h>
  #include <linux/tty_driver.h>
  #include <linux/delay.h>
  #include <linux/pci.h>
  #include <linux/init.h>
  #include <linux/bitops.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
45
  #include <linux/slab.h>
5a3c6b251   Manuel Zerpies   drivers/tty: use ...
46
  #include <linux/ratelimit.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
48
49
50
  
  #include <asm/system.h>
  #include <asm/io.h>
  #include <asm/uaccess.h>
037182346   Jiri Slaby   Char: moxa, add f...
51
  #include "moxa.h"
b9705b603   Jiri Slaby   Char: moxa, updat...
52
  #define MOXA_VERSION		"6.0k"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53

037182346   Jiri Slaby   Char: moxa, add f...
54
  #define MOXA_FW_HDRLEN		32
11324edd4   Jiri Slaby   [PATCH] Char: mox...
55
  #define MOXAMAJOR		172
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56

11324edd4   Jiri Slaby   [PATCH] Char: mox...
57
  #define MAX_BOARDS		4	/* Don't change this value */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
  #define MAX_PORTS_PER_BOARD	32	/* Don't change this value */
11324edd4   Jiri Slaby   [PATCH] Char: mox...
59
  #define MAX_PORTS		(MAX_BOARDS * MAX_PORTS_PER_BOARD)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60

08d01c792   Jiri Slaby   Char: moxa, intro...
61
62
  #define MOXA_IS_320(brd) ((brd)->boardType == MOXA_BOARD_C320_ISA || \
  		(brd)->boardType == MOXA_BOARD_C320_PCI)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
64
65
  /*
   *    Define the Moxa PCI vendor and device IDs.
   */
11324edd4   Jiri Slaby   [PATCH] Char: mox...
66
67
  #define MOXA_BUS_TYPE_ISA	0
  #define MOXA_BUS_TYPE_PCI	1
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
  enum {
  	MOXA_BOARD_C218_PCI = 1,
  	MOXA_BOARD_C218_ISA,
  	MOXA_BOARD_C320_PCI,
  	MOXA_BOARD_C320_ISA,
  	MOXA_BOARD_CP204J,
  };
  
  static char *moxa_brdname[] =
  {
  	"C218 Turbo PCI series",
  	"C218 Turbo ISA series",
  	"C320 Turbo PCI series",
  	"C320 Turbo ISA series",
  	"CP-204J series",
  };
  
  #ifdef CONFIG_PCI
  static struct pci_device_id moxa_pcibrds[] = {
5ebb4078a   Jiri Slaby   [PATCH] Char: mox...
88
89
90
91
92
93
  	{ PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C218),
  		.driver_data = MOXA_BOARD_C218_PCI },
  	{ PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C320),
  		.driver_data = MOXA_BOARD_C320_PCI },
  	{ PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP204J),
  		.driver_data = MOXA_BOARD_CP204J },
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
94
95
96
97
  	{ 0 }
  };
  MODULE_DEVICE_TABLE(pci, moxa_pcibrds);
  #endif /* CONFIG_PCI */
037182346   Jiri Slaby   Char: moxa, add f...
98
  struct moxa_port;
8f8ecbad0   Jiri Slaby   [PATCH] Char: mox...
99
  static struct moxa_board_conf {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100
101
  	int boardType;
  	int numPorts;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
  	int busType;
8f8ecbad0   Jiri Slaby   [PATCH] Char: mox...
103

810ab09b2   Jiri Slaby   Char: moxa, centr...
104
  	unsigned int ready;
8f8ecbad0   Jiri Slaby   [PATCH] Char: mox...
105

037182346   Jiri Slaby   Char: moxa, add f...
106
  	struct moxa_port *ports;
8f8ecbad0   Jiri Slaby   [PATCH] Char: mox...
107
108
109
110
111
112
113
114
115
116
117
118
  	void __iomem *basemem;
  	void __iomem *intNdx;
  	void __iomem *intPend;
  	void __iomem *intTable;
  } moxa_boards[MAX_BOARDS];
  
  struct mxser_mstatus {
  	tcflag_t cflag;
  	int cts;
  	int dsr;
  	int ri;
  	int dcd;
9dff89cd8   Jiri Slaby   [PATCH] Char: mox...
119
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
120

8f8ecbad0   Jiri Slaby   [PATCH] Char: mox...
121
122
123
124
  struct moxaq_str {
  	int inq;
  	int outq;
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125

8f8ecbad0   Jiri Slaby   [PATCH] Char: mox...
126
  struct moxa_port {
9de6a51fe   Alan Cox   moxa: use tty_port
127
  	struct tty_port port;
b4173f457   Jiri Slaby   Char: moxa, remov...
128
  	struct moxa_board_conf *board;
7bcf97d1d   Jiri Slaby   Char: moxa, merge...
129
  	void __iomem *tableAddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
130
  	int type;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
  	int cflag;
7bcf97d1d   Jiri Slaby   Char: moxa, merge...
132
  	unsigned long statusflags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
133

8482bcd58   Alan Cox   tty: moxa: Fix mo...
134
  	u8 DCDState;		/* Protected by the port lock */
7bcf97d1d   Jiri Slaby   Char: moxa, merge...
135
136
  	u8 lineCtrl;
  	u8 lowChkFlag;
8f8ecbad0   Jiri Slaby   [PATCH] Char: mox...
137
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
138

74d7d97b9   Jiri Slaby   Char: moxa, ioctl...
139
140
141
142
143
  struct mon_str {
  	int tick;
  	int rxcnt[MAX_PORTS];
  	int txcnt[MAX_PORTS];
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
  /* statusflags */
a808ac0c4   Alan Cox   tty: moxa: Lockin...
145
146
147
  #define TXSTOPPED	1
  #define LOWWAIT 	2
  #define EMPTYWAIT	3
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149
  #define SERIAL_DO_RESTART
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
150
  #define WAKEUP_CHARS		256
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
  static int ttymajor = MOXAMAJOR;
74d7d97b9   Jiri Slaby   Char: moxa, ioctl...
152
153
  static struct mon_str moxaLog;
  static unsigned int moxaFuncTout = HZ / 2;
7bcf97d1d   Jiri Slaby   Char: moxa, merge...
154
  static unsigned int moxaLowWaterChk;
a8f5cda06   Jiri Slaby   Char: moxa, rewor...
155
  static DEFINE_MUTEX(moxa_openlock);
e8c62103f   Alan Cox   tty: moxa: split ...
156
  static DEFINE_SPINLOCK(moxa_lock);
c6fc826e4   Rakib Mullick   tty: moxa: remove...
157

d353eca4e   Jiri Slaby   Char: moxa, clean...
158
159
160
  static unsigned long baseaddr[MAX_BOARDS];
  static unsigned int type[MAX_BOARDS];
  static unsigned int numports[MAX_BOARDS];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
162
163
164
  
  MODULE_AUTHOR("William Chen");
  MODULE_DESCRIPTION("MOXA Intellio Family Multiport Board Device Driver");
  MODULE_LICENSE("GPL");
e6c4ef984   Ben Hutchings   tty: declare MODU...
165
166
167
  MODULE_FIRMWARE("c218tunx.cod");
  MODULE_FIRMWARE("cp204unx.cod");
  MODULE_FIRMWARE("c320tunx.cod");
c6fc826e4   Rakib Mullick   tty: moxa: remove...
168

d353eca4e   Jiri Slaby   Char: moxa, clean...
169
170
171
172
173
174
  module_param_array(type, uint, NULL, 0);
  MODULE_PARM_DESC(type, "card type: C218=2, C320=4");
  module_param_array(baseaddr, ulong, NULL, 0);
  MODULE_PARM_DESC(baseaddr, "base address");
  module_param_array(numports, uint, NULL, 0);
  MODULE_PARM_DESC(numports, "numports (ignored for C218)");
c6fc826e4   Rakib Mullick   tty: moxa: remove...
175

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
176
  module_param(ttymajor, int, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
178
179
180
  /*
   * static functions:
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
182
183
184
185
186
  static int moxa_open(struct tty_struct *, struct file *);
  static void moxa_close(struct tty_struct *, struct file *);
  static int moxa_write(struct tty_struct *, const unsigned char *, int);
  static int moxa_write_room(struct tty_struct *);
  static void moxa_flush_buffer(struct tty_struct *);
  static int moxa_chars_in_buffer(struct tty_struct *);
606d099cd   Alan Cox   [PATCH] tty: swit...
187
  static void moxa_set_termios(struct tty_struct *, struct ktermios *);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188
189
190
  static void moxa_stop(struct tty_struct *);
  static void moxa_start(struct tty_struct *);
  static void moxa_hangup(struct tty_struct *);
60b33c133   Alan Cox   tiocmget: kill of...
191
  static int moxa_tiocmget(struct tty_struct *tty);
20b9d1771   Alan Cox   tiocmset: kill th...
192
  static int moxa_tiocmset(struct tty_struct *tty,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193
194
  			 unsigned int set, unsigned int clear);
  static void moxa_poll(unsigned long);
db1acaa63   Alan Cox   moxa: first pass ...
195
  static void moxa_set_tty_param(struct tty_struct *, struct ktermios *);
f176178ba   Alan Cox   tty: moxa: Use mo...
196
  static void moxa_shutdown(struct tty_port *);
31f35939d   Alan Cox   tty_port: Add a p...
197
  static int moxa_carrier_raised(struct tty_port *);
f176178ba   Alan Cox   tty: moxa: Use mo...
198
  static void moxa_dtr_rts(struct tty_port *, int);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
199
200
201
  /*
   * moxa board interface functions:
   */
b4173f457   Jiri Slaby   Char: moxa, remov...
202
203
204
205
206
207
208
  static void MoxaPortEnable(struct moxa_port *);
  static void MoxaPortDisable(struct moxa_port *);
  static int MoxaPortSetTermio(struct moxa_port *, struct ktermios *, speed_t);
  static int MoxaPortGetLineOut(struct moxa_port *, int *, int *);
  static void MoxaPortLineCtrl(struct moxa_port *, int, int);
  static void MoxaPortFlowCtrl(struct moxa_port *, int, int, int, int, int);
  static int MoxaPortLineStatus(struct moxa_port *);
b4173f457   Jiri Slaby   Char: moxa, remov...
209
  static void MoxaPortFlushData(struct moxa_port *, int);
d450b5a01   Alan Cox   tty: kref usage f...
210
  static int MoxaPortWriteData(struct tty_struct *, const unsigned char *, int);
7bcf97d1d   Jiri Slaby   Char: moxa, merge...
211
  static int MoxaPortReadData(struct moxa_port *);
b4173f457   Jiri Slaby   Char: moxa, remov...
212
213
214
215
216
  static int MoxaPortTxQueue(struct moxa_port *);
  static int MoxaPortRxQueue(struct moxa_port *);
  static int MoxaPortTxFree(struct moxa_port *);
  static void MoxaPortTxDisable(struct moxa_port *);
  static void MoxaPortTxEnable(struct moxa_port *);
8f8ecbad0   Jiri Slaby   [PATCH] Char: mox...
217
218
  static int moxa_get_serial_info(struct moxa_port *, struct serial_struct __user *);
  static int moxa_set_serial_info(struct moxa_port *, struct serial_struct __user *);
b4173f457   Jiri Slaby   Char: moxa, remov...
219
  static void MoxaSetFifo(struct moxa_port *port, int enable);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
220

74d7d97b9   Jiri Slaby   Char: moxa, ioctl...
221
222
223
  /*
   * I/O functions
   */
a808ac0c4   Alan Cox   tty: moxa: Lockin...
224
  static DEFINE_SPINLOCK(moxafunc_lock);
74d7d97b9   Jiri Slaby   Char: moxa, ioctl...
225
226
227
228
229
230
231
  static void moxa_wait_finish(void __iomem *ofsAddr)
  {
  	unsigned long end = jiffies + moxaFuncTout;
  
  	while (readw(ofsAddr + FuncCode) != 0)
  		if (time_after(jiffies, end))
  			return;
5a3c6b251   Manuel Zerpies   drivers/tty: use ...
232
233
234
  	if (readw(ofsAddr + FuncCode) != 0)
  		printk_ratelimited(KERN_WARNING "moxa function expired
  ");
74d7d97b9   Jiri Slaby   Char: moxa, ioctl...
235
  }
eaa95a8da   Jiri Slaby   Char: moxa, littl...
236
  static void moxafunc(void __iomem *ofsAddr, u16 cmd, u16 arg)
74d7d97b9   Jiri Slaby   Char: moxa, ioctl...
237
  {
f5c5a36d2   Alan Cox   tty: moxa: rework...
238
239
          unsigned long flags;
          spin_lock_irqsave(&moxafunc_lock, flags);
74d7d97b9   Jiri Slaby   Char: moxa, ioctl...
240
241
242
  	writew(arg, ofsAddr + FuncArg);
  	writew(cmd, ofsAddr + FuncCode);
  	moxa_wait_finish(ofsAddr);
f5c5a36d2   Alan Cox   tty: moxa: rework...
243
244
245
246
247
248
249
250
251
252
253
254
255
256
  	spin_unlock_irqrestore(&moxafunc_lock, flags);
  }
  
  static int moxafuncret(void __iomem *ofsAddr, u16 cmd, u16 arg)
  {
          unsigned long flags;
          u16 ret;
          spin_lock_irqsave(&moxafunc_lock, flags);
  	writew(arg, ofsAddr + FuncArg);
  	writew(cmd, ofsAddr + FuncCode);
  	moxa_wait_finish(ofsAddr);
  	ret = readw(ofsAddr + FuncArg);
  	spin_unlock_irqrestore(&moxafunc_lock, flags);
  	return ret;
74d7d97b9   Jiri Slaby   Char: moxa, ioctl...
257
  }
7bcf97d1d   Jiri Slaby   Char: moxa, merge...
258
259
260
261
262
263
264
265
266
267
268
269
270
  static void moxa_low_water_check(void __iomem *ofsAddr)
  {
  	u16 rptr, wptr, mask, len;
  
  	if (readb(ofsAddr + FlagStat) & Xoff_state) {
  		rptr = readw(ofsAddr + RXrptr);
  		wptr = readw(ofsAddr + RXwptr);
  		mask = readw(ofsAddr + RX_mask);
  		len = (wptr - rptr) & mask;
  		if (len <= Low_water)
  			moxafunc(ofsAddr, FC_SendXon, 0);
  	}
  }
74d7d97b9   Jiri Slaby   Char: moxa, ioctl...
271
272
273
  /*
   * TTY operations
   */
6caa76b77   Alan Cox   tty: now phase ou...
274
  static int moxa_ioctl(struct tty_struct *tty,
74d7d97b9   Jiri Slaby   Char: moxa, ioctl...
275
276
277
278
  		      unsigned int cmd, unsigned long arg)
  {
  	struct moxa_port *ch = tty->driver_data;
  	void __user *argp = (void __user *)arg;
a8f5cda06   Jiri Slaby   Char: moxa, rewor...
279
  	int status, ret = 0;
74d7d97b9   Jiri Slaby   Char: moxa, ioctl...
280
281
282
283
284
285
286
287
288
289
290
  
  	if (tty->index == MAX_PORTS) {
  		if (cmd != MOXA_GETDATACOUNT && cmd != MOXA_GET_IOQUEUE &&
  				cmd != MOXA_GETMSTATUS)
  			return -EINVAL;
  	} else if (!ch)
  		return -ENODEV;
  
  	switch (cmd) {
  	case MOXA_GETDATACOUNT:
  		moxaLog.tick = jiffies;
a8f5cda06   Jiri Slaby   Char: moxa, rewor...
291
292
293
  		if (copy_to_user(argp, &moxaLog, sizeof(moxaLog)))
  			ret = -EFAULT;
  		break;
74d7d97b9   Jiri Slaby   Char: moxa, ioctl...
294
295
  	case MOXA_FLUSH_QUEUE:
  		MoxaPortFlushData(ch, arg);
a8f5cda06   Jiri Slaby   Char: moxa, rewor...
296
  		break;
74d7d97b9   Jiri Slaby   Char: moxa, ioctl...
297
298
299
300
301
302
303
304
305
306
  	case MOXA_GET_IOQUEUE: {
  		struct moxaq_str __user *argm = argp;
  		struct moxaq_str tmp;
  		struct moxa_port *p;
  		unsigned int i, j;
  
  		for (i = 0; i < MAX_BOARDS; i++) {
  			p = moxa_boards[i].ports;
  			for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
  				memset(&tmp, 0, sizeof(tmp));
e8c62103f   Alan Cox   tty: moxa: split ...
307
  				spin_lock_bh(&moxa_lock);
74d7d97b9   Jiri Slaby   Char: moxa, ioctl...
308
309
310
311
  				if (moxa_boards[i].ready) {
  					tmp.inq = MoxaPortRxQueue(p);
  					tmp.outq = MoxaPortTxQueue(p);
  				}
e8c62103f   Alan Cox   tty: moxa: split ...
312
313
  				spin_unlock_bh(&moxa_lock);
  				if (copy_to_user(argm, &tmp, sizeof(tmp)))
74d7d97b9   Jiri Slaby   Char: moxa, ioctl...
314
315
316
  					return -EFAULT;
  			}
  		}
a8f5cda06   Jiri Slaby   Char: moxa, rewor...
317
  		break;
74d7d97b9   Jiri Slaby   Char: moxa, ioctl...
318
319
  	} case MOXA_GET_OQUEUE:
  		status = MoxaPortTxQueue(ch);
a8f5cda06   Jiri Slaby   Char: moxa, rewor...
320
321
  		ret = put_user(status, (unsigned long __user *)argp);
  		break;
74d7d97b9   Jiri Slaby   Char: moxa, ioctl...
322
323
  	case MOXA_GET_IQUEUE:
  		status = MoxaPortRxQueue(ch);
a8f5cda06   Jiri Slaby   Char: moxa, rewor...
324
325
  		ret = put_user(status, (unsigned long __user *)argp);
  		break;
74d7d97b9   Jiri Slaby   Char: moxa, ioctl...
326
327
328
329
330
331
332
333
334
  	case MOXA_GETMSTATUS: {
  		struct mxser_mstatus __user *argm = argp;
  		struct mxser_mstatus tmp;
  		struct moxa_port *p;
  		unsigned int i, j;
  
  		for (i = 0; i < MAX_BOARDS; i++) {
  			p = moxa_boards[i].ports;
  			for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
d450b5a01   Alan Cox   tty: kref usage f...
335
  				struct tty_struct *ttyp;
74d7d97b9   Jiri Slaby   Char: moxa, ioctl...
336
  				memset(&tmp, 0, sizeof(tmp));
e8c62103f   Alan Cox   tty: moxa: split ...
337
338
339
  				spin_lock_bh(&moxa_lock);
  				if (!moxa_boards[i].ready) {
  				        spin_unlock_bh(&moxa_lock);
74d7d97b9   Jiri Slaby   Char: moxa, ioctl...
340
  					goto copy;
e8c62103f   Alan Cox   tty: moxa: split ...
341
                                  }
74d7d97b9   Jiri Slaby   Char: moxa, ioctl...
342
343
  
  				status = MoxaPortLineStatus(p);
e8c62103f   Alan Cox   tty: moxa: split ...
344
  				spin_unlock_bh(&moxa_lock);
74d7d97b9   Jiri Slaby   Char: moxa, ioctl...
345
346
347
348
349
350
  				if (status & 1)
  					tmp.cts = 1;
  				if (status & 2)
  					tmp.dsr = 1;
  				if (status & 4)
  					tmp.dcd = 1;
d450b5a01   Alan Cox   tty: kref usage f...
351
352
  				ttyp = tty_port_tty_get(&p->port);
  				if (!ttyp || !ttyp->termios)
74d7d97b9   Jiri Slaby   Char: moxa, ioctl...
353
354
  					tmp.cflag = p->cflag;
  				else
d450b5a01   Alan Cox   tty: kref usage f...
355
  					tmp.cflag = ttyp->termios->c_cflag;
df43daaae   Julia Lawall   drivers/tty/moxa....
356
  				tty_kref_put(ttyp);
74d7d97b9   Jiri Slaby   Char: moxa, ioctl...
357
  copy:
e8c62103f   Alan Cox   tty: moxa: split ...
358
  				if (copy_to_user(argm, &tmp, sizeof(tmp)))
74d7d97b9   Jiri Slaby   Char: moxa, ioctl...
359
360
361
  					return -EFAULT;
  			}
  		}
a8f5cda06   Jiri Slaby   Char: moxa, rewor...
362
  		break;
74d7d97b9   Jiri Slaby   Char: moxa, ioctl...
363
364
  	}
  	case TIOCGSERIAL:
a808ac0c4   Alan Cox   tty: moxa: Lockin...
365
  	        mutex_lock(&ch->port.mutex);
a8f5cda06   Jiri Slaby   Char: moxa, rewor...
366
  		ret = moxa_get_serial_info(ch, argp);
a808ac0c4   Alan Cox   tty: moxa: Lockin...
367
  		mutex_unlock(&ch->port.mutex);
a8f5cda06   Jiri Slaby   Char: moxa, rewor...
368
  		break;
74d7d97b9   Jiri Slaby   Char: moxa, ioctl...
369
  	case TIOCSSERIAL:
a808ac0c4   Alan Cox   tty: moxa: Lockin...
370
  	        mutex_lock(&ch->port.mutex);
a8f5cda06   Jiri Slaby   Char: moxa, rewor...
371
  		ret = moxa_set_serial_info(ch, argp);
a808ac0c4   Alan Cox   tty: moxa: Lockin...
372
  		mutex_unlock(&ch->port.mutex);
a8f5cda06   Jiri Slaby   Char: moxa, rewor...
373
374
375
  		break;
  	default:
  		ret = -ENOIOCTLCMD;
74d7d97b9   Jiri Slaby   Char: moxa, ioctl...
376
  	}
a8f5cda06   Jiri Slaby   Char: moxa, rewor...
377
  	return ret;
74d7d97b9   Jiri Slaby   Char: moxa, ioctl...
378
  }
9e98966c7   Alan Cox   tty: rework break...
379
  static int moxa_break_ctl(struct tty_struct *tty, int state)
74d7d97b9   Jiri Slaby   Char: moxa, ioctl...
380
381
382
383
384
  {
  	struct moxa_port *port = tty->driver_data;
  
  	moxafunc(port->tableAddr, state ? FC_SendBreak : FC_StopBreak,
  			Magic_code);
9e98966c7   Alan Cox   tty: rework break...
385
  	return 0;
74d7d97b9   Jiri Slaby   Char: moxa, ioctl...
386
  }
b68e31d0e   Jeff Dike   [PATCH] const str...
387
  static const struct tty_operations moxa_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
388
389
390
391
392
393
  	.open = moxa_open,
  	.close = moxa_close,
  	.write = moxa_write,
  	.write_room = moxa_write_room,
  	.flush_buffer = moxa_flush_buffer,
  	.chars_in_buffer = moxa_chars_in_buffer,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
394
  	.ioctl = moxa_ioctl,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
395
396
397
398
  	.set_termios = moxa_set_termios,
  	.stop = moxa_stop,
  	.start = moxa_start,
  	.hangup = moxa_hangup,
74d7d97b9   Jiri Slaby   Char: moxa, ioctl...
399
  	.break_ctl = moxa_break_ctl,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
400
401
402
  	.tiocmget = moxa_tiocmget,
  	.tiocmset = moxa_tiocmset,
  };
31f35939d   Alan Cox   tty_port: Add a p...
403
404
  static const struct tty_port_operations moxa_port_ops = {
  	.carrier_raised = moxa_carrier_raised,
f176178ba   Alan Cox   tty: moxa: Use mo...
405
406
  	.dtr_rts = moxa_dtr_rts,
  	.shutdown = moxa_shutdown,
31f35939d   Alan Cox   tty_port: Add a p...
407
  };
aa7e5221f   Jiri Slaby   [PATCH] Char: mox...
408
  static struct tty_driver *moxaDriver;
aa7e5221f   Jiri Slaby   [PATCH] Char: mox...
409
  static DEFINE_TIMER(moxaTimer, moxa_poll, 0, 0);
33f0f88f1   Alan Cox   [PATCH] TTY layer...
410

74d7d97b9   Jiri Slaby   Char: moxa, ioctl...
411
412
413
  /*
   * HW init
   */
037182346   Jiri Slaby   Char: moxa, add f...
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
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
  static int moxa_check_fw_model(struct moxa_board_conf *brd, u8 model)
  {
  	switch (brd->boardType) {
  	case MOXA_BOARD_C218_ISA:
  	case MOXA_BOARD_C218_PCI:
  		if (model != 1)
  			goto err;
  		break;
  	case MOXA_BOARD_CP204J:
  		if (model != 3)
  			goto err;
  		break;
  	default:
  		if (model != 2)
  			goto err;
  		break;
  	}
  	return 0;
  err:
  	return -EINVAL;
  }
  
  static int moxa_check_fw(const void *ptr)
  {
  	const __le16 *lptr = ptr;
  
  	if (*lptr != cpu_to_le16(0x7980))
  		return -EINVAL;
  
  	return 0;
  }
  
  static int moxa_load_bios(struct moxa_board_conf *brd, const u8 *buf,
  		size_t len)
  {
  	void __iomem *baseAddr = brd->basemem;
  	u16 tmp;
  
  	writeb(HW_reset, baseAddr + Control_reg);	/* reset */
  	msleep(10);
  	memset_io(baseAddr, 0, 4096);
  	memcpy_toio(baseAddr, buf, len);	/* download BIOS */
  	writeb(0, baseAddr + Control_reg);	/* restart */
  
  	msleep(2000);
  
  	switch (brd->boardType) {
  	case MOXA_BOARD_C218_ISA:
  	case MOXA_BOARD_C218_PCI:
  		tmp = readw(baseAddr + C218_key);
  		if (tmp != C218_KeyCode)
  			goto err;
  		break;
  	case MOXA_BOARD_CP204J:
  		tmp = readw(baseAddr + C218_key);
  		if (tmp != CP204J_KeyCode)
  			goto err;
  		break;
  	default:
  		tmp = readw(baseAddr + C320_key);
  		if (tmp != C320_KeyCode)
  			goto err;
  		tmp = readw(baseAddr + C320_status);
  		if (tmp != STS_init) {
eaa95a8da   Jiri Slaby   Char: moxa, littl...
478
  			printk(KERN_ERR "MOXA: bios upload failed -- CPU/Basic "
037182346   Jiri Slaby   Char: moxa, add f...
479
480
481
482
483
484
485
486
487
  					"module not found
  ");
  			return -EIO;
  		}
  		break;
  	}
  
  	return 0;
  err:
eaa95a8da   Jiri Slaby   Char: moxa, littl...
488
489
  	printk(KERN_ERR "MOXA: bios upload failed -- board not found
  ");
037182346   Jiri Slaby   Char: moxa, add f...
490
491
492
493
494
495
496
497
498
  	return -EIO;
  }
  
  static int moxa_load_320b(struct moxa_board_conf *brd, const u8 *ptr,
  		size_t len)
  {
  	void __iomem *baseAddr = brd->basemem;
  
  	if (len < 7168) {
eaa95a8da   Jiri Slaby   Char: moxa, littl...
499
500
  		printk(KERN_ERR "MOXA: invalid 320 bios -- too short
  ");
037182346   Jiri Slaby   Char: moxa, add f...
501
502
503
504
505
506
507
508
509
510
511
  		return -EINVAL;
  	}
  
  	writew(len - 7168 - 2, baseAddr + C320bapi_len);
  	writeb(1, baseAddr + Control_reg);	/* Select Page 1 */
  	memcpy_toio(baseAddr + DynPage_addr, ptr, 7168);
  	writeb(2, baseAddr + Control_reg);	/* Select Page 2 */
  	memcpy_toio(baseAddr + DynPage_addr, ptr + 7168, len - 7168);
  
  	return 0;
  }
5292bcd38   Jiri Slaby   Char: moxa, merge...
512
  static int moxa_real_load_code(struct moxa_board_conf *brd, const void *ptr,
037182346   Jiri Slaby   Char: moxa, add f...
513
514
515
  		size_t len)
  {
  	void __iomem *baseAddr = brd->basemem;
b46f69cd2   Harvey Harrison   char: moxa.c spar...
516
  	const __le16 *uptr = ptr;
037182346   Jiri Slaby   Char: moxa, add f...
517
  	size_t wlen, len2, j;
5292bcd38   Jiri Slaby   Char: moxa, merge...
518
  	unsigned long key, loadbuf, loadlen, checksum, checksum_ok;
08d01c792   Jiri Slaby   Char: moxa, intro...
519
  	unsigned int i, retry;
037182346   Jiri Slaby   Char: moxa, add f...
520
  	u16 usum, keycode;
5292bcd38   Jiri Slaby   Char: moxa, merge...
521
522
  	keycode = (brd->boardType == MOXA_BOARD_CP204J) ? CP204J_KeyCode :
  				C218_KeyCode;
037182346   Jiri Slaby   Char: moxa, add f...
523

5292bcd38   Jiri Slaby   Char: moxa, merge...
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
  	switch (brd->boardType) {
  	case MOXA_BOARD_CP204J:
  	case MOXA_BOARD_C218_ISA:
  	case MOXA_BOARD_C218_PCI:
  		key = C218_key;
  		loadbuf = C218_LoadBuf;
  		loadlen = C218DLoad_len;
  		checksum = C218check_sum;
  		checksum_ok = C218chksum_ok;
  		break;
  	default:
  		key = C320_key;
  		keycode = C320_KeyCode;
  		loadbuf = C320_LoadBuf;
  		loadlen = C320DLoad_len;
  		checksum = C320check_sum;
  		checksum_ok = C320chksum_ok;
  		break;
037182346   Jiri Slaby   Char: moxa, add f...
542
  	}
037182346   Jiri Slaby   Char: moxa, add f...
543
544
545
546
547
548
549
550
551
552
553
554
  
  	usum = 0;
  	wlen = len >> 1;
  	for (i = 0; i < wlen; i++)
  		usum += le16_to_cpu(uptr[i]);
  	retry = 0;
  	do {
  		wlen = len >> 1;
  		j = 0;
  		while (wlen) {
  			len2 = (wlen > 2048) ? 2048 : wlen;
  			wlen -= len2;
5292bcd38   Jiri Slaby   Char: moxa, merge...
555
  			memcpy_toio(baseAddr + loadbuf, ptr + j, len2 << 1);
037182346   Jiri Slaby   Char: moxa, add f...
556
  			j += len2 << 1;
5292bcd38   Jiri Slaby   Char: moxa, merge...
557
558
559
560
561
  
  			writew(len2, baseAddr + loadlen);
  			writew(0, baseAddr + key);
  			for (i = 0; i < 100; i++) {
  				if (readw(baseAddr + key) == keycode)
037182346   Jiri Slaby   Char: moxa, add f...
562
563
564
  					break;
  				msleep(10);
  			}
5292bcd38   Jiri Slaby   Char: moxa, merge...
565
  			if (readw(baseAddr + key) != keycode)
037182346   Jiri Slaby   Char: moxa, add f...
566
567
  				return -EIO;
  		}
5292bcd38   Jiri Slaby   Char: moxa, merge...
568
569
570
571
572
  		writew(0, baseAddr + loadlen);
  		writew(usum, baseAddr + checksum);
  		writew(0, baseAddr + key);
  		for (i = 0; i < 100; i++) {
  			if (readw(baseAddr + key) == keycode)
037182346   Jiri Slaby   Char: moxa, add f...
573
574
575
576
  				break;
  			msleep(10);
  		}
  		retry++;
5292bcd38   Jiri Slaby   Char: moxa, merge...
577
578
  	} while ((readb(baseAddr + checksum_ok) != 1) && (retry < 3));
  	if (readb(baseAddr + checksum_ok) != 1)
037182346   Jiri Slaby   Char: moxa, add f...
579
  		return -EIO;
5292bcd38   Jiri Slaby   Char: moxa, merge...
580
  	writew(0, baseAddr + key);
037182346   Jiri Slaby   Char: moxa, add f...
581
582
583
584
585
586
587
  	for (i = 0; i < 600; i++) {
  		if (readw(baseAddr + Magic_no) == Magic_code)
  			break;
  		msleep(10);
  	}
  	if (readw(baseAddr + Magic_no) != Magic_code)
  		return -EIO;
08d01c792   Jiri Slaby   Char: moxa, intro...
588
  	if (MOXA_IS_320(brd)) {
5292bcd38   Jiri Slaby   Char: moxa, merge...
589
590
591
592
593
594
595
596
597
  		if (brd->busType == MOXA_BUS_TYPE_PCI) {	/* ASIC board */
  			writew(0x3800, baseAddr + TMS320_PORT1);
  			writew(0x3900, baseAddr + TMS320_PORT2);
  			writew(28499, baseAddr + TMS320_CLOCK);
  		} else {
  			writew(0x3200, baseAddr + TMS320_PORT1);
  			writew(0x3400, baseAddr + TMS320_PORT2);
  			writew(19999, baseAddr + TMS320_CLOCK);
  		}
037182346   Jiri Slaby   Char: moxa, add f...
598
599
600
601
602
603
604
605
606
607
  	}
  	writew(1, baseAddr + Disable_IRQ);
  	writew(0, baseAddr + Magic_no);
  	for (i = 0; i < 500; i++) {
  		if (readw(baseAddr + Magic_no) == Magic_code)
  			break;
  		msleep(10);
  	}
  	if (readw(baseAddr + Magic_no) != Magic_code)
  		return -EIO;
08d01c792   Jiri Slaby   Char: moxa, intro...
608
  	if (MOXA_IS_320(brd)) {
5292bcd38   Jiri Slaby   Char: moxa, merge...
609
610
611
612
613
614
615
616
617
618
619
620
621
  		j = readw(baseAddr + Module_cnt);
  		if (j <= 0)
  			return -EIO;
  		brd->numPorts = j * 8;
  		writew(j, baseAddr + Module_no);
  		writew(0, baseAddr + Magic_no);
  		for (i = 0; i < 600; i++) {
  			if (readw(baseAddr + Magic_no) == Magic_code)
  				break;
  			msleep(10);
  		}
  		if (readw(baseAddr + Magic_no) != Magic_code)
  			return -EIO;
037182346   Jiri Slaby   Char: moxa, add f...
622
  	}
037182346   Jiri Slaby   Char: moxa, add f...
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
  	brd->intNdx = baseAddr + IRQindex;
  	brd->intPend = baseAddr + IRQpending;
  	brd->intTable = baseAddr + IRQtable;
  
  	return 0;
  }
  
  static int moxa_load_code(struct moxa_board_conf *brd, const void *ptr,
  		size_t len)
  {
  	void __iomem *ofsAddr, *baseAddr = brd->basemem;
  	struct moxa_port *port;
  	int retval, i;
  
  	if (len % 2) {
eaa95a8da   Jiri Slaby   Char: moxa, littl...
638
639
  		printk(KERN_ERR "MOXA: bios length is not even
  ");
037182346   Jiri Slaby   Char: moxa, add f...
640
641
  		return -EINVAL;
  	}
5292bcd38   Jiri Slaby   Char: moxa, merge...
642
643
644
  	retval = moxa_real_load_code(brd, ptr, len); /* may change numPorts */
  	if (retval)
  		return retval;
037182346   Jiri Slaby   Char: moxa, add f...
645
646
647
648
  	switch (brd->boardType) {
  	case MOXA_BOARD_C218_ISA:
  	case MOXA_BOARD_C218_PCI:
  	case MOXA_BOARD_CP204J:
037182346   Jiri Slaby   Char: moxa, add f...
649
650
  		port = brd->ports;
  		for (i = 0; i < brd->numPorts; i++, port++) {
b4173f457   Jiri Slaby   Char: moxa, remov...
651
  			port->board = brd;
037182346   Jiri Slaby   Char: moxa, add f...
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
  			port->DCDState = 0;
  			port->tableAddr = baseAddr + Extern_table +
  					Extern_size * i;
  			ofsAddr = port->tableAddr;
  			writew(C218rx_mask, ofsAddr + RX_mask);
  			writew(C218tx_mask, ofsAddr + TX_mask);
  			writew(C218rx_spage + i * C218buf_pageno, ofsAddr + Page_rxb);
  			writew(readw(ofsAddr + Page_rxb) + C218rx_pageno, ofsAddr + EndPage_rxb);
  
  			writew(C218tx_spage + i * C218buf_pageno, ofsAddr + Page_txb);
  			writew(readw(ofsAddr + Page_txb) + C218tx_pageno, ofsAddr + EndPage_txb);
  
  		}
  		break;
  	default:
037182346   Jiri Slaby   Char: moxa, add f...
667
668
  		port = brd->ports;
  		for (i = 0; i < brd->numPorts; i++, port++) {
b4173f457   Jiri Slaby   Char: moxa, remov...
669
  			port->board = brd;
037182346   Jiri Slaby   Char: moxa, add f...
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
  			port->DCDState = 0;
  			port->tableAddr = baseAddr + Extern_table +
  					Extern_size * i;
  			ofsAddr = port->tableAddr;
  			switch (brd->numPorts) {
  			case 8:
  				writew(C320p8rx_mask, ofsAddr + RX_mask);
  				writew(C320p8tx_mask, ofsAddr + TX_mask);
  				writew(C320p8rx_spage + i * C320p8buf_pgno, ofsAddr + Page_rxb);
  				writew(readw(ofsAddr + Page_rxb) + C320p8rx_pgno, ofsAddr + EndPage_rxb);
  				writew(C320p8tx_spage + i * C320p8buf_pgno, ofsAddr + Page_txb);
  				writew(readw(ofsAddr + Page_txb) + C320p8tx_pgno, ofsAddr + EndPage_txb);
  
  				break;
  			case 16:
  				writew(C320p16rx_mask, ofsAddr + RX_mask);
  				writew(C320p16tx_mask, ofsAddr + TX_mask);
  				writew(C320p16rx_spage + i * C320p16buf_pgno, ofsAddr + Page_rxb);
  				writew(readw(ofsAddr + Page_rxb) + C320p16rx_pgno, ofsAddr + EndPage_rxb);
  				writew(C320p16tx_spage + i * C320p16buf_pgno, ofsAddr + Page_txb);
  				writew(readw(ofsAddr + Page_txb) + C320p16tx_pgno, ofsAddr + EndPage_txb);
  				break;
  
  			case 24:
  				writew(C320p24rx_mask, ofsAddr + RX_mask);
  				writew(C320p24tx_mask, ofsAddr + TX_mask);
  				writew(C320p24rx_spage + i * C320p24buf_pgno, ofsAddr + Page_rxb);
  				writew(readw(ofsAddr + Page_rxb) + C320p24rx_pgno, ofsAddr + EndPage_rxb);
  				writew(C320p24tx_spage + i * C320p24buf_pgno, ofsAddr + Page_txb);
  				writew(readw(ofsAddr + Page_txb), ofsAddr + EndPage_txb);
  				break;
  			case 32:
  				writew(C320p32rx_mask, ofsAddr + RX_mask);
  				writew(C320p32tx_mask, ofsAddr + TX_mask);
  				writew(C320p32tx_ofs, ofsAddr + Ofs_txb);
  				writew(C320p32rx_spage + i * C320p32buf_pgno, ofsAddr + Page_rxb);
  				writew(readb(ofsAddr + Page_rxb), ofsAddr + EndPage_rxb);
  				writew(C320p32tx_spage + i * C320p32buf_pgno, ofsAddr + Page_txb);
  				writew(readw(ofsAddr + Page_txb), ofsAddr + EndPage_txb);
  				break;
  			}
  		}
  		break;
  	}
037182346   Jiri Slaby   Char: moxa, add f...
714
715
716
717
718
  	return 0;
  }
  
  static int moxa_load_fw(struct moxa_board_conf *brd, const struct firmware *fw)
  {
2bca76e89   David Howells   Fix a const assig...
719
  	const void *ptr = fw->data;
037182346   Jiri Slaby   Char: moxa, add f...
720
721
722
723
724
725
726
727
728
729
730
731
  	char rsn[64];
  	u16 lens[5];
  	size_t len;
  	unsigned int a, lenp, lencnt;
  	int ret = -EINVAL;
  	struct {
  		__le32 magic;	/* 0x34303430 */
  		u8 reserved1[2];
  		u8 type;	/* UNIX = 3 */
  		u8 model;	/* C218T=1, C320T=2, CP204=3 */
  		u8 reserved2[8];
  		__le16 len[5];
2bca76e89   David Howells   Fix a const assig...
732
  	} const *hdr = ptr;
037182346   Jiri Slaby   Char: moxa, add f...
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
  
  	BUILD_BUG_ON(ARRAY_SIZE(hdr->len) != ARRAY_SIZE(lens));
  
  	if (fw->size < MOXA_FW_HDRLEN) {
  		strcpy(rsn, "too short (even header won't fit)");
  		goto err;
  	}
  	if (hdr->magic != cpu_to_le32(0x30343034)) {
  		sprintf(rsn, "bad magic: %.8x", le32_to_cpu(hdr->magic));
  		goto err;
  	}
  	if (hdr->type != 3) {
  		sprintf(rsn, "not for linux, type is %u", hdr->type);
  		goto err;
  	}
  	if (moxa_check_fw_model(brd, hdr->model)) {
  		sprintf(rsn, "not for this card, model is %u", hdr->model);
  		goto err;
  	}
  
  	len = MOXA_FW_HDRLEN;
  	lencnt = hdr->model == 2 ? 5 : 3;
  	for (a = 0; a < ARRAY_SIZE(lens); a++) {
  		lens[a] = le16_to_cpu(hdr->len[a]);
  		if (lens[a] && len + lens[a] <= fw->size &&
  				moxa_check_fw(&fw->data[len]))
eaa95a8da   Jiri Slaby   Char: moxa, littl...
759
  			printk(KERN_WARNING "MOXA firmware: unexpected input "
037182346   Jiri Slaby   Char: moxa, add f...
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
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
  				"at offset %u, but going on
  ", (u32)len);
  		if (!lens[a] && a < lencnt) {
  			sprintf(rsn, "too few entries in fw file");
  			goto err;
  		}
  		len += lens[a];
  	}
  
  	if (len != fw->size) {
  		sprintf(rsn, "bad length: %u (should be %u)", (u32)fw->size,
  				(u32)len);
  		goto err;
  	}
  
  	ptr += MOXA_FW_HDRLEN;
  	lenp = 0; /* bios */
  
  	strcpy(rsn, "read above");
  
  	ret = moxa_load_bios(brd, ptr, lens[lenp]);
  	if (ret)
  		goto err;
  
  	/* we skip the tty section (lens[1]), since we don't need it */
  	ptr += lens[lenp] + lens[lenp + 1];
  	lenp += 2; /* comm */
  
  	if (hdr->model == 2) {
  		ret = moxa_load_320b(brd, ptr, lens[lenp]);
  		if (ret)
  			goto err;
  		/* skip another tty */
  		ptr += lens[lenp] + lens[lenp + 1];
  		lenp += 2;
  	}
  
  	ret = moxa_load_code(brd, ptr, lens[lenp]);
  	if (ret)
  		goto err;
  
  	return 0;
  err:
  	printk(KERN_ERR "firmware failed to load, reason: %s
  ", rsn);
  	return ret;
  }
  
  static int moxa_init_board(struct moxa_board_conf *brd, struct device *dev)
  {
  	const struct firmware *fw;
  	const char *file;
810ab09b2   Jiri Slaby   Char: moxa, centr...
812
813
  	struct moxa_port *p;
  	unsigned int i;
037182346   Jiri Slaby   Char: moxa, add f...
814
  	int ret;
810ab09b2   Jiri Slaby   Char: moxa, centr...
815
816
817
818
819
820
821
822
823
824
  	brd->ports = kcalloc(MAX_PORTS_PER_BOARD, sizeof(*brd->ports),
  			GFP_KERNEL);
  	if (brd->ports == NULL) {
  		printk(KERN_ERR "cannot allocate memory for ports
  ");
  		ret = -ENOMEM;
  		goto err;
  	}
  
  	for (i = 0, p = brd->ports; i < MAX_PORTS_PER_BOARD; i++, p++) {
44b7d1b37   Alan Cox   tty: add more tty...
825
  		tty_port_init(&p->port);
31f35939d   Alan Cox   tty_port: Add a p...
826
  		p->port.ops = &moxa_port_ops;
810ab09b2   Jiri Slaby   Char: moxa, centr...
827
  		p->type = PORT_16550A;
810ab09b2   Jiri Slaby   Char: moxa, centr...
828
  		p->cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
810ab09b2   Jiri Slaby   Char: moxa, centr...
829
  	}
037182346   Jiri Slaby   Char: moxa, add f...
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
  	switch (brd->boardType) {
  	case MOXA_BOARD_C218_ISA:
  	case MOXA_BOARD_C218_PCI:
  		file = "c218tunx.cod";
  		break;
  	case MOXA_BOARD_CP204J:
  		file = "cp204unx.cod";
  		break;
  	default:
  		file = "c320tunx.cod";
  		break;
  	}
  
  	ret = request_firmware(&fw, file, dev);
  	if (ret) {
ec09cd562   Jiri Slaby   Char: moxa, add f...
845
846
847
848
849
  		printk(KERN_ERR "MOXA: request_firmware failed. Make sure "
  				"you've placed '%s' file into your firmware "
  				"loader directory (e.g. /lib/firmware)
  ",
  				file);
810ab09b2   Jiri Slaby   Char: moxa, centr...
850
  		goto err_free;
037182346   Jiri Slaby   Char: moxa, add f...
851
852
853
854
855
  	}
  
  	ret = moxa_load_fw(brd, fw);
  
  	release_firmware(fw);
810ab09b2   Jiri Slaby   Char: moxa, centr...
856
857
858
  
  	if (ret)
  		goto err_free;
2a5413416   Jiri Slaby   Char: moxa, seria...
859
  	spin_lock_bh(&moxa_lock);
810ab09b2   Jiri Slaby   Char: moxa, centr...
860
  	brd->ready = 1;
0bcc4caad   Jiri Slaby   Char: moxa, timer...
861
862
  	if (!timer_pending(&moxaTimer))
  		mod_timer(&moxaTimer, jiffies + HZ / 50);
2a5413416   Jiri Slaby   Char: moxa, seria...
863
  	spin_unlock_bh(&moxa_lock);
0bcc4caad   Jiri Slaby   Char: moxa, timer...
864

810ab09b2   Jiri Slaby   Char: moxa, centr...
865
866
867
868
  	return 0;
  err_free:
  	kfree(brd->ports);
  err:
037182346   Jiri Slaby   Char: moxa, add f...
869
870
  	return ret;
  }
810ab09b2   Jiri Slaby   Char: moxa, centr...
871
872
  static void moxa_board_deinit(struct moxa_board_conf *brd)
  {
a8f5cda06   Jiri Slaby   Char: moxa, rewor...
873
874
875
  	unsigned int a, opened;
  
  	mutex_lock(&moxa_openlock);
7bcf97d1d   Jiri Slaby   Char: moxa, merge...
876
  	spin_lock_bh(&moxa_lock);
810ab09b2   Jiri Slaby   Char: moxa, centr...
877
  	brd->ready = 0;
7bcf97d1d   Jiri Slaby   Char: moxa, merge...
878
  	spin_unlock_bh(&moxa_lock);
a8f5cda06   Jiri Slaby   Char: moxa, rewor...
879
880
881
  
  	/* pci hot-un-plug support */
  	for (a = 0; a < brd->numPorts; a++)
d450b5a01   Alan Cox   tty: kref usage f...
882
883
884
885
886
887
888
889
  		if (brd->ports[a].port.flags & ASYNC_INITIALIZED) {
  			struct tty_struct *tty = tty_port_tty_get(
  						&brd->ports[a].port);
  			if (tty) {
  				tty_hangup(tty);
  				tty_kref_put(tty);
  			}
  		}
a8f5cda06   Jiri Slaby   Char: moxa, rewor...
890
891
892
  	while (1) {
  		opened = 0;
  		for (a = 0; a < brd->numPorts; a++)
9de6a51fe   Alan Cox   moxa: use tty_port
893
  			if (brd->ports[a].port.flags & ASYNC_INITIALIZED)
a8f5cda06   Jiri Slaby   Char: moxa, rewor...
894
895
896
897
898
899
900
  				opened++;
  		mutex_unlock(&moxa_openlock);
  		if (!opened)
  			break;
  		msleep(50);
  		mutex_lock(&moxa_openlock);
  	}
810ab09b2   Jiri Slaby   Char: moxa, centr...
901
902
903
904
  	iounmap(brd->basemem);
  	brd->basemem = NULL;
  	kfree(brd->ports);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
905
  #ifdef CONFIG_PCI
9cde5bf02   Jiri Slaby   [PATCH] Char: mox...
906
907
  static int __devinit moxa_pci_probe(struct pci_dev *pdev,
  		const struct pci_device_id *ent)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
908
  {
9cde5bf02   Jiri Slaby   [PATCH] Char: mox...
909
910
911
912
913
914
  	struct moxa_board_conf *board;
  	unsigned int i;
  	int board_type = ent->driver_data;
  	int retval;
  
  	retval = pci_enable_device(pdev);
7aeb95daf   Jiri Slaby   Char: moxa, clean...
915
916
917
  	if (retval) {
  		dev_err(&pdev->dev, "can't enable pci device
  ");
9cde5bf02   Jiri Slaby   [PATCH] Char: mox...
918
  		goto err;
7aeb95daf   Jiri Slaby   Char: moxa, clean...
919
  	}
9cde5bf02   Jiri Slaby   [PATCH] Char: mox...
920
921
922
923
924
925
926
  
  	for (i = 0; i < MAX_BOARDS; i++)
  		if (moxa_boards[i].basemem == NULL)
  			break;
  
  	retval = -ENODEV;
  	if (i >= MAX_BOARDS) {
7aeb95daf   Jiri Slaby   Char: moxa, clean...
927
  		dev_warn(&pdev->dev, "more than %u MOXA Intellio family boards "
9cde5bf02   Jiri Slaby   [PATCH] Char: mox...
928
929
930
931
932
933
  				"found. Board is ignored.
  ", MAX_BOARDS);
  		goto err;
  	}
  
  	board = &moxa_boards[i];
e46a5e3ff   Jiri Slaby   Char: moxa, pci i...
934
935
936
937
938
939
940
  
  	retval = pci_request_region(pdev, 2, "moxa-base");
  	if (retval) {
  		dev_err(&pdev->dev, "can't request pci region 2
  ");
  		goto err;
  	}
24cb23352   Alan Cox   char serial: swit...
941
  	board->basemem = ioremap_nocache(pci_resource_start(pdev, 2), 0x4000);
7aeb95daf   Jiri Slaby   Char: moxa, clean...
942
943
944
  	if (board->basemem == NULL) {
  		dev_err(&pdev->dev, "can't remap io space 2
  ");
e46a5e3ff   Jiri Slaby   Char: moxa, pci i...
945
  		goto err_reg;
7aeb95daf   Jiri Slaby   Char: moxa, clean...
946
  	}
9cde5bf02   Jiri Slaby   [PATCH] Char: mox...
947

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
  	board->boardType = board_type;
  	switch (board_type) {
  	case MOXA_BOARD_C218_ISA:
  	case MOXA_BOARD_C218_PCI:
  		board->numPorts = 8;
  		break;
  
  	case MOXA_BOARD_CP204J:
  		board->numPorts = 4;
  		break;
  	default:
  		board->numPorts = 0;
  		break;
  	}
  	board->busType = MOXA_BUS_TYPE_PCI;
a784bf7c1   Jiri Slaby   [PATCH] Char: mox...
963

037182346   Jiri Slaby   Char: moxa, add f...
964
965
966
  	retval = moxa_init_board(board, &pdev->dev);
  	if (retval)
  		goto err_base;
9cde5bf02   Jiri Slaby   [PATCH] Char: mox...
967
  	pci_set_drvdata(pdev, board);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
968

bb9f910a1   Jiri Slaby   Char: moxa, notif...
969
970
971
  	dev_info(&pdev->dev, "board '%s' ready (%u ports, firmware loaded)
  ",
  			moxa_brdname[board_type - 1], board->numPorts);
eaa95a8da   Jiri Slaby   Char: moxa, littl...
972
  	return 0;
037182346   Jiri Slaby   Char: moxa, add f...
973
974
975
  err_base:
  	iounmap(board->basemem);
  	board->basemem = NULL;
e46a5e3ff   Jiri Slaby   Char: moxa, pci i...
976
977
  err_reg:
  	pci_release_region(pdev, 2);
9cde5bf02   Jiri Slaby   [PATCH] Char: mox...
978
979
980
981
982
983
984
  err:
  	return retval;
  }
  
  static void __devexit moxa_pci_remove(struct pci_dev *pdev)
  {
  	struct moxa_board_conf *brd = pci_get_drvdata(pdev);
810ab09b2   Jiri Slaby   Char: moxa, centr...
985
  	moxa_board_deinit(brd);
e46a5e3ff   Jiri Slaby   Char: moxa, pci i...
986
  	pci_release_region(pdev, 2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
987
  }
a784bf7c1   Jiri Slaby   [PATCH] Char: mox...
988
989
990
991
992
993
994
  
  static struct pci_driver moxa_pci_driver = {
  	.name = "moxa",
  	.id_table = moxa_pcibrds,
  	.probe = moxa_pci_probe,
  	.remove = __devexit_p(moxa_pci_remove)
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
995
996
997
998
  #endif /* CONFIG_PCI */
  
  static int __init moxa_init(void)
  {
810ab09b2   Jiri Slaby   Char: moxa, centr...
999
  	unsigned int isabrds = 0;
d353eca4e   Jiri Slaby   Char: moxa, clean...
1000
  	int retval = 0;
c6fc826e4   Rakib Mullick   tty: moxa: remove...
1001
1002
  	struct moxa_board_conf *brd = moxa_boards;
  	unsigned int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1003

7aeb95daf   Jiri Slaby   Char: moxa, clean...
1004
1005
1006
  	printk(KERN_INFO "MOXA Intellio family driver version %s
  ",
  			MOXA_VERSION);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1007
1008
1009
  	moxaDriver = alloc_tty_driver(MAX_PORTS + 1);
  	if (!moxaDriver)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1010
  	moxaDriver->owner = THIS_MODULE;
9b4e3b13b   Sergey Vlasov   [SERIAL] Fix moxa...
1011
  	moxaDriver->name = "ttyMX";
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1012
1013
1014
1015
1016
  	moxaDriver->major = ttymajor;
  	moxaDriver->minor_start = 0;
  	moxaDriver->type = TTY_DRIVER_TYPE_SERIAL;
  	moxaDriver->subtype = SERIAL_TYPE_NORMAL;
  	moxaDriver->init_termios = tty_std_termios;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1017
  	moxaDriver->init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
606d099cd   Alan Cox   [PATCH] tty: swit...
1018
1019
  	moxaDriver->init_termios.c_ispeed = 9600;
  	moxaDriver->init_termios.c_ospeed = 9600;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1020
1021
  	moxaDriver->flags = TTY_DRIVER_REAL_RAW;
  	tty_set_operations(moxaDriver, &moxa_ops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1022
  	if (tty_register_driver(moxaDriver)) {
eaa95a8da   Jiri Slaby   Char: moxa, littl...
1023
1024
  		printk(KERN_ERR "can't register MOXA Smartio tty driver!
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1025
1026
1027
  		put_tty_driver(moxaDriver);
  		return -1;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1028

d353eca4e   Jiri Slaby   Char: moxa, clean...
1029
  	/* Find the boards defined from module args. */
c6fc826e4   Rakib Mullick   tty: moxa: remove...
1030

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1031
  	for (i = 0; i < MAX_BOARDS; i++) {
d353eca4e   Jiri Slaby   Char: moxa, clean...
1032
1033
1034
1035
  		if (!baseaddr[i])
  			break;
  		if (type[i] == MOXA_BOARD_C218_ISA ||
  				type[i] == MOXA_BOARD_C320_ISA) {
7aeb95daf   Jiri Slaby   Char: moxa, clean...
1036
1037
  			pr_debug("Moxa board %2d: %s board(baseAddr=%lx)
  ",
d353eca4e   Jiri Slaby   Char: moxa, clean...
1038
1039
1040
1041
1042
1043
  					isabrds + 1, moxa_brdname[type[i] - 1],
  					baseaddr[i]);
  			brd->boardType = type[i];
  			brd->numPorts = type[i] == MOXA_BOARD_C218_ISA ? 8 :
  					numports[i];
  			brd->busType = MOXA_BUS_TYPE_ISA;
24cb23352   Alan Cox   char serial: swit...
1044
  			brd->basemem = ioremap_nocache(baseaddr[i], 0x4000);
d353eca4e   Jiri Slaby   Char: moxa, clean...
1045
  			if (!brd->basemem) {
eaa95a8da   Jiri Slaby   Char: moxa, littl...
1046
1047
  				printk(KERN_ERR "MOXA: can't remap %lx
  ",
d353eca4e   Jiri Slaby   Char: moxa, clean...
1048
  						baseaddr[i]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1049
1050
  				continue;
  			}
037182346   Jiri Slaby   Char: moxa, add f...
1051
1052
1053
1054
1055
  			if (moxa_init_board(brd, NULL)) {
  				iounmap(brd->basemem);
  				brd->basemem = NULL;
  				continue;
  			}
d353eca4e   Jiri Slaby   Char: moxa, clean...
1056

bb9f910a1   Jiri Slaby   Char: moxa, notif...
1057
1058
1059
1060
  			printk(KERN_INFO "MOXA isa board found at 0x%.8lu and "
  					"ready (%u ports, firmware loaded)
  ",
  					baseaddr[i], brd->numPorts);
d353eca4e   Jiri Slaby   Char: moxa, clean...
1061
1062
  			brd++;
  			isabrds++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1063
1064
  		}
  	}
a784bf7c1   Jiri Slaby   [PATCH] Char: mox...
1065

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1066
  #ifdef CONFIG_PCI
a784bf7c1   Jiri Slaby   [PATCH] Char: mox...
1067
1068
  	retval = pci_register_driver(&moxa_pci_driver);
  	if (retval) {
eaa95a8da   Jiri Slaby   Char: moxa, littl...
1069
1070
  		printk(KERN_ERR "Can't register MOXA pci driver!
  ");
d353eca4e   Jiri Slaby   Char: moxa, clean...
1071
  		if (isabrds)
a784bf7c1   Jiri Slaby   [PATCH] Char: mox...
1072
  			retval = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1073
1074
  	}
  #endif
a784bf7c1   Jiri Slaby   [PATCH] Char: mox...
1075

a784bf7c1   Jiri Slaby   [PATCH] Char: mox...
1076
  	return retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1077
1078
1079
1080
  }
  
  static void __exit moxa_exit(void)
  {
eaa95a8da   Jiri Slaby   Char: moxa, littl...
1081
  	unsigned int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1082

9cde5bf02   Jiri Slaby   [PATCH] Char: mox...
1083
  #ifdef CONFIG_PCI
a784bf7c1   Jiri Slaby   [PATCH] Char: mox...
1084
  	pci_unregister_driver(&moxa_pci_driver);
9cde5bf02   Jiri Slaby   [PATCH] Char: mox...
1085
  #endif
a784bf7c1   Jiri Slaby   [PATCH] Char: mox...
1086

810ab09b2   Jiri Slaby   Char: moxa, centr...
1087
1088
1089
  	for (i = 0; i < MAX_BOARDS; i++) /* ISA boards */
  		if (moxa_boards[i].ready)
  			moxa_board_deinit(&moxa_boards[i]);
2a5413416   Jiri Slaby   Char: moxa, seria...
1090
1091
1092
1093
1094
1095
1096
1097
  
  	del_timer_sync(&moxaTimer);
  
  	if (tty_unregister_driver(moxaDriver))
  		printk(KERN_ERR "Couldn't unregister MOXA Intellio family "
  				"serial driver
  ");
  	put_tty_driver(moxaDriver);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1098
1099
1100
1101
  }
  
  module_init(moxa_init);
  module_exit(moxa_exit);
f176178ba   Alan Cox   tty: moxa: Use mo...
1102
  static void moxa_shutdown(struct tty_port *port)
a8f5cda06   Jiri Slaby   Char: moxa, rewor...
1103
  {
f176178ba   Alan Cox   tty: moxa: Use mo...
1104
1105
  	struct moxa_port *ch = container_of(port, struct moxa_port, port);
          MoxaPortDisable(ch);
a8f5cda06   Jiri Slaby   Char: moxa, rewor...
1106
  	MoxaPortFlushData(ch, 2);
a8f5cda06   Jiri Slaby   Char: moxa, rewor...
1107
  }
31f35939d   Alan Cox   tty_port: Add a p...
1108
1109
1110
1111
  static int moxa_carrier_raised(struct tty_port *port)
  {
  	struct moxa_port *ch = container_of(port, struct moxa_port, port);
  	int dcd;
8482bcd58   Alan Cox   tty: moxa: Fix mo...
1112
  	spin_lock_irq(&port->lock);
31f35939d   Alan Cox   tty_port: Add a p...
1113
  	dcd = ch->DCDState;
8482bcd58   Alan Cox   tty: moxa: Fix mo...
1114
  	spin_unlock_irq(&port->lock);
31f35939d   Alan Cox   tty_port: Add a p...
1115
1116
  	return dcd;
  }
f176178ba   Alan Cox   tty: moxa: Use mo...
1117
  static void moxa_dtr_rts(struct tty_port *port, int onoff)
a8f5cda06   Jiri Slaby   Char: moxa, rewor...
1118
  {
f176178ba   Alan Cox   tty: moxa: Use mo...
1119
1120
  	struct moxa_port *ch = container_of(port, struct moxa_port, port);
  	MoxaPortLineCtrl(ch, onoff, onoff);
a8f5cda06   Jiri Slaby   Char: moxa, rewor...
1121
  }
f176178ba   Alan Cox   tty: moxa: Use mo...
1122

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1123
1124
  static int moxa_open(struct tty_struct *tty, struct file *filp)
  {
810ab09b2   Jiri Slaby   Char: moxa, centr...
1125
  	struct moxa_board_conf *brd;
8f8ecbad0   Jiri Slaby   [PATCH] Char: mox...
1126
  	struct moxa_port *ch;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1127
  	int port;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1128

11324edd4   Jiri Slaby   [PATCH] Char: mox...
1129
  	port = tty->index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1130
  	if (port == MAX_PORTS) {
74d7d97b9   Jiri Slaby   Char: moxa, ioctl...
1131
  		return capable(CAP_SYS_ADMIN) ? 0 : -EPERM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1132
  	}
a8f5cda06   Jiri Slaby   Char: moxa, rewor...
1133
1134
  	if (mutex_lock_interruptible(&moxa_openlock))
  		return -ERESTARTSYS;
810ab09b2   Jiri Slaby   Char: moxa, centr...
1135
  	brd = &moxa_boards[port / MAX_PORTS_PER_BOARD];
a8f5cda06   Jiri Slaby   Char: moxa, rewor...
1136
1137
  	if (!brd->ready) {
  		mutex_unlock(&moxa_openlock);
810ab09b2   Jiri Slaby   Char: moxa, centr...
1138
  		return -ENODEV;
a8f5cda06   Jiri Slaby   Char: moxa, rewor...
1139
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1140

f0e852772   Dirk Eibach   moxa: prevent ope...
1141
1142
1143
1144
  	if (port % MAX_PORTS_PER_BOARD >= brd->numPorts) {
  		mutex_unlock(&moxa_openlock);
  		return -ENODEV;
  	}
810ab09b2   Jiri Slaby   Char: moxa, centr...
1145
  	ch = &brd->ports[port % MAX_PORTS_PER_BOARD];
9de6a51fe   Alan Cox   moxa: use tty_port
1146
  	ch->port.count++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1147
  	tty->driver_data = ch;
d450b5a01   Alan Cox   tty: kref usage f...
1148
  	tty_port_tty_set(&ch->port, tty);
f176178ba   Alan Cox   tty: moxa: Use mo...
1149
  	mutex_lock(&ch->port.mutex);
9de6a51fe   Alan Cox   moxa: use tty_port
1150
  	if (!(ch->port.flags & ASYNC_INITIALIZED)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1151
  		ch->statusflags = 0;
db1acaa63   Alan Cox   moxa: first pass ...
1152
  		moxa_set_tty_param(tty, tty->termios);
b4173f457   Jiri Slaby   Char: moxa, remov...
1153
1154
  		MoxaPortLineCtrl(ch, 1, 1);
  		MoxaPortEnable(ch);
a8f5cda06   Jiri Slaby   Char: moxa, rewor...
1155
  		MoxaSetFifo(ch, ch->type == PORT_16550A);
9de6a51fe   Alan Cox   moxa: use tty_port
1156
  		ch->port.flags |= ASYNC_INITIALIZED;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1157
  	}
f176178ba   Alan Cox   tty: moxa: Use mo...
1158
  	mutex_unlock(&ch->port.mutex);
a8f5cda06   Jiri Slaby   Char: moxa, rewor...
1159
  	mutex_unlock(&moxa_openlock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1160

7c31bdb6b   Jiri Slaby   Char: moxa, do no...
1161
  	return tty_port_block_til_ready(&ch->port, tty, filp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1162
1163
1164
1165
  }
  
  static void moxa_close(struct tty_struct *tty, struct file *filp)
  {
f176178ba   Alan Cox   tty: moxa: Use mo...
1166
  	struct moxa_port *ch = tty->driver_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1167
  	ch->cflag = tty->termios->c_cflag;
f176178ba   Alan Cox   tty: moxa: Use mo...
1168
  	tty_port_close(&ch->port, tty, filp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1169
1170
1171
1172
1173
  }
  
  static int moxa_write(struct tty_struct *tty,
  		      const unsigned char *buf, int count)
  {
b4173f457   Jiri Slaby   Char: moxa, remov...
1174
  	struct moxa_port *ch = tty->driver_data;
0ad7c9af3   Jiri Slaby   Char: moxa, fix l...
1175
  	unsigned long flags;
b4173f457   Jiri Slaby   Char: moxa, remov...
1176
  	int len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1177

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1178
  	if (ch == NULL)
b4173f457   Jiri Slaby   Char: moxa, remov...
1179
  		return 0;
33f0f88f1   Alan Cox   [PATCH] TTY layer...
1180

0ad7c9af3   Jiri Slaby   Char: moxa, fix l...
1181
  	spin_lock_irqsave(&moxa_lock, flags);
d450b5a01   Alan Cox   tty: kref usage f...
1182
  	len = MoxaPortWriteData(tty, buf, count);
0ad7c9af3   Jiri Slaby   Char: moxa, fix l...
1183
  	spin_unlock_irqrestore(&moxa_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1184

a808ac0c4   Alan Cox   tty: moxa: Lockin...
1185
  	set_bit(LOWWAIT, &ch->statusflags);
eaa95a8da   Jiri Slaby   Char: moxa, littl...
1186
  	return len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1187
1188
1189
1190
  }
  
  static int moxa_write_room(struct tty_struct *tty)
  {
8f8ecbad0   Jiri Slaby   [PATCH] Char: mox...
1191
  	struct moxa_port *ch;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1192
1193
  
  	if (tty->stopped)
eaa95a8da   Jiri Slaby   Char: moxa, littl...
1194
  		return 0;
b4173f457   Jiri Slaby   Char: moxa, remov...
1195
  	ch = tty->driver_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1196
  	if (ch == NULL)
eaa95a8da   Jiri Slaby   Char: moxa, littl...
1197
  		return 0;
b4173f457   Jiri Slaby   Char: moxa, remov...
1198
  	return MoxaPortTxFree(ch);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1199
1200
1201
1202
  }
  
  static void moxa_flush_buffer(struct tty_struct *tty)
  {
b4173f457   Jiri Slaby   Char: moxa, remov...
1203
  	struct moxa_port *ch = tty->driver_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1204
1205
1206
  
  	if (ch == NULL)
  		return;
b4173f457   Jiri Slaby   Char: moxa, remov...
1207
  	MoxaPortFlushData(ch, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1208
1209
1210
1211
1212
  	tty_wakeup(tty);
  }
  
  static int moxa_chars_in_buffer(struct tty_struct *tty)
  {
b4173f457   Jiri Slaby   Char: moxa, remov...
1213
  	struct moxa_port *ch = tty->driver_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1214
  	int chars;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1215

b4173f457   Jiri Slaby   Char: moxa, remov...
1216
  	chars = MoxaPortTxQueue(ch);
f710ebd7f   Alan Cox   tty: moxa: Kill t...
1217
  	if (chars)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1218
1219
1220
1221
  		/*
  		 * Make it possible to wakeup anything waiting for output
  		 * in tty_ioctl.c, etc.
  		 */
f710ebd7f   Alan Cox   tty: moxa: Kill t...
1222
          	set_bit(EMPTYWAIT, &ch->statusflags);
eaa95a8da   Jiri Slaby   Char: moxa, littl...
1223
  	return chars;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1224
  }
60b33c133   Alan Cox   tiocmget: kill of...
1225
  static int moxa_tiocmget(struct tty_struct *tty)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1226
  {
8482bcd58   Alan Cox   tty: moxa: Fix mo...
1227
  	struct moxa_port *ch = tty->driver_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1228
  	int flag = 0, dtr, rts;
b4173f457   Jiri Slaby   Char: moxa, remov...
1229
  	MoxaPortGetLineOut(ch, &dtr, &rts);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1230
1231
1232
1233
  	if (dtr)
  		flag |= TIOCM_DTR;
  	if (rts)
  		flag |= TIOCM_RTS;
b4173f457   Jiri Slaby   Char: moxa, remov...
1234
  	dtr = MoxaPortLineStatus(ch);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1235
1236
1237
1238
1239
1240
1241
1242
  	if (dtr & 1)
  		flag |= TIOCM_CTS;
  	if (dtr & 2)
  		flag |= TIOCM_DSR;
  	if (dtr & 4)
  		flag |= TIOCM_CD;
  	return flag;
  }
20b9d1771   Alan Cox   tiocmset: kill th...
1243
  static int moxa_tiocmset(struct tty_struct *tty,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1244
1245
  			 unsigned int set, unsigned int clear)
  {
a8f5cda06   Jiri Slaby   Char: moxa, rewor...
1246
  	struct moxa_port *ch;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1247
  	int dtr, rts;
a8f5cda06   Jiri Slaby   Char: moxa, rewor...
1248
1249
1250
1251
  	mutex_lock(&moxa_openlock);
  	ch = tty->driver_data;
  	if (!ch) {
  		mutex_unlock(&moxa_openlock);
74d7d97b9   Jiri Slaby   Char: moxa, ioctl...
1252
  		return -EINVAL;
a8f5cda06   Jiri Slaby   Char: moxa, rewor...
1253
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1254

b4173f457   Jiri Slaby   Char: moxa, remov...
1255
  	MoxaPortGetLineOut(ch, &dtr, &rts);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1256
1257
1258
1259
1260
1261
1262
1263
  	if (set & TIOCM_RTS)
  		rts = 1;
  	if (set & TIOCM_DTR)
  		dtr = 1;
  	if (clear & TIOCM_RTS)
  		rts = 0;
  	if (clear & TIOCM_DTR)
  		dtr = 0;
b4173f457   Jiri Slaby   Char: moxa, remov...
1264
  	MoxaPortLineCtrl(ch, dtr, rts);
a8f5cda06   Jiri Slaby   Char: moxa, rewor...
1265
  	mutex_unlock(&moxa_openlock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1266
1267
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1268
  static void moxa_set_termios(struct tty_struct *tty,
eaa95a8da   Jiri Slaby   Char: moxa, littl...
1269
  		struct ktermios *old_termios)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1270
  {
eaa95a8da   Jiri Slaby   Char: moxa, littl...
1271
  	struct moxa_port *ch = tty->driver_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1272
1273
1274
  
  	if (ch == NULL)
  		return;
db1acaa63   Alan Cox   moxa: first pass ...
1275
  	moxa_set_tty_param(tty, old_termios);
eaa95a8da   Jiri Slaby   Char: moxa, littl...
1276
  	if (!(old_termios->c_cflag & CLOCAL) && C_CLOCAL(tty))
9de6a51fe   Alan Cox   moxa: use tty_port
1277
  		wake_up_interruptible(&ch->port.open_wait);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1278
1279
1280
1281
  }
  
  static void moxa_stop(struct tty_struct *tty)
  {
eaa95a8da   Jiri Slaby   Char: moxa, littl...
1282
  	struct moxa_port *ch = tty->driver_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1283
1284
1285
  
  	if (ch == NULL)
  		return;
b4173f457   Jiri Slaby   Char: moxa, remov...
1286
  	MoxaPortTxDisable(ch);
a808ac0c4   Alan Cox   tty: moxa: Lockin...
1287
  	set_bit(TXSTOPPED, &ch->statusflags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1288
1289
1290
1291
1292
  }
  
  
  static void moxa_start(struct tty_struct *tty)
  {
eaa95a8da   Jiri Slaby   Char: moxa, littl...
1293
  	struct moxa_port *ch = tty->driver_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1294
1295
1296
1297
1298
1299
  
  	if (ch == NULL)
  		return;
  
  	if (!(ch->statusflags & TXSTOPPED))
  		return;
b4173f457   Jiri Slaby   Char: moxa, remov...
1300
  	MoxaPortTxEnable(ch);
a808ac0c4   Alan Cox   tty: moxa: Lockin...
1301
  	clear_bit(TXSTOPPED, &ch->statusflags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1302
1303
1304
1305
  }
  
  static void moxa_hangup(struct tty_struct *tty)
  {
a808ac0c4   Alan Cox   tty: moxa: Lockin...
1306
  	struct moxa_port *ch = tty->driver_data;
f176178ba   Alan Cox   tty: moxa: Use mo...
1307
  	tty_port_hangup(&ch->port);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1308
  }
7bcf97d1d   Jiri Slaby   Char: moxa, merge...
1309
  static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1310
  {
d450b5a01   Alan Cox   tty: kref usage f...
1311
  	struct tty_struct *tty;
8482bcd58   Alan Cox   tty: moxa: Fix mo...
1312
  	unsigned long flags;
7bcf97d1d   Jiri Slaby   Char: moxa, merge...
1313
  	dcd = !!dcd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1314

8482bcd58   Alan Cox   tty: moxa: Fix mo...
1315
  	spin_lock_irqsave(&p->port.lock, flags);
d450b5a01   Alan Cox   tty: kref usage f...
1316
  	if (dcd != p->DCDState) {
8482bcd58   Alan Cox   tty: moxa: Fix mo...
1317
1318
          	p->DCDState = dcd;
          	spin_unlock_irqrestore(&p->port.lock, flags);
d450b5a01   Alan Cox   tty: kref usage f...
1319
1320
1321
1322
  		tty = tty_port_tty_get(&p->port);
  		if (tty && C_CLOCAL(tty) && !dcd)
  			tty_hangup(tty);
  		tty_kref_put(tty);
7bcf97d1d   Jiri Slaby   Char: moxa, merge...
1323
  	}
8482bcd58   Alan Cox   tty: moxa: Fix mo...
1324
1325
  	else
  		spin_unlock_irqrestore(&p->port.lock, flags);
7bcf97d1d   Jiri Slaby   Char: moxa, merge...
1326
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1327

7bcf97d1d   Jiri Slaby   Char: moxa, merge...
1328
1329
1330
  static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
  		u16 __iomem *ip)
  {
d450b5a01   Alan Cox   tty: kref usage f...
1331
  	struct tty_struct *tty = tty_port_tty_get(&p->port);
7bcf97d1d   Jiri Slaby   Char: moxa, merge...
1332
  	void __iomem *ofsAddr;
9de6a51fe   Alan Cox   moxa: use tty_port
1333
  	unsigned int inited = p->port.flags & ASYNC_INITIALIZED;
7bcf97d1d   Jiri Slaby   Char: moxa, merge...
1334
1335
1336
  	u16 intr;
  
  	if (tty) {
a808ac0c4   Alan Cox   tty: moxa: Lockin...
1337
  		if (test_bit(EMPTYWAIT, &p->statusflags) &&
7bcf97d1d   Jiri Slaby   Char: moxa, merge...
1338
  				MoxaPortTxQueue(p) == 0) {
a808ac0c4   Alan Cox   tty: moxa: Lockin...
1339
  			clear_bit(EMPTYWAIT, &p->statusflags);
7bcf97d1d   Jiri Slaby   Char: moxa, merge...
1340
1341
  			tty_wakeup(tty);
  		}
a808ac0c4   Alan Cox   tty: moxa: Lockin...
1342
  		if (test_bit(LOWWAIT, &p->statusflags) && !tty->stopped &&
7bcf97d1d   Jiri Slaby   Char: moxa, merge...
1343
  				MoxaPortTxQueue(p) <= WAKEUP_CHARS) {
a808ac0c4   Alan Cox   tty: moxa: Lockin...
1344
  			clear_bit(LOWWAIT, &p->statusflags);
7bcf97d1d   Jiri Slaby   Char: moxa, merge...
1345
1346
  			tty_wakeup(tty);
  		}
f9b412a8c   Alan Cox   tty: moxa: Kill o...
1347
  		if (inited && !test_bit(TTY_THROTTLED, &tty->flags) &&
7bcf97d1d   Jiri Slaby   Char: moxa, merge...
1348
1349
1350
1351
1352
  				MoxaPortRxQueue(p) > 0) { /* RX */
  			MoxaPortReadData(p);
  			tty_schedule_flip(tty);
  		}
  	} else {
a808ac0c4   Alan Cox   tty: moxa: Lockin...
1353
  		clear_bit(EMPTYWAIT, &p->statusflags);
7bcf97d1d   Jiri Slaby   Char: moxa, merge...
1354
  		MoxaPortFlushData(p, 0); /* flush RX */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1355
  	}
0bcc4caad   Jiri Slaby   Char: moxa, timer...
1356

7bcf97d1d   Jiri Slaby   Char: moxa, merge...
1357
  	if (!handle) /* nothing else to do */
0e0fd7d73   Jiri Slaby   tty: moxa, fix re...
1358
  		goto put;
7bcf97d1d   Jiri Slaby   Char: moxa, merge...
1359
1360
1361
  
  	intr = readw(ip); /* port irq status */
  	if (intr == 0)
0e0fd7d73   Jiri Slaby   tty: moxa, fix re...
1362
  		goto put;
7bcf97d1d   Jiri Slaby   Char: moxa, merge...
1363
1364
1365
1366
1367
1368
1369
1370
  
  	writew(0, ip); /* ACK port */
  	ofsAddr = p->tableAddr;
  	if (intr & IntrTx) /* disable tx intr */
  		writew(readw(ofsAddr + HostStat) & ~WakeupTx,
  				ofsAddr + HostStat);
  
  	if (!inited)
0e0fd7d73   Jiri Slaby   tty: moxa, fix re...
1371
  		goto put;
7bcf97d1d   Jiri Slaby   Char: moxa, merge...
1372
1373
1374
1375
1376
1377
1378
1379
  
  	if (tty && (intr & IntrBreak) && !I_IGNBRK(tty)) { /* BREAK */
  		tty_insert_flip_char(tty, 0, TTY_BREAK);
  		tty_schedule_flip(tty);
  	}
  
  	if (intr & IntrLine)
  		moxa_new_dcdstate(p, readb(ofsAddr + FlagStat) & DCD_state);
0e0fd7d73   Jiri Slaby   tty: moxa, fix re...
1380
1381
  put:
  	tty_kref_put(tty);
7bcf97d1d   Jiri Slaby   Char: moxa, merge...
1382
1383
1384
1385
1386
1387
1388
1389
  
  	return 0;
  }
  
  static void moxa_poll(unsigned long ignored)
  {
  	struct moxa_board_conf *brd;
  	u16 __iomem *ip;
2a5413416   Jiri Slaby   Char: moxa, seria...
1390
  	unsigned int card, port, served = 0;
7bcf97d1d   Jiri Slaby   Char: moxa, merge...
1391
1392
  
  	spin_lock(&moxa_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1393
  	for (card = 0; card < MAX_BOARDS; card++) {
7bcf97d1d   Jiri Slaby   Char: moxa, merge...
1394
1395
  		brd = &moxa_boards[card];
  		if (!brd->ready)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1396
  			continue;
7bcf97d1d   Jiri Slaby   Char: moxa, merge...
1397

2a5413416   Jiri Slaby   Char: moxa, seria...
1398
  		served++;
7bcf97d1d   Jiri Slaby   Char: moxa, merge...
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
  		ip = NULL;
  		if (readb(brd->intPend) == 0xff)
  			ip = brd->intTable + readb(brd->intNdx);
  
  		for (port = 0; port < brd->numPorts; port++)
  			moxa_poll_port(&brd->ports[port], !!ip, ip + port);
  
  		if (ip)
  			writeb(0, brd->intPend); /* ACK */
  
  		if (moxaLowWaterChk) {
  			struct moxa_port *p = brd->ports;
  			for (port = 0; port < brd->numPorts; port++, p++)
  				if (p->lowChkFlag) {
  					p->lowChkFlag = 0;
  					moxa_low_water_check(p->tableAddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1415
  				}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1416
1417
  		}
  	}
7bcf97d1d   Jiri Slaby   Char: moxa, merge...
1418
  	moxaLowWaterChk = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1419

2a5413416   Jiri Slaby   Char: moxa, seria...
1420
1421
1422
  	if (served)
  		mod_timer(&moxaTimer, jiffies + HZ / 50);
  	spin_unlock(&moxa_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1423
1424
1425
  }
  
  /******************************************************************************/
db1acaa63   Alan Cox   moxa: first pass ...
1426
  static void moxa_set_tty_param(struct tty_struct *tty, struct ktermios *old_termios)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1427
  {
eaa95a8da   Jiri Slaby   Char: moxa, littl...
1428
1429
  	register struct ktermios *ts = tty->termios;
  	struct moxa_port *ch = tty->driver_data;
db1acaa63   Alan Cox   moxa: first pass ...
1430
  	int rts, cts, txflow, rxflow, xany, baud;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1431

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1432
1433
1434
1435
1436
1437
1438
1439
1440
  	rts = cts = txflow = rxflow = xany = 0;
  	if (ts->c_cflag & CRTSCTS)
  		rts = cts = 1;
  	if (ts->c_iflag & IXON)
  		txflow = 1;
  	if (ts->c_iflag & IXOFF)
  		rxflow = 1;
  	if (ts->c_iflag & IXANY)
  		xany = 1;
db1acaa63   Alan Cox   moxa: first pass ...
1441
1442
1443
  
  	/* Clear the features we don't support */
  	ts->c_cflag &= ~CMSPAR;
b4173f457   Jiri Slaby   Char: moxa, remov...
1444
1445
  	MoxaPortFlowCtrl(ch, rts, cts, txflow, rxflow, xany);
  	baud = MoxaPortSetTermio(ch, ts, tty_get_baud_rate(tty));
db1acaa63   Alan Cox   moxa: first pass ...
1446
1447
1448
1449
  	if (baud == -1)
  		baud = tty_termios_baud_rate(old_termios);
  	/* Not put the baud rate into the termios data */
  	tty_encode_baud_rate(tty, baud, baud);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1450
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1451
1452
  /*****************************************************************************
   *	Driver level functions: 					     *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1453
   *****************************************************************************/
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1454

b4173f457   Jiri Slaby   Char: moxa, remov...
1455
  static void MoxaPortFlushData(struct moxa_port *port, int mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1456
1457
  {
  	void __iomem *ofsAddr;
eaa95a8da   Jiri Slaby   Char: moxa, littl...
1458
  	if (mode < 0 || mode > 2)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1459
  		return;
b4173f457   Jiri Slaby   Char: moxa, remov...
1460
  	ofsAddr = port->tableAddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1461
1462
  	moxafunc(ofsAddr, FC_FlushQueue, mode);
  	if (mode != 1) {
b4173f457   Jiri Slaby   Char: moxa, remov...
1463
  		port->lowChkFlag = 0;
6f56b658b   Jiri Slaby   Char: moxa, funct...
1464
  		moxa_low_water_check(ofsAddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1465
1466
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
  /*
   *    Moxa Port Number Description:
   *
   *      MOXA serial driver supports up to 4 MOXA-C218/C320 boards. And,
   *      the port number using in MOXA driver functions will be 0 to 31 for
   *      first MOXA board, 32 to 63 for second, 64 to 95 for third and 96
   *      to 127 for fourth. For example, if you setup three MOXA boards,
   *      first board is C218, second board is C320-16 and third board is
   *      C320-32. The port number of first board (C218 - 8 ports) is from
   *      0 to 7. The port number of second board (C320 - 16 ports) is form
   *      32 to 47. The port number of third board (C320 - 32 ports) is from
   *      64 to 95. And those port numbers form 8 to 31, 48 to 63 and 96 to
   *      127 will be invalid.
   *
   *
   *      Moxa Functions Description:
   *
   *      Function 1:     Driver initialization routine, this routine must be
   *                      called when initialized driver.
   *      Syntax:
   *      void MoxaDriverInit();
   *
   *
   *      Function 2:     Moxa driver private IOCTL command processing.
   *      Syntax:
   *      int  MoxaDriverIoctl(unsigned int cmd, unsigned long arg, int port);
   *
   *           unsigned int cmd   : IOCTL command
   *           unsigned long arg  : IOCTL argument
   *           int port           : port number (0 - 127)
   *
   *           return:    0  (OK)
   *                      -EINVAL
   *                      -ENOIOCTLCMD
   *
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
   *      Function 6:     Enable this port to start Tx/Rx data.
   *      Syntax:
   *      void MoxaPortEnable(int port);
   *           int port           : port number (0 - 127)
   *
   *
   *      Function 7:     Disable this port
   *      Syntax:
   *      void MoxaPortDisable(int port);
   *           int port           : port number (0 - 127)
   *
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1515
1516
   *      Function 10:    Setting baud rate of this port.
   *      Syntax:
08d01c792   Jiri Slaby   Char: moxa, intro...
1517
   *      speed_t MoxaPortSetBaud(int port, speed_t baud);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
   *           int port           : port number (0 - 127)
   *           long baud          : baud rate (50 - 115200)
   *
   *           return:    0       : this port is invalid or baud < 50
   *                      50 - 115200 : the real baud rate set to the port, if
   *                                    the argument baud is large than maximun
   *                                    available baud rate, the real setting
   *                                    baud rate will be the maximun baud rate.
   *
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1528
1529
   *      Function 12:    Configure the port.
   *      Syntax:
606d099cd   Alan Cox   [PATCH] tty: swit...
1530
   *      int  MoxaPortSetTermio(int port, struct ktermios *termio, speed_t baud);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1531
   *           int port           : port number (0 - 127)
606d099cd   Alan Cox   [PATCH] tty: swit...
1532
   *           struct ktermios * termio : termio structure pointer
c7bce3097   Alan Cox   [PATCH] serial: F...
1533
   *	     speed_t baud	: baud rate
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
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
1583
   *
   *           return:    -1      : this port is invalid or termio == NULL
   *                      0       : setting O.K.
   *
   *
   *      Function 13:    Get the DTR/RTS state of this port.
   *      Syntax:
   *      int  MoxaPortGetLineOut(int port, int *dtrState, int *rtsState);
   *           int port           : port number (0 - 127)
   *           int * dtrState     : pointer to INT to receive the current DTR
   *                                state. (if NULL, this function will not
   *                                write to this address)
   *           int * rtsState     : pointer to INT to receive the current RTS
   *                                state. (if NULL, this function will not
   *                                write to this address)
   *
   *           return:    -1      : this port is invalid
   *                      0       : O.K.
   *
   *
   *      Function 14:    Setting the DTR/RTS output state of this port.
   *      Syntax:
   *      void MoxaPortLineCtrl(int port, int dtrState, int rtsState);
   *           int port           : port number (0 - 127)
   *           int dtrState       : DTR output state (0: off, 1: on)
   *           int rtsState       : RTS output state (0: off, 1: on)
   *
   *
   *      Function 15:    Setting the flow control of this port.
   *      Syntax:
   *      void MoxaPortFlowCtrl(int port, int rtsFlow, int ctsFlow, int rxFlow,
   *                            int txFlow,int xany);
   *           int port           : port number (0 - 127)
   *           int rtsFlow        : H/W RTS flow control (0: no, 1: yes)
   *           int ctsFlow        : H/W CTS flow control (0: no, 1: yes)
   *           int rxFlow         : S/W Rx XON/XOFF flow control (0: no, 1: yes)
   *           int txFlow         : S/W Tx XON/XOFF flow control (0: no, 1: yes)
   *           int xany           : S/W XANY flow control (0: no, 1: yes)
   *
   *
   *      Function 16:    Get ths line status of this port
   *      Syntax:
   *      int  MoxaPortLineStatus(int port);
   *           int port           : port number (0 - 127)
   *
   *           return:    Bit 0 - CTS state (0: off, 1: on)
   *                      Bit 1 - DSR state (0: off, 1: on)
   *                      Bit 2 - DCD state (0: off, 1: on)
   *
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
   *      Function 19:    Flush the Rx/Tx buffer data of this port.
   *      Syntax:
   *      void MoxaPortFlushData(int port, int mode);
   *           int port           : port number (0 - 127)
   *           int mode    
   *                      0       : flush the Rx buffer 
   *                      1       : flush the Tx buffer 
   *                      2       : flush the Rx and Tx buffer 
   *
   *
   *      Function 20:    Write data.
   *      Syntax:
   *      int  MoxaPortWriteData(int port, unsigned char * buffer, int length);
   *           int port           : port number (0 - 127)
   *           unsigned char * buffer     : pointer to write data buffer.
   *           int length         : write data length
   *
   *           return:    0 - length      : real write data length
   *
   *
   *      Function 21:    Read data.
   *      Syntax:
33f0f88f1   Alan Cox   [PATCH] TTY layer...
1606
   *      int  MoxaPortReadData(int port, struct tty_struct *tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1607
   *           int port           : port number (0 - 127)
33f0f88f1   Alan Cox   [PATCH] TTY layer...
1608
   *	     struct tty_struct *tty : tty for data
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1609
1610
1611
1612
   *
   *           return:    0 - length      : real read data length
   *
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
   *      Function 24:    Get the Tx buffer current queued data bytes
   *      Syntax:
   *      int  MoxaPortTxQueue(int port);
   *           int port           : port number (0 - 127)
   *
   *           return:    ..      : Tx buffer current queued data bytes
   *
   *
   *      Function 25:    Get the Tx buffer current free space
   *      Syntax:
   *      int  MoxaPortTxFree(int port);
   *           int port           : port number (0 - 127)
   *
   *           return:    ..      : Tx buffer current free space
   *
   *
   *      Function 26:    Get the Rx buffer current queued data bytes
   *      Syntax:
   *      int  MoxaPortRxQueue(int port);
   *           int port           : port number (0 - 127)
   *
   *           return:    ..      : Rx buffer current queued data bytes
   *
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
   *      Function 28:    Disable port data transmission.
   *      Syntax:
   *      void MoxaPortTxDisable(int port);
   *           int port           : port number (0 - 127)
   *
   *
   *      Function 29:    Enable port data transmission.
   *      Syntax:
   *      void MoxaPortTxEnable(int port);
   *           int port           : port number (0 - 127)
   *
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1649
1650
1651
1652
1653
1654
1655
1656
   *      Function 31:    Get the received BREAK signal count and reset it.
   *      Syntax:
   *      int  MoxaPortResetBrkCnt(int port);
   *           int port           : port number (0 - 127)
   *
   *           return:    0 - ..  : BREAK signal count
   *
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1657
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1658

b4173f457   Jiri Slaby   Char: moxa, remov...
1659
  static void MoxaPortEnable(struct moxa_port *port)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1660
1661
  {
  	void __iomem *ofsAddr;
eaa95a8da   Jiri Slaby   Char: moxa, littl...
1662
  	u16 lowwater = 512;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1663

b4173f457   Jiri Slaby   Char: moxa, remov...
1664
  	ofsAddr = port->tableAddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1665
  	writew(lowwater, ofsAddr + Low_water);
08d01c792   Jiri Slaby   Char: moxa, intro...
1666
  	if (MOXA_IS_320(port->board))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1667
  		moxafunc(ofsAddr, FC_SetBreakIrq, 0);
eaa95a8da   Jiri Slaby   Char: moxa, littl...
1668
1669
1670
  	else
  		writew(readw(ofsAddr + HostStat) | WakeupBreak,
  				ofsAddr + HostStat);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1671
1672
1673
1674
1675
1676
1677
  
  	moxafunc(ofsAddr, FC_SetLineIrq, Magic_code);
  	moxafunc(ofsAddr, FC_FlushQueue, 2);
  
  	moxafunc(ofsAddr, FC_EnableCH, Magic_code);
  	MoxaPortLineStatus(port);
  }
b4173f457   Jiri Slaby   Char: moxa, remov...
1678
  static void MoxaPortDisable(struct moxa_port *port)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1679
  {
b4173f457   Jiri Slaby   Char: moxa, remov...
1680
  	void __iomem *ofsAddr = port->tableAddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1681
1682
1683
1684
1685
1686
  
  	moxafunc(ofsAddr, FC_SetFlowCtl, 0);	/* disable flow control */
  	moxafunc(ofsAddr, FC_ClrLineIrq, Magic_code);
  	writew(0, ofsAddr + HostStat);
  	moxafunc(ofsAddr, FC_DisableCH, Magic_code);
  }
08d01c792   Jiri Slaby   Char: moxa, intro...
1687
  static speed_t MoxaPortSetBaud(struct moxa_port *port, speed_t baud)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1688
  {
08d01c792   Jiri Slaby   Char: moxa, intro...
1689
1690
1691
  	void __iomem *ofsAddr = port->tableAddr;
  	unsigned int clock, val;
  	speed_t max;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1692

08d01c792   Jiri Slaby   Char: moxa, intro...
1693
1694
  	max = MOXA_IS_320(port->board) ? 460800 : 921600;
  	if (baud < 50)
eaa95a8da   Jiri Slaby   Char: moxa, littl...
1695
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1696
1697
  	if (baud > max)
  		baud = max;
08d01c792   Jiri Slaby   Char: moxa, intro...
1698
  	clock = 921600;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1699
1700
1701
  	val = clock / baud;
  	moxafunc(ofsAddr, FC_SetBaud, val);
  	baud = clock / val;
eaa95a8da   Jiri Slaby   Char: moxa, littl...
1702
  	return baud;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1703
  }
b4173f457   Jiri Slaby   Char: moxa, remov...
1704
1705
  static int MoxaPortSetTermio(struct moxa_port *port, struct ktermios *termio,
  		speed_t baud)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1706
1707
  {
  	void __iomem *ofsAddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1708
  	tcflag_t mode = 0;
b4173f457   Jiri Slaby   Char: moxa, remov...
1709
  	ofsAddr = port->tableAddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
  
  	mode = termio->c_cflag & CSIZE;
  	if (mode == CS5)
  		mode = MX_CS5;
  	else if (mode == CS6)
  		mode = MX_CS6;
  	else if (mode == CS7)
  		mode = MX_CS7;
  	else if (mode == CS8)
  		mode = MX_CS8;
  
  	if (termio->c_cflag & CSTOPB) {
  		if (mode == MX_CS5)
  			mode |= MX_STOP15;
  		else
  			mode |= MX_STOP2;
  	} else
  		mode |= MX_STOP1;
  
  	if (termio->c_cflag & PARENB) {
  		if (termio->c_cflag & PARODD)
  			mode |= MX_PARODD;
  		else
  			mode |= MX_PAREVEN;
  	} else
  		mode |= MX_PARNONE;
eaa95a8da   Jiri Slaby   Char: moxa, littl...
1736
  	moxafunc(ofsAddr, FC_SetDataMode, (u16)mode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1737

08d01c792   Jiri Slaby   Char: moxa, intro...
1738
1739
  	if (MOXA_IS_320(port->board) && baud >= 921600)
  		return -1;
db1acaa63   Alan Cox   moxa: first pass ...
1740
  	baud = MoxaPortSetBaud(port, baud);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1741
1742
  
  	if (termio->c_iflag & (IXON | IXOFF | IXANY)) {
f5c5a36d2   Alan Cox   tty: moxa: rework...
1743
  	        spin_lock_irq(&moxafunc_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1744
1745
1746
  		writeb(termio->c_cc[VSTART], ofsAddr + FuncArg);
  		writeb(termio->c_cc[VSTOP], ofsAddr + FuncArg1);
  		writeb(FC_SetXonXoff, ofsAddr + FuncCode);
6f56b658b   Jiri Slaby   Char: moxa, funct...
1747
  		moxa_wait_finish(ofsAddr);
a808ac0c4   Alan Cox   tty: moxa: Lockin...
1748
  		spin_unlock_irq(&moxafunc_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1749
1750
  
  	}
eaa95a8da   Jiri Slaby   Char: moxa, littl...
1751
  	return baud;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1752
  }
b4173f457   Jiri Slaby   Char: moxa, remov...
1753
1754
  static int MoxaPortGetLineOut(struct moxa_port *port, int *dtrState,
  		int *rtsState)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1755
  {
b4173f457   Jiri Slaby   Char: moxa, remov...
1756
1757
1758
1759
  	if (dtrState)
  		*dtrState = !!(port->lineCtrl & DTR_ON);
  	if (rtsState)
  		*rtsState = !!(port->lineCtrl & RTS_ON);
eaa95a8da   Jiri Slaby   Char: moxa, littl...
1760
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1761
  }
b4173f457   Jiri Slaby   Char: moxa, remov...
1762
  static void MoxaPortLineCtrl(struct moxa_port *port, int dtr, int rts)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1763
  {
eaa95a8da   Jiri Slaby   Char: moxa, littl...
1764
  	u8 mode = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1765

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1766
1767
1768
1769
  	if (dtr)
  		mode |= DTR_ON;
  	if (rts)
  		mode |= RTS_ON;
b4173f457   Jiri Slaby   Char: moxa, remov...
1770
1771
  	port->lineCtrl = mode;
  	moxafunc(port->tableAddr, FC_LineControl, mode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1772
  }
b4173f457   Jiri Slaby   Char: moxa, remov...
1773
1774
  static void MoxaPortFlowCtrl(struct moxa_port *port, int rts, int cts,
  		int txflow, int rxflow, int txany)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1775
  {
b4173f457   Jiri Slaby   Char: moxa, remov...
1776
  	int mode = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1777

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
  	if (rts)
  		mode |= RTS_FlowCtl;
  	if (cts)
  		mode |= CTS_FlowCtl;
  	if (txflow)
  		mode |= Tx_FlowCtl;
  	if (rxflow)
  		mode |= Rx_FlowCtl;
  	if (txany)
  		mode |= IXM_IXANY;
b4173f457   Jiri Slaby   Char: moxa, remov...
1788
  	moxafunc(port->tableAddr, FC_SetFlowCtl, mode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1789
  }
b4173f457   Jiri Slaby   Char: moxa, remov...
1790
  static int MoxaPortLineStatus(struct moxa_port *port)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1791
1792
1793
  {
  	void __iomem *ofsAddr;
  	int val;
b4173f457   Jiri Slaby   Char: moxa, remov...
1794
  	ofsAddr = port->tableAddr;
f5c5a36d2   Alan Cox   tty: moxa: rework...
1795
1796
1797
  	if (MOXA_IS_320(port->board))
  		val = moxafuncret(ofsAddr, FC_LineStatus, 0);
  	else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1798
  		val = readw(ofsAddr + FlagStat) >> 4;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1799
  	val &= 0x0B;
7bcf97d1d   Jiri Slaby   Char: moxa, merge...
1800
  	if (val & 8)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1801
  		val |= 4;
7bcf97d1d   Jiri Slaby   Char: moxa, merge...
1802
  	moxa_new_dcdstate(port, val & 8);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1803
  	val &= 7;
7bcf97d1d   Jiri Slaby   Char: moxa, merge...
1804
  	return val;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1805
  }
d450b5a01   Alan Cox   tty: kref usage f...
1806
  static int MoxaPortWriteData(struct tty_struct *tty,
2108eba5c   Jiri Slaby   Char: moxa, clean...
1807
  		const unsigned char *buffer, int len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1808
  {
d450b5a01   Alan Cox   tty: kref usage f...
1809
  	struct moxa_port *port = tty->driver_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1810
  	void __iomem *baseAddr, *ofsAddr, *ofs;
2108eba5c   Jiri Slaby   Char: moxa, clean...
1811
1812
1813
  	unsigned int c, total;
  	u16 head, tail, tx_mask, spage, epage;
  	u16 pageno, pageofs, bufhead;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1814

b4173f457   Jiri Slaby   Char: moxa, remov...
1815
1816
  	ofsAddr = port->tableAddr;
  	baseAddr = port->board->basemem;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1817
1818
1819
1820
1821
  	tx_mask = readw(ofsAddr + TX_mask);
  	spage = readw(ofsAddr + Page_txb);
  	epage = readw(ofsAddr + EndPage_txb);
  	tail = readw(ofsAddr + TXwptr);
  	head = readw(ofsAddr + TXrptr);
2108eba5c   Jiri Slaby   Char: moxa, clean...
1822
  	c = (head > tail) ? (head - tail - 1) : (head - tail + tx_mask);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1823
1824
  	if (c > len)
  		c = len;
9de6a51fe   Alan Cox   moxa: use tty_port
1825
  	moxaLog.txcnt[port->port.tty->index] += c;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
  	total = c;
  	if (spage == epage) {
  		bufhead = readw(ofsAddr + Ofs_txb);
  		writew(spage, baseAddr + Control_reg);
  		while (c > 0) {
  			if (head > tail)
  				len = head - tail - 1;
  			else
  				len = tx_mask + 1 - tail;
  			len = (c > len) ? len : c;
  			ofs = baseAddr + DynPage_addr + bufhead + tail;
2108eba5c   Jiri Slaby   Char: moxa, clean...
1837
1838
  			memcpy_toio(ofs, buffer, len);
  			buffer += len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1839
1840
1841
  			tail = (tail + len) & tx_mask;
  			c -= len;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1842
  	} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1843
1844
  		pageno = spage + (tail >> 13);
  		pageofs = tail & Page_mask;
2108eba5c   Jiri Slaby   Char: moxa, clean...
1845
1846
1847
1848
  		while (c > 0) {
  			len = Page_size - pageofs;
  			if (len > c)
  				len = c;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1849
1850
  			writeb(pageno, baseAddr + Control_reg);
  			ofs = baseAddr + DynPage_addr + pageofs;
2108eba5c   Jiri Slaby   Char: moxa, clean...
1851
1852
  			memcpy_toio(ofs, buffer, len);
  			buffer += len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1853
1854
1855
  			if (++pageno == epage)
  				pageno = spage;
  			pageofs = 0;
2108eba5c   Jiri Slaby   Char: moxa, clean...
1856
1857
1858
  			c -= len;
  		}
  		tail = (tail + total) & tx_mask;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1859
  	}
2108eba5c   Jiri Slaby   Char: moxa, clean...
1860
  	writew(tail, ofsAddr + TXwptr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1861
  	writeb(1, ofsAddr + CD180TXirq);	/* start to send */
2108eba5c   Jiri Slaby   Char: moxa, clean...
1862
  	return total;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1863
  }
7bcf97d1d   Jiri Slaby   Char: moxa, merge...
1864
  static int MoxaPortReadData(struct moxa_port *port)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1865
  {
9de6a51fe   Alan Cox   moxa: use tty_port
1866
  	struct tty_struct *tty = port->port.tty;
2108eba5c   Jiri Slaby   Char: moxa, clean...
1867
  	unsigned char *dst;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1868
  	void __iomem *baseAddr, *ofsAddr, *ofs;
2108eba5c   Jiri Slaby   Char: moxa, clean...
1869
1870
1871
  	unsigned int count, len, total;
  	u16 tail, rx_mask, spage, epage;
  	u16 pageno, pageofs, bufhead, head;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1872

b4173f457   Jiri Slaby   Char: moxa, remov...
1873
1874
  	ofsAddr = port->tableAddr;
  	baseAddr = port->board->basemem;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1875
1876
1877
1878
1879
  	head = readw(ofsAddr + RXrptr);
  	tail = readw(ofsAddr + RXwptr);
  	rx_mask = readw(ofsAddr + RX_mask);
  	spage = readw(ofsAddr + Page_rxb);
  	epage = readw(ofsAddr + EndPage_rxb);
2108eba5c   Jiri Slaby   Char: moxa, clean...
1880
  	count = (tail >= head) ? (tail - head) : (tail - head + rx_mask + 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1881
  	if (count == 0)
33f0f88f1   Alan Cox   [PATCH] TTY layer...
1882
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1883

33f0f88f1   Alan Cox   [PATCH] TTY layer...
1884
  	total = count;
7bcf97d1d   Jiri Slaby   Char: moxa, merge...
1885
  	moxaLog.rxcnt[tty->index] += total;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1886
1887
1888
1889
  	if (spage == epage) {
  		bufhead = readw(ofsAddr + Ofs_rxb);
  		writew(spage, baseAddr + Control_reg);
  		while (count > 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1890
  			ofs = baseAddr + DynPage_addr + bufhead + head;
2108eba5c   Jiri Slaby   Char: moxa, clean...
1891
1892
1893
1894
1895
  			len = (tail >= head) ? (tail - head) :
  					(rx_mask + 1 - head);
  			len = tty_prepare_flip_string(tty, &dst,
  					min(len, count));
  			memcpy_fromio(dst, ofs, len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1896
1897
1898
  			head = (head + len) & rx_mask;
  			count -= len;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1899
  	} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1900
1901
  		pageno = spage + (head >> 13);
  		pageofs = head & Page_mask;
2108eba5c   Jiri Slaby   Char: moxa, clean...
1902
  		while (count > 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1903
1904
  			writew(pageno, baseAddr + Control_reg);
  			ofs = baseAddr + DynPage_addr + pageofs;
2108eba5c   Jiri Slaby   Char: moxa, clean...
1905
1906
1907
1908
1909
1910
1911
  			len = tty_prepare_flip_string(tty, &dst,
  					min(Page_size - pageofs, count));
  			memcpy_fromio(dst, ofs, len);
  
  			count -= len;
  			pageofs = (pageofs + len) & Page_mask;
  			if (pageofs == 0 && ++pageno == epage)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1912
  				pageno = spage;
2108eba5c   Jiri Slaby   Char: moxa, clean...
1913
1914
  		}
  		head = (head + total) & rx_mask;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1915
  	}
2108eba5c   Jiri Slaby   Char: moxa, clean...
1916
1917
  	writew(head, ofsAddr + RXrptr);
  	if (readb(ofsAddr + FlagStat) & Xoff_state) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1918
  		moxaLowWaterChk = 1;
b4173f457   Jiri Slaby   Char: moxa, remov...
1919
  		port->lowChkFlag = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1920
  	}
2108eba5c   Jiri Slaby   Char: moxa, clean...
1921
  	return total;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1922
  }
b4173f457   Jiri Slaby   Char: moxa, remov...
1923
  static int MoxaPortTxQueue(struct moxa_port *port)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1924
  {
b4173f457   Jiri Slaby   Char: moxa, remov...
1925
  	void __iomem *ofsAddr = port->tableAddr;
2108eba5c   Jiri Slaby   Char: moxa, clean...
1926
  	u16 rptr, wptr, mask;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1927

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1928
1929
1930
  	rptr = readw(ofsAddr + TXrptr);
  	wptr = readw(ofsAddr + TXwptr);
  	mask = readw(ofsAddr + TX_mask);
2108eba5c   Jiri Slaby   Char: moxa, clean...
1931
  	return (wptr - rptr) & mask;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1932
  }
b4173f457   Jiri Slaby   Char: moxa, remov...
1933
  static int MoxaPortTxFree(struct moxa_port *port)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1934
  {
b4173f457   Jiri Slaby   Char: moxa, remov...
1935
  	void __iomem *ofsAddr = port->tableAddr;
2108eba5c   Jiri Slaby   Char: moxa, clean...
1936
  	u16 rptr, wptr, mask;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1937

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1938
1939
1940
  	rptr = readw(ofsAddr + TXrptr);
  	wptr = readw(ofsAddr + TXwptr);
  	mask = readw(ofsAddr + TX_mask);
2108eba5c   Jiri Slaby   Char: moxa, clean...
1941
  	return mask - ((wptr - rptr) & mask);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1942
  }
b4173f457   Jiri Slaby   Char: moxa, remov...
1943
  static int MoxaPortRxQueue(struct moxa_port *port)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1944
  {
b4173f457   Jiri Slaby   Char: moxa, remov...
1945
  	void __iomem *ofsAddr = port->tableAddr;
2108eba5c   Jiri Slaby   Char: moxa, clean...
1946
  	u16 rptr, wptr, mask;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1947

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1948
1949
1950
  	rptr = readw(ofsAddr + RXrptr);
  	wptr = readw(ofsAddr + RXwptr);
  	mask = readw(ofsAddr + RX_mask);
2108eba5c   Jiri Slaby   Char: moxa, clean...
1951
  	return (wptr - rptr) & mask;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1952
  }
b4173f457   Jiri Slaby   Char: moxa, remov...
1953
  static void MoxaPortTxDisable(struct moxa_port *port)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1954
  {
b4173f457   Jiri Slaby   Char: moxa, remov...
1955
  	moxafunc(port->tableAddr, FC_SetXoffState, Magic_code);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1956
  }
b4173f457   Jiri Slaby   Char: moxa, remov...
1957
  static void MoxaPortTxEnable(struct moxa_port *port)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1958
  {
b4173f457   Jiri Slaby   Char: moxa, remov...
1959
  	moxafunc(port->tableAddr, FC_SetXonState, Magic_code);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1960
  }
8f8ecbad0   Jiri Slaby   [PATCH] Char: mox...
1961
  static int moxa_get_serial_info(struct moxa_port *info,
eaa95a8da   Jiri Slaby   Char: moxa, littl...
1962
  		struct serial_struct __user *retinfo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1963
  {
eaa95a8da   Jiri Slaby   Char: moxa, littl...
1964
1965
  	struct serial_struct tmp = {
  		.type = info->type,
9de6a51fe   Alan Cox   moxa: use tty_port
1966
1967
  		.line = info->port.tty->index,
  		.flags = info->port.flags,
eaa95a8da   Jiri Slaby   Char: moxa, littl...
1968
  		.baud_base = 921600,
44b7d1b37   Alan Cox   tty: add more tty...
1969
  		.close_delay = info->port.close_delay
eaa95a8da   Jiri Slaby   Char: moxa, littl...
1970
1971
  	};
  	return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1972
  }
8f8ecbad0   Jiri Slaby   [PATCH] Char: mox...
1973
  static int moxa_set_serial_info(struct moxa_port *info,
eaa95a8da   Jiri Slaby   Char: moxa, littl...
1974
  		struct serial_struct __user *new_info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1975
1976
  {
  	struct serial_struct new_serial;
eaa95a8da   Jiri Slaby   Char: moxa, littl...
1977
  	if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1978
  		return -EFAULT;
eaa95a8da   Jiri Slaby   Char: moxa, littl...
1979
1980
1981
1982
  	if (new_serial.irq != 0 || new_serial.port != 0 ||
  			new_serial.custom_divisor != 0 ||
  			new_serial.baud_base != 921600)
  		return -EPERM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1983
1984
1985
  
  	if (!capable(CAP_SYS_ADMIN)) {
  		if (((new_serial.flags & ~ASYNC_USR_MASK) !=
9de6a51fe   Alan Cox   moxa: use tty_port
1986
  		     (info->port.flags & ~ASYNC_USR_MASK)))
eaa95a8da   Jiri Slaby   Char: moxa, littl...
1987
1988
  			return -EPERM;
  	} else
44b7d1b37   Alan Cox   tty: add more tty...
1989
  		info->port.close_delay = new_serial.close_delay * HZ / 100;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1990
1991
  
  	new_serial.flags = (new_serial.flags & ~ASYNC_FLAGS);
9de6a51fe   Alan Cox   moxa: use tty_port
1992
  	new_serial.flags |= (info->port.flags & ASYNC_FLAGS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1993

eaa95a8da   Jiri Slaby   Char: moxa, littl...
1994
  	MoxaSetFifo(info, new_serial.type == PORT_16550A);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1995
1996
  
  	info->type = new_serial.type;
eaa95a8da   Jiri Slaby   Char: moxa, littl...
1997
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1998
1999
2000
2001
2002
2003
2004
  }
  
  
  
  /*****************************************************************************
   *	Static local functions: 					     *
   *****************************************************************************/
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2005

b4173f457   Jiri Slaby   Char: moxa, remov...
2006
  static void MoxaSetFifo(struct moxa_port *port, int enable)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2007
  {
b4173f457   Jiri Slaby   Char: moxa, remov...
2008
  	void __iomem *ofsAddr = port->tableAddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2009
2010
2011
2012
2013
2014
2015
2016
2017
  
  	if (!enable) {
  		moxafunc(ofsAddr, FC_SetRxFIFOTrig, 0);
  		moxafunc(ofsAddr, FC_SetTxFIFOCnt, 1);
  	} else {
  		moxafunc(ofsAddr, FC_SetRxFIFOTrig, 3);
  		moxafunc(ofsAddr, FC_SetTxFIFOCnt, 16);
  	}
  }