Blame view

drivers/tty/mxser.c 69.1 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
  /*
   *          mxser.c  -- MOXA Smartio/Industio family multiport serial driver.
   *
80ff8a805   Jiri Slaby   Char: mxser, add ...
4
5
   *      Copyright (C) 1999-2006  Moxa Technologies (support@moxa.com).
   *	Copyright (C) 2006-2008  Jiri Slaby <jirislaby@gmail.com>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6
   *
1c45607ad   Jiri Slaby   Char: mxser, remo...
7
8
9
   *      This code is loosely based on the 1.8 moxa driver which is based on
   *	Linux serial driver, written by Linus Torvalds, Theodore T'so and
   *	others.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
11
12
13
   *
   *      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
8ea2c2ecf   Jesper Juhl   [PATCH] moxa: par...
14
   *      (at your option) any later version.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
   *	Fed through a cleanup, indent and remove of non 2.6 code by Alan Cox
8eb04cf34   Alan Cox   tty: trivial - fi...
17
18
   *	<alan@lxorguk.ukuu.org.uk>. The original 1.8 code is available on
   *	www.moxa.com.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
   *	- Fixed x86_64 cleanness
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
  #include <linux/module.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
23
24
25
26
27
28
29
30
31
32
33
34
  #include <linux/errno.h>
  #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/serial.h>
  #include <linux/serial_reg.h>
  #include <linux/major.h>
  #include <linux/string.h>
  #include <linux/fcntl.h>
  #include <linux/ptrace.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
36
  #include <linux/ioport.h>
  #include <linux/mm.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
38
  #include <linux/delay.h>
  #include <linux/pci.h>
1977f0327   Jiri Slaby   remove asm/bitops...
39
  #include <linux/bitops.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
40
  #include <linux/slab.h>
5a3c6b251   Manuel Zerpies   drivers/tty: use ...
41
  #include <linux/ratelimit.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
43
44
45
  
  #include <asm/system.h>
  #include <asm/io.h>
  #include <asm/irq.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
47
48
  #include <asm/uaccess.h>
  
  #include "mxser.h"
502f295f6   Jiri Slaby   tty: Char: mxser,...
49
  #define	MXSER_VERSION	"2.0.5"		/* 1.14 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
  #define	MXSERMAJOR	 174
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
  #define MXSER_BOARDS		4	/* Max. boards */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53
  #define MXSER_PORTS_PER_BOARD	8	/* Max. ports per board */
1c45607ad   Jiri Slaby   Char: mxser, remo...
54
55
  #define MXSER_PORTS		(MXSER_BOARDS * MXSER_PORTS_PER_BOARD)
  #define MXSER_ISR_PASS_LIMIT	100
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56

1c45607ad   Jiri Slaby   Char: mxser, remo...
57
58
59
60
  /*CheckIsMoxaMust return value*/
  #define MOXA_OTHER_UART		0x00
  #define MOXA_MUST_MU150_HWID	0x01
  #define MOXA_MUST_MU860_HWID	0x02
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
62
63
64
  #define WAKEUP_CHARS		256
  
  #define UART_MCR_AFE		0x20
  #define UART_LSR_SPECIAL	0x1E
e129deff3   Jiri Slaby   Char: mxser, add ...
65
  #define PCI_DEVICE_ID_POS104UL	0x1044
1c45607ad   Jiri Slaby   Char: mxser, remo...
66
  #define PCI_DEVICE_ID_CB108	0x1080
e129deff3   Jiri Slaby   Char: mxser, add ...
67
  #define PCI_DEVICE_ID_CP102UF	0x1023
502f295f6   Jiri Slaby   tty: Char: mxser,...
68
  #define PCI_DEVICE_ID_CP112UL	0x1120
1c45607ad   Jiri Slaby   Char: mxser, remo...
69
  #define PCI_DEVICE_ID_CB114	0x1142
80ff8a805   Jiri Slaby   Char: mxser, add ...
70
  #define PCI_DEVICE_ID_CP114UL	0x1143
1c45607ad   Jiri Slaby   Char: mxser, remo...
71
72
  #define PCI_DEVICE_ID_CB134I	0x1341
  #define PCI_DEVICE_ID_CP138U	0x1380
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74
75
76
77
78
79
80
  
  #define C168_ASIC_ID    1
  #define C104_ASIC_ID    2
  #define C102_ASIC_ID	0xB
  #define CI132_ASIC_ID	4
  #define CI134_ASIC_ID	3
  #define CI104J_ASIC_ID  5
1c45607ad   Jiri Slaby   Char: mxser, remo...
81
82
  #define MXSER_HIGHBAUD	1
  #define MXSER_HAS2	2
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83

8ea2c2ecf   Jesper Juhl   [PATCH] moxa: par...
84
  /* This is only for PCI */
1c45607ad   Jiri Slaby   Char: mxser, remo...
85
  static const struct {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
87
88
89
90
91
92
93
  	int type;
  	int tx_fifo;
  	int rx_fifo;
  	int xmit_fifo_size;
  	int rx_high_water;
  	int rx_trigger;
  	int rx_low_water;
  	long max_baud;
1c45607ad   Jiri Slaby   Char: mxser, remo...
94
  } Gpci_uart_info[] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95
96
97
98
  	{MOXA_OTHER_UART, 16, 16, 16, 14, 14, 1, 921600L},
  	{MOXA_MUST_MU150_HWID, 64, 64, 64, 48, 48, 16, 230400L},
  	{MOXA_MUST_MU860_HWID, 128, 128, 128, 96, 96, 32, 921600L}
  };
1c45607ad   Jiri Slaby   Char: mxser, remo...
99
  #define UART_INFO_NUM	ARRAY_SIZE(Gpci_uart_info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100

1c45607ad   Jiri Slaby   Char: mxser, remo...
101
102
103
104
105
  struct mxser_cardinfo {
  	char *name;
  	unsigned int nports;
  	unsigned int flags;
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
106

1c45607ad   Jiri Slaby   Char: mxser, remo...
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
  static const struct mxser_cardinfo mxser_cards[] = {
  /* 0*/	{ "C168 series",	8, },
  	{ "C104 series",	4, },
  	{ "CI-104J series",	4, },
  	{ "C168H/PCI series",	8, },
  	{ "C104H/PCI series",	4, },
  /* 5*/	{ "C102 series",	4, MXSER_HAS2 },	/* C102-ISA */
  	{ "CI-132 series",	4, MXSER_HAS2 },
  	{ "CI-134 series",	4, },
  	{ "CP-132 series",	2, },
  	{ "CP-114 series",	4, },
  /*10*/	{ "CT-114 series",	4, },
  	{ "CP-102 series",	2, MXSER_HIGHBAUD },
  	{ "CP-104U series",	4, },
  	{ "CP-168U series",	8, },
  	{ "CP-132U series",	2, },
  /*15*/	{ "CP-134U series",	4, },
  	{ "CP-104JU series",	4, },
  	{ "Moxa UC7000 Serial",	8, },		/* RC7000 */
  	{ "CP-118U series",	8, },
  	{ "CP-102UL series",	2, },
  /*20*/	{ "CP-102U series",	2, },
  	{ "CP-118EL series",	8, },
  	{ "CP-168EL series",	8, },
  	{ "CP-104EL series",	4, },
  	{ "CB-108 series",	8, },
  /*25*/	{ "CB-114 series",	4, },
  	{ "CB-134I series",	4, },
  	{ "CP-138U series",	8, },
80ff8a805   Jiri Slaby   Char: mxser, add ...
136
  	{ "POS-104UL series",	4, },
e129deff3   Jiri Slaby   Char: mxser, add ...
137
  	{ "CP-114UL series",	4, },
502f295f6   Jiri Slaby   tty: Char: mxser,...
138
139
  /*30*/	{ "CP-102UF series",	2, },
  	{ "CP-112UL series",	2, },
1c45607ad   Jiri Slaby   Char: mxser, remo...
140
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141

1c45607ad   Jiri Slaby   Char: mxser, remo...
142
143
  /* driver_data correspond to the lines in the structure above
     see also ISA probe function before you change something */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
  static struct pci_device_id mxser_pcibrds[] = {
1c45607ad   Jiri Slaby   Char: mxser, remo...
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
  	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_C168),	.driver_data = 3 },
  	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_C104),	.driver_data = 4 },
  	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132),	.driver_data = 8 },
  	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP114),	.driver_data = 9 },
  	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CT114),	.driver_data = 10 },
  	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102),	.driver_data = 11 },
  	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104U),	.driver_data = 12 },
  	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP168U),	.driver_data = 13 },
  	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132U),	.driver_data = 14 },
  	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP134U),	.driver_data = 15 },
  	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104JU),.driver_data = 16 },
  	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_RC7000),	.driver_data = 17 },
  	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118U),	.driver_data = 18 },
  	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102UL),.driver_data = 19 },
  	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102U),	.driver_data = 20 },
  	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118EL),.driver_data = 21 },
  	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP168EL),.driver_data = 22 },
  	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104EL),.driver_data = 23 },
  	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB108),	.driver_data = 24 },
  	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB114),	.driver_data = 25 },
  	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB134I),	.driver_data = 26 },
  	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP138U),	.driver_data = 27 },
  	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_POS104UL),	.driver_data = 28 },
80ff8a805   Jiri Slaby   Char: mxser, add ...
168
  	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP114UL),	.driver_data = 29 },
e129deff3   Jiri Slaby   Char: mxser, add ...
169
  	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP102UF),	.driver_data = 30 },
502f295f6   Jiri Slaby   tty: Char: mxser,...
170
  	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP112UL),	.driver_data = 31 },
1c45607ad   Jiri Slaby   Char: mxser, remo...
171
  	{ }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
172
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173
  MODULE_DEVICE_TABLE(pci, mxser_pcibrds);
1df009247   Jiri Slaby   Char: mxser, remo...
174
  static unsigned long ioaddr[MXSER_BOARDS];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
  static int ttymajor = MXSERMAJOR;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
176
177
178
179
180
  
  /* Variables for insmod */
  
  MODULE_AUTHOR("Casper Yang");
  MODULE_DESCRIPTION("MOXA Smartio/Industio Family Multiport Board Device Driver");
1df009247   Jiri Slaby   Char: mxser, remo...
181
182
  module_param_array(ioaddr, ulong, NULL, 0);
  MODULE_PARM_DESC(ioaddr, "ISA io addresses to look for a moxa board");
8d3b33f67   Rusty Russell   [PATCH] Remove MO...
183
  module_param(ttymajor, int, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
184
185
186
187
188
189
190
  MODULE_LICENSE("GPL");
  
  struct mxser_log {
  	int tick;
  	unsigned long rxcnt[MXSER_PORTS];
  	unsigned long txcnt[MXSER_PORTS];
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
  struct mxser_mon {
  	unsigned long rxcnt;
  	unsigned long txcnt;
  	unsigned long up_rxcnt;
  	unsigned long up_txcnt;
  	int modem_status;
  	unsigned char hold_reason;
  };
  
  struct mxser_mon_ext {
  	unsigned long rx_cnt[32];
  	unsigned long tx_cnt[32];
  	unsigned long up_rxcnt[32];
  	unsigned long up_txcnt[32];
  	int modem_status[32];
  
  	long baudrate[32];
  	int databits[32];
  	int stopbits[32];
  	int parity[32];
  	int flowctrl[32];
  	int fifo[32];
  	int iftype[32];
  };
8ea2c2ecf   Jesper Juhl   [PATCH] moxa: par...
215

1c45607ad   Jiri Slaby   Char: mxser, remo...
216
217
218
  struct mxser_board;
  
  struct mxser_port {
0ad9e7d1d   Alan Cox   mxser: use tty_port
219
  	struct tty_port port;
1c45607ad   Jiri Slaby   Char: mxser, remo...
220
  	struct mxser_board *board;
1c45607ad   Jiri Slaby   Char: mxser, remo...
221
222
223
224
  
  	unsigned long ioaddr;
  	unsigned long opmode_ioaddr;
  	int max_baud;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
227
228
229
  	int rx_high_water;
  	int rx_trigger;		/* Rx fifo trigger level */
  	int rx_low_water;
  	int baud_base;		/* max. speed */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
230
  	int type;		/* UART type */
1c45607ad   Jiri Slaby   Char: mxser, remo...
231

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232
  	int x_char;		/* xon/xoff character */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
233
234
  	int IER;		/* Interrupt Enable Register */
  	int MCR;		/* Modem control register */
1c45607ad   Jiri Slaby   Char: mxser, remo...
235
236
237
238
239
  
  	unsigned char stop_rx;
  	unsigned char ldisc_stop_rx;
  
  	int custom_divisor;
1c45607ad   Jiri Slaby   Char: mxser, remo...
240
  	unsigned char err_shadow;
1c45607ad   Jiri Slaby   Char: mxser, remo...
241

1c45607ad   Jiri Slaby   Char: mxser, remo...
242
243
244
245
246
247
  	struct async_icount icount; /* kernel counters for 4 input interrupts */
  	int timeout;
  
  	int read_status_mask;
  	int ignore_status_mask;
  	int xmit_fifo_size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
248
249
250
  	int xmit_head;
  	int xmit_tail;
  	int xmit_cnt;
1c45607ad   Jiri Slaby   Char: mxser, remo...
251

606d099cd   Alan Cox   [PATCH] tty: swit...
252
  	struct ktermios normal_termios;
1c45607ad   Jiri Slaby   Char: mxser, remo...
253

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
254
  	struct mxser_mon mon_data;
1c45607ad   Jiri Slaby   Char: mxser, remo...
255

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
256
  	spinlock_t slock;
1c45607ad   Jiri Slaby   Char: mxser, remo...
257
258
259
260
261
262
263
264
265
266
267
268
269
  };
  
  struct mxser_board {
  	unsigned int idx;
  	int irq;
  	const struct mxser_cardinfo *info;
  	unsigned long vector;
  	unsigned long vector_mask;
  
  	int chip_flag;
  	int uart_type;
  
  	struct mxser_port ports[MXSER_PORTS_PER_BOARD];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
270
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
272
273
274
275
276
277
  struct mxser_mstatus {
  	tcflag_t cflag;
  	int cts;
  	int dsr;
  	int ri;
  	int dcd;
  };
1c45607ad   Jiri Slaby   Char: mxser, remo...
278
  static struct mxser_board mxser_boards[MXSER_BOARDS];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
279
  static struct tty_driver *mxvar_sdriver;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
280
  static struct mxser_log mxvar_log;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
281
  static int mxser_set_baud_method[MXSER_PORTS + 1];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
282

148ff86b1   Christoph Hellwig   mxser: convert la...
283
284
285
286
287
288
289
290
291
292
293
294
295
296
  static void mxser_enable_must_enchance_mode(unsigned long baseio)
  {
  	u8 oldlcr;
  	u8 efr;
  
  	oldlcr = inb(baseio + UART_LCR);
  	outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
  
  	efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
  	efr |= MOXA_MUST_EFR_EFRB_ENABLE;
  
  	outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
  	outb(oldlcr, baseio + UART_LCR);
  }
e89d67cfb   Rakib Mullick   drivers/char/mxse...
297
  #ifdef	CONFIG_PCI
148ff86b1   Christoph Hellwig   mxser: convert la...
298
299
300
301
302
303
304
305
306
307
308
309
310
311
  static void mxser_disable_must_enchance_mode(unsigned long baseio)
  {
  	u8 oldlcr;
  	u8 efr;
  
  	oldlcr = inb(baseio + UART_LCR);
  	outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
  
  	efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
  	efr &= ~MOXA_MUST_EFR_EFRB_ENABLE;
  
  	outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
  	outb(oldlcr, baseio + UART_LCR);
  }
e89d67cfb   Rakib Mullick   drivers/char/mxse...
312
  #endif
148ff86b1   Christoph Hellwig   mxser: convert la...
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
  
  static void mxser_set_must_xon1_value(unsigned long baseio, u8 value)
  {
  	u8 oldlcr;
  	u8 efr;
  
  	oldlcr = inb(baseio + UART_LCR);
  	outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
  
  	efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
  	efr &= ~MOXA_MUST_EFR_BANK_MASK;
  	efr |= MOXA_MUST_EFR_BANK0;
  
  	outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
  	outb(value, baseio + MOXA_MUST_XON1_REGISTER);
  	outb(oldlcr, baseio + UART_LCR);
  }
  
  static void mxser_set_must_xoff1_value(unsigned long baseio, u8 value)
  {
  	u8 oldlcr;
  	u8 efr;
  
  	oldlcr = inb(baseio + UART_LCR);
  	outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
  
  	efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
  	efr &= ~MOXA_MUST_EFR_BANK_MASK;
  	efr |= MOXA_MUST_EFR_BANK0;
  
  	outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
  	outb(value, baseio + MOXA_MUST_XOFF1_REGISTER);
  	outb(oldlcr, baseio + UART_LCR);
  }
  
  static void mxser_set_must_fifo_value(struct mxser_port *info)
  {
  	u8 oldlcr;
  	u8 efr;
  
  	oldlcr = inb(info->ioaddr + UART_LCR);
  	outb(MOXA_MUST_ENTER_ENCHANCE, info->ioaddr + UART_LCR);
  
  	efr = inb(info->ioaddr + MOXA_MUST_EFR_REGISTER);
  	efr &= ~MOXA_MUST_EFR_BANK_MASK;
  	efr |= MOXA_MUST_EFR_BANK1;
  
  	outb(efr, info->ioaddr + MOXA_MUST_EFR_REGISTER);
  	outb((u8)info->rx_high_water, info->ioaddr + MOXA_MUST_RBRTH_REGISTER);
  	outb((u8)info->rx_trigger, info->ioaddr + MOXA_MUST_RBRTI_REGISTER);
  	outb((u8)info->rx_low_water, info->ioaddr + MOXA_MUST_RBRTL_REGISTER);
  	outb(oldlcr, info->ioaddr + UART_LCR);
  }
  
  static void mxser_set_must_enum_value(unsigned long baseio, u8 value)
  {
  	u8 oldlcr;
  	u8 efr;
  
  	oldlcr = inb(baseio + UART_LCR);
  	outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
  
  	efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
  	efr &= ~MOXA_MUST_EFR_BANK_MASK;
  	efr |= MOXA_MUST_EFR_BANK2;
  
  	outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
  	outb(value, baseio + MOXA_MUST_ENUM_REGISTER);
  	outb(oldlcr, baseio + UART_LCR);
  }
e89d67cfb   Rakib Mullick   drivers/char/mxse...
383
  #ifdef CONFIG_PCI
148ff86b1   Christoph Hellwig   mxser: convert la...
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
  static void mxser_get_must_hardware_id(unsigned long baseio, u8 *pId)
  {
  	u8 oldlcr;
  	u8 efr;
  
  	oldlcr = inb(baseio + UART_LCR);
  	outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
  
  	efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
  	efr &= ~MOXA_MUST_EFR_BANK_MASK;
  	efr |= MOXA_MUST_EFR_BANK2;
  
  	outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
  	*pId = inb(baseio + MOXA_MUST_HWID_REGISTER);
  	outb(oldlcr, baseio + UART_LCR);
  }
e89d67cfb   Rakib Mullick   drivers/char/mxse...
400
  #endif
148ff86b1   Christoph Hellwig   mxser: convert la...
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
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 void SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(unsigned long baseio)
  {
  	u8 oldlcr;
  	u8 efr;
  
  	oldlcr = inb(baseio + UART_LCR);
  	outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
  
  	efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
  	efr &= ~MOXA_MUST_EFR_SF_MASK;
  
  	outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
  	outb(oldlcr, baseio + UART_LCR);
  }
  
  static void mxser_enable_must_tx_software_flow_control(unsigned long baseio)
  {
  	u8 oldlcr;
  	u8 efr;
  
  	oldlcr = inb(baseio + UART_LCR);
  	outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
  
  	efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
  	efr &= ~MOXA_MUST_EFR_SF_TX_MASK;
  	efr |= MOXA_MUST_EFR_SF_TX1;
  
  	outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
  	outb(oldlcr, baseio + UART_LCR);
  }
  
  static void mxser_disable_must_tx_software_flow_control(unsigned long baseio)
  {
  	u8 oldlcr;
  	u8 efr;
  
  	oldlcr = inb(baseio + UART_LCR);
  	outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
  
  	efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
  	efr &= ~MOXA_MUST_EFR_SF_TX_MASK;
  
  	outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
  	outb(oldlcr, baseio + UART_LCR);
  }
  
  static void mxser_enable_must_rx_software_flow_control(unsigned long baseio)
  {
  	u8 oldlcr;
  	u8 efr;
  
  	oldlcr = inb(baseio + UART_LCR);
  	outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
  
  	efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
  	efr &= ~MOXA_MUST_EFR_SF_RX_MASK;
  	efr |= MOXA_MUST_EFR_SF_RX1;
  
  	outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
  	outb(oldlcr, baseio + UART_LCR);
  }
  
  static void mxser_disable_must_rx_software_flow_control(unsigned long baseio)
  {
  	u8 oldlcr;
  	u8 efr;
  
  	oldlcr = inb(baseio + UART_LCR);
  	outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
  
  	efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
  	efr &= ~MOXA_MUST_EFR_SF_RX_MASK;
  
  	outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
  	outb(oldlcr, baseio + UART_LCR);
  }
b8cc55493   Jesper Juhl   mxser: fix compil...
478
  #ifdef CONFIG_PCI
1c45607ad   Jiri Slaby   Char: mxser, remo...
479
  static int __devinit CheckIsMoxaMust(unsigned long io)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
480
481
482
483
484
  {
  	u8 oldmcr, hwid;
  	int i;
  
  	outb(0, io + UART_LCR);
148ff86b1   Christoph Hellwig   mxser: convert la...
485
  	mxser_disable_must_enchance_mode(io);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
486
487
  	oldmcr = inb(io + UART_MCR);
  	outb(0, io + UART_MCR);
148ff86b1   Christoph Hellwig   mxser: convert la...
488
  	mxser_set_must_xon1_value(io, 0x11);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
489
490
  	if ((hwid = inb(io + UART_MCR)) != 0) {
  		outb(oldmcr, io + UART_MCR);
8ea2c2ecf   Jesper Juhl   [PATCH] moxa: par...
491
  		return MOXA_OTHER_UART;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
492
  	}
148ff86b1   Christoph Hellwig   mxser: convert la...
493
  	mxser_get_must_hardware_id(io, &hwid);
1c45607ad   Jiri Slaby   Char: mxser, remo...
494
495
  	for (i = 1; i < UART_INFO_NUM; i++) { /* 0 = OTHER_UART */
  		if (hwid == Gpci_uart_info[i].type)
8ea2c2ecf   Jesper Juhl   [PATCH] moxa: par...
496
  			return (int)hwid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
497
498
499
  	}
  	return MOXA_OTHER_UART;
  }
b8cc55493   Jesper Juhl   mxser: fix compil...
500
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
501

1c45607ad   Jiri Slaby   Char: mxser, remo...
502
  static void process_txrx_fifo(struct mxser_port *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
503
504
505
506
507
508
509
510
  {
  	int i;
  
  	if ((info->type == PORT_16450) || (info->type == PORT_8250)) {
  		info->rx_trigger = 1;
  		info->rx_high_water = 1;
  		info->rx_low_water = 1;
  		info->xmit_fifo_size = 1;
1c45607ad   Jiri Slaby   Char: mxser, remo...
511
512
513
  	} else
  		for (i = 0; i < UART_INFO_NUM; i++)
  			if (info->board->chip_flag == Gpci_uart_info[i].type) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
514
515
516
517
518
519
  				info->rx_trigger = Gpci_uart_info[i].rx_trigger;
  				info->rx_low_water = Gpci_uart_info[i].rx_low_water;
  				info->rx_high_water = Gpci_uart_info[i].rx_high_water;
  				info->xmit_fifo_size = Gpci_uart_info[i].xmit_fifo_size;
  				break;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
520
  }
1c45607ad   Jiri Slaby   Char: mxser, remo...
521
  static unsigned char mxser_get_msr(int baseaddr, int mode, int port)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
522
  {
72800df9b   Jiri Slaby   Char: mxser, glob...
523
  	static unsigned char mxser_msr[MXSER_PORTS + 1];
1c45607ad   Jiri Slaby   Char: mxser, remo...
524
  	unsigned char status = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
525

1c45607ad   Jiri Slaby   Char: mxser, remo...
526
  	status = inb(baseaddr + UART_MSR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
527

1c45607ad   Jiri Slaby   Char: mxser, remo...
528
529
530
531
532
  	mxser_msr[port] &= 0x0F;
  	mxser_msr[port] |= status;
  	status = mxser_msr[port];
  	if (mode)
  		mxser_msr[port] = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
533

1c45607ad   Jiri Slaby   Char: mxser, remo...
534
535
  	return status;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
536

31f35939d   Alan Cox   tty_port: Add a p...
537
538
539
540
541
  static int mxser_carrier_raised(struct tty_port *port)
  {
  	struct mxser_port *mp = container_of(port, struct mxser_port, port);
  	return (inb(mp->ioaddr + UART_MSR) & UART_MSR_DCD)?1:0;
  }
fcc8ac182   Alan Cox   tty: Add carrier ...
542
  static void mxser_dtr_rts(struct tty_port *port, int on)
5d951fb45   Alan Cox   tty: Pull the dtr...
543
544
545
546
547
  {
  	struct mxser_port *mp = container_of(port, struct mxser_port, port);
  	unsigned long flags;
  
  	spin_lock_irqsave(&mp->slock, flags);
fcc8ac182   Alan Cox   tty: Add carrier ...
548
549
550
551
552
553
  	if (on)
  		outb(inb(mp->ioaddr + UART_MCR) |
  			UART_MCR_DTR | UART_MCR_RTS, mp->ioaddr + UART_MCR);
  	else
  		outb(inb(mp->ioaddr + UART_MCR)&~(UART_MCR_DTR | UART_MCR_RTS),
  			mp->ioaddr + UART_MCR);
5d951fb45   Alan Cox   tty: Pull the dtr...
554
555
  	spin_unlock_irqrestore(&mp->slock, flags);
  }
216ba023a   Alan Cox   mxser: Switch to ...
556
  static int mxser_set_baud(struct tty_struct *tty, long newspd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
557
  {
216ba023a   Alan Cox   mxser: Switch to ...
558
  	struct mxser_port *info = tty->driver_data;
1c45607ad   Jiri Slaby   Char: mxser, remo...
559
560
  	int quot = 0, baud;
  	unsigned char cval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
561

216ba023a   Alan Cox   mxser: Switch to ...
562
  	if (!info->ioaddr)
1c45607ad   Jiri Slaby   Char: mxser, remo...
563
  		return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
564

1c45607ad   Jiri Slaby   Char: mxser, remo...
565
566
  	if (newspd > info->max_baud)
  		return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
567

1c45607ad   Jiri Slaby   Char: mxser, remo...
568
569
  	if (newspd == 134) {
  		quot = 2 * info->baud_base / 269;
216ba023a   Alan Cox   mxser: Switch to ...
570
  		tty_encode_baud_rate(tty, 134, 134);
1c45607ad   Jiri Slaby   Char: mxser, remo...
571
572
573
574
575
  	} else if (newspd) {
  		quot = info->baud_base / newspd;
  		if (quot == 0)
  			quot = 1;
  		baud = info->baud_base/quot;
216ba023a   Alan Cox   mxser: Switch to ...
576
  		tty_encode_baud_rate(tty, baud, baud);
1c45607ad   Jiri Slaby   Char: mxser, remo...
577
578
579
  	} else {
  		quot = 0;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
580

1c45607ad   Jiri Slaby   Char: mxser, remo...
581
582
  	info->timeout = ((info->xmit_fifo_size * HZ * 10 * quot) / info->baud_base);
  	info->timeout += HZ / 50;	/* Add .02 seconds of slop */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
583

1c45607ad   Jiri Slaby   Char: mxser, remo...
584
585
586
587
588
589
590
591
  	if (quot) {
  		info->MCR |= UART_MCR_DTR;
  		outb(info->MCR, info->ioaddr + UART_MCR);
  	} else {
  		info->MCR &= ~UART_MCR_DTR;
  		outb(info->MCR, info->ioaddr + UART_MCR);
  		return 0;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
592

1c45607ad   Jiri Slaby   Char: mxser, remo...
593
  	cval = inb(info->ioaddr + UART_LCR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
594

1c45607ad   Jiri Slaby   Char: mxser, remo...
595
  	outb(cval | UART_LCR_DLAB, info->ioaddr + UART_LCR);	/* set DLAB */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
596

1c45607ad   Jiri Slaby   Char: mxser, remo...
597
598
599
  	outb(quot & 0xff, info->ioaddr + UART_DLL);	/* LS of divisor */
  	outb(quot >> 8, info->ioaddr + UART_DLM);	/* MS of divisor */
  	outb(cval, info->ioaddr + UART_LCR);	/* reset DLAB */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
600

1c45607ad   Jiri Slaby   Char: mxser, remo...
601
  #ifdef BOTHER
216ba023a   Alan Cox   mxser: Switch to ...
602
  	if (C_BAUD(tty) == BOTHER) {
1c45607ad   Jiri Slaby   Char: mxser, remo...
603
604
605
606
607
608
609
  		quot = info->baud_base % newspd;
  		quot *= 8;
  		if (quot % newspd > newspd / 2) {
  			quot /= newspd;
  			quot++;
  		} else
  			quot /= newspd;
148ff86b1   Christoph Hellwig   mxser: convert la...
610
  		mxser_set_must_enum_value(info->ioaddr, quot);
1c45607ad   Jiri Slaby   Char: mxser, remo...
611
612
  	} else
  #endif
148ff86b1   Christoph Hellwig   mxser: convert la...
613
  		mxser_set_must_enum_value(info->ioaddr, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
614

8ea2c2ecf   Jesper Juhl   [PATCH] moxa: par...
615
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
616
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
617

1c45607ad   Jiri Slaby   Char: mxser, remo...
618
619
620
621
  /*
   * This routine is called to set the UART divisor registers to match
   * the specified baud rate for a serial port.
   */
216ba023a   Alan Cox   mxser: Switch to ...
622
623
  static int mxser_change_speed(struct tty_struct *tty,
  					struct ktermios *old_termios)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
624
  {
216ba023a   Alan Cox   mxser: Switch to ...
625
  	struct mxser_port *info = tty->driver_data;
1c45607ad   Jiri Slaby   Char: mxser, remo...
626
627
628
  	unsigned cflag, cval, fcr;
  	int ret = 0;
  	unsigned char status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
629

216ba023a   Alan Cox   mxser: Switch to ...
630
631
  	cflag = tty->termios->c_cflag;
  	if (!info->ioaddr)
1c45607ad   Jiri Slaby   Char: mxser, remo...
632
  		return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
633

216ba023a   Alan Cox   mxser: Switch to ...
634
635
  	if (mxser_set_baud_method[tty->index] == 0)
  		mxser_set_baud(tty, tty_get_baud_rate(tty));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
636

1c45607ad   Jiri Slaby   Char: mxser, remo...
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
  	/* byte size and parity */
  	switch (cflag & CSIZE) {
  	case CS5:
  		cval = 0x00;
  		break;
  	case CS6:
  		cval = 0x01;
  		break;
  	case CS7:
  		cval = 0x02;
  		break;
  	case CS8:
  		cval = 0x03;
  		break;
  	default:
  		cval = 0x00;
  		break;		/* too keep GCC shut... */
  	}
  	if (cflag & CSTOPB)
  		cval |= 0x04;
  	if (cflag & PARENB)
  		cval |= UART_LCR_PARITY;
  	if (!(cflag & PARODD))
  		cval |= UART_LCR_EPAR;
  	if (cflag & CMSPAR)
  		cval |= UART_LCR_SPAR;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
663

1c45607ad   Jiri Slaby   Char: mxser, remo...
664
665
666
667
  	if ((info->type == PORT_8250) || (info->type == PORT_16450)) {
  		if (info->board->chip_flag) {
  			fcr = UART_FCR_ENABLE_FIFO;
  			fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE;
148ff86b1   Christoph Hellwig   mxser: convert la...
668
  			mxser_set_must_fifo_value(info);
1c45607ad   Jiri Slaby   Char: mxser, remo...
669
670
671
672
673
674
  		} else
  			fcr = 0;
  	} else {
  		fcr = UART_FCR_ENABLE_FIFO;
  		if (info->board->chip_flag) {
  			fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE;
148ff86b1   Christoph Hellwig   mxser: convert la...
675
  			mxser_set_must_fifo_value(info);
1c45607ad   Jiri Slaby   Char: mxser, remo...
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
  		} else {
  			switch (info->rx_trigger) {
  			case 1:
  				fcr |= UART_FCR_TRIGGER_1;
  				break;
  			case 4:
  				fcr |= UART_FCR_TRIGGER_4;
  				break;
  			case 8:
  				fcr |= UART_FCR_TRIGGER_8;
  				break;
  			default:
  				fcr |= UART_FCR_TRIGGER_14;
  				break;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
691
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
692
  	}
1c45607ad   Jiri Slaby   Char: mxser, remo...
693
694
695
696
  	/* CTS flow control flag and modem status interrupts */
  	info->IER &= ~UART_IER_MSI;
  	info->MCR &= ~UART_MCR_AFE;
  	if (cflag & CRTSCTS) {
0ad9e7d1d   Alan Cox   mxser: use tty_port
697
  		info->port.flags |= ASYNC_CTS_FLOW;
1c45607ad   Jiri Slaby   Char: mxser, remo...
698
699
700
701
702
  		info->IER |= UART_IER_MSI;
  		if ((info->type == PORT_16550A) || (info->board->chip_flag)) {
  			info->MCR |= UART_MCR_AFE;
  		} else {
  			status = inb(info->ioaddr + UART_MSR);
216ba023a   Alan Cox   mxser: Switch to ...
703
  			if (tty->hw_stopped) {
1c45607ad   Jiri Slaby   Char: mxser, remo...
704
  				if (status & UART_MSR_CTS) {
216ba023a   Alan Cox   mxser: Switch to ...
705
  					tty->hw_stopped = 0;
1c45607ad   Jiri Slaby   Char: mxser, remo...
706
707
708
709
710
711
712
713
714
  					if (info->type != PORT_16550A &&
  							!info->board->chip_flag) {
  						outb(info->IER & ~UART_IER_THRI,
  							info->ioaddr +
  							UART_IER);
  						info->IER |= UART_IER_THRI;
  						outb(info->IER, info->ioaddr +
  								UART_IER);
  					}
216ba023a   Alan Cox   mxser: Switch to ...
715
  					tty_wakeup(tty);
1c45607ad   Jiri Slaby   Char: mxser, remo...
716
717
718
  				}
  			} else {
  				if (!(status & UART_MSR_CTS)) {
216ba023a   Alan Cox   mxser: Switch to ...
719
  					tty->hw_stopped = 1;
1c45607ad   Jiri Slaby   Char: mxser, remo...
720
721
722
723
724
725
726
727
  					if ((info->type != PORT_16550A) &&
  							(!info->board->chip_flag)) {
  						info->IER &= ~UART_IER_THRI;
  						outb(info->IER, info->ioaddr +
  								UART_IER);
  					}
  				}
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
728
  		}
1c45607ad   Jiri Slaby   Char: mxser, remo...
729
  	} else {
0ad9e7d1d   Alan Cox   mxser: use tty_port
730
  		info->port.flags &= ~ASYNC_CTS_FLOW;
1c45607ad   Jiri Slaby   Char: mxser, remo...
731
732
733
  	}
  	outb(info->MCR, info->ioaddr + UART_MCR);
  	if (cflag & CLOCAL) {
0ad9e7d1d   Alan Cox   mxser: use tty_port
734
  		info->port.flags &= ~ASYNC_CHECK_CD;
1c45607ad   Jiri Slaby   Char: mxser, remo...
735
  	} else {
0ad9e7d1d   Alan Cox   mxser: use tty_port
736
  		info->port.flags |= ASYNC_CHECK_CD;
1c45607ad   Jiri Slaby   Char: mxser, remo...
737
738
739
740
741
742
743
744
  		info->IER |= UART_IER_MSI;
  	}
  	outb(info->IER, info->ioaddr + UART_IER);
  
  	/*
  	 * Set up parity check flag
  	 */
  	info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
216ba023a   Alan Cox   mxser: Switch to ...
745
  	if (I_INPCK(tty))
1c45607ad   Jiri Slaby   Char: mxser, remo...
746
  		info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
216ba023a   Alan Cox   mxser: Switch to ...
747
  	if (I_BRKINT(tty) || I_PARMRK(tty))
1c45607ad   Jiri Slaby   Char: mxser, remo...
748
  		info->read_status_mask |= UART_LSR_BI;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
749

1c45607ad   Jiri Slaby   Char: mxser, remo...
750
  	info->ignore_status_mask = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
751

216ba023a   Alan Cox   mxser: Switch to ...
752
  	if (I_IGNBRK(tty)) {
1c45607ad   Jiri Slaby   Char: mxser, remo...
753
754
  		info->ignore_status_mask |= UART_LSR_BI;
  		info->read_status_mask |= UART_LSR_BI;
8ea2c2ecf   Jesper Juhl   [PATCH] moxa: par...
755
  		/*
1c45607ad   Jiri Slaby   Char: mxser, remo...
756
757
  		 * If we're ignore parity and break indicators, ignore
  		 * overruns too.  (For real raw support).
8ea2c2ecf   Jesper Juhl   [PATCH] moxa: par...
758
  		 */
216ba023a   Alan Cox   mxser: Switch to ...
759
  		if (I_IGNPAR(tty)) {
1c45607ad   Jiri Slaby   Char: mxser, remo...
760
761
762
763
764
765
766
767
768
  			info->ignore_status_mask |=
  						UART_LSR_OE |
  						UART_LSR_PE |
  						UART_LSR_FE;
  			info->read_status_mask |=
  						UART_LSR_OE |
  						UART_LSR_PE |
  						UART_LSR_FE;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
769
  	}
1c45607ad   Jiri Slaby   Char: mxser, remo...
770
  	if (info->board->chip_flag) {
216ba023a   Alan Cox   mxser: Switch to ...
771
772
773
  		mxser_set_must_xon1_value(info->ioaddr, START_CHAR(tty));
  		mxser_set_must_xoff1_value(info->ioaddr, STOP_CHAR(tty));
  		if (I_IXON(tty)) {
148ff86b1   Christoph Hellwig   mxser: convert la...
774
775
  			mxser_enable_must_rx_software_flow_control(
  					info->ioaddr);
1c45607ad   Jiri Slaby   Char: mxser, remo...
776
  		} else {
148ff86b1   Christoph Hellwig   mxser: convert la...
777
778
  			mxser_disable_must_rx_software_flow_control(
  					info->ioaddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
779
  		}
216ba023a   Alan Cox   mxser: Switch to ...
780
  		if (I_IXOFF(tty)) {
148ff86b1   Christoph Hellwig   mxser: convert la...
781
782
  			mxser_enable_must_tx_software_flow_control(
  					info->ioaddr);
1c45607ad   Jiri Slaby   Char: mxser, remo...
783
  		} else {
148ff86b1   Christoph Hellwig   mxser: convert la...
784
785
  			mxser_disable_must_tx_software_flow_control(
  					info->ioaddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
786
787
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
788

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
789

1c45607ad   Jiri Slaby   Char: mxser, remo...
790
791
  	outb(fcr, info->ioaddr + UART_FCR);	/* set fcr */
  	outb(cval, info->ioaddr + UART_LCR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
792

1c45607ad   Jiri Slaby   Char: mxser, remo...
793
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
794
  }
216ba023a   Alan Cox   mxser: Switch to ...
795
796
  static void mxser_check_modem_status(struct tty_struct *tty,
  				struct mxser_port *port, int status)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
797
  {
1c45607ad   Jiri Slaby   Char: mxser, remo...
798
799
800
801
802
803
804
805
806
807
  	/* update input line counters */
  	if (status & UART_MSR_TERI)
  		port->icount.rng++;
  	if (status & UART_MSR_DDSR)
  		port->icount.dsr++;
  	if (status & UART_MSR_DDCD)
  		port->icount.dcd++;
  	if (status & UART_MSR_DCTS)
  		port->icount.cts++;
  	port->mon_data.modem_status = status;
bdc04e317   Alan Cox   serial: move delt...
808
  	wake_up_interruptible(&port->port.delta_msr_wait);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
809

0ad9e7d1d   Alan Cox   mxser: use tty_port
810
  	if ((port->port.flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
1c45607ad   Jiri Slaby   Char: mxser, remo...
811
  		if (status & UART_MSR_DCD)
0ad9e7d1d   Alan Cox   mxser: use tty_port
812
  			wake_up_interruptible(&port->port.open_wait);
1c45607ad   Jiri Slaby   Char: mxser, remo...
813
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
814

0ad9e7d1d   Alan Cox   mxser: use tty_port
815
  	if (port->port.flags & ASYNC_CTS_FLOW) {
216ba023a   Alan Cox   mxser: Switch to ...
816
  		if (tty->hw_stopped) {
1c45607ad   Jiri Slaby   Char: mxser, remo...
817
  			if (status & UART_MSR_CTS) {
216ba023a   Alan Cox   mxser: Switch to ...
818
  				tty->hw_stopped = 0;
1c45607ad   Jiri Slaby   Char: mxser, remo...
819
820
821
822
823
824
825
826
827
  
  				if ((port->type != PORT_16550A) &&
  						(!port->board->chip_flag)) {
  					outb(port->IER & ~UART_IER_THRI,
  						port->ioaddr + UART_IER);
  					port->IER |= UART_IER_THRI;
  					outb(port->IER, port->ioaddr +
  							UART_IER);
  				}
216ba023a   Alan Cox   mxser: Switch to ...
828
  				tty_wakeup(tty);
1c45607ad   Jiri Slaby   Char: mxser, remo...
829
830
831
  			}
  		} else {
  			if (!(status & UART_MSR_CTS)) {
216ba023a   Alan Cox   mxser: Switch to ...
832
  				tty->hw_stopped = 1;
1c45607ad   Jiri Slaby   Char: mxser, remo...
833
834
835
836
837
838
839
840
  				if (port->type != PORT_16550A &&
  						!port->board->chip_flag) {
  					port->IER &= ~UART_IER_THRI;
  					outb(port->IER, port->ioaddr +
  							UART_IER);
  				}
  			}
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
841
842
  	}
  }
6769140d3   Alan Cox   tty: mxser: use t...
843
  static int mxser_activate(struct tty_port *port, struct tty_struct *tty)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
844
  {
6769140d3   Alan Cox   tty: mxser: use t...
845
  	struct mxser_port *info = container_of(port, struct mxser_port, port);
1c45607ad   Jiri Slaby   Char: mxser, remo...
846
847
  	unsigned long page;
  	unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
848

1c45607ad   Jiri Slaby   Char: mxser, remo...
849
850
851
  	page = __get_free_page(GFP_KERNEL);
  	if (!page)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
852

1c45607ad   Jiri Slaby   Char: mxser, remo...
853
  	spin_lock_irqsave(&info->slock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
854

1c45607ad   Jiri Slaby   Char: mxser, remo...
855
  	if (!info->ioaddr || !info->type) {
216ba023a   Alan Cox   mxser: Switch to ...
856
  		set_bit(TTY_IO_ERROR, &tty->flags);
1c45607ad   Jiri Slaby   Char: mxser, remo...
857
858
  		free_page(page);
  		spin_unlock_irqrestore(&info->slock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
859
  		return 0;
1c45607ad   Jiri Slaby   Char: mxser, remo...
860
  	}
6769140d3   Alan Cox   tty: mxser: use t...
861
  	info->port.xmit_buf = (unsigned char *) page;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
862

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
863
  	/*
1c45607ad   Jiri Slaby   Char: mxser, remo...
864
865
  	 * Clear the FIFO buffers and disable them
  	 * (they will be reenabled in mxser_change_speed())
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
866
  	 */
1c45607ad   Jiri Slaby   Char: mxser, remo...
867
868
869
870
871
872
873
  	if (info->board->chip_flag)
  		outb((UART_FCR_CLEAR_RCVR |
  			UART_FCR_CLEAR_XMIT |
  			MOXA_MUST_FCR_GDA_MODE_ENABLE), info->ioaddr + UART_FCR);
  	else
  		outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
  			info->ioaddr + UART_FCR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
874

1c45607ad   Jiri Slaby   Char: mxser, remo...
875
876
877
878
879
880
881
882
  	/*
  	 * At this point there's no way the LSR could still be 0xFF;
  	 * if it is, then bail out, because there's likely no UART
  	 * here.
  	 */
  	if (inb(info->ioaddr + UART_LSR) == 0xff) {
  		spin_unlock_irqrestore(&info->slock, flags);
  		if (capable(CAP_SYS_ADMIN)) {
f43a510de   Jiri Slaby   tty: char: mxser,...
883
  			set_bit(TTY_IO_ERROR, &tty->flags);
1c45607ad   Jiri Slaby   Char: mxser, remo...
884
885
886
887
  			return 0;
  		} else
  			return -ENODEV;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
888

1c45607ad   Jiri Slaby   Char: mxser, remo...
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
  	/*
  	 * Clear the interrupt registers.
  	 */
  	(void) inb(info->ioaddr + UART_LSR);
  	(void) inb(info->ioaddr + UART_RX);
  	(void) inb(info->ioaddr + UART_IIR);
  	(void) inb(info->ioaddr + UART_MSR);
  
  	/*
  	 * Now, initialize the UART
  	 */
  	outb(UART_LCR_WLEN8, info->ioaddr + UART_LCR);	/* reset DLAB */
  	info->MCR = UART_MCR_DTR | UART_MCR_RTS;
  	outb(info->MCR, info->ioaddr + UART_MCR);
  
  	/*
  	 * Finally, enable interrupts
  	 */
  	info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
  
  	if (info->board->chip_flag)
  		info->IER |= MOXA_MUST_IER_EGDAI;
  	outb(info->IER, info->ioaddr + UART_IER);	/* enable interrupts */
  
  	/*
  	 * And clear the interrupt registers again for luck.
  	 */
  	(void) inb(info->ioaddr + UART_LSR);
  	(void) inb(info->ioaddr + UART_RX);
  	(void) inb(info->ioaddr + UART_IIR);
  	(void) inb(info->ioaddr + UART_MSR);
216ba023a   Alan Cox   mxser: Switch to ...
920
  	clear_bit(TTY_IO_ERROR, &tty->flags);
1c45607ad   Jiri Slaby   Char: mxser, remo...
921
922
923
924
925
  	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
  
  	/*
  	 * and set the speed of the serial port
  	 */
216ba023a   Alan Cox   mxser: Switch to ...
926
  	mxser_change_speed(tty, NULL);
1c45607ad   Jiri Slaby   Char: mxser, remo...
927
928
929
930
931
932
  	spin_unlock_irqrestore(&info->slock, flags);
  
  	return 0;
  }
  
  /*
6769140d3   Alan Cox   tty: mxser: use t...
933
   * This routine will shutdown a serial port
1c45607ad   Jiri Slaby   Char: mxser, remo...
934
   */
6769140d3   Alan Cox   tty: mxser: use t...
935
  static void mxser_shutdown_port(struct tty_port *port)
1c45607ad   Jiri Slaby   Char: mxser, remo...
936
  {
6769140d3   Alan Cox   tty: mxser: use t...
937
  	struct mxser_port *info = container_of(port, struct mxser_port, port);
1c45607ad   Jiri Slaby   Char: mxser, remo...
938
  	unsigned long flags;
1c45607ad   Jiri Slaby   Char: mxser, remo...
939
940
941
942
943
944
  	spin_lock_irqsave(&info->slock, flags);
  
  	/*
  	 * clear delta_msr_wait queue to avoid mem leaks: we may free the irq
  	 * here so the queue might never be waken up
  	 */
bdc04e317   Alan Cox   serial: move delt...
945
  	wake_up_interruptible(&info->port.delta_msr_wait);
1c45607ad   Jiri Slaby   Char: mxser, remo...
946
947
  
  	/*
6769140d3   Alan Cox   tty: mxser: use t...
948
  	 * Free the xmit buffer, if necessary
1c45607ad   Jiri Slaby   Char: mxser, remo...
949
  	 */
0ad9e7d1d   Alan Cox   mxser: use tty_port
950
951
952
  	if (info->port.xmit_buf) {
  		free_page((unsigned long) info->port.xmit_buf);
  		info->port.xmit_buf = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
953
  	}
1c45607ad   Jiri Slaby   Char: mxser, remo...
954
955
  	info->IER = 0;
  	outb(0x00, info->ioaddr + UART_IER);
1c45607ad   Jiri Slaby   Char: mxser, remo...
956
957
958
959
960
961
962
963
964
965
966
  	/* clear Rx/Tx FIFO's */
  	if (info->board->chip_flag)
  		outb(UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT |
  				MOXA_MUST_FCR_GDA_MODE_ENABLE,
  				info->ioaddr + UART_FCR);
  	else
  		outb(UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
  			info->ioaddr + UART_FCR);
  
  	/* read data port to reset things */
  	(void) inb(info->ioaddr + UART_RX);
1c45607ad   Jiri Slaby   Char: mxser, remo...
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
  
  	if (info->board->chip_flag)
  		SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(info->ioaddr);
  
  	spin_unlock_irqrestore(&info->slock, flags);
  }
  
  /*
   * This routine is called whenever a serial port is opened.  It
   * enables interrupts for a serial port, linking in its async structure into
   * the IRQ chain.   It also performs the serial-specific
   * initialization for the tty structure.
   */
  static int mxser_open(struct tty_struct *tty, struct file *filp)
  {
  	struct mxser_port *info;
6769140d3   Alan Cox   tty: mxser: use t...
983
  	int line;
1c45607ad   Jiri Slaby   Char: mxser, remo...
984
985
986
987
988
989
990
991
992
  
  	line = tty->index;
  	if (line == MXSER_PORTS)
  		return 0;
  	if (line < 0 || line > MXSER_PORTS)
  		return -ENODEV;
  	info = &mxser_boards[line / MXSER_PORTS_PER_BOARD].ports[line % MXSER_PORTS_PER_BOARD];
  	if (!info->ioaddr)
  		return -ENODEV;
a2d1e3516   Alan Cox   tty: Fix regressi...
993
  	tty->driver_data = info;
6769140d3   Alan Cox   tty: mxser: use t...
994
  	return tty_port_open(&info->port, tty, filp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
995
  }
978e595f8   Alan Cox   tty/serial: lay t...
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
  static void mxser_flush_buffer(struct tty_struct *tty)
  {
  	struct mxser_port *info = tty->driver_data;
  	char fcr;
  	unsigned long flags;
  
  
  	spin_lock_irqsave(&info->slock, flags);
  	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
  
  	fcr = inb(info->ioaddr + UART_FCR);
  	outb((fcr | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
  		info->ioaddr + UART_FCR);
  	outb(fcr, info->ioaddr + UART_FCR);
  
  	spin_unlock_irqrestore(&info->slock, flags);
  
  	tty_wakeup(tty);
  }
6769140d3   Alan Cox   tty: mxser: use t...
1015
  static void mxser_close_port(struct tty_port *port)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1016
  {
1e2b02545   Alan Cox   mxser: Split clos...
1017
  	struct mxser_port *info = container_of(port, struct mxser_port, port);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1018
  	unsigned long timeout;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1019
  	/*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1020
1021
1022
1023
1024
1025
  	 * At this point we stop accepting input.  To do this, we
  	 * disable the receive line status interrupts, and tell the
  	 * interrupt driver to stop checking the data ready bit in the
  	 * line status register.
  	 */
  	info->IER &= ~UART_IER_RLSI;
1c45607ad   Jiri Slaby   Char: mxser, remo...
1026
  	if (info->board->chip_flag)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1027
  		info->IER &= ~MOXA_MUST_RECV_ISR;
1c45607ad   Jiri Slaby   Char: mxser, remo...
1028

6769140d3   Alan Cox   tty: mxser: use t...
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
  	outb(info->IER, info->ioaddr + UART_IER);
  	/*
  	 * Before we drop DTR, make sure the UART transmitter
  	 * has completely drained; this is especially
  	 * important if there is a transmit FIFO!
  	 */
  	timeout = jiffies + HZ;
  	while (!(inb(info->ioaddr + UART_LSR) & UART_LSR_TEMT)) {
  		schedule_timeout_interruptible(5);
  		if (time_after(jiffies, timeout))
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1040
  	}
1e2b02545   Alan Cox   mxser: Split clos...
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
  }
  
  /*
   * This routine is called when the serial port gets closed.  First, we
   * wait for the last remaining data to be sent.  Then, we unlink its
   * async structure from the interrupt chain if necessary, and we free
   * that IRQ if nothing is left in the chain.
   */
  static void mxser_close(struct tty_struct *tty, struct file *filp)
  {
  	struct mxser_port *info = tty->driver_data;
  	struct tty_port *port = &info->port;
a2d1e3516   Alan Cox   tty: Fix regressi...
1053
  	if (tty->index == MXSER_PORTS || info == NULL)
1e2b02545   Alan Cox   mxser: Split clos...
1054
1055
1056
  		return;
  	if (tty_port_close_start(port, tty, filp) == 0)
  		return;
6769140d3   Alan Cox   tty: mxser: use t...
1057
1058
  	mutex_lock(&port->mutex);
  	mxser_close_port(port);
1e2b02545   Alan Cox   mxser: Split clos...
1059
  	mxser_flush_buffer(tty);
6769140d3   Alan Cox   tty: mxser: use t...
1060
1061
1062
  	mxser_shutdown_port(port);
  	clear_bit(ASYNCB_INITIALIZED, &port->flags);
  	mutex_unlock(&port->mutex);
a6614999e   Alan Cox   tty: Introduce so...
1063
1064
1065
1066
  	/* Right now the tty_port set is done outside of the close_end helper
  	   as we don't yet have everyone using refcounts */	
  	tty_port_close_end(port, tty);
  	tty_port_tty_set(port, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1067
1068
1069
1070
1071
  }
  
  static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int count)
  {
  	int c, total = 0;
1c45607ad   Jiri Slaby   Char: mxser, remo...
1072
  	struct mxser_port *info = tty->driver_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1073
  	unsigned long flags;
0ad9e7d1d   Alan Cox   mxser: use tty_port
1074
  	if (!info->port.xmit_buf)
8ea2c2ecf   Jesper Juhl   [PATCH] moxa: par...
1075
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1076
1077
  
  	while (1) {
8ea2c2ecf   Jesper Juhl   [PATCH] moxa: par...
1078
1079
  		c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
  					  SERIAL_XMIT_SIZE - info->xmit_head));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1080
1081
  		if (c <= 0)
  			break;
0ad9e7d1d   Alan Cox   mxser: use tty_port
1082
  		memcpy(info->port.xmit_buf + info->xmit_head, buf, c);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1083
  		spin_lock_irqsave(&info->slock, flags);
8ea2c2ecf   Jesper Juhl   [PATCH] moxa: par...
1084
1085
  		info->xmit_head = (info->xmit_head + c) &
  				  (SERIAL_XMIT_SIZE - 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1086
1087
1088
1089
1090
1091
  		info->xmit_cnt += c;
  		spin_unlock_irqrestore(&info->slock, flags);
  
  		buf += c;
  		count -= c;
  		total += c;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1092
  	}
1c45607ad   Jiri Slaby   Char: mxser, remo...
1093
  	if (info->xmit_cnt && !tty->stopped) {
8ea2c2ecf   Jesper Juhl   [PATCH] moxa: par...
1094
1095
  		if (!tty->hw_stopped ||
  				(info->type == PORT_16550A) ||
1c45607ad   Jiri Slaby   Char: mxser, remo...
1096
  				(info->board->chip_flag)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1097
  			spin_lock_irqsave(&info->slock, flags);
1c45607ad   Jiri Slaby   Char: mxser, remo...
1098
1099
  			outb(info->IER & ~UART_IER_THRI, info->ioaddr +
  					UART_IER);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1100
  			info->IER |= UART_IER_THRI;
1c45607ad   Jiri Slaby   Char: mxser, remo...
1101
  			outb(info->IER, info->ioaddr + UART_IER);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1102
1103
1104
1105
1106
  			spin_unlock_irqrestore(&info->slock, flags);
  		}
  	}
  	return total;
  }
0be2eadee   Alan Cox   mxser: switch to ...
1107
  static int mxser_put_char(struct tty_struct *tty, unsigned char ch)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1108
  {
1c45607ad   Jiri Slaby   Char: mxser, remo...
1109
  	struct mxser_port *info = tty->driver_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1110
  	unsigned long flags;
0ad9e7d1d   Alan Cox   mxser: use tty_port
1111
  	if (!info->port.xmit_buf)
0be2eadee   Alan Cox   mxser: switch to ...
1112
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1113
1114
  
  	if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1)
0be2eadee   Alan Cox   mxser: switch to ...
1115
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1116
1117
  
  	spin_lock_irqsave(&info->slock, flags);
0ad9e7d1d   Alan Cox   mxser: use tty_port
1118
  	info->port.xmit_buf[info->xmit_head++] = ch;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1119
1120
1121
  	info->xmit_head &= SERIAL_XMIT_SIZE - 1;
  	info->xmit_cnt++;
  	spin_unlock_irqrestore(&info->slock, flags);
1c45607ad   Jiri Slaby   Char: mxser, remo...
1122
  	if (!tty->stopped) {
8ea2c2ecf   Jesper Juhl   [PATCH] moxa: par...
1123
1124
  		if (!tty->hw_stopped ||
  				(info->type == PORT_16550A) ||
1c45607ad   Jiri Slaby   Char: mxser, remo...
1125
  				info->board->chip_flag) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1126
  			spin_lock_irqsave(&info->slock, flags);
1c45607ad   Jiri Slaby   Char: mxser, remo...
1127
  			outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1128
  			info->IER |= UART_IER_THRI;
1c45607ad   Jiri Slaby   Char: mxser, remo...
1129
  			outb(info->IER, info->ioaddr + UART_IER);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1130
1131
1132
  			spin_unlock_irqrestore(&info->slock, flags);
  		}
  	}
0be2eadee   Alan Cox   mxser: switch to ...
1133
  	return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1134
1135
1136
1137
1138
  }
  
  
  static void mxser_flush_chars(struct tty_struct *tty)
  {
1c45607ad   Jiri Slaby   Char: mxser, remo...
1139
  	struct mxser_port *info = tty->driver_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1140
  	unsigned long flags;
ace7dd966   Jiri Slaby   Char: mxser, vari...
1141
1142
1143
  	if (info->xmit_cnt <= 0 || tty->stopped || !info->port.xmit_buf ||
  			(tty->hw_stopped && info->type != PORT_16550A &&
  			 !info->board->chip_flag))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1144
1145
1146
  		return;
  
  	spin_lock_irqsave(&info->slock, flags);
1c45607ad   Jiri Slaby   Char: mxser, remo...
1147
  	outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1148
  	info->IER |= UART_IER_THRI;
1c45607ad   Jiri Slaby   Char: mxser, remo...
1149
  	outb(info->IER, info->ioaddr + UART_IER);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1150
1151
1152
1153
1154
1155
  
  	spin_unlock_irqrestore(&info->slock, flags);
  }
  
  static int mxser_write_room(struct tty_struct *tty)
  {
1c45607ad   Jiri Slaby   Char: mxser, remo...
1156
  	struct mxser_port *info = tty->driver_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1157
1158
1159
  	int ret;
  
  	ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
ace7dd966   Jiri Slaby   Char: mxser, vari...
1160
  	return ret < 0 ? 0 : ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1161
1162
1163
1164
  }
  
  static int mxser_chars_in_buffer(struct tty_struct *tty)
  {
1c45607ad   Jiri Slaby   Char: mxser, remo...
1165
  	struct mxser_port *info = tty->driver_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1166
1167
  	return info->xmit_cnt;
  }
1c45607ad   Jiri Slaby   Char: mxser, remo...
1168
1169
1170
1171
1172
  /*
   * ------------------------------------------------------------
   * friends of mxser_ioctl()
   * ------------------------------------------------------------
   */
216ba023a   Alan Cox   mxser: Switch to ...
1173
  static int mxser_get_serial_info(struct tty_struct *tty,
1c45607ad   Jiri Slaby   Char: mxser, remo...
1174
1175
  		struct serial_struct __user *retinfo)
  {
216ba023a   Alan Cox   mxser: Switch to ...
1176
  	struct mxser_port *info = tty->driver_data;
1c45607ad   Jiri Slaby   Char: mxser, remo...
1177
1178
  	struct serial_struct tmp = {
  		.type = info->type,
216ba023a   Alan Cox   mxser: Switch to ...
1179
  		.line = tty->index,
1c45607ad   Jiri Slaby   Char: mxser, remo...
1180
1181
  		.port = info->ioaddr,
  		.irq = info->board->irq,
0ad9e7d1d   Alan Cox   mxser: use tty_port
1182
  		.flags = info->port.flags,
1c45607ad   Jiri Slaby   Char: mxser, remo...
1183
  		.baud_base = info->baud_base,
44b7d1b37   Alan Cox   tty: add more tty...
1184
1185
  		.close_delay = info->port.close_delay,
  		.closing_wait = info->port.closing_wait,
1c45607ad   Jiri Slaby   Char: mxser, remo...
1186
1187
1188
1189
1190
1191
1192
  		.custom_divisor = info->custom_divisor,
  		.hub6 = 0
  	};
  	if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
  		return -EFAULT;
  	return 0;
  }
216ba023a   Alan Cox   mxser: Switch to ...
1193
  static int mxser_set_serial_info(struct tty_struct *tty,
1c45607ad   Jiri Slaby   Char: mxser, remo...
1194
  		struct serial_struct __user *new_info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1195
  {
216ba023a   Alan Cox   mxser: Switch to ...
1196
  	struct mxser_port *info = tty->driver_data;
07f86c03f   Alan Cox   tty: mxser: Use t...
1197
  	struct tty_port *port = &info->port;
1c45607ad   Jiri Slaby   Char: mxser, remo...
1198
  	struct serial_struct new_serial;
80ff8a805   Jiri Slaby   Char: mxser, add ...
1199
  	speed_t baud;
1c45607ad   Jiri Slaby   Char: mxser, remo...
1200
1201
1202
  	unsigned long sl_flags;
  	unsigned int flags;
  	int retval = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1203

1c45607ad   Jiri Slaby   Char: mxser, remo...
1204
  	if (!new_info || !info->ioaddr)
80ff8a805   Jiri Slaby   Char: mxser, add ...
1205
  		return -ENODEV;
1c45607ad   Jiri Slaby   Char: mxser, remo...
1206
1207
  	if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
  		return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1208

80ff8a805   Jiri Slaby   Char: mxser, add ...
1209
1210
1211
  	if (new_serial.irq != info->board->irq ||
  			new_serial.port != info->ioaddr)
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1212

07f86c03f   Alan Cox   tty: mxser: Use t...
1213
  	flags = port->flags & ASYNC_SPD_MASK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1214

1c45607ad   Jiri Slaby   Char: mxser, remo...
1215
1216
  	if (!capable(CAP_SYS_ADMIN)) {
  		if ((new_serial.baud_base != info->baud_base) ||
44b7d1b37   Alan Cox   tty: add more tty...
1217
  				(new_serial.close_delay != info->port.close_delay) ||
0ad9e7d1d   Alan Cox   mxser: use tty_port
1218
  				((new_serial.flags & ~ASYNC_USR_MASK) != (info->port.flags & ~ASYNC_USR_MASK)))
1c45607ad   Jiri Slaby   Char: mxser, remo...
1219
  			return -EPERM;
0ad9e7d1d   Alan Cox   mxser: use tty_port
1220
  		info->port.flags = ((info->port.flags & ~ASYNC_USR_MASK) |
1c45607ad   Jiri Slaby   Char: mxser, remo...
1221
1222
  				(new_serial.flags & ASYNC_USR_MASK));
  	} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1223
  		/*
1c45607ad   Jiri Slaby   Char: mxser, remo...
1224
1225
  		 * OK, past this point, all the error checking has been done.
  		 * At this point, we start making changes.....
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1226
  		 */
07f86c03f   Alan Cox   tty: mxser: Use t...
1227
  		port->flags = ((port->flags & ~ASYNC_FLAGS) |
1c45607ad   Jiri Slaby   Char: mxser, remo...
1228
  				(new_serial.flags & ASYNC_FLAGS));
07f86c03f   Alan Cox   tty: mxser: Use t...
1229
1230
1231
1232
  		port->close_delay = new_serial.close_delay * HZ / 100;
  		port->closing_wait = new_serial.closing_wait * HZ / 100;
  		tty->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
  		if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST &&
80ff8a805   Jiri Slaby   Char: mxser, add ...
1233
1234
1235
  				(new_serial.baud_base != info->baud_base ||
  				new_serial.custom_divisor !=
  				info->custom_divisor)) {
07f86c03f   Alan Cox   tty: mxser: Use t...
1236
1237
  			if (new_serial.custom_divisor == 0)
  				return -EINVAL;
80ff8a805   Jiri Slaby   Char: mxser, add ...
1238
  			baud = new_serial.baud_base / new_serial.custom_divisor;
216ba023a   Alan Cox   mxser: Switch to ...
1239
  			tty_encode_baud_rate(tty, baud, baud);
80ff8a805   Jiri Slaby   Char: mxser, add ...
1240
  		}
1c45607ad   Jiri Slaby   Char: mxser, remo...
1241
  	}
fc83815c3   Jiri Slaby   Char: mxser, fix ...
1242

1c45607ad   Jiri Slaby   Char: mxser, remo...
1243
  	info->type = new_serial.type;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1244

1c45607ad   Jiri Slaby   Char: mxser, remo...
1245
  	process_txrx_fifo(info);
07f86c03f   Alan Cox   tty: mxser: Use t...
1246
1247
  	if (test_bit(ASYNCB_INITIALIZED, &port->flags)) {
  		if (flags != (port->flags & ASYNC_SPD_MASK)) {
1c45607ad   Jiri Slaby   Char: mxser, remo...
1248
  			spin_lock_irqsave(&info->slock, sl_flags);
216ba023a   Alan Cox   mxser: Switch to ...
1249
  			mxser_change_speed(tty, NULL);
1c45607ad   Jiri Slaby   Char: mxser, remo...
1250
  			spin_unlock_irqrestore(&info->slock, sl_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1251
  		}
6769140d3   Alan Cox   tty: mxser: use t...
1252
  	} else {
07f86c03f   Alan Cox   tty: mxser: Use t...
1253
  		retval = mxser_activate(port, tty);
6769140d3   Alan Cox   tty: mxser: use t...
1254
  		if (retval == 0)
07f86c03f   Alan Cox   tty: mxser: Use t...
1255
  			set_bit(ASYNCB_INITIALIZED, &port->flags);
6769140d3   Alan Cox   tty: mxser: use t...
1256
  	}
1c45607ad   Jiri Slaby   Char: mxser, remo...
1257
1258
  	return retval;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1259

1c45607ad   Jiri Slaby   Char: mxser, remo...
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
  /*
   * mxser_get_lsr_info - get line status register info
   *
   * Purpose: Let user call ioctl() to get info when the UART physically
   *	    is emptied.  On bus types like RS485, the transmitter must
   *	    release the bus after transmitting. This must be done when
   *	    the transmit shift register is empty, not be done when the
   *	    transmit holding register is empty.  This functionality
   *	    allows an RS485 driver to be written in user space.
   */
  static int mxser_get_lsr_info(struct mxser_port *info,
  		unsigned int __user *value)
  {
  	unsigned char status;
  	unsigned int result;
  	unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1276

1c45607ad   Jiri Slaby   Char: mxser, remo...
1277
1278
1279
1280
1281
1282
  	spin_lock_irqsave(&info->slock, flags);
  	status = inb(info->ioaddr + UART_LSR);
  	spin_unlock_irqrestore(&info->slock, flags);
  	result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
  	return put_user(result, value);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1283

60b33c133   Alan Cox   tiocmget: kill of...
1284
  static int mxser_tiocmget(struct tty_struct *tty)
1c45607ad   Jiri Slaby   Char: mxser, remo...
1285
1286
1287
1288
  {
  	struct mxser_port *info = tty->driver_data;
  	unsigned char control, status;
  	unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1289

8ea2c2ecf   Jesper Juhl   [PATCH] moxa: par...
1290

1c45607ad   Jiri Slaby   Char: mxser, remo...
1291
1292
1293
1294
  	if (tty->index == MXSER_PORTS)
  		return -ENOIOCTLCMD;
  	if (test_bit(TTY_IO_ERROR, &tty->flags))
  		return -EIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1295

1c45607ad   Jiri Slaby   Char: mxser, remo...
1296
  	control = info->MCR;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1297

1c45607ad   Jiri Slaby   Char: mxser, remo...
1298
1299
1300
  	spin_lock_irqsave(&info->slock, flags);
  	status = inb(info->ioaddr + UART_MSR);
  	if (status & UART_MSR_ANY_DELTA)
216ba023a   Alan Cox   mxser: Switch to ...
1301
  		mxser_check_modem_status(tty, info, status);
1c45607ad   Jiri Slaby   Char: mxser, remo...
1302
1303
1304
1305
1306
1307
1308
1309
  	spin_unlock_irqrestore(&info->slock, flags);
  	return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) |
  		    ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) |
  		    ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) |
  		    ((status & UART_MSR_RI) ? TIOCM_RNG : 0) |
  		    ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) |
  		    ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1310

20b9d1771   Alan Cox   tiocmset: kill th...
1311
  static int mxser_tiocmset(struct tty_struct *tty,
1c45607ad   Jiri Slaby   Char: mxser, remo...
1312
1313
1314
1315
  		unsigned int set, unsigned int clear)
  {
  	struct mxser_port *info = tty->driver_data;
  	unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1316

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1317

1c45607ad   Jiri Slaby   Char: mxser, remo...
1318
1319
1320
1321
  	if (tty->index == MXSER_PORTS)
  		return -ENOIOCTLCMD;
  	if (test_bit(TTY_IO_ERROR, &tty->flags))
  		return -EIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1322

1c45607ad   Jiri Slaby   Char: mxser, remo...
1323
  	spin_lock_irqsave(&info->slock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1324

1c45607ad   Jiri Slaby   Char: mxser, remo...
1325
1326
1327
1328
  	if (set & TIOCM_RTS)
  		info->MCR |= UART_MCR_RTS;
  	if (set & TIOCM_DTR)
  		info->MCR |= UART_MCR_DTR;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1329

1c45607ad   Jiri Slaby   Char: mxser, remo...
1330
1331
1332
1333
  	if (clear & TIOCM_RTS)
  		info->MCR &= ~UART_MCR_RTS;
  	if (clear & TIOCM_DTR)
  		info->MCR &= ~UART_MCR_DTR;
8ea2c2ecf   Jesper Juhl   [PATCH] moxa: par...
1334

1c45607ad   Jiri Slaby   Char: mxser, remo...
1335
1336
1337
1338
  	outb(info->MCR, info->ioaddr + UART_MCR);
  	spin_unlock_irqrestore(&info->slock, flags);
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1339

1c45607ad   Jiri Slaby   Char: mxser, remo...
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
  static int __init mxser_program_mode(int port)
  {
  	int id, i, j, n;
  
  	outb(0, port);
  	outb(0, port);
  	outb(0, port);
  	(void)inb(port);
  	(void)inb(port);
  	outb(0, port);
  	(void)inb(port);
  
  	id = inb(port + 1) & 0x1F;
  	if ((id != C168_ASIC_ID) &&
  			(id != C104_ASIC_ID) &&
  			(id != C102_ASIC_ID) &&
  			(id != CI132_ASIC_ID) &&
  			(id != CI134_ASIC_ID) &&
  			(id != CI104J_ASIC_ID))
  		return -1;
  	for (i = 0, j = 0; i < 4; i++) {
  		n = inb(port + 2);
  		if (n == 'M') {
  			j = 1;
  		} else if ((j == 1) && (n == 1)) {
  			j = 2;
  			break;
  		} else
  			j = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1369
  	}
1c45607ad   Jiri Slaby   Char: mxser, remo...
1370
1371
1372
  	if (j != 2)
  		id = -2;
  	return id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1373
  }
1c45607ad   Jiri Slaby   Char: mxser, remo...
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
  static void __init mxser_normal_mode(int port)
  {
  	int i, n;
  
  	outb(0xA5, port + 1);
  	outb(0x80, port + 3);
  	outb(12, port + 0);	/* 9600 bps */
  	outb(0, port + 1);
  	outb(0x03, port + 3);	/* 8 data bits */
  	outb(0x13, port + 4);	/* loop back mode */
  	for (i = 0; i < 16; i++) {
  		n = inb(port + 5);
  		if ((n & 0x61) == 0x60)
  			break;
  		if ((n & 1) == 1)
  			(void)inb(port);
  	}
  	outb(0x00, port + 4);
  }
  
  #define CHIP_SK 	0x01	/* Serial Data Clock  in Eprom */
  #define CHIP_DO 	0x02	/* Serial Data Output in Eprom */
  #define CHIP_CS 	0x04	/* Serial Chip Select in Eprom */
  #define CHIP_DI 	0x08	/* Serial Data Input  in Eprom */
  #define EN_CCMD 	0x000	/* Chip's command register     */
  #define EN0_RSARLO	0x008	/* Remote start address reg 0  */
  #define EN0_RSARHI	0x009	/* Remote start address reg 1  */
  #define EN0_RCNTLO	0x00A	/* Remote byte count reg WR    */
  #define EN0_RCNTHI	0x00B	/* Remote byte count reg WR    */
  #define EN0_DCFG	0x00E	/* Data configuration reg WR   */
  #define EN0_PORT	0x010	/* Rcv missed frame error counter RD */
  #define ENC_PAGE0	0x000	/* Select page 0 of chip registers   */
  #define ENC_PAGE3	0x0C0	/* Select page 3 of chip registers   */
  static int __init mxser_read_register(int port, unsigned short *regs)
  {
  	int i, k, value, id;
  	unsigned int j;
  
  	id = mxser_program_mode(port);
  	if (id < 0)
  		return id;
  	for (i = 0; i < 14; i++) {
  		k = (i & 0x3F) | 0x180;
  		for (j = 0x100; j > 0; j >>= 1) {
  			outb(CHIP_CS, port);
  			if (k & j) {
  				outb(CHIP_CS | CHIP_DO, port);
  				outb(CHIP_CS | CHIP_DO | CHIP_SK, port);	/* A? bit of read */
  			} else {
  				outb(CHIP_CS, port);
  				outb(CHIP_CS | CHIP_SK, port);	/* A? bit of read */
  			}
  		}
  		(void)inb(port);
  		value = 0;
  		for (k = 0, j = 0x8000; k < 16; k++, j >>= 1) {
  			outb(CHIP_CS, port);
  			outb(CHIP_CS | CHIP_SK, port);
  			if (inb(port) & CHIP_DI)
  				value |= j;
  		}
  		regs[i] = value;
  		outb(0, port);
  	}
  	mxser_normal_mode(port);
  	return id;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1441
1442
1443
  
  static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
  {
07f86c03f   Alan Cox   tty: mxser: Use t...
1444
1445
  	struct mxser_port *ip;
  	struct tty_port *port;
216ba023a   Alan Cox   mxser: Switch to ...
1446
  	struct tty_struct *tty;
1c45607ad   Jiri Slaby   Char: mxser, remo...
1447
1448
  	int result, status;
  	unsigned int i, j;
9d6d162d4   Alan Cox   mxser: prepare fo...
1449
  	int ret = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1450
1451
  
  	switch (cmd) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1452
  	case MOXA_GET_MAJOR:
5a3c6b251   Manuel Zerpies   drivers/tty: use ...
1453
  		printk_ratelimited(KERN_WARNING "mxser: '%s' uses deprecated ioctl "
8f3d137e0   Jiri Slaby   Char: mxser, rate...
1454
1455
1456
  					"%x (GET_MAJOR), fix your userspace
  ",
  					current->comm, cmd);
1c45607ad   Jiri Slaby   Char: mxser, remo...
1457
  		return put_user(ttymajor, (int __user *)argp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1458
1459
1460
  
  	case MOXA_CHKPORTENABLE:
  		result = 0;
1c45607ad   Jiri Slaby   Char: mxser, remo...
1461
1462
1463
1464
  		for (i = 0; i < MXSER_BOARDS; i++)
  			for (j = 0; j < MXSER_PORTS_PER_BOARD; j++)
  				if (mxser_boards[i].ports[j].ioaddr)
  					result |= (1 << i);
8ea2c2ecf   Jesper Juhl   [PATCH] moxa: par...
1465
  		return put_user(result, (unsigned long __user *)argp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1466
  	case MOXA_GETDATACOUNT:
07f86c03f   Alan Cox   tty: mxser: Use t...
1467
1468
  		/* The receive side is locked by port->slock but it isn't
  		   clear that an exact snapshot is worth copying here */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1469
  		if (copy_to_user(argp, &mxvar_log, sizeof(mxvar_log)))
9d6d162d4   Alan Cox   mxser: prepare fo...
1470
  			ret = -EFAULT;
9d6d162d4   Alan Cox   mxser: prepare fo...
1471
  		return ret;
72800df9b   Jiri Slaby   Char: mxser, glob...
1472
1473
  	case MOXA_GETMSTATUS: {
  		struct mxser_mstatus ms, __user *msu = argp;
1c45607ad   Jiri Slaby   Char: mxser, remo...
1474
1475
  		for (i = 0; i < MXSER_BOARDS; i++)
  			for (j = 0; j < MXSER_PORTS_PER_BOARD; j++) {
07f86c03f   Alan Cox   tty: mxser: Use t...
1476
1477
  				ip = &mxser_boards[i].ports[j];
  				port = &ip->port;
72800df9b   Jiri Slaby   Char: mxser, glob...
1478
  				memset(&ms, 0, sizeof(ms));
1c45607ad   Jiri Slaby   Char: mxser, remo...
1479

07f86c03f   Alan Cox   tty: mxser: Use t...
1480
1481
  				mutex_lock(&port->mutex);
  				if (!ip->ioaddr)
72800df9b   Jiri Slaby   Char: mxser, glob...
1482
  					goto copy;
216ba023a   Alan Cox   mxser: Switch to ...
1483
  				
07f86c03f   Alan Cox   tty: mxser: Use t...
1484
  				tty = tty_port_tty_get(port);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1485

216ba023a   Alan Cox   mxser: Switch to ...
1486
  				if (!tty || !tty->termios)
07f86c03f   Alan Cox   tty: mxser: Use t...
1487
  					ms.cflag = ip->normal_termios.c_cflag;
1c45607ad   Jiri Slaby   Char: mxser, remo...
1488
  				else
216ba023a   Alan Cox   mxser: Switch to ...
1489
1490
  					ms.cflag = tty->termios->c_cflag;
  				tty_kref_put(tty);
07f86c03f   Alan Cox   tty: mxser: Use t...
1491
1492
1493
  				spin_lock_irq(&ip->slock);
  				status = inb(ip->ioaddr + UART_MSR);
  				spin_unlock_irq(&ip->slock);
72800df9b   Jiri Slaby   Char: mxser, glob...
1494
1495
1496
1497
1498
1499
1500
  				if (status & UART_MSR_DCD)
  					ms.dcd = 1;
  				if (status & UART_MSR_DSR)
  					ms.dsr = 1;
  				if (status & UART_MSR_CTS)
  					ms.cts = 1;
  			copy:
07f86c03f   Alan Cox   tty: mxser: Use t...
1501
1502
  				mutex_unlock(&port->mutex);
  				if (copy_to_user(msu, &ms, sizeof(ms)))
72800df9b   Jiri Slaby   Char: mxser, glob...
1503
  					return -EFAULT;
72800df9b   Jiri Slaby   Char: mxser, glob...
1504
  				msu++;
1c45607ad   Jiri Slaby   Char: mxser, remo...
1505
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1506
  		return 0;
72800df9b   Jiri Slaby   Char: mxser, glob...
1507
  	}
8ea2c2ecf   Jesper Juhl   [PATCH] moxa: par...
1508
  	case MOXA_ASPP_MON_EXT: {
72800df9b   Jiri Slaby   Char: mxser, glob...
1509
1510
1511
1512
1513
1514
1515
  		struct mxser_mon_ext *me; /* it's 2k, stack unfriendly */
  		unsigned int cflag, iflag, p;
  		u8 opmode;
  
  		me = kzalloc(sizeof(*me), GFP_KERNEL);
  		if (!me)
  			return -ENOMEM;
1c45607ad   Jiri Slaby   Char: mxser, remo...
1516

72800df9b   Jiri Slaby   Char: mxser, glob...
1517
1518
1519
1520
1521
1522
  		for (i = 0, p = 0; i < MXSER_BOARDS; i++) {
  			for (j = 0; j < MXSER_PORTS_PER_BOARD; j++, p++) {
  				if (p >= ARRAY_SIZE(me->rx_cnt)) {
  					i = MXSER_BOARDS;
  					break;
  				}
07f86c03f   Alan Cox   tty: mxser: Use t...
1523
1524
1525
1526
1527
1528
  				ip = &mxser_boards[i].ports[j];
  				port = &ip->port;
  
  				mutex_lock(&port->mutex);
  				if (!ip->ioaddr) {
  					mutex_unlock(&port->mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1529
  					continue;
07f86c03f   Alan Cox   tty: mxser: Use t...
1530
  				}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1531

07f86c03f   Alan Cox   tty: mxser: Use t...
1532
1533
  				spin_lock_irq(&ip->slock);
  				status = mxser_get_msr(ip->ioaddr, 0, p);
1c45607ad   Jiri Slaby   Char: mxser, remo...
1534

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1535
  				if (status & UART_MSR_TERI)
07f86c03f   Alan Cox   tty: mxser: Use t...
1536
  					ip->icount.rng++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1537
  				if (status & UART_MSR_DDSR)
07f86c03f   Alan Cox   tty: mxser: Use t...
1538
  					ip->icount.dsr++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1539
  				if (status & UART_MSR_DDCD)
07f86c03f   Alan Cox   tty: mxser: Use t...
1540
  					ip->icount.dcd++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1541
  				if (status & UART_MSR_DCTS)
07f86c03f   Alan Cox   tty: mxser: Use t...
1542
  					ip->icount.cts++;
1c45607ad   Jiri Slaby   Char: mxser, remo...
1543

07f86c03f   Alan Cox   tty: mxser: Use t...
1544
1545
1546
1547
1548
  				ip->mon_data.modem_status = status;
  				me->rx_cnt[p] = ip->mon_data.rxcnt;
  				me->tx_cnt[p] = ip->mon_data.txcnt;
  				me->up_rxcnt[p] = ip->mon_data.up_rxcnt;
  				me->up_txcnt[p] = ip->mon_data.up_txcnt;
72800df9b   Jiri Slaby   Char: mxser, glob...
1549
  				me->modem_status[p] =
07f86c03f   Alan Cox   tty: mxser: Use t...
1550
1551
1552
1553
  					ip->mon_data.modem_status;
  				spin_unlock_irq(&ip->slock);
  
  				tty = tty_port_tty_get(&ip->port);
1c45607ad   Jiri Slaby   Char: mxser, remo...
1554

216ba023a   Alan Cox   mxser: Switch to ...
1555
  				if (!tty || !tty->termios) {
07f86c03f   Alan Cox   tty: mxser: Use t...
1556
1557
1558
  					cflag = ip->normal_termios.c_cflag;
  					iflag = ip->normal_termios.c_iflag;
  					me->baudrate[p] = tty_termios_baud_rate(&ip->normal_termios);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1559
  				} else {
216ba023a   Alan Cox   mxser: Switch to ...
1560
1561
1562
  					cflag = tty->termios->c_cflag;
  					iflag = tty->termios->c_iflag;
  					me->baudrate[p] = tty_get_baud_rate(tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1563
  				}
216ba023a   Alan Cox   mxser: Switch to ...
1564
  				tty_kref_put(tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1565

72800df9b   Jiri Slaby   Char: mxser, glob...
1566
1567
1568
1569
  				me->databits[p] = cflag & CSIZE;
  				me->stopbits[p] = cflag & CSTOPB;
  				me->parity[p] = cflag & (PARENB | PARODD |
  						CMSPAR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1570
1571
  
  				if (cflag & CRTSCTS)
72800df9b   Jiri Slaby   Char: mxser, glob...
1572
  					me->flowctrl[p] |= 0x03;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1573
1574
  
  				if (iflag & (IXON | IXOFF))
72800df9b   Jiri Slaby   Char: mxser, glob...
1575
  					me->flowctrl[p] |= 0x0C;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1576

07f86c03f   Alan Cox   tty: mxser: Use t...
1577
  				if (ip->type == PORT_16550A)
72800df9b   Jiri Slaby   Char: mxser, glob...
1578
  					me->fifo[p] = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1579

07f86c03f   Alan Cox   tty: mxser: Use t...
1580
  				opmode = inb(ip->opmode_ioaddr)>>((p % 4) * 2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1581
  				opmode &= OP_MODE_MASK;
72800df9b   Jiri Slaby   Char: mxser, glob...
1582
  				me->iftype[p] = opmode;
07f86c03f   Alan Cox   tty: mxser: Use t...
1583
  				mutex_unlock(&port->mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1584
  			}
9d6d162d4   Alan Cox   mxser: prepare fo...
1585
  		}
72800df9b   Jiri Slaby   Char: mxser, glob...
1586
1587
1588
1589
  		if (copy_to_user(argp, me, sizeof(*me)))
  			ret = -EFAULT;
  		kfree(me);
  		return ret;
9d6d162d4   Alan Cox   mxser: prepare fo...
1590
1591
  	}
  	default:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1592
1593
1594
1595
  		return -ENOIOCTLCMD;
  	}
  	return 0;
  }
1c45607ad   Jiri Slaby   Char: mxser, remo...
1596
1597
  static int mxser_cflags_changed(struct mxser_port *info, unsigned long arg,
  		struct async_icount *cprev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1598
  {
1c45607ad   Jiri Slaby   Char: mxser, remo...
1599
1600
1601
  	struct async_icount cnow;
  	unsigned long flags;
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1602

1c45607ad   Jiri Slaby   Char: mxser, remo...
1603
1604
1605
  	spin_lock_irqsave(&info->slock, flags);
  	cnow = info->icount;	/* atomic copy */
  	spin_unlock_irqrestore(&info->slock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1606

1c45607ad   Jiri Slaby   Char: mxser, remo...
1607
1608
1609
1610
  	ret =	((arg & TIOCM_RNG) && (cnow.rng != cprev->rng)) ||
  		((arg & TIOCM_DSR) && (cnow.dsr != cprev->dsr)) ||
  		((arg & TIOCM_CD)  && (cnow.dcd != cprev->dcd)) ||
  		((arg & TIOCM_CTS) && (cnow.cts != cprev->cts));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1611

1c45607ad   Jiri Slaby   Char: mxser, remo...
1612
1613
1614
1615
  	*cprev = cnow;
  
  	return ret;
  }
6caa76b77   Alan Cox   tty: now phase ou...
1616
  static int mxser_ioctl(struct tty_struct *tty,
1c45607ad   Jiri Slaby   Char: mxser, remo...
1617
  		unsigned int cmd, unsigned long arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1618
  {
1c45607ad   Jiri Slaby   Char: mxser, remo...
1619
  	struct mxser_port *info = tty->driver_data;
07f86c03f   Alan Cox   tty: mxser: Use t...
1620
  	struct tty_port *port = &info->port;
1c45607ad   Jiri Slaby   Char: mxser, remo...
1621
  	struct async_icount cnow;
1c45607ad   Jiri Slaby   Char: mxser, remo...
1622
1623
1624
  	unsigned long flags;
  	void __user *argp = (void __user *)arg;
  	int retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1625

1c45607ad   Jiri Slaby   Char: mxser, remo...
1626
1627
  	if (tty->index == MXSER_PORTS)
  		return mxser_ioctl_special(cmd, argp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1628

1c45607ad   Jiri Slaby   Char: mxser, remo...
1629
1630
1631
1632
1633
1634
  	if (cmd == MOXA_SET_OP_MODE || cmd == MOXA_GET_OP_MODE) {
  		int p;
  		unsigned long opmode;
  		static unsigned char ModeMask[] = { 0xfc, 0xf3, 0xcf, 0x3f };
  		int shiftbit;
  		unsigned char val, mask;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1635

1c45607ad   Jiri Slaby   Char: mxser, remo...
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
  		p = tty->index % 4;
  		if (cmd == MOXA_SET_OP_MODE) {
  			if (get_user(opmode, (int __user *) argp))
  				return -EFAULT;
  			if (opmode != RS232_MODE &&
  					opmode != RS485_2WIRE_MODE &&
  					opmode != RS422_MODE &&
  					opmode != RS485_4WIRE_MODE)
  				return -EFAULT;
  			mask = ModeMask[p];
  			shiftbit = p * 2;
07f86c03f   Alan Cox   tty: mxser: Use t...
1647
  			spin_lock_irq(&info->slock);
1c45607ad   Jiri Slaby   Char: mxser, remo...
1648
1649
1650
1651
  			val = inb(info->opmode_ioaddr);
  			val &= mask;
  			val |= (opmode << shiftbit);
  			outb(val, info->opmode_ioaddr);
07f86c03f   Alan Cox   tty: mxser: Use t...
1652
  			spin_unlock_irq(&info->slock);
1c45607ad   Jiri Slaby   Char: mxser, remo...
1653
1654
  		} else {
  			shiftbit = p * 2;
07f86c03f   Alan Cox   tty: mxser: Use t...
1655
  			spin_lock_irq(&info->slock);
1c45607ad   Jiri Slaby   Char: mxser, remo...
1656
  			opmode = inb(info->opmode_ioaddr) >> shiftbit;
07f86c03f   Alan Cox   tty: mxser: Use t...
1657
  			spin_unlock_irq(&info->slock);
1c45607ad   Jiri Slaby   Char: mxser, remo...
1658
1659
1660
1661
1662
1663
  			opmode &= OP_MODE_MASK;
  			if (put_user(opmode, (int __user *)argp))
  				return -EFAULT;
  		}
  		return 0;
  	}
0587102cf   Alan Cox   tty: icount chang...
1664
  	if (cmd != TIOCGSERIAL && cmd != TIOCMIWAIT &&
1c45607ad   Jiri Slaby   Char: mxser, remo...
1665
1666
1667
1668
  			test_bit(TTY_IO_ERROR, &tty->flags))
  		return -EIO;
  
  	switch (cmd) {
1c45607ad   Jiri Slaby   Char: mxser, remo...
1669
  	case TIOCGSERIAL:
07f86c03f   Alan Cox   tty: mxser: Use t...
1670
  		mutex_lock(&port->mutex);
216ba023a   Alan Cox   mxser: Switch to ...
1671
  		retval = mxser_get_serial_info(tty, argp);
07f86c03f   Alan Cox   tty: mxser: Use t...
1672
  		mutex_unlock(&port->mutex);
9d6d162d4   Alan Cox   mxser: prepare fo...
1673
  		return retval;
1c45607ad   Jiri Slaby   Char: mxser, remo...
1674
  	case TIOCSSERIAL:
07f86c03f   Alan Cox   tty: mxser: Use t...
1675
  		mutex_lock(&port->mutex);
216ba023a   Alan Cox   mxser: Switch to ...
1676
  		retval = mxser_set_serial_info(tty, argp);
07f86c03f   Alan Cox   tty: mxser: Use t...
1677
  		mutex_unlock(&port->mutex);
9d6d162d4   Alan Cox   mxser: prepare fo...
1678
  		return retval;
1c45607ad   Jiri Slaby   Char: mxser, remo...
1679
  	case TIOCSERGETLSR:	/* Get line status register */
9d6d162d4   Alan Cox   mxser: prepare fo...
1680
  		return  mxser_get_lsr_info(info, argp);
1c45607ad   Jiri Slaby   Char: mxser, remo...
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
  		/*
  		 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
  		 * - mask passed in arg for lines of interest
  		 *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
  		 * Caller should use TIOCGICOUNT to see which one it was
  		 */
  	case TIOCMIWAIT:
  		spin_lock_irqsave(&info->slock, flags);
  		cnow = info->icount;	/* note the counters on entry */
  		spin_unlock_irqrestore(&info->slock, flags);
bdc04e317   Alan Cox   serial: move delt...
1691
  		return wait_event_interruptible(info->port.delta_msr_wait,
1c45607ad   Jiri Slaby   Char: mxser, remo...
1692
  				mxser_cflags_changed(info, arg, &cnow));
1c45607ad   Jiri Slaby   Char: mxser, remo...
1693
1694
1695
  	case MOXA_HighSpeedOn:
  		return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *)argp);
  	case MOXA_SDS_RSTICOUNTER:
07f86c03f   Alan Cox   tty: mxser: Use t...
1696
  		spin_lock_irq(&info->slock);
1c45607ad   Jiri Slaby   Char: mxser, remo...
1697
1698
  		info->mon_data.rxcnt = 0;
  		info->mon_data.txcnt = 0;
07f86c03f   Alan Cox   tty: mxser: Use t...
1699
  		spin_unlock_irq(&info->slock);
1c45607ad   Jiri Slaby   Char: mxser, remo...
1700
1701
1702
1703
1704
1705
  		return 0;
  
  	case MOXA_ASPP_OQUEUE:{
  		int len, lsr;
  
  		len = mxser_chars_in_buffer(tty);
c6eb69acf   Dan Carpenter   mxser: spin_lock(...
1706
  		spin_lock_irq(&info->slock);
a75b7b68e   Jiri Slaby   tty: Char: mxser,...
1707
  		lsr = inb(info->ioaddr + UART_LSR) & UART_LSR_THRE;
07f86c03f   Alan Cox   tty: mxser: Use t...
1708
  		spin_unlock_irq(&info->slock);
1c45607ad   Jiri Slaby   Char: mxser, remo...
1709
1710
1711
1712
1713
1714
  		len += (lsr ? 0 : 1);
  
  		return put_user(len, (int __user *)argp);
  	}
  	case MOXA_ASPP_MON: {
  		int mcr, status;
c6eb69acf   Dan Carpenter   mxser: spin_lock(...
1715
  		spin_lock_irq(&info->slock);
1c45607ad   Jiri Slaby   Char: mxser, remo...
1716
  		status = mxser_get_msr(info->ioaddr, 1, tty->index);
216ba023a   Alan Cox   mxser: Switch to ...
1717
  		mxser_check_modem_status(tty, info, status);
1c45607ad   Jiri Slaby   Char: mxser, remo...
1718
1719
  
  		mcr = inb(info->ioaddr + UART_MCR);
c6eb69acf   Dan Carpenter   mxser: spin_lock(...
1720
  		spin_unlock_irq(&info->slock);
07f86c03f   Alan Cox   tty: mxser: Use t...
1721

1c45607ad   Jiri Slaby   Char: mxser, remo...
1722
1723
1724
1725
1726
1727
1728
1729
1730
  		if (mcr & MOXA_MUST_MCR_XON_FLAG)
  			info->mon_data.hold_reason &= ~NPPI_NOTIFY_XOFFHOLD;
  		else
  			info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFHOLD;
  
  		if (mcr & MOXA_MUST_MCR_TX_XON)
  			info->mon_data.hold_reason &= ~NPPI_NOTIFY_XOFFXENT;
  		else
  			info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFXENT;
216ba023a   Alan Cox   mxser: Switch to ...
1731
  		if (tty->hw_stopped)
1c45607ad   Jiri Slaby   Char: mxser, remo...
1732
1733
1734
  			info->mon_data.hold_reason |= NPPI_NOTIFY_CTSHOLD;
  		else
  			info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD;
07f86c03f   Alan Cox   tty: mxser: Use t...
1735

1c45607ad   Jiri Slaby   Char: mxser, remo...
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
  		if (copy_to_user(argp, &info->mon_data,
  				sizeof(struct mxser_mon)))
  			return -EFAULT;
  
  		return 0;
  	}
  	case MOXA_ASPP_LSTATUS: {
  		if (put_user(info->err_shadow, (unsigned char __user *)argp))
  			return -EFAULT;
  
  		info->err_shadow = 0;
  		return 0;
  	}
  	case MOXA_SET_BAUD_METHOD: {
  		int method;
  
  		if (get_user(method, (int __user *)argp))
  			return -EFAULT;
  		mxser_set_baud_method[tty->index] = method;
  		return put_user(method, (int __user *)argp);
  	}
  	default:
  		return -ENOIOCTLCMD;
  	}
  	return 0;
  }
0587102cf   Alan Cox   tty: icount chang...
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
  	/*
  	 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
  	 * Return: write counters to the user passed counter struct
  	 * NB: both 1->0 and 0->1 transitions are counted except for
  	 *     RI where only 0->1 is counted.
  	 */
  
  static int mxser_get_icount(struct tty_struct *tty,
  		struct serial_icounter_struct *icount)
  
  {
  	struct mxser_port *info = tty->driver_data;
  	struct async_icount cnow;
  	unsigned long flags;
  
  	spin_lock_irqsave(&info->slock, flags);
  	cnow = info->icount;
  	spin_unlock_irqrestore(&info->slock, flags);
  
  	icount->frame = cnow.frame;
  	icount->brk = cnow.brk;
  	icount->overrun = cnow.overrun;
  	icount->buf_overrun = cnow.buf_overrun;
  	icount->parity = cnow.parity;
  	icount->rx = cnow.rx;
  	icount->tx = cnow.tx;
  	icount->cts = cnow.cts;
  	icount->dsr = cnow.dsr;
  	icount->rng = cnow.rng;
  	icount->dcd = cnow.dcd;
  	return 0;
  }
1c45607ad   Jiri Slaby   Char: mxser, remo...
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
  static void mxser_stoprx(struct tty_struct *tty)
  {
  	struct mxser_port *info = tty->driver_data;
  
  	info->ldisc_stop_rx = 1;
  	if (I_IXOFF(tty)) {
  		if (info->board->chip_flag) {
  			info->IER &= ~MOXA_MUST_RECV_ISR;
  			outb(info->IER, info->ioaddr + UART_IER);
  		} else {
  			info->x_char = STOP_CHAR(tty);
  			outb(0, info->ioaddr + UART_IER);
  			info->IER |= UART_IER_THRI;
  			outb(info->IER, info->ioaddr + UART_IER);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1808
1809
  		}
  	}
216ba023a   Alan Cox   mxser: Switch to ...
1810
  	if (tty->termios->c_cflag & CRTSCTS) {
1c45607ad   Jiri Slaby   Char: mxser, remo...
1811
1812
  		info->MCR &= ~UART_MCR_RTS;
  		outb(info->MCR, info->ioaddr + UART_MCR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1813
1814
1815
1816
1817
1818
1819
1820
1821
  	}
  }
  
  /*
   * This routine is called by the upper-layer tty layer to signal that
   * incoming characters should be throttled.
   */
  static void mxser_throttle(struct tty_struct *tty)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1822
  	mxser_stoprx(tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1823
1824
1825
1826
  }
  
  static void mxser_unthrottle(struct tty_struct *tty)
  {
1c45607ad   Jiri Slaby   Char: mxser, remo...
1827
  	struct mxser_port *info = tty->driver_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1828

1c45607ad   Jiri Slaby   Char: mxser, remo...
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
  	/* startrx */
  	info->ldisc_stop_rx = 0;
  	if (I_IXOFF(tty)) {
  		if (info->x_char)
  			info->x_char = 0;
  		else {
  			if (info->board->chip_flag) {
  				info->IER |= MOXA_MUST_RECV_ISR;
  				outb(info->IER, info->ioaddr + UART_IER);
  			} else {
  				info->x_char = START_CHAR(tty);
  				outb(0, info->ioaddr + UART_IER);
  				info->IER |= UART_IER_THRI;
  				outb(info->IER, info->ioaddr + UART_IER);
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1844
  		}
1c45607ad   Jiri Slaby   Char: mxser, remo...
1845
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1846

216ba023a   Alan Cox   mxser: Switch to ...
1847
  	if (tty->termios->c_cflag & CRTSCTS) {
1c45607ad   Jiri Slaby   Char: mxser, remo...
1848
1849
  		info->MCR |= UART_MCR_RTS;
  		outb(info->MCR, info->ioaddr + UART_MCR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
  	}
  }
  
  /*
   * mxser_stop() and mxser_start()
   *
   * This routines are called before setting or resetting tty->stopped.
   * They enable or disable transmitter interrupts, as necessary.
   */
  static void mxser_stop(struct tty_struct *tty)
  {
1c45607ad   Jiri Slaby   Char: mxser, remo...
1861
  	struct mxser_port *info = tty->driver_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1862
1863
1864
1865
1866
  	unsigned long flags;
  
  	spin_lock_irqsave(&info->slock, flags);
  	if (info->IER & UART_IER_THRI) {
  		info->IER &= ~UART_IER_THRI;
1c45607ad   Jiri Slaby   Char: mxser, remo...
1867
  		outb(info->IER, info->ioaddr + UART_IER);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1868
1869
1870
1871
1872
1873
  	}
  	spin_unlock_irqrestore(&info->slock, flags);
  }
  
  static void mxser_start(struct tty_struct *tty)
  {
1c45607ad   Jiri Slaby   Char: mxser, remo...
1874
  	struct mxser_port *info = tty->driver_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1875
1876
1877
  	unsigned long flags;
  
  	spin_lock_irqsave(&info->slock, flags);
0ad9e7d1d   Alan Cox   mxser: use tty_port
1878
  	if (info->xmit_cnt && info->port.xmit_buf) {
1c45607ad   Jiri Slaby   Char: mxser, remo...
1879
  		outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1880
  		info->IER |= UART_IER_THRI;
1c45607ad   Jiri Slaby   Char: mxser, remo...
1881
  		outb(info->IER, info->ioaddr + UART_IER);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1882
1883
1884
  	}
  	spin_unlock_irqrestore(&info->slock, flags);
  }
1c45607ad   Jiri Slaby   Char: mxser, remo...
1885
1886
1887
1888
1889
1890
  static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
  {
  	struct mxser_port *info = tty->driver_data;
  	unsigned long flags;
  
  	spin_lock_irqsave(&info->slock, flags);
216ba023a   Alan Cox   mxser: Switch to ...
1891
  	mxser_change_speed(tty, old_termios);
1c45607ad   Jiri Slaby   Char: mxser, remo...
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
  	spin_unlock_irqrestore(&info->slock, flags);
  
  	if ((old_termios->c_cflag & CRTSCTS) &&
  			!(tty->termios->c_cflag & CRTSCTS)) {
  		tty->hw_stopped = 0;
  		mxser_start(tty);
  	}
  
  	/* Handle sw stopped */
  	if ((old_termios->c_iflag & IXON) &&
  			!(tty->termios->c_iflag & IXON)) {
  		tty->stopped = 0;
  
  		if (info->board->chip_flag) {
  			spin_lock_irqsave(&info->slock, flags);
148ff86b1   Christoph Hellwig   mxser: convert la...
1907
1908
  			mxser_disable_must_rx_software_flow_control(
  					info->ioaddr);
1c45607ad   Jiri Slaby   Char: mxser, remo...
1909
1910
1911
1912
1913
1914
  			spin_unlock_irqrestore(&info->slock, flags);
  		}
  
  		mxser_start(tty);
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1915
1916
1917
1918
1919
  /*
   * mxser_wait_until_sent() --- wait until the transmitter is empty
   */
  static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
  {
1c45607ad   Jiri Slaby   Char: mxser, remo...
1920
  	struct mxser_port *info = tty->driver_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1921
  	unsigned long orig_jiffies, char_time;
07f86c03f   Alan Cox   tty: mxser: Use t...
1922
  	unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
  	int lsr;
  
  	if (info->type == PORT_UNKNOWN)
  		return;
  
  	if (info->xmit_fifo_size == 0)
  		return;		/* Just in case.... */
  
  	orig_jiffies = jiffies;
  	/*
  	 * Set the check interval to be 1/5 of the estimated time to
  	 * send a single character, and make it at least 1.  The check
  	 * interval should also be less than the timeout.
  	 *
  	 * Note: we have to use pretty tight timings here to satisfy
  	 * the NIST-PCTS.
  	 */
  	char_time = (info->timeout - HZ / 50) / info->xmit_fifo_size;
  	char_time = char_time / 5;
  	if (char_time == 0)
  		char_time = 1;
  	if (timeout && timeout < char_time)
  		char_time = timeout;
  	/*
  	 * If the transmitter hasn't cleared in twice the approximate
  	 * amount of time to send the entire FIFO, it probably won't
  	 * ever clear.  This assumes the UART isn't doing flow
  	 * control, which is currently the case.  Hence, if it ever
  	 * takes longer than info->timeout, this is probably due to a
  	 * UART bug of some kind.  So, we clamp the timeout parameter at
  	 * 2*info->timeout.
  	 */
  	if (!timeout || timeout > 2 * info->timeout)
  		timeout = 2 * info->timeout;
8bab534b5   Jiri Slaby   TTY: mxser+cyclad...
1957

07f86c03f   Alan Cox   tty: mxser: Use t...
1958
  	spin_lock_irqsave(&info->slock, flags);
1c45607ad   Jiri Slaby   Char: mxser, remo...
1959
  	while (!((lsr = inb(info->ioaddr + UART_LSR)) & UART_LSR_TEMT)) {
07f86c03f   Alan Cox   tty: mxser: Use t...
1960
  		spin_unlock_irqrestore(&info->slock, flags);
da4cd8dfe   Nishanth Aravamudan   [PATCH] drivers/c...
1961
  		schedule_timeout_interruptible(char_time);
07f86c03f   Alan Cox   tty: mxser: Use t...
1962
  		spin_lock_irqsave(&info->slock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1963
  		if (signal_pending(current))
1c45607ad   Jiri Slaby   Char: mxser, remo...
1964
1965
1966
  			break;
  		if (timeout && time_after(jiffies, orig_jiffies + timeout))
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1967
  	}
07f86c03f   Alan Cox   tty: mxser: Use t...
1968
  	spin_unlock_irqrestore(&info->slock, flags);
1c45607ad   Jiri Slaby   Char: mxser, remo...
1969
  	set_current_state(TASK_RUNNING);
1c45607ad   Jiri Slaby   Char: mxser, remo...
1970
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1971

1c45607ad   Jiri Slaby   Char: mxser, remo...
1972
1973
1974
1975
1976
1977
  /*
   * This routine is called by tty_hangup() when a hangup is signaled.
   */
  static void mxser_hangup(struct tty_struct *tty)
  {
  	struct mxser_port *info = tty->driver_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1978

1c45607ad   Jiri Slaby   Char: mxser, remo...
1979
  	mxser_flush_buffer(tty);
3b6826b25   Alan Cox   tty: relock the m...
1980
  	tty_port_hangup(&info->port);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1981
  }
1c45607ad   Jiri Slaby   Char: mxser, remo...
1982
1983
1984
  /*
   * mxser_rs_break() --- routine which turns the break handling on or off
   */
9e98966c7   Alan Cox   tty: rework break...
1985
  static int mxser_rs_break(struct tty_struct *tty, int break_state)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1986
  {
1c45607ad   Jiri Slaby   Char: mxser, remo...
1987
  	struct mxser_port *info = tty->driver_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1988
  	unsigned long flags;
1c45607ad   Jiri Slaby   Char: mxser, remo...
1989
1990
1991
1992
1993
1994
1995
1996
  	spin_lock_irqsave(&info->slock, flags);
  	if (break_state == -1)
  		outb(inb(info->ioaddr + UART_LCR) | UART_LCR_SBC,
  			info->ioaddr + UART_LCR);
  	else
  		outb(inb(info->ioaddr + UART_LCR) & ~UART_LCR_SBC,
  			info->ioaddr + UART_LCR);
  	spin_unlock_irqrestore(&info->slock, flags);
9e98966c7   Alan Cox   tty: rework break...
1997
  	return 0;
1c45607ad   Jiri Slaby   Char: mxser, remo...
1998
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1999

216ba023a   Alan Cox   mxser: Switch to ...
2000
2001
  static void mxser_receive_chars(struct tty_struct *tty,
  				struct mxser_port *port, int *status)
1c45607ad   Jiri Slaby   Char: mxser, remo...
2002
  {
1c45607ad   Jiri Slaby   Char: mxser, remo...
2003
2004
2005
2006
2007
  	unsigned char ch, gdl;
  	int ignored = 0;
  	int cnt = 0;
  	int recv_room;
  	int max = 256;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2008

1c45607ad   Jiri Slaby   Char: mxser, remo...
2009
  	recv_room = tty->receive_room;
216ba023a   Alan Cox   mxser: Switch to ...
2010
  	if (recv_room == 0 && !port->ldisc_stop_rx)
1c45607ad   Jiri Slaby   Char: mxser, remo...
2011
  		mxser_stoprx(tty);
1c45607ad   Jiri Slaby   Char: mxser, remo...
2012
  	if (port->board->chip_flag != MOXA_OTHER_UART) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2013

1c45607ad   Jiri Slaby   Char: mxser, remo...
2014
2015
2016
2017
2018
2019
2020
  		if (*status & UART_LSR_SPECIAL)
  			goto intr_old;
  		if (port->board->chip_flag == MOXA_MUST_MU860_HWID &&
  				(*status & MOXA_MUST_LSR_RERR))
  			goto intr_old;
  		if (*status & MOXA_MUST_LSR_RERR)
  			goto intr_old;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2021

1c45607ad   Jiri Slaby   Char: mxser, remo...
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
  		gdl = inb(port->ioaddr + MOXA_MUST_GDL_REGISTER);
  
  		if (port->board->chip_flag == MOXA_MUST_MU150_HWID)
  			gdl &= MOXA_MUST_GDL_MASK;
  		if (gdl >= recv_room) {
  			if (!port->ldisc_stop_rx)
  				mxser_stoprx(tty);
  		}
  		while (gdl--) {
  			ch = inb(port->ioaddr + UART_RX);
  			tty_insert_flip_char(tty, ch, 0);
  			cnt++;
  		}
  		goto end_intr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2036
  	}
1c45607ad   Jiri Slaby   Char: mxser, remo...
2037
2038
2039
2040
2041
  intr_old:
  
  	do {
  		if (max-- < 0)
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2042

1c45607ad   Jiri Slaby   Char: mxser, remo...
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
  		ch = inb(port->ioaddr + UART_RX);
  		if (port->board->chip_flag && (*status & UART_LSR_OE))
  			outb(0x23, port->ioaddr + UART_FCR);
  		*status &= port->read_status_mask;
  		if (*status & port->ignore_status_mask) {
  			if (++ignored > 100)
  				break;
  		} else {
  			char flag = 0;
  			if (*status & UART_LSR_SPECIAL) {
  				if (*status & UART_LSR_BI) {
  					flag = TTY_BREAK;
  					port->icount.brk++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2056

0ad9e7d1d   Alan Cox   mxser: use tty_port
2057
  					if (port->port.flags & ASYNC_SAK)
1c45607ad   Jiri Slaby   Char: mxser, remo...
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
  						do_SAK(tty);
  				} else if (*status & UART_LSR_PE) {
  					flag = TTY_PARITY;
  					port->icount.parity++;
  				} else if (*status & UART_LSR_FE) {
  					flag = TTY_FRAME;
  					port->icount.frame++;
  				} else if (*status & UART_LSR_OE) {
  					flag = TTY_OVERRUN;
  					port->icount.overrun++;
  				} else
  					flag = TTY_BREAK;
  			}
  			tty_insert_flip_char(tty, ch, flag);
  			cnt++;
  			if (cnt >= recv_room) {
  				if (!port->ldisc_stop_rx)
  					mxser_stoprx(tty);
  				break;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2078

1c45607ad   Jiri Slaby   Char: mxser, remo...
2079
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2080

1c45607ad   Jiri Slaby   Char: mxser, remo...
2081
2082
  		if (port->board->chip_flag)
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2083

1c45607ad   Jiri Slaby   Char: mxser, remo...
2084
2085
  		*status = inb(port->ioaddr + UART_LSR);
  	} while (*status & UART_LSR_DR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2086

1c45607ad   Jiri Slaby   Char: mxser, remo...
2087
  end_intr:
216ba023a   Alan Cox   mxser: Switch to ...
2088
  	mxvar_log.rxcnt[tty->index] += cnt;
1c45607ad   Jiri Slaby   Char: mxser, remo...
2089
2090
  	port->mon_data.rxcnt += cnt;
  	port->mon_data.up_rxcnt += cnt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2091

1c45607ad   Jiri Slaby   Char: mxser, remo...
2092
2093
2094
2095
2096
2097
2098
2099
  	/*
  	 * We are called from an interrupt context with &port->slock
  	 * being held. Drop it temporarily in order to prevent
  	 * recursive locking.
  	 */
  	spin_unlock(&port->slock);
  	tty_flip_buffer_push(tty);
  	spin_lock(&port->slock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2100
  }
216ba023a   Alan Cox   mxser: Switch to ...
2101
  static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2102
  {
1c45607ad   Jiri Slaby   Char: mxser, remo...
2103
  	int count, cnt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2104

1c45607ad   Jiri Slaby   Char: mxser, remo...
2105
2106
2107
  	if (port->x_char) {
  		outb(port->x_char, port->ioaddr + UART_TX);
  		port->x_char = 0;
216ba023a   Alan Cox   mxser: Switch to ...
2108
  		mxvar_log.txcnt[tty->index]++;
1c45607ad   Jiri Slaby   Char: mxser, remo...
2109
2110
2111
2112
2113
  		port->mon_data.txcnt++;
  		port->mon_data.up_txcnt++;
  		port->icount.tx++;
  		return;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2114

0ad9e7d1d   Alan Cox   mxser: use tty_port
2115
  	if (port->port.xmit_buf == NULL)
1c45607ad   Jiri Slaby   Char: mxser, remo...
2116
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2117

216ba023a   Alan Cox   mxser: Switch to ...
2118
2119
  	if (port->xmit_cnt <= 0 || tty->stopped ||
  			(tty->hw_stopped &&
1c45607ad   Jiri Slaby   Char: mxser, remo...
2120
2121
2122
2123
2124
  			(port->type != PORT_16550A) &&
  			(!port->board->chip_flag))) {
  		port->IER &= ~UART_IER_THRI;
  		outb(port->IER, port->ioaddr + UART_IER);
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2125
  	}
1c45607ad   Jiri Slaby   Char: mxser, remo...
2126
2127
2128
  	cnt = port->xmit_cnt;
  	count = port->xmit_fifo_size;
  	do {
0ad9e7d1d   Alan Cox   mxser: use tty_port
2129
  		outb(port->port.xmit_buf[port->xmit_tail++],
1c45607ad   Jiri Slaby   Char: mxser, remo...
2130
2131
2132
2133
2134
  			port->ioaddr + UART_TX);
  		port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE - 1);
  		if (--port->xmit_cnt <= 0)
  			break;
  	} while (--count > 0);
216ba023a   Alan Cox   mxser: Switch to ...
2135
  	mxvar_log.txcnt[tty->index] += (cnt - port->xmit_cnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2136

1c45607ad   Jiri Slaby   Char: mxser, remo...
2137
2138
2139
  	port->mon_data.txcnt += (cnt - port->xmit_cnt);
  	port->mon_data.up_txcnt += (cnt - port->xmit_cnt);
  	port->icount.tx += (cnt - port->xmit_cnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2140

464eb8f59   Kulikov Vasiliy   mxser: remove unn...
2141
  	if (port->xmit_cnt < WAKEUP_CHARS)
216ba023a   Alan Cox   mxser: Switch to ...
2142
  		tty_wakeup(tty);
1c45607ad   Jiri Slaby   Char: mxser, remo...
2143
2144
2145
2146
  
  	if (port->xmit_cnt <= 0) {
  		port->IER &= ~UART_IER_THRI;
  		outb(port->IER, port->ioaddr + UART_IER);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2147
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2148
2149
2150
  }
  
  /*
1c45607ad   Jiri Slaby   Char: mxser, remo...
2151
   * This is the serial driver's generic interrupt routine
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2152
   */
1c45607ad   Jiri Slaby   Char: mxser, remo...
2153
  static irqreturn_t mxser_interrupt(int irq, void *dev_id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2154
  {
1c45607ad   Jiri Slaby   Char: mxser, remo...
2155
2156
2157
2158
2159
2160
  	int status, iir, i;
  	struct mxser_board *brd = NULL;
  	struct mxser_port *port;
  	int max, irqbits, bits, msr;
  	unsigned int int_cnt, pass_counter = 0;
  	int handled = IRQ_NONE;
216ba023a   Alan Cox   mxser: Switch to ...
2161
  	struct tty_struct *tty;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2162

1c45607ad   Jiri Slaby   Char: mxser, remo...
2163
2164
2165
2166
2167
  	for (i = 0; i < MXSER_BOARDS; i++)
  		if (dev_id == &mxser_boards[i]) {
  			brd = dev_id;
  			break;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2168

1c45607ad   Jiri Slaby   Char: mxser, remo...
2169
2170
2171
2172
2173
2174
2175
2176
2177
  	if (i == MXSER_BOARDS)
  		goto irq_stop;
  	if (brd == NULL)
  		goto irq_stop;
  	max = brd->info->nports;
  	while (pass_counter++ < MXSER_ISR_PASS_LIMIT) {
  		irqbits = inb(brd->vector) & brd->vector_mask;
  		if (irqbits == brd->vector_mask)
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2178

1c45607ad   Jiri Slaby   Char: mxser, remo...
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
  		handled = IRQ_HANDLED;
  		for (i = 0, bits = 1; i < max; i++, irqbits |= bits, bits <<= 1) {
  			if (irqbits == brd->vector_mask)
  				break;
  			if (bits & irqbits)
  				continue;
  			port = &brd->ports[i];
  
  			int_cnt = 0;
  			spin_lock(&port->slock);
  			do {
  				iir = inb(port->ioaddr + UART_IIR);
  				if (iir & UART_IIR_NO_INT)
  					break;
  				iir &= MOXA_MUST_IIR_MASK;
216ba023a   Alan Cox   mxser: Switch to ...
2194
2195
  				tty = tty_port_tty_get(&port->port);
  				if (!tty ||
0ad9e7d1d   Alan Cox   mxser: use tty_port
2196
2197
  						(port->port.flags & ASYNC_CLOSING) ||
  						!(port->port.flags &
1c45607ad   Jiri Slaby   Char: mxser, remo...
2198
2199
2200
2201
  							ASYNC_INITIALIZED)) {
  					status = inb(port->ioaddr + UART_LSR);
  					outb(0x27, port->ioaddr + UART_FCR);
  					inb(port->ioaddr + UART_MSR);
216ba023a   Alan Cox   mxser: Switch to ...
2202
  					tty_kref_put(tty);
1c45607ad   Jiri Slaby   Char: mxser, remo...
2203
2204
  					break;
  				}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2205

1c45607ad   Jiri Slaby   Char: mxser, remo...
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
  				status = inb(port->ioaddr + UART_LSR);
  
  				if (status & UART_LSR_PE)
  					port->err_shadow |= NPPI_NOTIFY_PARITY;
  				if (status & UART_LSR_FE)
  					port->err_shadow |= NPPI_NOTIFY_FRAMING;
  				if (status & UART_LSR_OE)
  					port->err_shadow |=
  						NPPI_NOTIFY_HW_OVERRUN;
  				if (status & UART_LSR_BI)
  					port->err_shadow |= NPPI_NOTIFY_BREAK;
  
  				if (port->board->chip_flag) {
  					if (iir == MOXA_MUST_IIR_GDA ||
  					    iir == MOXA_MUST_IIR_RDA ||
  					    iir == MOXA_MUST_IIR_RTO ||
  					    iir == MOXA_MUST_IIR_LSR)
216ba023a   Alan Cox   mxser: Switch to ...
2223
  						mxser_receive_chars(tty, port,
1c45607ad   Jiri Slaby   Char: mxser, remo...
2224
2225
2226
2227
2228
  								&status);
  
  				} else {
  					status &= port->read_status_mask;
  					if (status & UART_LSR_DR)
216ba023a   Alan Cox   mxser: Switch to ...
2229
  						mxser_receive_chars(tty, port,
1c45607ad   Jiri Slaby   Char: mxser, remo...
2230
2231
2232
2233
  								&status);
  				}
  				msr = inb(port->ioaddr + UART_MSR);
  				if (msr & UART_MSR_ANY_DELTA)
216ba023a   Alan Cox   mxser: Switch to ...
2234
  					mxser_check_modem_status(tty, port, msr);
1c45607ad   Jiri Slaby   Char: mxser, remo...
2235
2236
2237
2238
  
  				if (port->board->chip_flag) {
  					if (iir == 0x02 && (status &
  								UART_LSR_THRE))
216ba023a   Alan Cox   mxser: Switch to ...
2239
  						mxser_transmit_chars(tty, port);
1c45607ad   Jiri Slaby   Char: mxser, remo...
2240
2241
  				} else {
  					if (status & UART_LSR_THRE)
216ba023a   Alan Cox   mxser: Switch to ...
2242
  						mxser_transmit_chars(tty, port);
1c45607ad   Jiri Slaby   Char: mxser, remo...
2243
  				}
216ba023a   Alan Cox   mxser: Switch to ...
2244
  				tty_kref_put(tty);
1c45607ad   Jiri Slaby   Char: mxser, remo...
2245
2246
2247
2248
  			} while (int_cnt++ < MXSER_ISR_PASS_LIMIT);
  			spin_unlock(&port->slock);
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2249

1c45607ad   Jiri Slaby   Char: mxser, remo...
2250
2251
2252
  irq_stop:
  	return handled;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2253

1c45607ad   Jiri Slaby   Char: mxser, remo...
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
  static const struct tty_operations mxser_ops = {
  	.open = mxser_open,
  	.close = mxser_close,
  	.write = mxser_write,
  	.put_char = mxser_put_char,
  	.flush_chars = mxser_flush_chars,
  	.write_room = mxser_write_room,
  	.chars_in_buffer = mxser_chars_in_buffer,
  	.flush_buffer = mxser_flush_buffer,
  	.ioctl = mxser_ioctl,
  	.throttle = mxser_throttle,
  	.unthrottle = mxser_unthrottle,
  	.set_termios = mxser_set_termios,
  	.stop = mxser_stop,
  	.start = mxser_start,
  	.hangup = mxser_hangup,
  	.break_ctl = mxser_rs_break,
  	.wait_until_sent = mxser_wait_until_sent,
  	.tiocmget = mxser_tiocmget,
  	.tiocmset = mxser_tiocmset,
0587102cf   Alan Cox   tty: icount chang...
2274
  	.get_icount = mxser_get_icount,
1c45607ad   Jiri Slaby   Char: mxser, remo...
2275
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2276

31f35939d   Alan Cox   tty_port: Add a p...
2277
2278
  struct tty_port_operations mxser_port_ops = {
  	.carrier_raised = mxser_carrier_raised,
fcc8ac182   Alan Cox   tty: Add carrier ...
2279
  	.dtr_rts = mxser_dtr_rts,
6769140d3   Alan Cox   tty: mxser: use t...
2280
2281
  	.activate = mxser_activate,
  	.shutdown = mxser_shutdown_port,
31f35939d   Alan Cox   tty_port: Add a p...
2282
  };
1c45607ad   Jiri Slaby   Char: mxser, remo...
2283
2284
2285
  /*
   * The MOXA Smartio/Industio serial driver boot-time initialization code!
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2286

df480518a   Jiri Slaby   Char: mxser, call...
2287
  static void mxser_release_ISA_res(struct mxser_board *brd)
1c45607ad   Jiri Slaby   Char: mxser, remo...
2288
  {
df480518a   Jiri Slaby   Char: mxser, call...
2289
2290
2291
  	free_irq(brd->irq, brd);
  	release_region(brd->ports[0].ioaddr, 8 * brd->info->nports);
  	release_region(brd->vector, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2292
  }
1c45607ad   Jiri Slaby   Char: mxser, remo...
2293
2294
  static int __devinit mxser_initbrd(struct mxser_board *brd,
  		struct pci_dev *pdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2295
  {
1c45607ad   Jiri Slaby   Char: mxser, remo...
2296
2297
2298
  	struct mxser_port *info;
  	unsigned int i;
  	int retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2299

83766bc63   Jiri Slaby   Char: mxser, prin...
2300
2301
2302
  	printk(KERN_INFO "mxser: max. baud rate = %d bps
  ",
  			brd->ports[0].max_baud);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2303

1c45607ad   Jiri Slaby   Char: mxser, remo...
2304
2305
  	for (i = 0; i < brd->info->nports; i++) {
  		info = &brd->ports[i];
44b7d1b37   Alan Cox   tty: add more tty...
2306
  		tty_port_init(&info->port);
31f35939d   Alan Cox   tty_port: Add a p...
2307
  		info->port.ops = &mxser_port_ops;
1c45607ad   Jiri Slaby   Char: mxser, remo...
2308
2309
2310
  		info->board = brd;
  		info->stop_rx = 0;
  		info->ldisc_stop_rx = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2311

1c45607ad   Jiri Slaby   Char: mxser, remo...
2312
2313
  		/* Enhance mode enabled here */
  		if (brd->chip_flag != MOXA_OTHER_UART)
148ff86b1   Christoph Hellwig   mxser: convert la...
2314
  			mxser_enable_must_enchance_mode(info->ioaddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2315

0ad9e7d1d   Alan Cox   mxser: use tty_port
2316
  		info->port.flags = ASYNC_SHARE_IRQ;
1c45607ad   Jiri Slaby   Char: mxser, remo...
2317
  		info->type = brd->uart_type;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2318

1c45607ad   Jiri Slaby   Char: mxser, remo...
2319
  		process_txrx_fifo(info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2320

1c45607ad   Jiri Slaby   Char: mxser, remo...
2321
  		info->custom_divisor = info->baud_base * 16;
44b7d1b37   Alan Cox   tty: add more tty...
2322
2323
  		info->port.close_delay = 5 * HZ / 10;
  		info->port.closing_wait = 30 * HZ;
1c45607ad   Jiri Slaby   Char: mxser, remo...
2324
  		info->normal_termios = mxvar_sdriver->init_termios;
1c45607ad   Jiri Slaby   Char: mxser, remo...
2325
2326
2327
  		memset(&info->mon_data, 0, sizeof(struct mxser_mon));
  		info->err_shadow = 0;
  		spin_lock_init(&info->slock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2328

1c45607ad   Jiri Slaby   Char: mxser, remo...
2329
2330
2331
2332
  		/* before set INT ISR, disable all int */
  		outb(inb(info->ioaddr + UART_IER) & 0xf0,
  			info->ioaddr + UART_IER);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2333

1c45607ad   Jiri Slaby   Char: mxser, remo...
2334
2335
  	retval = request_irq(brd->irq, mxser_interrupt, IRQF_SHARED, "mxser",
  			brd);
df480518a   Jiri Slaby   Char: mxser, call...
2336
  	if (retval)
1c45607ad   Jiri Slaby   Char: mxser, remo...
2337
2338
2339
2340
  		printk(KERN_ERR "Board %s: Request irq failed, IRQ (%d) may "
  			"conflict with another device.
  ",
  			brd->info->name, brd->irq);
df480518a   Jiri Slaby   Char: mxser, call...
2341

1c45607ad   Jiri Slaby   Char: mxser, remo...
2342
2343
  	return retval;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2344

1c45607ad   Jiri Slaby   Char: mxser, remo...
2345
  static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2346
2347
2348
2349
  {
  	int id, i, bits;
  	unsigned short regs[16], irq;
  	unsigned char scratch, scratch2;
1c45607ad   Jiri Slaby   Char: mxser, remo...
2350
  	brd->chip_flag = MOXA_OTHER_UART;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2351
2352
  
  	id = mxser_read_register(cap, regs);
1c45607ad   Jiri Slaby   Char: mxser, remo...
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
  	switch (id) {
  	case C168_ASIC_ID:
  		brd->info = &mxser_cards[0];
  		break;
  	case C104_ASIC_ID:
  		brd->info = &mxser_cards[1];
  		break;
  	case CI104J_ASIC_ID:
  		brd->info = &mxser_cards[2];
  		break;
  	case C102_ASIC_ID:
  		brd->info = &mxser_cards[5];
  		break;
  	case CI132_ASIC_ID:
  		brd->info = &mxser_cards[6];
  		break;
  	case CI134_ASIC_ID:
  		brd->info = &mxser_cards[7];
  		break;
  	default:
8ea2c2ecf   Jesper Juhl   [PATCH] moxa: par...
2373
  		return 0;
1c45607ad   Jiri Slaby   Char: mxser, remo...
2374
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2375
2376
  
  	irq = 0;
1c45607ad   Jiri Slaby   Char: mxser, remo...
2377
2378
2379
  	/* some ISA cards have 2 ports, but we want to see them as 4-port (why?)
  	   Flag-hack checks if configuration should be read as 2-port here. */
  	if (brd->info->nports == 2 || (brd->info->flags & MXSER_HAS2)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2380
2381
2382
  		irq = regs[9] & 0xF000;
  		irq = irq | (irq >> 4);
  		if (irq != (regs[9] & 0xFF00))
83766bc63   Jiri Slaby   Char: mxser, prin...
2383
  			goto err_irqconflict;
1c45607ad   Jiri Slaby   Char: mxser, remo...
2384
  	} else if (brd->info->nports == 4) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2385
2386
2387
2388
  		irq = regs[9] & 0xF000;
  		irq = irq | (irq >> 4);
  		irq = irq | (irq >> 8);
  		if (irq != regs[9])
83766bc63   Jiri Slaby   Char: mxser, prin...
2389
  			goto err_irqconflict;
1c45607ad   Jiri Slaby   Char: mxser, remo...
2390
  	} else if (brd->info->nports == 8) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2391
2392
2393
2394
  		irq = regs[9] & 0xF000;
  		irq = irq | (irq >> 4);
  		irq = irq | (irq >> 8);
  		if ((irq != regs[9]) || (irq != regs[10]))
83766bc63   Jiri Slaby   Char: mxser, prin...
2395
  			goto err_irqconflict;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2396
  	}
83766bc63   Jiri Slaby   Char: mxser, prin...
2397
2398
2399
2400
2401
  	if (!irq) {
  		printk(KERN_ERR "mxser: interrupt number unset
  ");
  		return -EIO;
  	}
1c45607ad   Jiri Slaby   Char: mxser, remo...
2402
  	brd->irq = ((int)(irq & 0xF000) >> 12);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2403
  	for (i = 0; i < 8; i++)
1c45607ad   Jiri Slaby   Char: mxser, remo...
2404
  		brd->ports[i].ioaddr = (int) regs[i + 1] & 0xFFF8;
83766bc63   Jiri Slaby   Char: mxser, prin...
2405
2406
2407
2408
2409
  	if ((regs[12] & 0x80) == 0) {
  		printk(KERN_ERR "mxser: invalid interrupt vector
  ");
  		return -EIO;
  	}
1c45607ad   Jiri Slaby   Char: mxser, remo...
2410
  	brd->vector = (int)regs[11];	/* interrupt vector */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2411
  	if (id == 1)
1c45607ad   Jiri Slaby   Char: mxser, remo...
2412
  		brd->vector_mask = 0x00FF;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2413
  	else
1c45607ad   Jiri Slaby   Char: mxser, remo...
2414
  		brd->vector_mask = 0x000F;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2415
2416
  	for (i = 7, bits = 0x0100; i >= 0; i--, bits <<= 1) {
  		if (regs[12] & bits) {
1c45607ad   Jiri Slaby   Char: mxser, remo...
2417
2418
  			brd->ports[i].baud_base = 921600;
  			brd->ports[i].max_baud = 921600;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2419
  		} else {
1c45607ad   Jiri Slaby   Char: mxser, remo...
2420
2421
  			brd->ports[i].baud_base = 115200;
  			brd->ports[i].max_baud = 115200;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
  		}
  	}
  	scratch2 = inb(cap + UART_LCR) & (~UART_LCR_DLAB);
  	outb(scratch2 | UART_LCR_DLAB, cap + UART_LCR);
  	outb(0, cap + UART_EFR);	/* EFR is the same as FCR */
  	outb(scratch2, cap + UART_LCR);
  	outb(UART_FCR_ENABLE_FIFO, cap + UART_FCR);
  	scratch = inb(cap + UART_IIR);
  
  	if (scratch & 0xC0)
1c45607ad   Jiri Slaby   Char: mxser, remo...
2432
  		brd->uart_type = PORT_16550A;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2433
  	else
1c45607ad   Jiri Slaby   Char: mxser, remo...
2434
2435
  		brd->uart_type = PORT_16450;
  	if (!request_region(brd->ports[0].ioaddr, 8 * brd->info->nports,
83766bc63   Jiri Slaby   Char: mxser, prin...
2436
2437
2438
2439
2440
2441
2442
2443
  			"mxser(IO)")) {
  		printk(KERN_ERR "mxser: can't request ports I/O region: "
  				"0x%.8lx-0x%.8lx
  ",
  				brd->ports[0].ioaddr, brd->ports[0].ioaddr +
  				8 * brd->info->nports - 1);
  		return -EIO;
  	}
1c45607ad   Jiri Slaby   Char: mxser, remo...
2444
2445
  	if (!request_region(brd->vector, 1, "mxser(vector)")) {
  		release_region(brd->ports[0].ioaddr, 8 * brd->info->nports);
83766bc63   Jiri Slaby   Char: mxser, prin...
2446
2447
2448
2449
2450
2451
  		printk(KERN_ERR "mxser: can't request interrupt vector region: "
  				"0x%.8lx-0x%.8lx
  ",
  				brd->ports[0].ioaddr, brd->ports[0].ioaddr +
  				8 * brd->info->nports - 1);
  		return -EIO;
1c45607ad   Jiri Slaby   Char: mxser, remo...
2452
2453
  	}
  	return brd->info->nports;
83766bc63   Jiri Slaby   Char: mxser, prin...
2454
2455
2456
2457
2458
  
  err_irqconflict:
  	printk(KERN_ERR "mxser: invalid interrupt number
  ");
  	return -EIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2459
  }
1c45607ad   Jiri Slaby   Char: mxser, remo...
2460
2461
  static int __devinit mxser_probe(struct pci_dev *pdev,
  		const struct pci_device_id *ent)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2462
  {
1c45607ad   Jiri Slaby   Char: mxser, remo...
2463
2464
2465
2466
2467
  #ifdef CONFIG_PCI
  	struct mxser_board *brd;
  	unsigned int i, j;
  	unsigned long ioaddress;
  	int retval = -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2468

1c45607ad   Jiri Slaby   Char: mxser, remo...
2469
2470
2471
2472
2473
  	for (i = 0; i < MXSER_BOARDS; i++)
  		if (mxser_boards[i].info == NULL)
  			break;
  
  	if (i >= MXSER_BOARDS) {
83766bc63   Jiri Slaby   Char: mxser, prin...
2474
2475
2476
  		dev_err(&pdev->dev, "too many boards found (maximum %d), board "
  				"not configured
  ", MXSER_BOARDS);
1c45607ad   Jiri Slaby   Char: mxser, remo...
2477
2478
2479
2480
2481
  		goto err;
  	}
  
  	brd = &mxser_boards[i];
  	brd->idx = i * MXSER_PORTS_PER_BOARD;
83766bc63   Jiri Slaby   Char: mxser, prin...
2482
2483
  	dev_info(&pdev->dev, "found MOXA %s board (BusNo=%d, DevNo=%d)
  ",
1c45607ad   Jiri Slaby   Char: mxser, remo...
2484
2485
2486
2487
2488
  		mxser_cards[ent->driver_data].name,
  		pdev->bus->number, PCI_SLOT(pdev->devfn));
  
  	retval = pci_enable_device(pdev);
  	if (retval) {
83766bc63   Jiri Slaby   Char: mxser, prin...
2489
2490
  		dev_err(&pdev->dev, "PCI enable failed
  ");
1c45607ad   Jiri Slaby   Char: mxser, remo...
2491
2492
2493
2494
2495
2496
2497
  		goto err;
  	}
  
  	/* io address */
  	ioaddress = pci_resource_start(pdev, 2);
  	retval = pci_request_region(pdev, 2, "mxser(IO)");
  	if (retval)
df480518a   Jiri Slaby   Char: mxser, call...
2498
  		goto err_dis;
1c45607ad   Jiri Slaby   Char: mxser, remo...
2499
2500
2501
2502
2503
2504
2505
2506
2507
  
  	brd->info = &mxser_cards[ent->driver_data];
  	for (i = 0; i < brd->info->nports; i++)
  		brd->ports[i].ioaddr = ioaddress + 8 * i;
  
  	/* vector */
  	ioaddress = pci_resource_start(pdev, 3);
  	retval = pci_request_region(pdev, 3, "mxser(vector)");
  	if (retval)
df480518a   Jiri Slaby   Char: mxser, call...
2508
  		goto err_zero;
1c45607ad   Jiri Slaby   Char: mxser, remo...
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
  	brd->vector = ioaddress;
  
  	/* irq */
  	brd->irq = pdev->irq;
  
  	brd->chip_flag = CheckIsMoxaMust(brd->ports[0].ioaddr);
  	brd->uart_type = PORT_16550A;
  	brd->vector_mask = 0;
  
  	for (i = 0; i < brd->info->nports; i++) {
  		for (j = 0; j < UART_INFO_NUM; j++) {
  			if (Gpci_uart_info[j].type == brd->chip_flag) {
  				brd->ports[i].max_baud =
  					Gpci_uart_info[j].max_baud;
  
  				/* exception....CP-102 */
  				if (brd->info->flags & MXSER_HIGHBAUD)
  					brd->ports[i].max_baud = 921600;
  				break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2528
2529
  			}
  		}
1c45607ad   Jiri Slaby   Char: mxser, remo...
2530
2531
2532
2533
2534
2535
2536
2537
  	}
  
  	if (brd->chip_flag == MOXA_MUST_MU860_HWID) {
  		for (i = 0; i < brd->info->nports; i++) {
  			if (i < 4)
  				brd->ports[i].opmode_ioaddr = ioaddress + 4;
  			else
  				brd->ports[i].opmode_ioaddr = ioaddress + 0x0c;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2538
  		}
1c45607ad   Jiri Slaby   Char: mxser, remo...
2539
2540
  		outb(0, ioaddress + 4);	/* default set to RS232 mode */
  		outb(0, ioaddress + 0x0c);	/* default set to RS232 mode */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2541
  	}
1c45607ad   Jiri Slaby   Char: mxser, remo...
2542
2543
2544
2545
2546
2547
2548
2549
2550
  
  	for (i = 0; i < brd->info->nports; i++) {
  		brd->vector_mask |= (1 << i);
  		brd->ports[i].baud_base = 921600;
  	}
  
  	/* mxser_initbrd will hook ISR. */
  	retval = mxser_initbrd(brd, pdev);
  	if (retval)
df480518a   Jiri Slaby   Char: mxser, call...
2551
  		goto err_rel3;
1c45607ad   Jiri Slaby   Char: mxser, remo...
2552
2553
2554
2555
2556
2557
2558
  
  	for (i = 0; i < brd->info->nports; i++)
  		tty_register_device(mxvar_sdriver, brd->idx + i, &pdev->dev);
  
  	pci_set_drvdata(pdev, brd);
  
  	return 0;
df480518a   Jiri Slaby   Char: mxser, call...
2559
2560
2561
  err_rel3:
  	pci_release_region(pdev, 3);
  err_zero:
1c45607ad   Jiri Slaby   Char: mxser, remo...
2562
  	brd->info = NULL;
df480518a   Jiri Slaby   Char: mxser, call...
2563
2564
2565
  	pci_release_region(pdev, 2);
  err_dis:
  	pci_disable_device(pdev);
1c45607ad   Jiri Slaby   Char: mxser, remo...
2566
2567
2568
2569
2570
  err:
  	return retval;
  #else
  	return -ENODEV;
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2571
  }
1c45607ad   Jiri Slaby   Char: mxser, remo...
2572
  static void __devexit mxser_remove(struct pci_dev *pdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2573
  {
df480518a   Jiri Slaby   Char: mxser, call...
2574
  #ifdef CONFIG_PCI
1c45607ad   Jiri Slaby   Char: mxser, remo...
2575
2576
  	struct mxser_board *brd = pci_get_drvdata(pdev);
  	unsigned int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2577

1c45607ad   Jiri Slaby   Char: mxser, remo...
2578
2579
  	for (i = 0; i < brd->info->nports; i++)
  		tty_unregister_device(mxvar_sdriver, brd->idx + i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2580

df480518a   Jiri Slaby   Char: mxser, call...
2581
2582
2583
2584
  	free_irq(pdev->irq, brd);
  	pci_release_region(pdev, 2);
  	pci_release_region(pdev, 3);
  	pci_disable_device(pdev);
1c45607ad   Jiri Slaby   Char: mxser, remo...
2585
  	brd->info = NULL;
df480518a   Jiri Slaby   Char: mxser, call...
2586
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2587
  }
1c45607ad   Jiri Slaby   Char: mxser, remo...
2588
2589
2590
2591
2592
2593
2594
2595
  static struct pci_driver mxser_driver = {
  	.name = "mxser",
  	.id_table = mxser_pcibrds,
  	.probe = mxser_probe,
  	.remove = __devexit_p(mxser_remove)
  };
  
  static int __init mxser_module_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2596
  {
1c45607ad   Jiri Slaby   Char: mxser, remo...
2597
  	struct mxser_board *brd;
1df009247   Jiri Slaby   Char: mxser, remo...
2598
2599
  	unsigned int b, i, m;
  	int retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2600

1c45607ad   Jiri Slaby   Char: mxser, remo...
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
  	mxvar_sdriver = alloc_tty_driver(MXSER_PORTS + 1);
  	if (!mxvar_sdriver)
  		return -ENOMEM;
  
  	printk(KERN_INFO "MOXA Smartio/Industio family driver version %s
  ",
  		MXSER_VERSION);
  
  	/* Initialize the tty_driver structure */
  	mxvar_sdriver->owner = THIS_MODULE;
  	mxvar_sdriver->magic = TTY_DRIVER_MAGIC;
  	mxvar_sdriver->name = "ttyMI";
  	mxvar_sdriver->major = ttymajor;
  	mxvar_sdriver->minor_start = 0;
  	mxvar_sdriver->num = MXSER_PORTS + 1;
  	mxvar_sdriver->type = TTY_DRIVER_TYPE_SERIAL;
  	mxvar_sdriver->subtype = SERIAL_TYPE_NORMAL;
  	mxvar_sdriver->init_termios = tty_std_termios;
  	mxvar_sdriver->init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL;
  	mxvar_sdriver->flags = TTY_DRIVER_REAL_RAW|TTY_DRIVER_DYNAMIC_DEV;
  	tty_set_operations(mxvar_sdriver, &mxser_ops);
  
  	retval = tty_register_driver(mxvar_sdriver);
  	if (retval) {
  		printk(KERN_ERR "Couldn't install MOXA Smartio/Industio family "
  				"tty driver !
  ");
  		goto err_put;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2629
  	}
1c45607ad   Jiri Slaby   Char: mxser, remo...
2630

1c45607ad   Jiri Slaby   Char: mxser, remo...
2631
  	/* Start finding ISA boards here */
1df009247   Jiri Slaby   Char: mxser, remo...
2632
2633
2634
2635
2636
  	for (m = 0, b = 0; b < MXSER_BOARDS; b++) {
  		if (!ioaddr[b])
  			continue;
  
  		brd = &mxser_boards[m];
96050dfb2   Peter Botha   char: mxser, fix ...
2637
  		retval = mxser_get_ISA_conf(ioaddr[b], brd);
1df009247   Jiri Slaby   Char: mxser, remo...
2638
2639
2640
2641
  		if (retval <= 0) {
  			brd->info = NULL;
  			continue;
  		}
1c45607ad   Jiri Slaby   Char: mxser, remo...
2642

1df009247   Jiri Slaby   Char: mxser, remo...
2643
2644
2645
  		printk(KERN_INFO "mxser: found MOXA %s board (CAP=0x%lx)
  ",
  				brd->info->name, ioaddr[b]);
83766bc63   Jiri Slaby   Char: mxser, prin...
2646

1df009247   Jiri Slaby   Char: mxser, remo...
2647
2648
2649
2650
2651
  		/* mxser_initbrd will hook ISR. */
  		if (mxser_initbrd(brd, NULL) < 0) {
  			brd->info = NULL;
  			continue;
  		}
1c45607ad   Jiri Slaby   Char: mxser, remo...
2652

1df009247   Jiri Slaby   Char: mxser, remo...
2653
2654
2655
  		brd->idx = m * MXSER_PORTS_PER_BOARD;
  		for (i = 0; i < brd->info->nports; i++)
  			tty_register_device(mxvar_sdriver, brd->idx + i, NULL);
1c45607ad   Jiri Slaby   Char: mxser, remo...
2656

1df009247   Jiri Slaby   Char: mxser, remo...
2657
2658
  		m++;
  	}
1c45607ad   Jiri Slaby   Char: mxser, remo...
2659
2660
2661
  
  	retval = pci_register_driver(&mxser_driver);
  	if (retval) {
83766bc63   Jiri Slaby   Char: mxser, prin...
2662
2663
  		printk(KERN_ERR "mxser: can't register pci driver
  ");
1c45607ad   Jiri Slaby   Char: mxser, remo...
2664
2665
2666
2667
2668
  		if (!m) {
  			retval = -ENODEV;
  			goto err_unr;
  		} /* else: we have some ISA cards under control */
  	}
1c45607ad   Jiri Slaby   Char: mxser, remo...
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
  	return 0;
  err_unr:
  	tty_unregister_driver(mxvar_sdriver);
  err_put:
  	put_tty_driver(mxvar_sdriver);
  	return retval;
  }
  
  static void __exit mxser_module_exit(void)
  {
  	unsigned int i, j;
1c45607ad   Jiri Slaby   Char: mxser, remo...
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
  	pci_unregister_driver(&mxser_driver);
  
  	for (i = 0; i < MXSER_BOARDS; i++) /* ISA remains */
  		if (mxser_boards[i].info != NULL)
  			for (j = 0; j < mxser_boards[i].info->nports; j++)
  				tty_unregister_device(mxvar_sdriver,
  						mxser_boards[i].idx + j);
  	tty_unregister_driver(mxvar_sdriver);
  	put_tty_driver(mxvar_sdriver);
  
  	for (i = 0; i < MXSER_BOARDS; i++)
  		if (mxser_boards[i].info != NULL)
df480518a   Jiri Slaby   Char: mxser, call...
2692
  			mxser_release_ISA_res(&mxser_boards[i]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2693
2694
2695
2696
  }
  
  module_init(mxser_module_init);
  module_exit(mxser_module_exit);