xref: /openbmc/linux/drivers/tty/moxa.c (revision 191c5f10275cfbb36802edadbdb10c73537327b4)
1a6afd9f3SGreg Kroah-Hartman /*****************************************************************************/
2a6afd9f3SGreg Kroah-Hartman /*
3a6afd9f3SGreg Kroah-Hartman  *           moxa.c  -- MOXA Intellio family multiport serial driver.
4a6afd9f3SGreg Kroah-Hartman  *
5a6afd9f3SGreg Kroah-Hartman  *      Copyright (C) 1999-2000  Moxa Technologies (support@moxa.com).
6a6afd9f3SGreg Kroah-Hartman  *      Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com>
7a6afd9f3SGreg Kroah-Hartman  *
8a6afd9f3SGreg Kroah-Hartman  *      This code is loosely based on the Linux serial driver, written by
9a6afd9f3SGreg Kroah-Hartman  *      Linus Torvalds, Theodore T'so and others.
10a6afd9f3SGreg Kroah-Hartman  *
11a6afd9f3SGreg Kroah-Hartman  *      This program is free software; you can redistribute it and/or modify
12a6afd9f3SGreg Kroah-Hartman  *      it under the terms of the GNU General Public License as published by
13a6afd9f3SGreg Kroah-Hartman  *      the Free Software Foundation; either version 2 of the License, or
14a6afd9f3SGreg Kroah-Hartman  *      (at your option) any later version.
15a6afd9f3SGreg Kroah-Hartman  */
16a6afd9f3SGreg Kroah-Hartman 
17a6afd9f3SGreg Kroah-Hartman /*
18a6afd9f3SGreg Kroah-Hartman  *    MOXA Intellio Series Driver
19a6afd9f3SGreg Kroah-Hartman  *      for             : LINUX
20a6afd9f3SGreg Kroah-Hartman  *      date            : 1999/1/7
21a6afd9f3SGreg Kroah-Hartman  *      version         : 5.1
22a6afd9f3SGreg Kroah-Hartman  */
23a6afd9f3SGreg Kroah-Hartman 
24a6afd9f3SGreg Kroah-Hartman #include <linux/module.h>
25a6afd9f3SGreg Kroah-Hartman #include <linux/types.h>
26a6afd9f3SGreg Kroah-Hartman #include <linux/mm.h>
27a6afd9f3SGreg Kroah-Hartman #include <linux/ioport.h>
28a6afd9f3SGreg Kroah-Hartman #include <linux/errno.h>
29a6afd9f3SGreg Kroah-Hartman #include <linux/firmware.h>
30a6afd9f3SGreg Kroah-Hartman #include <linux/signal.h>
31a6afd9f3SGreg Kroah-Hartman #include <linux/sched.h>
32a6afd9f3SGreg Kroah-Hartman #include <linux/timer.h>
33a6afd9f3SGreg Kroah-Hartman #include <linux/interrupt.h>
34a6afd9f3SGreg Kroah-Hartman #include <linux/tty.h>
35a6afd9f3SGreg Kroah-Hartman #include <linux/tty_flip.h>
36a6afd9f3SGreg Kroah-Hartman #include <linux/major.h>
37a6afd9f3SGreg Kroah-Hartman #include <linux/string.h>
38a6afd9f3SGreg Kroah-Hartman #include <linux/fcntl.h>
39a6afd9f3SGreg Kroah-Hartman #include <linux/ptrace.h>
40a6afd9f3SGreg Kroah-Hartman #include <linux/serial.h>
41a6afd9f3SGreg Kroah-Hartman #include <linux/tty_driver.h>
42a6afd9f3SGreg Kroah-Hartman #include <linux/delay.h>
43a6afd9f3SGreg Kroah-Hartman #include <linux/pci.h>
44a6afd9f3SGreg Kroah-Hartman #include <linux/init.h>
45a6afd9f3SGreg Kroah-Hartman #include <linux/bitops.h>
46a6afd9f3SGreg Kroah-Hartman #include <linux/slab.h>
475a3c6b25SManuel Zerpies #include <linux/ratelimit.h>
48a6afd9f3SGreg Kroah-Hartman 
49a6afd9f3SGreg Kroah-Hartman #include <asm/io.h>
50a6afd9f3SGreg Kroah-Hartman #include <asm/uaccess.h>
51a6afd9f3SGreg Kroah-Hartman 
52a6afd9f3SGreg Kroah-Hartman #include "moxa.h"
53a6afd9f3SGreg Kroah-Hartman 
54a6afd9f3SGreg Kroah-Hartman #define MOXA_VERSION		"6.0k"
55a6afd9f3SGreg Kroah-Hartman 
56a6afd9f3SGreg Kroah-Hartman #define MOXA_FW_HDRLEN		32
57a6afd9f3SGreg Kroah-Hartman 
58a6afd9f3SGreg Kroah-Hartman #define MOXAMAJOR		172
59a6afd9f3SGreg Kroah-Hartman 
60a6afd9f3SGreg Kroah-Hartman #define MAX_BOARDS		4	/* Don't change this value */
61a6afd9f3SGreg Kroah-Hartman #define MAX_PORTS_PER_BOARD	32	/* Don't change this value */
62a6afd9f3SGreg Kroah-Hartman #define MAX_PORTS		(MAX_BOARDS * MAX_PORTS_PER_BOARD)
63a6afd9f3SGreg Kroah-Hartman 
64a6afd9f3SGreg Kroah-Hartman #define MOXA_IS_320(brd) ((brd)->boardType == MOXA_BOARD_C320_ISA || \
65a6afd9f3SGreg Kroah-Hartman 		(brd)->boardType == MOXA_BOARD_C320_PCI)
66a6afd9f3SGreg Kroah-Hartman 
67a6afd9f3SGreg Kroah-Hartman /*
68a6afd9f3SGreg Kroah-Hartman  *    Define the Moxa PCI vendor and device IDs.
69a6afd9f3SGreg Kroah-Hartman  */
70a6afd9f3SGreg Kroah-Hartman #define MOXA_BUS_TYPE_ISA	0
71a6afd9f3SGreg Kroah-Hartman #define MOXA_BUS_TYPE_PCI	1
72a6afd9f3SGreg Kroah-Hartman 
73a6afd9f3SGreg Kroah-Hartman enum {
74a6afd9f3SGreg Kroah-Hartman 	MOXA_BOARD_C218_PCI = 1,
75a6afd9f3SGreg Kroah-Hartman 	MOXA_BOARD_C218_ISA,
76a6afd9f3SGreg Kroah-Hartman 	MOXA_BOARD_C320_PCI,
77a6afd9f3SGreg Kroah-Hartman 	MOXA_BOARD_C320_ISA,
78a6afd9f3SGreg Kroah-Hartman 	MOXA_BOARD_CP204J,
79a6afd9f3SGreg Kroah-Hartman };
80a6afd9f3SGreg Kroah-Hartman 
81a6afd9f3SGreg Kroah-Hartman static char *moxa_brdname[] =
82a6afd9f3SGreg Kroah-Hartman {
83a6afd9f3SGreg Kroah-Hartman 	"C218 Turbo PCI series",
84a6afd9f3SGreg Kroah-Hartman 	"C218 Turbo ISA series",
85a6afd9f3SGreg Kroah-Hartman 	"C320 Turbo PCI series",
86a6afd9f3SGreg Kroah-Hartman 	"C320 Turbo ISA series",
87a6afd9f3SGreg Kroah-Hartman 	"CP-204J series",
88a6afd9f3SGreg Kroah-Hartman };
89a6afd9f3SGreg Kroah-Hartman 
90a6afd9f3SGreg Kroah-Hartman #ifdef CONFIG_PCI
91a6afd9f3SGreg Kroah-Hartman static struct pci_device_id moxa_pcibrds[] = {
92a6afd9f3SGreg Kroah-Hartman 	{ PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C218),
93a6afd9f3SGreg Kroah-Hartman 		.driver_data = MOXA_BOARD_C218_PCI },
94a6afd9f3SGreg Kroah-Hartman 	{ PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C320),
95a6afd9f3SGreg Kroah-Hartman 		.driver_data = MOXA_BOARD_C320_PCI },
96a6afd9f3SGreg Kroah-Hartman 	{ PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP204J),
97a6afd9f3SGreg Kroah-Hartman 		.driver_data = MOXA_BOARD_CP204J },
98a6afd9f3SGreg Kroah-Hartman 	{ 0 }
99a6afd9f3SGreg Kroah-Hartman };
100a6afd9f3SGreg Kroah-Hartman MODULE_DEVICE_TABLE(pci, moxa_pcibrds);
101a6afd9f3SGreg Kroah-Hartman #endif /* CONFIG_PCI */
102a6afd9f3SGreg Kroah-Hartman 
103a6afd9f3SGreg Kroah-Hartman struct moxa_port;
104a6afd9f3SGreg Kroah-Hartman 
105a6afd9f3SGreg Kroah-Hartman static struct moxa_board_conf {
106a6afd9f3SGreg Kroah-Hartman 	int boardType;
107a6afd9f3SGreg Kroah-Hartman 	int numPorts;
108a6afd9f3SGreg Kroah-Hartman 	int busType;
109a6afd9f3SGreg Kroah-Hartman 
110a6afd9f3SGreg Kroah-Hartman 	unsigned int ready;
111a6afd9f3SGreg Kroah-Hartman 
112a6afd9f3SGreg Kroah-Hartman 	struct moxa_port *ports;
113a6afd9f3SGreg Kroah-Hartman 
114a6afd9f3SGreg Kroah-Hartman 	void __iomem *basemem;
115a6afd9f3SGreg Kroah-Hartman 	void __iomem *intNdx;
116a6afd9f3SGreg Kroah-Hartman 	void __iomem *intPend;
117a6afd9f3SGreg Kroah-Hartman 	void __iomem *intTable;
118a6afd9f3SGreg Kroah-Hartman } moxa_boards[MAX_BOARDS];
119a6afd9f3SGreg Kroah-Hartman 
120a6afd9f3SGreg Kroah-Hartman struct mxser_mstatus {
121a6afd9f3SGreg Kroah-Hartman 	tcflag_t cflag;
122a6afd9f3SGreg Kroah-Hartman 	int cts;
123a6afd9f3SGreg Kroah-Hartman 	int dsr;
124a6afd9f3SGreg Kroah-Hartman 	int ri;
125a6afd9f3SGreg Kroah-Hartman 	int dcd;
126a6afd9f3SGreg Kroah-Hartman };
127a6afd9f3SGreg Kroah-Hartman 
128a6afd9f3SGreg Kroah-Hartman struct moxaq_str {
129a6afd9f3SGreg Kroah-Hartman 	int inq;
130a6afd9f3SGreg Kroah-Hartman 	int outq;
131a6afd9f3SGreg Kroah-Hartman };
132a6afd9f3SGreg Kroah-Hartman 
133a6afd9f3SGreg Kroah-Hartman struct moxa_port {
134a6afd9f3SGreg Kroah-Hartman 	struct tty_port port;
135a6afd9f3SGreg Kroah-Hartman 	struct moxa_board_conf *board;
136a6afd9f3SGreg Kroah-Hartman 	void __iomem *tableAddr;
137a6afd9f3SGreg Kroah-Hartman 
138a6afd9f3SGreg Kroah-Hartman 	int type;
139a6afd9f3SGreg Kroah-Hartman 	int cflag;
140a6afd9f3SGreg Kroah-Hartman 	unsigned long statusflags;
141a6afd9f3SGreg Kroah-Hartman 
142a6afd9f3SGreg Kroah-Hartman 	u8 DCDState;		/* Protected by the port lock */
143a6afd9f3SGreg Kroah-Hartman 	u8 lineCtrl;
144a6afd9f3SGreg Kroah-Hartman 	u8 lowChkFlag;
145a6afd9f3SGreg Kroah-Hartman };
146a6afd9f3SGreg Kroah-Hartman 
147a6afd9f3SGreg Kroah-Hartman struct mon_str {
148a6afd9f3SGreg Kroah-Hartman 	int tick;
149a6afd9f3SGreg Kroah-Hartman 	int rxcnt[MAX_PORTS];
150a6afd9f3SGreg Kroah-Hartman 	int txcnt[MAX_PORTS];
151a6afd9f3SGreg Kroah-Hartman };
152a6afd9f3SGreg Kroah-Hartman 
153a6afd9f3SGreg Kroah-Hartman /* statusflags */
154a6afd9f3SGreg Kroah-Hartman #define TXSTOPPED	1
155a6afd9f3SGreg Kroah-Hartman #define LOWWAIT 	2
156a6afd9f3SGreg Kroah-Hartman #define EMPTYWAIT	3
157a6afd9f3SGreg Kroah-Hartman 
158a6afd9f3SGreg Kroah-Hartman #define SERIAL_DO_RESTART
159a6afd9f3SGreg Kroah-Hartman 
160a6afd9f3SGreg Kroah-Hartman #define WAKEUP_CHARS		256
161a6afd9f3SGreg Kroah-Hartman 
162a6afd9f3SGreg Kroah-Hartman static int ttymajor = MOXAMAJOR;
163a6afd9f3SGreg Kroah-Hartman static struct mon_str moxaLog;
164a6afd9f3SGreg Kroah-Hartman static unsigned int moxaFuncTout = HZ / 2;
165a6afd9f3SGreg Kroah-Hartman static unsigned int moxaLowWaterChk;
166a6afd9f3SGreg Kroah-Hartman static DEFINE_MUTEX(moxa_openlock);
167a6afd9f3SGreg Kroah-Hartman static DEFINE_SPINLOCK(moxa_lock);
168a6afd9f3SGreg Kroah-Hartman 
169a6afd9f3SGreg Kroah-Hartman static unsigned long baseaddr[MAX_BOARDS];
170a6afd9f3SGreg Kroah-Hartman static unsigned int type[MAX_BOARDS];
171a6afd9f3SGreg Kroah-Hartman static unsigned int numports[MAX_BOARDS];
172793be898SJiri Slaby static struct tty_port moxa_service_port;
173a6afd9f3SGreg Kroah-Hartman 
174a6afd9f3SGreg Kroah-Hartman MODULE_AUTHOR("William Chen");
175a6afd9f3SGreg Kroah-Hartman MODULE_DESCRIPTION("MOXA Intellio Family Multiport Board Device Driver");
176a6afd9f3SGreg Kroah-Hartman MODULE_LICENSE("GPL");
177a6afd9f3SGreg Kroah-Hartman MODULE_FIRMWARE("c218tunx.cod");
178a6afd9f3SGreg Kroah-Hartman MODULE_FIRMWARE("cp204unx.cod");
179a6afd9f3SGreg Kroah-Hartman MODULE_FIRMWARE("c320tunx.cod");
180a6afd9f3SGreg Kroah-Hartman 
181a6afd9f3SGreg Kroah-Hartman module_param_array(type, uint, NULL, 0);
182a6afd9f3SGreg Kroah-Hartman MODULE_PARM_DESC(type, "card type: C218=2, C320=4");
183a6afd9f3SGreg Kroah-Hartman module_param_array(baseaddr, ulong, NULL, 0);
184a6afd9f3SGreg Kroah-Hartman MODULE_PARM_DESC(baseaddr, "base address");
185a6afd9f3SGreg Kroah-Hartman module_param_array(numports, uint, NULL, 0);
186a6afd9f3SGreg Kroah-Hartman MODULE_PARM_DESC(numports, "numports (ignored for C218)");
187a6afd9f3SGreg Kroah-Hartman 
188a6afd9f3SGreg Kroah-Hartman module_param(ttymajor, int, 0);
189a6afd9f3SGreg Kroah-Hartman 
190a6afd9f3SGreg Kroah-Hartman /*
191a6afd9f3SGreg Kroah-Hartman  * static functions:
192a6afd9f3SGreg Kroah-Hartman  */
193a6afd9f3SGreg Kroah-Hartman static int moxa_open(struct tty_struct *, struct file *);
194a6afd9f3SGreg Kroah-Hartman static void moxa_close(struct tty_struct *, struct file *);
195a6afd9f3SGreg Kroah-Hartman static int moxa_write(struct tty_struct *, const unsigned char *, int);
196a6afd9f3SGreg Kroah-Hartman static int moxa_write_room(struct tty_struct *);
197a6afd9f3SGreg Kroah-Hartman static void moxa_flush_buffer(struct tty_struct *);
198a6afd9f3SGreg Kroah-Hartman static int moxa_chars_in_buffer(struct tty_struct *);
199a6afd9f3SGreg Kroah-Hartman static void moxa_set_termios(struct tty_struct *, struct ktermios *);
200a6afd9f3SGreg Kroah-Hartman static void moxa_stop(struct tty_struct *);
201a6afd9f3SGreg Kroah-Hartman static void moxa_start(struct tty_struct *);
202a6afd9f3SGreg Kroah-Hartman static void moxa_hangup(struct tty_struct *);
203a6afd9f3SGreg Kroah-Hartman static int moxa_tiocmget(struct tty_struct *tty);
204a6afd9f3SGreg Kroah-Hartman static int moxa_tiocmset(struct tty_struct *tty,
205a6afd9f3SGreg Kroah-Hartman 			 unsigned int set, unsigned int clear);
206a6afd9f3SGreg Kroah-Hartman static void moxa_poll(unsigned long);
207a6afd9f3SGreg Kroah-Hartman static void moxa_set_tty_param(struct tty_struct *, struct ktermios *);
208a6afd9f3SGreg Kroah-Hartman static void moxa_shutdown(struct tty_port *);
209a6afd9f3SGreg Kroah-Hartman static int moxa_carrier_raised(struct tty_port *);
210a6afd9f3SGreg Kroah-Hartman static void moxa_dtr_rts(struct tty_port *, int);
211a6afd9f3SGreg Kroah-Hartman /*
212a6afd9f3SGreg Kroah-Hartman  * moxa board interface functions:
213a6afd9f3SGreg Kroah-Hartman  */
214a6afd9f3SGreg Kroah-Hartman static void MoxaPortEnable(struct moxa_port *);
215a6afd9f3SGreg Kroah-Hartman static void MoxaPortDisable(struct moxa_port *);
216a6afd9f3SGreg Kroah-Hartman static int MoxaPortSetTermio(struct moxa_port *, struct ktermios *, speed_t);
217a6afd9f3SGreg Kroah-Hartman static int MoxaPortGetLineOut(struct moxa_port *, int *, int *);
218a6afd9f3SGreg Kroah-Hartman static void MoxaPortLineCtrl(struct moxa_port *, int, int);
219a6afd9f3SGreg Kroah-Hartman static void MoxaPortFlowCtrl(struct moxa_port *, int, int, int, int, int);
220a6afd9f3SGreg Kroah-Hartman static int MoxaPortLineStatus(struct moxa_port *);
221a6afd9f3SGreg Kroah-Hartman static void MoxaPortFlushData(struct moxa_port *, int);
222a6afd9f3SGreg Kroah-Hartman static int MoxaPortWriteData(struct tty_struct *, const unsigned char *, int);
223a6afd9f3SGreg Kroah-Hartman static int MoxaPortReadData(struct moxa_port *);
224a6afd9f3SGreg Kroah-Hartman static int MoxaPortTxQueue(struct moxa_port *);
225a6afd9f3SGreg Kroah-Hartman static int MoxaPortRxQueue(struct moxa_port *);
226a6afd9f3SGreg Kroah-Hartman static int MoxaPortTxFree(struct moxa_port *);
227a6afd9f3SGreg Kroah-Hartman static void MoxaPortTxDisable(struct moxa_port *);
228a6afd9f3SGreg Kroah-Hartman static void MoxaPortTxEnable(struct moxa_port *);
229a6afd9f3SGreg Kroah-Hartman static int moxa_get_serial_info(struct moxa_port *, struct serial_struct __user *);
230a6afd9f3SGreg Kroah-Hartman static int moxa_set_serial_info(struct moxa_port *, struct serial_struct __user *);
231a6afd9f3SGreg Kroah-Hartman static void MoxaSetFifo(struct moxa_port *port, int enable);
232a6afd9f3SGreg Kroah-Hartman 
233a6afd9f3SGreg Kroah-Hartman /*
234a6afd9f3SGreg Kroah-Hartman  * I/O functions
235a6afd9f3SGreg Kroah-Hartman  */
236a6afd9f3SGreg Kroah-Hartman 
237a6afd9f3SGreg Kroah-Hartman static DEFINE_SPINLOCK(moxafunc_lock);
238a6afd9f3SGreg Kroah-Hartman 
239a6afd9f3SGreg Kroah-Hartman static void moxa_wait_finish(void __iomem *ofsAddr)
240a6afd9f3SGreg Kroah-Hartman {
241a6afd9f3SGreg Kroah-Hartman 	unsigned long end = jiffies + moxaFuncTout;
242a6afd9f3SGreg Kroah-Hartman 
243a6afd9f3SGreg Kroah-Hartman 	while (readw(ofsAddr + FuncCode) != 0)
244a6afd9f3SGreg Kroah-Hartman 		if (time_after(jiffies, end))
245a6afd9f3SGreg Kroah-Hartman 			return;
2465a3c6b25SManuel Zerpies 	if (readw(ofsAddr + FuncCode) != 0)
2475a3c6b25SManuel Zerpies 		printk_ratelimited(KERN_WARNING "moxa function expired\n");
248a6afd9f3SGreg Kroah-Hartman }
249a6afd9f3SGreg Kroah-Hartman 
250a6afd9f3SGreg Kroah-Hartman static void moxafunc(void __iomem *ofsAddr, u16 cmd, u16 arg)
251a6afd9f3SGreg Kroah-Hartman {
252a6afd9f3SGreg Kroah-Hartman         unsigned long flags;
253a6afd9f3SGreg Kroah-Hartman         spin_lock_irqsave(&moxafunc_lock, flags);
254a6afd9f3SGreg Kroah-Hartman 	writew(arg, ofsAddr + FuncArg);
255a6afd9f3SGreg Kroah-Hartman 	writew(cmd, ofsAddr + FuncCode);
256a6afd9f3SGreg Kroah-Hartman 	moxa_wait_finish(ofsAddr);
257a6afd9f3SGreg Kroah-Hartman 	spin_unlock_irqrestore(&moxafunc_lock, flags);
258a6afd9f3SGreg Kroah-Hartman }
259a6afd9f3SGreg Kroah-Hartman 
260a6afd9f3SGreg Kroah-Hartman static int moxafuncret(void __iomem *ofsAddr, u16 cmd, u16 arg)
261a6afd9f3SGreg Kroah-Hartman {
262a6afd9f3SGreg Kroah-Hartman         unsigned long flags;
263a6afd9f3SGreg Kroah-Hartman         u16 ret;
264a6afd9f3SGreg Kroah-Hartman         spin_lock_irqsave(&moxafunc_lock, flags);
265a6afd9f3SGreg Kroah-Hartman 	writew(arg, ofsAddr + FuncArg);
266a6afd9f3SGreg Kroah-Hartman 	writew(cmd, ofsAddr + FuncCode);
267a6afd9f3SGreg Kroah-Hartman 	moxa_wait_finish(ofsAddr);
268a6afd9f3SGreg Kroah-Hartman 	ret = readw(ofsAddr + FuncArg);
269a6afd9f3SGreg Kroah-Hartman 	spin_unlock_irqrestore(&moxafunc_lock, flags);
270a6afd9f3SGreg Kroah-Hartman 	return ret;
271a6afd9f3SGreg Kroah-Hartman }
272a6afd9f3SGreg Kroah-Hartman 
273a6afd9f3SGreg Kroah-Hartman static void moxa_low_water_check(void __iomem *ofsAddr)
274a6afd9f3SGreg Kroah-Hartman {
275a6afd9f3SGreg Kroah-Hartman 	u16 rptr, wptr, mask, len;
276a6afd9f3SGreg Kroah-Hartman 
277a6afd9f3SGreg Kroah-Hartman 	if (readb(ofsAddr + FlagStat) & Xoff_state) {
278a6afd9f3SGreg Kroah-Hartman 		rptr = readw(ofsAddr + RXrptr);
279a6afd9f3SGreg Kroah-Hartman 		wptr = readw(ofsAddr + RXwptr);
280a6afd9f3SGreg Kroah-Hartman 		mask = readw(ofsAddr + RX_mask);
281a6afd9f3SGreg Kroah-Hartman 		len = (wptr - rptr) & mask;
282a6afd9f3SGreg Kroah-Hartman 		if (len <= Low_water)
283a6afd9f3SGreg Kroah-Hartman 			moxafunc(ofsAddr, FC_SendXon, 0);
284a6afd9f3SGreg Kroah-Hartman 	}
285a6afd9f3SGreg Kroah-Hartman }
286a6afd9f3SGreg Kroah-Hartman 
287a6afd9f3SGreg Kroah-Hartman /*
288a6afd9f3SGreg Kroah-Hartman  * TTY operations
289a6afd9f3SGreg Kroah-Hartman  */
290a6afd9f3SGreg Kroah-Hartman 
291a6afd9f3SGreg Kroah-Hartman static int moxa_ioctl(struct tty_struct *tty,
292a6afd9f3SGreg Kroah-Hartman 		      unsigned int cmd, unsigned long arg)
293a6afd9f3SGreg Kroah-Hartman {
294a6afd9f3SGreg Kroah-Hartman 	struct moxa_port *ch = tty->driver_data;
295a6afd9f3SGreg Kroah-Hartman 	void __user *argp = (void __user *)arg;
296a6afd9f3SGreg Kroah-Hartman 	int status, ret = 0;
297a6afd9f3SGreg Kroah-Hartman 
298a6afd9f3SGreg Kroah-Hartman 	if (tty->index == MAX_PORTS) {
299a6afd9f3SGreg Kroah-Hartman 		if (cmd != MOXA_GETDATACOUNT && cmd != MOXA_GET_IOQUEUE &&
300a6afd9f3SGreg Kroah-Hartman 				cmd != MOXA_GETMSTATUS)
301a6afd9f3SGreg Kroah-Hartman 			return -EINVAL;
302a6afd9f3SGreg Kroah-Hartman 	} else if (!ch)
303a6afd9f3SGreg Kroah-Hartman 		return -ENODEV;
304a6afd9f3SGreg Kroah-Hartman 
305a6afd9f3SGreg Kroah-Hartman 	switch (cmd) {
306a6afd9f3SGreg Kroah-Hartman 	case MOXA_GETDATACOUNT:
307a6afd9f3SGreg Kroah-Hartman 		moxaLog.tick = jiffies;
308a6afd9f3SGreg Kroah-Hartman 		if (copy_to_user(argp, &moxaLog, sizeof(moxaLog)))
309a6afd9f3SGreg Kroah-Hartman 			ret = -EFAULT;
310a6afd9f3SGreg Kroah-Hartman 		break;
311a6afd9f3SGreg Kroah-Hartman 	case MOXA_FLUSH_QUEUE:
312a6afd9f3SGreg Kroah-Hartman 		MoxaPortFlushData(ch, arg);
313a6afd9f3SGreg Kroah-Hartman 		break;
314a6afd9f3SGreg Kroah-Hartman 	case MOXA_GET_IOQUEUE: {
315a6afd9f3SGreg Kroah-Hartman 		struct moxaq_str __user *argm = argp;
316a6afd9f3SGreg Kroah-Hartman 		struct moxaq_str tmp;
317a6afd9f3SGreg Kroah-Hartman 		struct moxa_port *p;
318a6afd9f3SGreg Kroah-Hartman 		unsigned int i, j;
319a6afd9f3SGreg Kroah-Hartman 
320a6afd9f3SGreg Kroah-Hartman 		for (i = 0; i < MAX_BOARDS; i++) {
321a6afd9f3SGreg Kroah-Hartman 			p = moxa_boards[i].ports;
322a6afd9f3SGreg Kroah-Hartman 			for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
323a6afd9f3SGreg Kroah-Hartman 				memset(&tmp, 0, sizeof(tmp));
324a6afd9f3SGreg Kroah-Hartman 				spin_lock_bh(&moxa_lock);
325a6afd9f3SGreg Kroah-Hartman 				if (moxa_boards[i].ready) {
326a6afd9f3SGreg Kroah-Hartman 					tmp.inq = MoxaPortRxQueue(p);
327a6afd9f3SGreg Kroah-Hartman 					tmp.outq = MoxaPortTxQueue(p);
328a6afd9f3SGreg Kroah-Hartman 				}
329a6afd9f3SGreg Kroah-Hartman 				spin_unlock_bh(&moxa_lock);
330a6afd9f3SGreg Kroah-Hartman 				if (copy_to_user(argm, &tmp, sizeof(tmp)))
331a6afd9f3SGreg Kroah-Hartman 					return -EFAULT;
332a6afd9f3SGreg Kroah-Hartman 			}
333a6afd9f3SGreg Kroah-Hartman 		}
334a6afd9f3SGreg Kroah-Hartman 		break;
335a6afd9f3SGreg Kroah-Hartman 	} case MOXA_GET_OQUEUE:
336a6afd9f3SGreg Kroah-Hartman 		status = MoxaPortTxQueue(ch);
337a6afd9f3SGreg Kroah-Hartman 		ret = put_user(status, (unsigned long __user *)argp);
338a6afd9f3SGreg Kroah-Hartman 		break;
339a6afd9f3SGreg Kroah-Hartman 	case MOXA_GET_IQUEUE:
340a6afd9f3SGreg Kroah-Hartman 		status = MoxaPortRxQueue(ch);
341a6afd9f3SGreg Kroah-Hartman 		ret = put_user(status, (unsigned long __user *)argp);
342a6afd9f3SGreg Kroah-Hartman 		break;
343a6afd9f3SGreg Kroah-Hartman 	case MOXA_GETMSTATUS: {
344a6afd9f3SGreg Kroah-Hartman 		struct mxser_mstatus __user *argm = argp;
345a6afd9f3SGreg Kroah-Hartman 		struct mxser_mstatus tmp;
346a6afd9f3SGreg Kroah-Hartman 		struct moxa_port *p;
347a6afd9f3SGreg Kroah-Hartman 		unsigned int i, j;
348a6afd9f3SGreg Kroah-Hartman 
349a6afd9f3SGreg Kroah-Hartman 		for (i = 0; i < MAX_BOARDS; i++) {
350a6afd9f3SGreg Kroah-Hartman 			p = moxa_boards[i].ports;
351a6afd9f3SGreg Kroah-Hartman 			for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
352a6afd9f3SGreg Kroah-Hartman 				struct tty_struct *ttyp;
353a6afd9f3SGreg Kroah-Hartman 				memset(&tmp, 0, sizeof(tmp));
354a6afd9f3SGreg Kroah-Hartman 				spin_lock_bh(&moxa_lock);
355a6afd9f3SGreg Kroah-Hartman 				if (!moxa_boards[i].ready) {
356a6afd9f3SGreg Kroah-Hartman 				        spin_unlock_bh(&moxa_lock);
357a6afd9f3SGreg Kroah-Hartman 					goto copy;
358a6afd9f3SGreg Kroah-Hartman                                 }
359a6afd9f3SGreg Kroah-Hartman 
360a6afd9f3SGreg Kroah-Hartman 				status = MoxaPortLineStatus(p);
361a6afd9f3SGreg Kroah-Hartman 				spin_unlock_bh(&moxa_lock);
362a6afd9f3SGreg Kroah-Hartman 
363a6afd9f3SGreg Kroah-Hartman 				if (status & 1)
364a6afd9f3SGreg Kroah-Hartman 					tmp.cts = 1;
365a6afd9f3SGreg Kroah-Hartman 				if (status & 2)
366a6afd9f3SGreg Kroah-Hartman 					tmp.dsr = 1;
367a6afd9f3SGreg Kroah-Hartman 				if (status & 4)
368a6afd9f3SGreg Kroah-Hartman 					tmp.dcd = 1;
369a6afd9f3SGreg Kroah-Hartman 
370a6afd9f3SGreg Kroah-Hartman 				ttyp = tty_port_tty_get(&p->port);
371adc8d746SAlan Cox 				if (!ttyp)
372a6afd9f3SGreg Kroah-Hartman 					tmp.cflag = p->cflag;
373a6afd9f3SGreg Kroah-Hartman 				else
374adc8d746SAlan Cox 					tmp.cflag = ttyp->termios.c_cflag;
375df43daaaSJulia Lawall 				tty_kref_put(ttyp);
376a6afd9f3SGreg Kroah-Hartman copy:
377a6afd9f3SGreg Kroah-Hartman 				if (copy_to_user(argm, &tmp, sizeof(tmp)))
378a6afd9f3SGreg Kroah-Hartman 					return -EFAULT;
379a6afd9f3SGreg Kroah-Hartman 			}
380a6afd9f3SGreg Kroah-Hartman 		}
381a6afd9f3SGreg Kroah-Hartman 		break;
382a6afd9f3SGreg Kroah-Hartman 	}
383a6afd9f3SGreg Kroah-Hartman 	case TIOCGSERIAL:
384a6afd9f3SGreg Kroah-Hartman 	        mutex_lock(&ch->port.mutex);
385a6afd9f3SGreg Kroah-Hartman 		ret = moxa_get_serial_info(ch, argp);
386a6afd9f3SGreg Kroah-Hartman 		mutex_unlock(&ch->port.mutex);
387a6afd9f3SGreg Kroah-Hartman 		break;
388a6afd9f3SGreg Kroah-Hartman 	case TIOCSSERIAL:
389a6afd9f3SGreg Kroah-Hartman 	        mutex_lock(&ch->port.mutex);
390a6afd9f3SGreg Kroah-Hartman 		ret = moxa_set_serial_info(ch, argp);
391a6afd9f3SGreg Kroah-Hartman 		mutex_unlock(&ch->port.mutex);
392a6afd9f3SGreg Kroah-Hartman 		break;
393a6afd9f3SGreg Kroah-Hartman 	default:
394a6afd9f3SGreg Kroah-Hartman 		ret = -ENOIOCTLCMD;
395a6afd9f3SGreg Kroah-Hartman 	}
396a6afd9f3SGreg Kroah-Hartman 	return ret;
397a6afd9f3SGreg Kroah-Hartman }
398a6afd9f3SGreg Kroah-Hartman 
399a6afd9f3SGreg Kroah-Hartman static int moxa_break_ctl(struct tty_struct *tty, int state)
400a6afd9f3SGreg Kroah-Hartman {
401a6afd9f3SGreg Kroah-Hartman 	struct moxa_port *port = tty->driver_data;
402a6afd9f3SGreg Kroah-Hartman 
403a6afd9f3SGreg Kroah-Hartman 	moxafunc(port->tableAddr, state ? FC_SendBreak : FC_StopBreak,
404a6afd9f3SGreg Kroah-Hartman 			Magic_code);
405a6afd9f3SGreg Kroah-Hartman 	return 0;
406a6afd9f3SGreg Kroah-Hartman }
407a6afd9f3SGreg Kroah-Hartman 
408a6afd9f3SGreg Kroah-Hartman static const struct tty_operations moxa_ops = {
409a6afd9f3SGreg Kroah-Hartman 	.open = moxa_open,
410a6afd9f3SGreg Kroah-Hartman 	.close = moxa_close,
411a6afd9f3SGreg Kroah-Hartman 	.write = moxa_write,
412a6afd9f3SGreg Kroah-Hartman 	.write_room = moxa_write_room,
413a6afd9f3SGreg Kroah-Hartman 	.flush_buffer = moxa_flush_buffer,
414a6afd9f3SGreg Kroah-Hartman 	.chars_in_buffer = moxa_chars_in_buffer,
415a6afd9f3SGreg Kroah-Hartman 	.ioctl = moxa_ioctl,
416a6afd9f3SGreg Kroah-Hartman 	.set_termios = moxa_set_termios,
417a6afd9f3SGreg Kroah-Hartman 	.stop = moxa_stop,
418a6afd9f3SGreg Kroah-Hartman 	.start = moxa_start,
419a6afd9f3SGreg Kroah-Hartman 	.hangup = moxa_hangup,
420a6afd9f3SGreg Kroah-Hartman 	.break_ctl = moxa_break_ctl,
421a6afd9f3SGreg Kroah-Hartman 	.tiocmget = moxa_tiocmget,
422a6afd9f3SGreg Kroah-Hartman 	.tiocmset = moxa_tiocmset,
423a6afd9f3SGreg Kroah-Hartman };
424a6afd9f3SGreg Kroah-Hartman 
425a6afd9f3SGreg Kroah-Hartman static const struct tty_port_operations moxa_port_ops = {
426a6afd9f3SGreg Kroah-Hartman 	.carrier_raised = moxa_carrier_raised,
427a6afd9f3SGreg Kroah-Hartman 	.dtr_rts = moxa_dtr_rts,
428a6afd9f3SGreg Kroah-Hartman 	.shutdown = moxa_shutdown,
429a6afd9f3SGreg Kroah-Hartman };
430a6afd9f3SGreg Kroah-Hartman 
431a6afd9f3SGreg Kroah-Hartman static struct tty_driver *moxaDriver;
432a6afd9f3SGreg Kroah-Hartman static DEFINE_TIMER(moxaTimer, moxa_poll, 0, 0);
433a6afd9f3SGreg Kroah-Hartman 
434a6afd9f3SGreg Kroah-Hartman /*
435a6afd9f3SGreg Kroah-Hartman  * HW init
436a6afd9f3SGreg Kroah-Hartman  */
437a6afd9f3SGreg Kroah-Hartman 
438a6afd9f3SGreg Kroah-Hartman static int moxa_check_fw_model(struct moxa_board_conf *brd, u8 model)
439a6afd9f3SGreg Kroah-Hartman {
440a6afd9f3SGreg Kroah-Hartman 	switch (brd->boardType) {
441a6afd9f3SGreg Kroah-Hartman 	case MOXA_BOARD_C218_ISA:
442a6afd9f3SGreg Kroah-Hartman 	case MOXA_BOARD_C218_PCI:
443a6afd9f3SGreg Kroah-Hartman 		if (model != 1)
444a6afd9f3SGreg Kroah-Hartman 			goto err;
445a6afd9f3SGreg Kroah-Hartman 		break;
446a6afd9f3SGreg Kroah-Hartman 	case MOXA_BOARD_CP204J:
447a6afd9f3SGreg Kroah-Hartman 		if (model != 3)
448a6afd9f3SGreg Kroah-Hartman 			goto err;
449a6afd9f3SGreg Kroah-Hartman 		break;
450a6afd9f3SGreg Kroah-Hartman 	default:
451a6afd9f3SGreg Kroah-Hartman 		if (model != 2)
452a6afd9f3SGreg Kroah-Hartman 			goto err;
453a6afd9f3SGreg Kroah-Hartman 		break;
454a6afd9f3SGreg Kroah-Hartman 	}
455a6afd9f3SGreg Kroah-Hartman 	return 0;
456a6afd9f3SGreg Kroah-Hartman err:
457a6afd9f3SGreg Kroah-Hartman 	return -EINVAL;
458a6afd9f3SGreg Kroah-Hartman }
459a6afd9f3SGreg Kroah-Hartman 
460a6afd9f3SGreg Kroah-Hartman static int moxa_check_fw(const void *ptr)
461a6afd9f3SGreg Kroah-Hartman {
462a6afd9f3SGreg Kroah-Hartman 	const __le16 *lptr = ptr;
463a6afd9f3SGreg Kroah-Hartman 
464a6afd9f3SGreg Kroah-Hartman 	if (*lptr != cpu_to_le16(0x7980))
465a6afd9f3SGreg Kroah-Hartman 		return -EINVAL;
466a6afd9f3SGreg Kroah-Hartman 
467a6afd9f3SGreg Kroah-Hartman 	return 0;
468a6afd9f3SGreg Kroah-Hartman }
469a6afd9f3SGreg Kroah-Hartman 
470a6afd9f3SGreg Kroah-Hartman static int moxa_load_bios(struct moxa_board_conf *brd, const u8 *buf,
471a6afd9f3SGreg Kroah-Hartman 		size_t len)
472a6afd9f3SGreg Kroah-Hartman {
473a6afd9f3SGreg Kroah-Hartman 	void __iomem *baseAddr = brd->basemem;
474a6afd9f3SGreg Kroah-Hartman 	u16 tmp;
475a6afd9f3SGreg Kroah-Hartman 
476a6afd9f3SGreg Kroah-Hartman 	writeb(HW_reset, baseAddr + Control_reg);	/* reset */
477a6afd9f3SGreg Kroah-Hartman 	msleep(10);
478a6afd9f3SGreg Kroah-Hartman 	memset_io(baseAddr, 0, 4096);
479a6afd9f3SGreg Kroah-Hartman 	memcpy_toio(baseAddr, buf, len);	/* download BIOS */
480a6afd9f3SGreg Kroah-Hartman 	writeb(0, baseAddr + Control_reg);	/* restart */
481a6afd9f3SGreg Kroah-Hartman 
482a6afd9f3SGreg Kroah-Hartman 	msleep(2000);
483a6afd9f3SGreg Kroah-Hartman 
484a6afd9f3SGreg Kroah-Hartman 	switch (brd->boardType) {
485a6afd9f3SGreg Kroah-Hartman 	case MOXA_BOARD_C218_ISA:
486a6afd9f3SGreg Kroah-Hartman 	case MOXA_BOARD_C218_PCI:
487a6afd9f3SGreg Kroah-Hartman 		tmp = readw(baseAddr + C218_key);
488a6afd9f3SGreg Kroah-Hartman 		if (tmp != C218_KeyCode)
489a6afd9f3SGreg Kroah-Hartman 			goto err;
490a6afd9f3SGreg Kroah-Hartman 		break;
491a6afd9f3SGreg Kroah-Hartman 	case MOXA_BOARD_CP204J:
492a6afd9f3SGreg Kroah-Hartman 		tmp = readw(baseAddr + C218_key);
493a6afd9f3SGreg Kroah-Hartman 		if (tmp != CP204J_KeyCode)
494a6afd9f3SGreg Kroah-Hartman 			goto err;
495a6afd9f3SGreg Kroah-Hartman 		break;
496a6afd9f3SGreg Kroah-Hartman 	default:
497a6afd9f3SGreg Kroah-Hartman 		tmp = readw(baseAddr + C320_key);
498a6afd9f3SGreg Kroah-Hartman 		if (tmp != C320_KeyCode)
499a6afd9f3SGreg Kroah-Hartman 			goto err;
500a6afd9f3SGreg Kroah-Hartman 		tmp = readw(baseAddr + C320_status);
501a6afd9f3SGreg Kroah-Hartman 		if (tmp != STS_init) {
502a6afd9f3SGreg Kroah-Hartman 			printk(KERN_ERR "MOXA: bios upload failed -- CPU/Basic "
503a6afd9f3SGreg Kroah-Hartman 					"module not found\n");
504a6afd9f3SGreg Kroah-Hartman 			return -EIO;
505a6afd9f3SGreg Kroah-Hartman 		}
506a6afd9f3SGreg Kroah-Hartman 		break;
507a6afd9f3SGreg Kroah-Hartman 	}
508a6afd9f3SGreg Kroah-Hartman 
509a6afd9f3SGreg Kroah-Hartman 	return 0;
510a6afd9f3SGreg Kroah-Hartman err:
511a6afd9f3SGreg Kroah-Hartman 	printk(KERN_ERR "MOXA: bios upload failed -- board not found\n");
512a6afd9f3SGreg Kroah-Hartman 	return -EIO;
513a6afd9f3SGreg Kroah-Hartman }
514a6afd9f3SGreg Kroah-Hartman 
515a6afd9f3SGreg Kroah-Hartman static int moxa_load_320b(struct moxa_board_conf *brd, const u8 *ptr,
516a6afd9f3SGreg Kroah-Hartman 		size_t len)
517a6afd9f3SGreg Kroah-Hartman {
518a6afd9f3SGreg Kroah-Hartman 	void __iomem *baseAddr = brd->basemem;
519a6afd9f3SGreg Kroah-Hartman 
520a6afd9f3SGreg Kroah-Hartman 	if (len < 7168) {
521a6afd9f3SGreg Kroah-Hartman 		printk(KERN_ERR "MOXA: invalid 320 bios -- too short\n");
522a6afd9f3SGreg Kroah-Hartman 		return -EINVAL;
523a6afd9f3SGreg Kroah-Hartman 	}
524a6afd9f3SGreg Kroah-Hartman 
525a6afd9f3SGreg Kroah-Hartman 	writew(len - 7168 - 2, baseAddr + C320bapi_len);
526a6afd9f3SGreg Kroah-Hartman 	writeb(1, baseAddr + Control_reg);	/* Select Page 1 */
527a6afd9f3SGreg Kroah-Hartman 	memcpy_toio(baseAddr + DynPage_addr, ptr, 7168);
528a6afd9f3SGreg Kroah-Hartman 	writeb(2, baseAddr + Control_reg);	/* Select Page 2 */
529a6afd9f3SGreg Kroah-Hartman 	memcpy_toio(baseAddr + DynPage_addr, ptr + 7168, len - 7168);
530a6afd9f3SGreg Kroah-Hartman 
531a6afd9f3SGreg Kroah-Hartman 	return 0;
532a6afd9f3SGreg Kroah-Hartman }
533a6afd9f3SGreg Kroah-Hartman 
534a6afd9f3SGreg Kroah-Hartman static int moxa_real_load_code(struct moxa_board_conf *brd, const void *ptr,
535a6afd9f3SGreg Kroah-Hartman 		size_t len)
536a6afd9f3SGreg Kroah-Hartman {
537a6afd9f3SGreg Kroah-Hartman 	void __iomem *baseAddr = brd->basemem;
538a6afd9f3SGreg Kroah-Hartman 	const __le16 *uptr = ptr;
539a6afd9f3SGreg Kroah-Hartman 	size_t wlen, len2, j;
540a6afd9f3SGreg Kroah-Hartman 	unsigned long key, loadbuf, loadlen, checksum, checksum_ok;
541a6afd9f3SGreg Kroah-Hartman 	unsigned int i, retry;
542a6afd9f3SGreg Kroah-Hartman 	u16 usum, keycode;
543a6afd9f3SGreg Kroah-Hartman 
544a6afd9f3SGreg Kroah-Hartman 	keycode = (brd->boardType == MOXA_BOARD_CP204J) ? CP204J_KeyCode :
545a6afd9f3SGreg Kroah-Hartman 				C218_KeyCode;
546a6afd9f3SGreg Kroah-Hartman 
547a6afd9f3SGreg Kroah-Hartman 	switch (brd->boardType) {
548a6afd9f3SGreg Kroah-Hartman 	case MOXA_BOARD_CP204J:
549a6afd9f3SGreg Kroah-Hartman 	case MOXA_BOARD_C218_ISA:
550a6afd9f3SGreg Kroah-Hartman 	case MOXA_BOARD_C218_PCI:
551a6afd9f3SGreg Kroah-Hartman 		key = C218_key;
552a6afd9f3SGreg Kroah-Hartman 		loadbuf = C218_LoadBuf;
553a6afd9f3SGreg Kroah-Hartman 		loadlen = C218DLoad_len;
554a6afd9f3SGreg Kroah-Hartman 		checksum = C218check_sum;
555a6afd9f3SGreg Kroah-Hartman 		checksum_ok = C218chksum_ok;
556a6afd9f3SGreg Kroah-Hartman 		break;
557a6afd9f3SGreg Kroah-Hartman 	default:
558a6afd9f3SGreg Kroah-Hartman 		key = C320_key;
559a6afd9f3SGreg Kroah-Hartman 		keycode = C320_KeyCode;
560a6afd9f3SGreg Kroah-Hartman 		loadbuf = C320_LoadBuf;
561a6afd9f3SGreg Kroah-Hartman 		loadlen = C320DLoad_len;
562a6afd9f3SGreg Kroah-Hartman 		checksum = C320check_sum;
563a6afd9f3SGreg Kroah-Hartman 		checksum_ok = C320chksum_ok;
564a6afd9f3SGreg Kroah-Hartman 		break;
565a6afd9f3SGreg Kroah-Hartman 	}
566a6afd9f3SGreg Kroah-Hartman 
567a6afd9f3SGreg Kroah-Hartman 	usum = 0;
568a6afd9f3SGreg Kroah-Hartman 	wlen = len >> 1;
569a6afd9f3SGreg Kroah-Hartman 	for (i = 0; i < wlen; i++)
570a6afd9f3SGreg Kroah-Hartman 		usum += le16_to_cpu(uptr[i]);
571a6afd9f3SGreg Kroah-Hartman 	retry = 0;
572a6afd9f3SGreg Kroah-Hartman 	do {
573a6afd9f3SGreg Kroah-Hartman 		wlen = len >> 1;
574a6afd9f3SGreg Kroah-Hartman 		j = 0;
575a6afd9f3SGreg Kroah-Hartman 		while (wlen) {
576a6afd9f3SGreg Kroah-Hartman 			len2 = (wlen > 2048) ? 2048 : wlen;
577a6afd9f3SGreg Kroah-Hartman 			wlen -= len2;
578a6afd9f3SGreg Kroah-Hartman 			memcpy_toio(baseAddr + loadbuf, ptr + j, len2 << 1);
579a6afd9f3SGreg Kroah-Hartman 			j += len2 << 1;
580a6afd9f3SGreg Kroah-Hartman 
581a6afd9f3SGreg Kroah-Hartman 			writew(len2, baseAddr + loadlen);
582a6afd9f3SGreg Kroah-Hartman 			writew(0, baseAddr + key);
583a6afd9f3SGreg Kroah-Hartman 			for (i = 0; i < 100; i++) {
584a6afd9f3SGreg Kroah-Hartman 				if (readw(baseAddr + key) == keycode)
585a6afd9f3SGreg Kroah-Hartman 					break;
586a6afd9f3SGreg Kroah-Hartman 				msleep(10);
587a6afd9f3SGreg Kroah-Hartman 			}
588a6afd9f3SGreg Kroah-Hartman 			if (readw(baseAddr + key) != keycode)
589a6afd9f3SGreg Kroah-Hartman 				return -EIO;
590a6afd9f3SGreg Kroah-Hartman 		}
591a6afd9f3SGreg Kroah-Hartman 		writew(0, baseAddr + loadlen);
592a6afd9f3SGreg Kroah-Hartman 		writew(usum, baseAddr + checksum);
593a6afd9f3SGreg Kroah-Hartman 		writew(0, baseAddr + key);
594a6afd9f3SGreg Kroah-Hartman 		for (i = 0; i < 100; i++) {
595a6afd9f3SGreg Kroah-Hartman 			if (readw(baseAddr + key) == keycode)
596a6afd9f3SGreg Kroah-Hartman 				break;
597a6afd9f3SGreg Kroah-Hartman 			msleep(10);
598a6afd9f3SGreg Kroah-Hartman 		}
599a6afd9f3SGreg Kroah-Hartman 		retry++;
600a6afd9f3SGreg Kroah-Hartman 	} while ((readb(baseAddr + checksum_ok) != 1) && (retry < 3));
601a6afd9f3SGreg Kroah-Hartman 	if (readb(baseAddr + checksum_ok) != 1)
602a6afd9f3SGreg Kroah-Hartman 		return -EIO;
603a6afd9f3SGreg Kroah-Hartman 
604a6afd9f3SGreg Kroah-Hartman 	writew(0, baseAddr + key);
605a6afd9f3SGreg Kroah-Hartman 	for (i = 0; i < 600; i++) {
606a6afd9f3SGreg Kroah-Hartman 		if (readw(baseAddr + Magic_no) == Magic_code)
607a6afd9f3SGreg Kroah-Hartman 			break;
608a6afd9f3SGreg Kroah-Hartman 		msleep(10);
609a6afd9f3SGreg Kroah-Hartman 	}
610a6afd9f3SGreg Kroah-Hartman 	if (readw(baseAddr + Magic_no) != Magic_code)
611a6afd9f3SGreg Kroah-Hartman 		return -EIO;
612a6afd9f3SGreg Kroah-Hartman 
613a6afd9f3SGreg Kroah-Hartman 	if (MOXA_IS_320(brd)) {
614a6afd9f3SGreg Kroah-Hartman 		if (brd->busType == MOXA_BUS_TYPE_PCI) {	/* ASIC board */
615a6afd9f3SGreg Kroah-Hartman 			writew(0x3800, baseAddr + TMS320_PORT1);
616a6afd9f3SGreg Kroah-Hartman 			writew(0x3900, baseAddr + TMS320_PORT2);
617a6afd9f3SGreg Kroah-Hartman 			writew(28499, baseAddr + TMS320_CLOCK);
618a6afd9f3SGreg Kroah-Hartman 		} else {
619a6afd9f3SGreg Kroah-Hartman 			writew(0x3200, baseAddr + TMS320_PORT1);
620a6afd9f3SGreg Kroah-Hartman 			writew(0x3400, baseAddr + TMS320_PORT2);
621a6afd9f3SGreg Kroah-Hartman 			writew(19999, baseAddr + TMS320_CLOCK);
622a6afd9f3SGreg Kroah-Hartman 		}
623a6afd9f3SGreg Kroah-Hartman 	}
624a6afd9f3SGreg Kroah-Hartman 	writew(1, baseAddr + Disable_IRQ);
625a6afd9f3SGreg Kroah-Hartman 	writew(0, baseAddr + Magic_no);
626a6afd9f3SGreg Kroah-Hartman 	for (i = 0; i < 500; i++) {
627a6afd9f3SGreg Kroah-Hartman 		if (readw(baseAddr + Magic_no) == Magic_code)
628a6afd9f3SGreg Kroah-Hartman 			break;
629a6afd9f3SGreg Kroah-Hartman 		msleep(10);
630a6afd9f3SGreg Kroah-Hartman 	}
631a6afd9f3SGreg Kroah-Hartman 	if (readw(baseAddr + Magic_no) != Magic_code)
632a6afd9f3SGreg Kroah-Hartman 		return -EIO;
633a6afd9f3SGreg Kroah-Hartman 
634a6afd9f3SGreg Kroah-Hartman 	if (MOXA_IS_320(brd)) {
635a6afd9f3SGreg Kroah-Hartman 		j = readw(baseAddr + Module_cnt);
636a6afd9f3SGreg Kroah-Hartman 		if (j <= 0)
637a6afd9f3SGreg Kroah-Hartman 			return -EIO;
638a6afd9f3SGreg Kroah-Hartman 		brd->numPorts = j * 8;
639a6afd9f3SGreg Kroah-Hartman 		writew(j, baseAddr + Module_no);
640a6afd9f3SGreg Kroah-Hartman 		writew(0, baseAddr + Magic_no);
641a6afd9f3SGreg Kroah-Hartman 		for (i = 0; i < 600; i++) {
642a6afd9f3SGreg Kroah-Hartman 			if (readw(baseAddr + Magic_no) == Magic_code)
643a6afd9f3SGreg Kroah-Hartman 				break;
644a6afd9f3SGreg Kroah-Hartman 			msleep(10);
645a6afd9f3SGreg Kroah-Hartman 		}
646a6afd9f3SGreg Kroah-Hartman 		if (readw(baseAddr + Magic_no) != Magic_code)
647a6afd9f3SGreg Kroah-Hartman 			return -EIO;
648a6afd9f3SGreg Kroah-Hartman 	}
649a6afd9f3SGreg Kroah-Hartman 	brd->intNdx = baseAddr + IRQindex;
650a6afd9f3SGreg Kroah-Hartman 	brd->intPend = baseAddr + IRQpending;
651a6afd9f3SGreg Kroah-Hartman 	brd->intTable = baseAddr + IRQtable;
652a6afd9f3SGreg Kroah-Hartman 
653a6afd9f3SGreg Kroah-Hartman 	return 0;
654a6afd9f3SGreg Kroah-Hartman }
655a6afd9f3SGreg Kroah-Hartman 
656a6afd9f3SGreg Kroah-Hartman static int moxa_load_code(struct moxa_board_conf *brd, const void *ptr,
657a6afd9f3SGreg Kroah-Hartman 		size_t len)
658a6afd9f3SGreg Kroah-Hartman {
659a6afd9f3SGreg Kroah-Hartman 	void __iomem *ofsAddr, *baseAddr = brd->basemem;
660a6afd9f3SGreg Kroah-Hartman 	struct moxa_port *port;
661a6afd9f3SGreg Kroah-Hartman 	int retval, i;
662a6afd9f3SGreg Kroah-Hartman 
663a6afd9f3SGreg Kroah-Hartman 	if (len % 2) {
664a6afd9f3SGreg Kroah-Hartman 		printk(KERN_ERR "MOXA: bios length is not even\n");
665a6afd9f3SGreg Kroah-Hartman 		return -EINVAL;
666a6afd9f3SGreg Kroah-Hartman 	}
667a6afd9f3SGreg Kroah-Hartman 
668a6afd9f3SGreg Kroah-Hartman 	retval = moxa_real_load_code(brd, ptr, len); /* may change numPorts */
669a6afd9f3SGreg Kroah-Hartman 	if (retval)
670a6afd9f3SGreg Kroah-Hartman 		return retval;
671a6afd9f3SGreg Kroah-Hartman 
672a6afd9f3SGreg Kroah-Hartman 	switch (brd->boardType) {
673a6afd9f3SGreg Kroah-Hartman 	case MOXA_BOARD_C218_ISA:
674a6afd9f3SGreg Kroah-Hartman 	case MOXA_BOARD_C218_PCI:
675a6afd9f3SGreg Kroah-Hartman 	case MOXA_BOARD_CP204J:
676a6afd9f3SGreg Kroah-Hartman 		port = brd->ports;
677a6afd9f3SGreg Kroah-Hartman 		for (i = 0; i < brd->numPorts; i++, port++) {
678a6afd9f3SGreg Kroah-Hartman 			port->board = brd;
679a6afd9f3SGreg Kroah-Hartman 			port->DCDState = 0;
680a6afd9f3SGreg Kroah-Hartman 			port->tableAddr = baseAddr + Extern_table +
681a6afd9f3SGreg Kroah-Hartman 					Extern_size * i;
682a6afd9f3SGreg Kroah-Hartman 			ofsAddr = port->tableAddr;
683a6afd9f3SGreg Kroah-Hartman 			writew(C218rx_mask, ofsAddr + RX_mask);
684a6afd9f3SGreg Kroah-Hartman 			writew(C218tx_mask, ofsAddr + TX_mask);
685a6afd9f3SGreg Kroah-Hartman 			writew(C218rx_spage + i * C218buf_pageno, ofsAddr + Page_rxb);
686a6afd9f3SGreg Kroah-Hartman 			writew(readw(ofsAddr + Page_rxb) + C218rx_pageno, ofsAddr + EndPage_rxb);
687a6afd9f3SGreg Kroah-Hartman 
688a6afd9f3SGreg Kroah-Hartman 			writew(C218tx_spage + i * C218buf_pageno, ofsAddr + Page_txb);
689a6afd9f3SGreg Kroah-Hartman 			writew(readw(ofsAddr + Page_txb) + C218tx_pageno, ofsAddr + EndPage_txb);
690a6afd9f3SGreg Kroah-Hartman 
691a6afd9f3SGreg Kroah-Hartman 		}
692a6afd9f3SGreg Kroah-Hartman 		break;
693a6afd9f3SGreg Kroah-Hartman 	default:
694a6afd9f3SGreg Kroah-Hartman 		port = brd->ports;
695a6afd9f3SGreg Kroah-Hartman 		for (i = 0; i < brd->numPorts; i++, port++) {
696a6afd9f3SGreg Kroah-Hartman 			port->board = brd;
697a6afd9f3SGreg Kroah-Hartman 			port->DCDState = 0;
698a6afd9f3SGreg Kroah-Hartman 			port->tableAddr = baseAddr + Extern_table +
699a6afd9f3SGreg Kroah-Hartman 					Extern_size * i;
700a6afd9f3SGreg Kroah-Hartman 			ofsAddr = port->tableAddr;
701a6afd9f3SGreg Kroah-Hartman 			switch (brd->numPorts) {
702a6afd9f3SGreg Kroah-Hartman 			case 8:
703a6afd9f3SGreg Kroah-Hartman 				writew(C320p8rx_mask, ofsAddr + RX_mask);
704a6afd9f3SGreg Kroah-Hartman 				writew(C320p8tx_mask, ofsAddr + TX_mask);
705a6afd9f3SGreg Kroah-Hartman 				writew(C320p8rx_spage + i * C320p8buf_pgno, ofsAddr + Page_rxb);
706a6afd9f3SGreg Kroah-Hartman 				writew(readw(ofsAddr + Page_rxb) + C320p8rx_pgno, ofsAddr + EndPage_rxb);
707a6afd9f3SGreg Kroah-Hartman 				writew(C320p8tx_spage + i * C320p8buf_pgno, ofsAddr + Page_txb);
708a6afd9f3SGreg Kroah-Hartman 				writew(readw(ofsAddr + Page_txb) + C320p8tx_pgno, ofsAddr + EndPage_txb);
709a6afd9f3SGreg Kroah-Hartman 
710a6afd9f3SGreg Kroah-Hartman 				break;
711a6afd9f3SGreg Kroah-Hartman 			case 16:
712a6afd9f3SGreg Kroah-Hartman 				writew(C320p16rx_mask, ofsAddr + RX_mask);
713a6afd9f3SGreg Kroah-Hartman 				writew(C320p16tx_mask, ofsAddr + TX_mask);
714a6afd9f3SGreg Kroah-Hartman 				writew(C320p16rx_spage + i * C320p16buf_pgno, ofsAddr + Page_rxb);
715a6afd9f3SGreg Kroah-Hartman 				writew(readw(ofsAddr + Page_rxb) + C320p16rx_pgno, ofsAddr + EndPage_rxb);
716a6afd9f3SGreg Kroah-Hartman 				writew(C320p16tx_spage + i * C320p16buf_pgno, ofsAddr + Page_txb);
717a6afd9f3SGreg Kroah-Hartman 				writew(readw(ofsAddr + Page_txb) + C320p16tx_pgno, ofsAddr + EndPage_txb);
718a6afd9f3SGreg Kroah-Hartman 				break;
719a6afd9f3SGreg Kroah-Hartman 
720a6afd9f3SGreg Kroah-Hartman 			case 24:
721a6afd9f3SGreg Kroah-Hartman 				writew(C320p24rx_mask, ofsAddr + RX_mask);
722a6afd9f3SGreg Kroah-Hartman 				writew(C320p24tx_mask, ofsAddr + TX_mask);
723a6afd9f3SGreg Kroah-Hartman 				writew(C320p24rx_spage + i * C320p24buf_pgno, ofsAddr + Page_rxb);
724a6afd9f3SGreg Kroah-Hartman 				writew(readw(ofsAddr + Page_rxb) + C320p24rx_pgno, ofsAddr + EndPage_rxb);
725a6afd9f3SGreg Kroah-Hartman 				writew(C320p24tx_spage + i * C320p24buf_pgno, ofsAddr + Page_txb);
726a6afd9f3SGreg Kroah-Hartman 				writew(readw(ofsAddr + Page_txb), ofsAddr + EndPage_txb);
727a6afd9f3SGreg Kroah-Hartman 				break;
728a6afd9f3SGreg Kroah-Hartman 			case 32:
729a6afd9f3SGreg Kroah-Hartman 				writew(C320p32rx_mask, ofsAddr + RX_mask);
730a6afd9f3SGreg Kroah-Hartman 				writew(C320p32tx_mask, ofsAddr + TX_mask);
731a6afd9f3SGreg Kroah-Hartman 				writew(C320p32tx_ofs, ofsAddr + Ofs_txb);
732a6afd9f3SGreg Kroah-Hartman 				writew(C320p32rx_spage + i * C320p32buf_pgno, ofsAddr + Page_rxb);
733a6afd9f3SGreg Kroah-Hartman 				writew(readb(ofsAddr + Page_rxb), ofsAddr + EndPage_rxb);
734a6afd9f3SGreg Kroah-Hartman 				writew(C320p32tx_spage + i * C320p32buf_pgno, ofsAddr + Page_txb);
735a6afd9f3SGreg Kroah-Hartman 				writew(readw(ofsAddr + Page_txb), ofsAddr + EndPage_txb);
736a6afd9f3SGreg Kroah-Hartman 				break;
737a6afd9f3SGreg Kroah-Hartman 			}
738a6afd9f3SGreg Kroah-Hartman 		}
739a6afd9f3SGreg Kroah-Hartman 		break;
740a6afd9f3SGreg Kroah-Hartman 	}
741a6afd9f3SGreg Kroah-Hartman 	return 0;
742a6afd9f3SGreg Kroah-Hartman }
743a6afd9f3SGreg Kroah-Hartman 
744a6afd9f3SGreg Kroah-Hartman static int moxa_load_fw(struct moxa_board_conf *brd, const struct firmware *fw)
745a6afd9f3SGreg Kroah-Hartman {
746a6afd9f3SGreg Kroah-Hartman 	const void *ptr = fw->data;
747a6afd9f3SGreg Kroah-Hartman 	char rsn[64];
748a6afd9f3SGreg Kroah-Hartman 	u16 lens[5];
749a6afd9f3SGreg Kroah-Hartman 	size_t len;
750a6afd9f3SGreg Kroah-Hartman 	unsigned int a, lenp, lencnt;
751a6afd9f3SGreg Kroah-Hartman 	int ret = -EINVAL;
752a6afd9f3SGreg Kroah-Hartman 	struct {
753a6afd9f3SGreg Kroah-Hartman 		__le32 magic;	/* 0x34303430 */
754a6afd9f3SGreg Kroah-Hartman 		u8 reserved1[2];
755a6afd9f3SGreg Kroah-Hartman 		u8 type;	/* UNIX = 3 */
756a6afd9f3SGreg Kroah-Hartman 		u8 model;	/* C218T=1, C320T=2, CP204=3 */
757a6afd9f3SGreg Kroah-Hartman 		u8 reserved2[8];
758a6afd9f3SGreg Kroah-Hartman 		__le16 len[5];
759a6afd9f3SGreg Kroah-Hartman 	} const *hdr = ptr;
760a6afd9f3SGreg Kroah-Hartman 
761a6afd9f3SGreg Kroah-Hartman 	BUILD_BUG_ON(ARRAY_SIZE(hdr->len) != ARRAY_SIZE(lens));
762a6afd9f3SGreg Kroah-Hartman 
763a6afd9f3SGreg Kroah-Hartman 	if (fw->size < MOXA_FW_HDRLEN) {
764a6afd9f3SGreg Kroah-Hartman 		strcpy(rsn, "too short (even header won't fit)");
765a6afd9f3SGreg Kroah-Hartman 		goto err;
766a6afd9f3SGreg Kroah-Hartman 	}
767a6afd9f3SGreg Kroah-Hartman 	if (hdr->magic != cpu_to_le32(0x30343034)) {
768a6afd9f3SGreg Kroah-Hartman 		sprintf(rsn, "bad magic: %.8x", le32_to_cpu(hdr->magic));
769a6afd9f3SGreg Kroah-Hartman 		goto err;
770a6afd9f3SGreg Kroah-Hartman 	}
771a6afd9f3SGreg Kroah-Hartman 	if (hdr->type != 3) {
772a6afd9f3SGreg Kroah-Hartman 		sprintf(rsn, "not for linux, type is %u", hdr->type);
773a6afd9f3SGreg Kroah-Hartman 		goto err;
774a6afd9f3SGreg Kroah-Hartman 	}
775a6afd9f3SGreg Kroah-Hartman 	if (moxa_check_fw_model(brd, hdr->model)) {
776a6afd9f3SGreg Kroah-Hartman 		sprintf(rsn, "not for this card, model is %u", hdr->model);
777a6afd9f3SGreg Kroah-Hartman 		goto err;
778a6afd9f3SGreg Kroah-Hartman 	}
779a6afd9f3SGreg Kroah-Hartman 
780a6afd9f3SGreg Kroah-Hartman 	len = MOXA_FW_HDRLEN;
781a6afd9f3SGreg Kroah-Hartman 	lencnt = hdr->model == 2 ? 5 : 3;
782a6afd9f3SGreg Kroah-Hartman 	for (a = 0; a < ARRAY_SIZE(lens); a++) {
783a6afd9f3SGreg Kroah-Hartman 		lens[a] = le16_to_cpu(hdr->len[a]);
784a6afd9f3SGreg Kroah-Hartman 		if (lens[a] && len + lens[a] <= fw->size &&
785a6afd9f3SGreg Kroah-Hartman 				moxa_check_fw(&fw->data[len]))
786a6afd9f3SGreg Kroah-Hartman 			printk(KERN_WARNING "MOXA firmware: unexpected input "
787a6afd9f3SGreg Kroah-Hartman 				"at offset %u, but going on\n", (u32)len);
788a6afd9f3SGreg Kroah-Hartman 		if (!lens[a] && a < lencnt) {
789a6afd9f3SGreg Kroah-Hartman 			sprintf(rsn, "too few entries in fw file");
790a6afd9f3SGreg Kroah-Hartman 			goto err;
791a6afd9f3SGreg Kroah-Hartman 		}
792a6afd9f3SGreg Kroah-Hartman 		len += lens[a];
793a6afd9f3SGreg Kroah-Hartman 	}
794a6afd9f3SGreg Kroah-Hartman 
795a6afd9f3SGreg Kroah-Hartman 	if (len != fw->size) {
796a6afd9f3SGreg Kroah-Hartman 		sprintf(rsn, "bad length: %u (should be %u)", (u32)fw->size,
797a6afd9f3SGreg Kroah-Hartman 				(u32)len);
798a6afd9f3SGreg Kroah-Hartman 		goto err;
799a6afd9f3SGreg Kroah-Hartman 	}
800a6afd9f3SGreg Kroah-Hartman 
801a6afd9f3SGreg Kroah-Hartman 	ptr += MOXA_FW_HDRLEN;
802a6afd9f3SGreg Kroah-Hartman 	lenp = 0; /* bios */
803a6afd9f3SGreg Kroah-Hartman 
804a6afd9f3SGreg Kroah-Hartman 	strcpy(rsn, "read above");
805a6afd9f3SGreg Kroah-Hartman 
806a6afd9f3SGreg Kroah-Hartman 	ret = moxa_load_bios(brd, ptr, lens[lenp]);
807a6afd9f3SGreg Kroah-Hartman 	if (ret)
808a6afd9f3SGreg Kroah-Hartman 		goto err;
809a6afd9f3SGreg Kroah-Hartman 
810a6afd9f3SGreg Kroah-Hartman 	/* we skip the tty section (lens[1]), since we don't need it */
811a6afd9f3SGreg Kroah-Hartman 	ptr += lens[lenp] + lens[lenp + 1];
812a6afd9f3SGreg Kroah-Hartman 	lenp += 2; /* comm */
813a6afd9f3SGreg Kroah-Hartman 
814a6afd9f3SGreg Kroah-Hartman 	if (hdr->model == 2) {
815a6afd9f3SGreg Kroah-Hartman 		ret = moxa_load_320b(brd, ptr, lens[lenp]);
816a6afd9f3SGreg Kroah-Hartman 		if (ret)
817a6afd9f3SGreg Kroah-Hartman 			goto err;
818a6afd9f3SGreg Kroah-Hartman 		/* skip another tty */
819a6afd9f3SGreg Kroah-Hartman 		ptr += lens[lenp] + lens[lenp + 1];
820a6afd9f3SGreg Kroah-Hartman 		lenp += 2;
821a6afd9f3SGreg Kroah-Hartman 	}
822a6afd9f3SGreg Kroah-Hartman 
823a6afd9f3SGreg Kroah-Hartman 	ret = moxa_load_code(brd, ptr, lens[lenp]);
824a6afd9f3SGreg Kroah-Hartman 	if (ret)
825a6afd9f3SGreg Kroah-Hartman 		goto err;
826a6afd9f3SGreg Kroah-Hartman 
827a6afd9f3SGreg Kroah-Hartman 	return 0;
828a6afd9f3SGreg Kroah-Hartman err:
829a6afd9f3SGreg Kroah-Hartman 	printk(KERN_ERR "firmware failed to load, reason: %s\n", rsn);
830a6afd9f3SGreg Kroah-Hartman 	return ret;
831a6afd9f3SGreg Kroah-Hartman }
832a6afd9f3SGreg Kroah-Hartman 
833a6afd9f3SGreg Kroah-Hartman static int moxa_init_board(struct moxa_board_conf *brd, struct device *dev)
834a6afd9f3SGreg Kroah-Hartman {
835a6afd9f3SGreg Kroah-Hartman 	const struct firmware *fw;
836a6afd9f3SGreg Kroah-Hartman 	const char *file;
837a6afd9f3SGreg Kroah-Hartman 	struct moxa_port *p;
838793be898SJiri Slaby 	unsigned int i, first_idx;
839a6afd9f3SGreg Kroah-Hartman 	int ret;
840a6afd9f3SGreg Kroah-Hartman 
841a6afd9f3SGreg Kroah-Hartman 	brd->ports = kcalloc(MAX_PORTS_PER_BOARD, sizeof(*brd->ports),
842a6afd9f3SGreg Kroah-Hartman 			GFP_KERNEL);
843a6afd9f3SGreg Kroah-Hartman 	if (brd->ports == NULL) {
844a6afd9f3SGreg Kroah-Hartman 		printk(KERN_ERR "cannot allocate memory for ports\n");
845a6afd9f3SGreg Kroah-Hartman 		ret = -ENOMEM;
846a6afd9f3SGreg Kroah-Hartman 		goto err;
847a6afd9f3SGreg Kroah-Hartman 	}
848a6afd9f3SGreg Kroah-Hartman 
849a6afd9f3SGreg Kroah-Hartman 	for (i = 0, p = brd->ports; i < MAX_PORTS_PER_BOARD; i++, p++) {
850a6afd9f3SGreg Kroah-Hartman 		tty_port_init(&p->port);
851a6afd9f3SGreg Kroah-Hartman 		p->port.ops = &moxa_port_ops;
852a6afd9f3SGreg Kroah-Hartman 		p->type = PORT_16550A;
853a6afd9f3SGreg Kroah-Hartman 		p->cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
854a6afd9f3SGreg Kroah-Hartman 	}
855a6afd9f3SGreg Kroah-Hartman 
856a6afd9f3SGreg Kroah-Hartman 	switch (brd->boardType) {
857a6afd9f3SGreg Kroah-Hartman 	case MOXA_BOARD_C218_ISA:
858a6afd9f3SGreg Kroah-Hartman 	case MOXA_BOARD_C218_PCI:
859a6afd9f3SGreg Kroah-Hartman 		file = "c218tunx.cod";
860a6afd9f3SGreg Kroah-Hartman 		break;
861a6afd9f3SGreg Kroah-Hartman 	case MOXA_BOARD_CP204J:
862a6afd9f3SGreg Kroah-Hartman 		file = "cp204unx.cod";
863a6afd9f3SGreg Kroah-Hartman 		break;
864a6afd9f3SGreg Kroah-Hartman 	default:
865a6afd9f3SGreg Kroah-Hartman 		file = "c320tunx.cod";
866a6afd9f3SGreg Kroah-Hartman 		break;
867a6afd9f3SGreg Kroah-Hartman 	}
868a6afd9f3SGreg Kroah-Hartman 
869a6afd9f3SGreg Kroah-Hartman 	ret = request_firmware(&fw, file, dev);
870a6afd9f3SGreg Kroah-Hartman 	if (ret) {
871a6afd9f3SGreg Kroah-Hartman 		printk(KERN_ERR "MOXA: request_firmware failed. Make sure "
872a6afd9f3SGreg Kroah-Hartman 				"you've placed '%s' file into your firmware "
873a6afd9f3SGreg Kroah-Hartman 				"loader directory (e.g. /lib/firmware)\n",
874a6afd9f3SGreg Kroah-Hartman 				file);
875a6afd9f3SGreg Kroah-Hartman 		goto err_free;
876a6afd9f3SGreg Kroah-Hartman 	}
877a6afd9f3SGreg Kroah-Hartman 
878a6afd9f3SGreg Kroah-Hartman 	ret = moxa_load_fw(brd, fw);
879a6afd9f3SGreg Kroah-Hartman 
880a6afd9f3SGreg Kroah-Hartman 	release_firmware(fw);
881a6afd9f3SGreg Kroah-Hartman 
882a6afd9f3SGreg Kroah-Hartman 	if (ret)
883a6afd9f3SGreg Kroah-Hartman 		goto err_free;
884a6afd9f3SGreg Kroah-Hartman 
885a6afd9f3SGreg Kroah-Hartman 	spin_lock_bh(&moxa_lock);
886a6afd9f3SGreg Kroah-Hartman 	brd->ready = 1;
887a6afd9f3SGreg Kroah-Hartman 	if (!timer_pending(&moxaTimer))
888a6afd9f3SGreg Kroah-Hartman 		mod_timer(&moxaTimer, jiffies + HZ / 50);
889a6afd9f3SGreg Kroah-Hartman 	spin_unlock_bh(&moxa_lock);
890a6afd9f3SGreg Kroah-Hartman 
891793be898SJiri Slaby 	first_idx = (brd - moxa_boards) * MAX_PORTS_PER_BOARD;
892793be898SJiri Slaby 	for (i = 0; i < brd->numPorts; i++)
893793be898SJiri Slaby 		tty_port_register_device(&brd->ports[i].port, moxaDriver,
894793be898SJiri Slaby 				first_idx + i, dev);
895793be898SJiri Slaby 
896a6afd9f3SGreg Kroah-Hartman 	return 0;
897a6afd9f3SGreg Kroah-Hartman err_free:
898*191c5f10SJiri Slaby 	for (i = 0; i < MAX_PORTS_PER_BOARD; i++)
899*191c5f10SJiri Slaby 		tty_port_destroy(&brd->ports[i].port);
900a6afd9f3SGreg Kroah-Hartman 	kfree(brd->ports);
901a6afd9f3SGreg Kroah-Hartman err:
902a6afd9f3SGreg Kroah-Hartman 	return ret;
903a6afd9f3SGreg Kroah-Hartman }
904a6afd9f3SGreg Kroah-Hartman 
905a6afd9f3SGreg Kroah-Hartman static void moxa_board_deinit(struct moxa_board_conf *brd)
906a6afd9f3SGreg Kroah-Hartman {
907793be898SJiri Slaby 	unsigned int a, opened, first_idx;
908a6afd9f3SGreg Kroah-Hartman 
909a6afd9f3SGreg Kroah-Hartman 	mutex_lock(&moxa_openlock);
910a6afd9f3SGreg Kroah-Hartman 	spin_lock_bh(&moxa_lock);
911a6afd9f3SGreg Kroah-Hartman 	brd->ready = 0;
912a6afd9f3SGreg Kroah-Hartman 	spin_unlock_bh(&moxa_lock);
913a6afd9f3SGreg Kroah-Hartman 
914a6afd9f3SGreg Kroah-Hartman 	/* pci hot-un-plug support */
915a6afd9f3SGreg Kroah-Hartman 	for (a = 0; a < brd->numPorts; a++)
916a6afd9f3SGreg Kroah-Hartman 		if (brd->ports[a].port.flags & ASYNC_INITIALIZED) {
917a6afd9f3SGreg Kroah-Hartman 			struct tty_struct *tty = tty_port_tty_get(
918a6afd9f3SGreg Kroah-Hartman 						&brd->ports[a].port);
919a6afd9f3SGreg Kroah-Hartman 			if (tty) {
920a6afd9f3SGreg Kroah-Hartman 				tty_hangup(tty);
921a6afd9f3SGreg Kroah-Hartman 				tty_kref_put(tty);
922a6afd9f3SGreg Kroah-Hartman 			}
923a6afd9f3SGreg Kroah-Hartman 		}
924*191c5f10SJiri Slaby 	for (a = 0; a < MAX_PORTS_PER_BOARD; a++)
925*191c5f10SJiri Slaby 		tty_port_destroy(&brd->ports[a].port);
926a6afd9f3SGreg Kroah-Hartman 	while (1) {
927a6afd9f3SGreg Kroah-Hartman 		opened = 0;
928a6afd9f3SGreg Kroah-Hartman 		for (a = 0; a < brd->numPorts; a++)
929a6afd9f3SGreg Kroah-Hartman 			if (brd->ports[a].port.flags & ASYNC_INITIALIZED)
930a6afd9f3SGreg Kroah-Hartman 				opened++;
931a6afd9f3SGreg Kroah-Hartman 		mutex_unlock(&moxa_openlock);
932a6afd9f3SGreg Kroah-Hartman 		if (!opened)
933a6afd9f3SGreg Kroah-Hartman 			break;
934a6afd9f3SGreg Kroah-Hartman 		msleep(50);
935a6afd9f3SGreg Kroah-Hartman 		mutex_lock(&moxa_openlock);
936a6afd9f3SGreg Kroah-Hartman 	}
937a6afd9f3SGreg Kroah-Hartman 
938793be898SJiri Slaby 	first_idx = (brd - moxa_boards) * MAX_PORTS_PER_BOARD;
939793be898SJiri Slaby 	for (a = 0; a < brd->numPorts; a++)
940793be898SJiri Slaby 		tty_unregister_device(moxaDriver, first_idx + a);
941793be898SJiri Slaby 
942a6afd9f3SGreg Kroah-Hartman 	iounmap(brd->basemem);
943a6afd9f3SGreg Kroah-Hartman 	brd->basemem = NULL;
944a6afd9f3SGreg Kroah-Hartman 	kfree(brd->ports);
945a6afd9f3SGreg Kroah-Hartman }
946a6afd9f3SGreg Kroah-Hartman 
947a6afd9f3SGreg Kroah-Hartman #ifdef CONFIG_PCI
948a6afd9f3SGreg Kroah-Hartman static int __devinit moxa_pci_probe(struct pci_dev *pdev,
949a6afd9f3SGreg Kroah-Hartman 		const struct pci_device_id *ent)
950a6afd9f3SGreg Kroah-Hartman {
951a6afd9f3SGreg Kroah-Hartman 	struct moxa_board_conf *board;
952a6afd9f3SGreg Kroah-Hartman 	unsigned int i;
953a6afd9f3SGreg Kroah-Hartman 	int board_type = ent->driver_data;
954a6afd9f3SGreg Kroah-Hartman 	int retval;
955a6afd9f3SGreg Kroah-Hartman 
956a6afd9f3SGreg Kroah-Hartman 	retval = pci_enable_device(pdev);
957a6afd9f3SGreg Kroah-Hartman 	if (retval) {
958a6afd9f3SGreg Kroah-Hartman 		dev_err(&pdev->dev, "can't enable pci device\n");
959a6afd9f3SGreg Kroah-Hartman 		goto err;
960a6afd9f3SGreg Kroah-Hartman 	}
961a6afd9f3SGreg Kroah-Hartman 
962a6afd9f3SGreg Kroah-Hartman 	for (i = 0; i < MAX_BOARDS; i++)
963a6afd9f3SGreg Kroah-Hartman 		if (moxa_boards[i].basemem == NULL)
964a6afd9f3SGreg Kroah-Hartman 			break;
965a6afd9f3SGreg Kroah-Hartman 
966a6afd9f3SGreg Kroah-Hartman 	retval = -ENODEV;
967a6afd9f3SGreg Kroah-Hartman 	if (i >= MAX_BOARDS) {
968a6afd9f3SGreg Kroah-Hartman 		dev_warn(&pdev->dev, "more than %u MOXA Intellio family boards "
969a6afd9f3SGreg Kroah-Hartman 				"found. Board is ignored.\n", MAX_BOARDS);
970a6afd9f3SGreg Kroah-Hartman 		goto err;
971a6afd9f3SGreg Kroah-Hartman 	}
972a6afd9f3SGreg Kroah-Hartman 
973a6afd9f3SGreg Kroah-Hartman 	board = &moxa_boards[i];
974a6afd9f3SGreg Kroah-Hartman 
975a6afd9f3SGreg Kroah-Hartman 	retval = pci_request_region(pdev, 2, "moxa-base");
976a6afd9f3SGreg Kroah-Hartman 	if (retval) {
977a6afd9f3SGreg Kroah-Hartman 		dev_err(&pdev->dev, "can't request pci region 2\n");
978a6afd9f3SGreg Kroah-Hartman 		goto err;
979a6afd9f3SGreg Kroah-Hartman 	}
980a6afd9f3SGreg Kroah-Hartman 
981a6afd9f3SGreg Kroah-Hartman 	board->basemem = ioremap_nocache(pci_resource_start(pdev, 2), 0x4000);
982a6afd9f3SGreg Kroah-Hartman 	if (board->basemem == NULL) {
983a6afd9f3SGreg Kroah-Hartman 		dev_err(&pdev->dev, "can't remap io space 2\n");
984386d95b3SJulia Lawall 		retval = -ENOMEM;
985a6afd9f3SGreg Kroah-Hartman 		goto err_reg;
986a6afd9f3SGreg Kroah-Hartman 	}
987a6afd9f3SGreg Kroah-Hartman 
988a6afd9f3SGreg Kroah-Hartman 	board->boardType = board_type;
989a6afd9f3SGreg Kroah-Hartman 	switch (board_type) {
990a6afd9f3SGreg Kroah-Hartman 	case MOXA_BOARD_C218_ISA:
991a6afd9f3SGreg Kroah-Hartman 	case MOXA_BOARD_C218_PCI:
992a6afd9f3SGreg Kroah-Hartman 		board->numPorts = 8;
993a6afd9f3SGreg Kroah-Hartman 		break;
994a6afd9f3SGreg Kroah-Hartman 
995a6afd9f3SGreg Kroah-Hartman 	case MOXA_BOARD_CP204J:
996a6afd9f3SGreg Kroah-Hartman 		board->numPorts = 4;
997a6afd9f3SGreg Kroah-Hartman 		break;
998a6afd9f3SGreg Kroah-Hartman 	default:
999a6afd9f3SGreg Kroah-Hartman 		board->numPorts = 0;
1000a6afd9f3SGreg Kroah-Hartman 		break;
1001a6afd9f3SGreg Kroah-Hartman 	}
1002a6afd9f3SGreg Kroah-Hartman 	board->busType = MOXA_BUS_TYPE_PCI;
1003a6afd9f3SGreg Kroah-Hartman 
1004a6afd9f3SGreg Kroah-Hartman 	retval = moxa_init_board(board, &pdev->dev);
1005a6afd9f3SGreg Kroah-Hartman 	if (retval)
1006a6afd9f3SGreg Kroah-Hartman 		goto err_base;
1007a6afd9f3SGreg Kroah-Hartman 
1008a6afd9f3SGreg Kroah-Hartman 	pci_set_drvdata(pdev, board);
1009a6afd9f3SGreg Kroah-Hartman 
1010a6afd9f3SGreg Kroah-Hartman 	dev_info(&pdev->dev, "board '%s' ready (%u ports, firmware loaded)\n",
1011a6afd9f3SGreg Kroah-Hartman 			moxa_brdname[board_type - 1], board->numPorts);
1012a6afd9f3SGreg Kroah-Hartman 
1013a6afd9f3SGreg Kroah-Hartman 	return 0;
1014a6afd9f3SGreg Kroah-Hartman err_base:
1015a6afd9f3SGreg Kroah-Hartman 	iounmap(board->basemem);
1016a6afd9f3SGreg Kroah-Hartman 	board->basemem = NULL;
1017a6afd9f3SGreg Kroah-Hartman err_reg:
1018a6afd9f3SGreg Kroah-Hartman 	pci_release_region(pdev, 2);
1019a6afd9f3SGreg Kroah-Hartman err:
1020a6afd9f3SGreg Kroah-Hartman 	return retval;
1021a6afd9f3SGreg Kroah-Hartman }
1022a6afd9f3SGreg Kroah-Hartman 
1023a6afd9f3SGreg Kroah-Hartman static void __devexit moxa_pci_remove(struct pci_dev *pdev)
1024a6afd9f3SGreg Kroah-Hartman {
1025a6afd9f3SGreg Kroah-Hartman 	struct moxa_board_conf *brd = pci_get_drvdata(pdev);
1026a6afd9f3SGreg Kroah-Hartman 
1027a6afd9f3SGreg Kroah-Hartman 	moxa_board_deinit(brd);
1028a6afd9f3SGreg Kroah-Hartman 
1029a6afd9f3SGreg Kroah-Hartman 	pci_release_region(pdev, 2);
1030a6afd9f3SGreg Kroah-Hartman }
1031a6afd9f3SGreg Kroah-Hartman 
1032a6afd9f3SGreg Kroah-Hartman static struct pci_driver moxa_pci_driver = {
1033a6afd9f3SGreg Kroah-Hartman 	.name = "moxa",
1034a6afd9f3SGreg Kroah-Hartman 	.id_table = moxa_pcibrds,
1035a6afd9f3SGreg Kroah-Hartman 	.probe = moxa_pci_probe,
1036a6afd9f3SGreg Kroah-Hartman 	.remove = __devexit_p(moxa_pci_remove)
1037a6afd9f3SGreg Kroah-Hartman };
1038a6afd9f3SGreg Kroah-Hartman #endif /* CONFIG_PCI */
1039a6afd9f3SGreg Kroah-Hartman 
1040a6afd9f3SGreg Kroah-Hartman static int __init moxa_init(void)
1041a6afd9f3SGreg Kroah-Hartman {
1042a6afd9f3SGreg Kroah-Hartman 	unsigned int isabrds = 0;
1043a6afd9f3SGreg Kroah-Hartman 	int retval = 0;
1044a6afd9f3SGreg Kroah-Hartman 	struct moxa_board_conf *brd = moxa_boards;
1045a6afd9f3SGreg Kroah-Hartman 	unsigned int i;
1046a6afd9f3SGreg Kroah-Hartman 
1047a6afd9f3SGreg Kroah-Hartman 	printk(KERN_INFO "MOXA Intellio family driver version %s\n",
1048a6afd9f3SGreg Kroah-Hartman 			MOXA_VERSION);
1049793be898SJiri Slaby 
1050793be898SJiri Slaby 	tty_port_init(&moxa_service_port);
1051793be898SJiri Slaby 
1052793be898SJiri Slaby 	moxaDriver = tty_alloc_driver(MAX_PORTS + 1,
1053793be898SJiri Slaby 			TTY_DRIVER_REAL_RAW |
1054793be898SJiri Slaby 			TTY_DRIVER_DYNAMIC_DEV);
1055c3a6344aSDan Carpenter 	if (IS_ERR(moxaDriver))
1056c3a6344aSDan Carpenter 		return PTR_ERR(moxaDriver);
1057a6afd9f3SGreg Kroah-Hartman 
1058a6afd9f3SGreg Kroah-Hartman 	moxaDriver->name = "ttyMX";
1059a6afd9f3SGreg Kroah-Hartman 	moxaDriver->major = ttymajor;
1060a6afd9f3SGreg Kroah-Hartman 	moxaDriver->minor_start = 0;
1061a6afd9f3SGreg Kroah-Hartman 	moxaDriver->type = TTY_DRIVER_TYPE_SERIAL;
1062a6afd9f3SGreg Kroah-Hartman 	moxaDriver->subtype = SERIAL_TYPE_NORMAL;
1063a6afd9f3SGreg Kroah-Hartman 	moxaDriver->init_termios = tty_std_termios;
1064a6afd9f3SGreg Kroah-Hartman 	moxaDriver->init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
1065a6afd9f3SGreg Kroah-Hartman 	moxaDriver->init_termios.c_ispeed = 9600;
1066a6afd9f3SGreg Kroah-Hartman 	moxaDriver->init_termios.c_ospeed = 9600;
1067a6afd9f3SGreg Kroah-Hartman 	tty_set_operations(moxaDriver, &moxa_ops);
1068793be898SJiri Slaby 	/* Having one more port only for ioctls is ugly */
1069793be898SJiri Slaby 	tty_port_link_device(&moxa_service_port, moxaDriver, MAX_PORTS);
1070a6afd9f3SGreg Kroah-Hartman 
1071a6afd9f3SGreg Kroah-Hartman 	if (tty_register_driver(moxaDriver)) {
1072a6afd9f3SGreg Kroah-Hartman 		printk(KERN_ERR "can't register MOXA Smartio tty driver!\n");
1073a6afd9f3SGreg Kroah-Hartman 		put_tty_driver(moxaDriver);
1074a6afd9f3SGreg Kroah-Hartman 		return -1;
1075a6afd9f3SGreg Kroah-Hartman 	}
1076a6afd9f3SGreg Kroah-Hartman 
1077a6afd9f3SGreg Kroah-Hartman 	/* Find the boards defined from module args. */
1078a6afd9f3SGreg Kroah-Hartman 
1079a6afd9f3SGreg Kroah-Hartman 	for (i = 0; i < MAX_BOARDS; i++) {
1080a6afd9f3SGreg Kroah-Hartman 		if (!baseaddr[i])
1081a6afd9f3SGreg Kroah-Hartman 			break;
1082a6afd9f3SGreg Kroah-Hartman 		if (type[i] == MOXA_BOARD_C218_ISA ||
1083a6afd9f3SGreg Kroah-Hartman 				type[i] == MOXA_BOARD_C320_ISA) {
1084a6afd9f3SGreg Kroah-Hartman 			pr_debug("Moxa board %2d: %s board(baseAddr=%lx)\n",
1085a6afd9f3SGreg Kroah-Hartman 					isabrds + 1, moxa_brdname[type[i] - 1],
1086a6afd9f3SGreg Kroah-Hartman 					baseaddr[i]);
1087a6afd9f3SGreg Kroah-Hartman 			brd->boardType = type[i];
1088a6afd9f3SGreg Kroah-Hartman 			brd->numPorts = type[i] == MOXA_BOARD_C218_ISA ? 8 :
1089a6afd9f3SGreg Kroah-Hartman 					numports[i];
1090a6afd9f3SGreg Kroah-Hartman 			brd->busType = MOXA_BUS_TYPE_ISA;
1091a6afd9f3SGreg Kroah-Hartman 			brd->basemem = ioremap_nocache(baseaddr[i], 0x4000);
1092a6afd9f3SGreg Kroah-Hartman 			if (!brd->basemem) {
1093a6afd9f3SGreg Kroah-Hartman 				printk(KERN_ERR "MOXA: can't remap %lx\n",
1094a6afd9f3SGreg Kroah-Hartman 						baseaddr[i]);
1095a6afd9f3SGreg Kroah-Hartman 				continue;
1096a6afd9f3SGreg Kroah-Hartman 			}
1097a6afd9f3SGreg Kroah-Hartman 			if (moxa_init_board(brd, NULL)) {
1098a6afd9f3SGreg Kroah-Hartman 				iounmap(brd->basemem);
1099a6afd9f3SGreg Kroah-Hartman 				brd->basemem = NULL;
1100a6afd9f3SGreg Kroah-Hartman 				continue;
1101a6afd9f3SGreg Kroah-Hartman 			}
1102a6afd9f3SGreg Kroah-Hartman 
1103a6afd9f3SGreg Kroah-Hartman 			printk(KERN_INFO "MOXA isa board found at 0x%.8lu and "
1104a6afd9f3SGreg Kroah-Hartman 					"ready (%u ports, firmware loaded)\n",
1105a6afd9f3SGreg Kroah-Hartman 					baseaddr[i], brd->numPorts);
1106a6afd9f3SGreg Kroah-Hartman 
1107a6afd9f3SGreg Kroah-Hartman 			brd++;
1108a6afd9f3SGreg Kroah-Hartman 			isabrds++;
1109a6afd9f3SGreg Kroah-Hartman 		}
1110a6afd9f3SGreg Kroah-Hartman 	}
1111a6afd9f3SGreg Kroah-Hartman 
1112a6afd9f3SGreg Kroah-Hartman #ifdef CONFIG_PCI
1113a6afd9f3SGreg Kroah-Hartman 	retval = pci_register_driver(&moxa_pci_driver);
1114a6afd9f3SGreg Kroah-Hartman 	if (retval) {
1115a6afd9f3SGreg Kroah-Hartman 		printk(KERN_ERR "Can't register MOXA pci driver!\n");
1116a6afd9f3SGreg Kroah-Hartman 		if (isabrds)
1117a6afd9f3SGreg Kroah-Hartman 			retval = 0;
1118a6afd9f3SGreg Kroah-Hartman 	}
1119a6afd9f3SGreg Kroah-Hartman #endif
1120a6afd9f3SGreg Kroah-Hartman 
1121a6afd9f3SGreg Kroah-Hartman 	return retval;
1122a6afd9f3SGreg Kroah-Hartman }
1123a6afd9f3SGreg Kroah-Hartman 
1124a6afd9f3SGreg Kroah-Hartman static void __exit moxa_exit(void)
1125a6afd9f3SGreg Kroah-Hartman {
1126a6afd9f3SGreg Kroah-Hartman 	unsigned int i;
1127a6afd9f3SGreg Kroah-Hartman 
1128a6afd9f3SGreg Kroah-Hartman #ifdef CONFIG_PCI
1129a6afd9f3SGreg Kroah-Hartman 	pci_unregister_driver(&moxa_pci_driver);
1130a6afd9f3SGreg Kroah-Hartman #endif
1131a6afd9f3SGreg Kroah-Hartman 
1132a6afd9f3SGreg Kroah-Hartman 	for (i = 0; i < MAX_BOARDS; i++) /* ISA boards */
1133a6afd9f3SGreg Kroah-Hartman 		if (moxa_boards[i].ready)
1134a6afd9f3SGreg Kroah-Hartman 			moxa_board_deinit(&moxa_boards[i]);
1135a6afd9f3SGreg Kroah-Hartman 
1136a6afd9f3SGreg Kroah-Hartman 	del_timer_sync(&moxaTimer);
1137a6afd9f3SGreg Kroah-Hartman 
1138a6afd9f3SGreg Kroah-Hartman 	if (tty_unregister_driver(moxaDriver))
1139a6afd9f3SGreg Kroah-Hartman 		printk(KERN_ERR "Couldn't unregister MOXA Intellio family "
1140a6afd9f3SGreg Kroah-Hartman 				"serial driver\n");
1141a6afd9f3SGreg Kroah-Hartman 	put_tty_driver(moxaDriver);
1142a6afd9f3SGreg Kroah-Hartman }
1143a6afd9f3SGreg Kroah-Hartman 
1144a6afd9f3SGreg Kroah-Hartman module_init(moxa_init);
1145a6afd9f3SGreg Kroah-Hartman module_exit(moxa_exit);
1146a6afd9f3SGreg Kroah-Hartman 
1147a6afd9f3SGreg Kroah-Hartman static void moxa_shutdown(struct tty_port *port)
1148a6afd9f3SGreg Kroah-Hartman {
1149a6afd9f3SGreg Kroah-Hartman 	struct moxa_port *ch = container_of(port, struct moxa_port, port);
1150a6afd9f3SGreg Kroah-Hartman         MoxaPortDisable(ch);
1151a6afd9f3SGreg Kroah-Hartman 	MoxaPortFlushData(ch, 2);
1152a6afd9f3SGreg Kroah-Hartman }
1153a6afd9f3SGreg Kroah-Hartman 
1154a6afd9f3SGreg Kroah-Hartman static int moxa_carrier_raised(struct tty_port *port)
1155a6afd9f3SGreg Kroah-Hartman {
1156a6afd9f3SGreg Kroah-Hartman 	struct moxa_port *ch = container_of(port, struct moxa_port, port);
1157a6afd9f3SGreg Kroah-Hartman 	int dcd;
1158a6afd9f3SGreg Kroah-Hartman 
1159a6afd9f3SGreg Kroah-Hartman 	spin_lock_irq(&port->lock);
1160a6afd9f3SGreg Kroah-Hartman 	dcd = ch->DCDState;
1161a6afd9f3SGreg Kroah-Hartman 	spin_unlock_irq(&port->lock);
1162a6afd9f3SGreg Kroah-Hartman 	return dcd;
1163a6afd9f3SGreg Kroah-Hartman }
1164a6afd9f3SGreg Kroah-Hartman 
1165a6afd9f3SGreg Kroah-Hartman static void moxa_dtr_rts(struct tty_port *port, int onoff)
1166a6afd9f3SGreg Kroah-Hartman {
1167a6afd9f3SGreg Kroah-Hartman 	struct moxa_port *ch = container_of(port, struct moxa_port, port);
1168a6afd9f3SGreg Kroah-Hartman 	MoxaPortLineCtrl(ch, onoff, onoff);
1169a6afd9f3SGreg Kroah-Hartman }
1170a6afd9f3SGreg Kroah-Hartman 
1171a6afd9f3SGreg Kroah-Hartman 
1172a6afd9f3SGreg Kroah-Hartman static int moxa_open(struct tty_struct *tty, struct file *filp)
1173a6afd9f3SGreg Kroah-Hartman {
1174a6afd9f3SGreg Kroah-Hartman 	struct moxa_board_conf *brd;
1175a6afd9f3SGreg Kroah-Hartman 	struct moxa_port *ch;
1176a6afd9f3SGreg Kroah-Hartman 	int port;
1177a6afd9f3SGreg Kroah-Hartman 
1178a6afd9f3SGreg Kroah-Hartman 	port = tty->index;
1179a6afd9f3SGreg Kroah-Hartman 	if (port == MAX_PORTS) {
1180a6afd9f3SGreg Kroah-Hartman 		return capable(CAP_SYS_ADMIN) ? 0 : -EPERM;
1181a6afd9f3SGreg Kroah-Hartman 	}
1182a6afd9f3SGreg Kroah-Hartman 	if (mutex_lock_interruptible(&moxa_openlock))
1183a6afd9f3SGreg Kroah-Hartman 		return -ERESTARTSYS;
1184a6afd9f3SGreg Kroah-Hartman 	brd = &moxa_boards[port / MAX_PORTS_PER_BOARD];
1185a6afd9f3SGreg Kroah-Hartman 	if (!brd->ready) {
1186a6afd9f3SGreg Kroah-Hartman 		mutex_unlock(&moxa_openlock);
1187a6afd9f3SGreg Kroah-Hartman 		return -ENODEV;
1188a6afd9f3SGreg Kroah-Hartman 	}
1189a6afd9f3SGreg Kroah-Hartman 
1190a6afd9f3SGreg Kroah-Hartman 	if (port % MAX_PORTS_PER_BOARD >= brd->numPorts) {
1191a6afd9f3SGreg Kroah-Hartman 		mutex_unlock(&moxa_openlock);
1192a6afd9f3SGreg Kroah-Hartman 		return -ENODEV;
1193a6afd9f3SGreg Kroah-Hartman 	}
1194a6afd9f3SGreg Kroah-Hartman 
1195a6afd9f3SGreg Kroah-Hartman 	ch = &brd->ports[port % MAX_PORTS_PER_BOARD];
1196a6afd9f3SGreg Kroah-Hartman 	ch->port.count++;
1197a6afd9f3SGreg Kroah-Hartman 	tty->driver_data = ch;
1198a6afd9f3SGreg Kroah-Hartman 	tty_port_tty_set(&ch->port, tty);
1199a6afd9f3SGreg Kroah-Hartman 	mutex_lock(&ch->port.mutex);
1200a6afd9f3SGreg Kroah-Hartman 	if (!(ch->port.flags & ASYNC_INITIALIZED)) {
1201a6afd9f3SGreg Kroah-Hartman 		ch->statusflags = 0;
1202adc8d746SAlan Cox 		moxa_set_tty_param(tty, &tty->termios);
1203a6afd9f3SGreg Kroah-Hartman 		MoxaPortLineCtrl(ch, 1, 1);
1204a6afd9f3SGreg Kroah-Hartman 		MoxaPortEnable(ch);
1205a6afd9f3SGreg Kroah-Hartman 		MoxaSetFifo(ch, ch->type == PORT_16550A);
1206a6afd9f3SGreg Kroah-Hartman 		ch->port.flags |= ASYNC_INITIALIZED;
1207a6afd9f3SGreg Kroah-Hartman 	}
1208a6afd9f3SGreg Kroah-Hartman 	mutex_unlock(&ch->port.mutex);
1209a6afd9f3SGreg Kroah-Hartman 	mutex_unlock(&moxa_openlock);
1210a6afd9f3SGreg Kroah-Hartman 
12117c31bdb6SJiri Slaby 	return tty_port_block_til_ready(&ch->port, tty, filp);
1212a6afd9f3SGreg Kroah-Hartman }
1213a6afd9f3SGreg Kroah-Hartman 
1214a6afd9f3SGreg Kroah-Hartman static void moxa_close(struct tty_struct *tty, struct file *filp)
1215a6afd9f3SGreg Kroah-Hartman {
1216a6afd9f3SGreg Kroah-Hartman 	struct moxa_port *ch = tty->driver_data;
1217adc8d746SAlan Cox 	ch->cflag = tty->termios.c_cflag;
1218a6afd9f3SGreg Kroah-Hartman 	tty_port_close(&ch->port, tty, filp);
1219a6afd9f3SGreg Kroah-Hartman }
1220a6afd9f3SGreg Kroah-Hartman 
1221a6afd9f3SGreg Kroah-Hartman static int moxa_write(struct tty_struct *tty,
1222a6afd9f3SGreg Kroah-Hartman 		      const unsigned char *buf, int count)
1223a6afd9f3SGreg Kroah-Hartman {
1224a6afd9f3SGreg Kroah-Hartman 	struct moxa_port *ch = tty->driver_data;
12250ad7c9afSJiri Slaby 	unsigned long flags;
1226a6afd9f3SGreg Kroah-Hartman 	int len;
1227a6afd9f3SGreg Kroah-Hartman 
1228a6afd9f3SGreg Kroah-Hartman 	if (ch == NULL)
1229a6afd9f3SGreg Kroah-Hartman 		return 0;
1230a6afd9f3SGreg Kroah-Hartman 
12310ad7c9afSJiri Slaby 	spin_lock_irqsave(&moxa_lock, flags);
1232a6afd9f3SGreg Kroah-Hartman 	len = MoxaPortWriteData(tty, buf, count);
12330ad7c9afSJiri Slaby 	spin_unlock_irqrestore(&moxa_lock, flags);
1234a6afd9f3SGreg Kroah-Hartman 
1235a6afd9f3SGreg Kroah-Hartman 	set_bit(LOWWAIT, &ch->statusflags);
1236a6afd9f3SGreg Kroah-Hartman 	return len;
1237a6afd9f3SGreg Kroah-Hartman }
1238a6afd9f3SGreg Kroah-Hartman 
1239a6afd9f3SGreg Kroah-Hartman static int moxa_write_room(struct tty_struct *tty)
1240a6afd9f3SGreg Kroah-Hartman {
1241a6afd9f3SGreg Kroah-Hartman 	struct moxa_port *ch;
1242a6afd9f3SGreg Kroah-Hartman 
1243a6afd9f3SGreg Kroah-Hartman 	if (tty->stopped)
1244a6afd9f3SGreg Kroah-Hartman 		return 0;
1245a6afd9f3SGreg Kroah-Hartman 	ch = tty->driver_data;
1246a6afd9f3SGreg Kroah-Hartman 	if (ch == NULL)
1247a6afd9f3SGreg Kroah-Hartman 		return 0;
1248a6afd9f3SGreg Kroah-Hartman 	return MoxaPortTxFree(ch);
1249a6afd9f3SGreg Kroah-Hartman }
1250a6afd9f3SGreg Kroah-Hartman 
1251a6afd9f3SGreg Kroah-Hartman static void moxa_flush_buffer(struct tty_struct *tty)
1252a6afd9f3SGreg Kroah-Hartman {
1253a6afd9f3SGreg Kroah-Hartman 	struct moxa_port *ch = tty->driver_data;
1254a6afd9f3SGreg Kroah-Hartman 
1255a6afd9f3SGreg Kroah-Hartman 	if (ch == NULL)
1256a6afd9f3SGreg Kroah-Hartman 		return;
1257a6afd9f3SGreg Kroah-Hartman 	MoxaPortFlushData(ch, 1);
1258a6afd9f3SGreg Kroah-Hartman 	tty_wakeup(tty);
1259a6afd9f3SGreg Kroah-Hartman }
1260a6afd9f3SGreg Kroah-Hartman 
1261a6afd9f3SGreg Kroah-Hartman static int moxa_chars_in_buffer(struct tty_struct *tty)
1262a6afd9f3SGreg Kroah-Hartman {
1263a6afd9f3SGreg Kroah-Hartman 	struct moxa_port *ch = tty->driver_data;
1264a6afd9f3SGreg Kroah-Hartman 	int chars;
1265a6afd9f3SGreg Kroah-Hartman 
1266a6afd9f3SGreg Kroah-Hartman 	chars = MoxaPortTxQueue(ch);
1267a6afd9f3SGreg Kroah-Hartman 	if (chars)
1268a6afd9f3SGreg Kroah-Hartman 		/*
1269a6afd9f3SGreg Kroah-Hartman 		 * Make it possible to wakeup anything waiting for output
1270a6afd9f3SGreg Kroah-Hartman 		 * in tty_ioctl.c, etc.
1271a6afd9f3SGreg Kroah-Hartman 		 */
1272a6afd9f3SGreg Kroah-Hartman         	set_bit(EMPTYWAIT, &ch->statusflags);
1273a6afd9f3SGreg Kroah-Hartman 	return chars;
1274a6afd9f3SGreg Kroah-Hartman }
1275a6afd9f3SGreg Kroah-Hartman 
1276a6afd9f3SGreg Kroah-Hartman static int moxa_tiocmget(struct tty_struct *tty)
1277a6afd9f3SGreg Kroah-Hartman {
1278a6afd9f3SGreg Kroah-Hartman 	struct moxa_port *ch = tty->driver_data;
1279a6afd9f3SGreg Kroah-Hartman 	int flag = 0, dtr, rts;
1280a6afd9f3SGreg Kroah-Hartman 
1281a6afd9f3SGreg Kroah-Hartman 	MoxaPortGetLineOut(ch, &dtr, &rts);
1282a6afd9f3SGreg Kroah-Hartman 	if (dtr)
1283a6afd9f3SGreg Kroah-Hartman 		flag |= TIOCM_DTR;
1284a6afd9f3SGreg Kroah-Hartman 	if (rts)
1285a6afd9f3SGreg Kroah-Hartman 		flag |= TIOCM_RTS;
1286a6afd9f3SGreg Kroah-Hartman 	dtr = MoxaPortLineStatus(ch);
1287a6afd9f3SGreg Kroah-Hartman 	if (dtr & 1)
1288a6afd9f3SGreg Kroah-Hartman 		flag |= TIOCM_CTS;
1289a6afd9f3SGreg Kroah-Hartman 	if (dtr & 2)
1290a6afd9f3SGreg Kroah-Hartman 		flag |= TIOCM_DSR;
1291a6afd9f3SGreg Kroah-Hartman 	if (dtr & 4)
1292a6afd9f3SGreg Kroah-Hartman 		flag |= TIOCM_CD;
1293a6afd9f3SGreg Kroah-Hartman 	return flag;
1294a6afd9f3SGreg Kroah-Hartman }
1295a6afd9f3SGreg Kroah-Hartman 
1296a6afd9f3SGreg Kroah-Hartman static int moxa_tiocmset(struct tty_struct *tty,
1297a6afd9f3SGreg Kroah-Hartman 			 unsigned int set, unsigned int clear)
1298a6afd9f3SGreg Kroah-Hartman {
1299a6afd9f3SGreg Kroah-Hartman 	struct moxa_port *ch;
1300a6afd9f3SGreg Kroah-Hartman 	int dtr, rts;
1301a6afd9f3SGreg Kroah-Hartman 
1302a6afd9f3SGreg Kroah-Hartman 	mutex_lock(&moxa_openlock);
1303a6afd9f3SGreg Kroah-Hartman 	ch = tty->driver_data;
1304a6afd9f3SGreg Kroah-Hartman 	if (!ch) {
1305a6afd9f3SGreg Kroah-Hartman 		mutex_unlock(&moxa_openlock);
1306a6afd9f3SGreg Kroah-Hartman 		return -EINVAL;
1307a6afd9f3SGreg Kroah-Hartman 	}
1308a6afd9f3SGreg Kroah-Hartman 
1309a6afd9f3SGreg Kroah-Hartman 	MoxaPortGetLineOut(ch, &dtr, &rts);
1310a6afd9f3SGreg Kroah-Hartman 	if (set & TIOCM_RTS)
1311a6afd9f3SGreg Kroah-Hartman 		rts = 1;
1312a6afd9f3SGreg Kroah-Hartman 	if (set & TIOCM_DTR)
1313a6afd9f3SGreg Kroah-Hartman 		dtr = 1;
1314a6afd9f3SGreg Kroah-Hartman 	if (clear & TIOCM_RTS)
1315a6afd9f3SGreg Kroah-Hartman 		rts = 0;
1316a6afd9f3SGreg Kroah-Hartman 	if (clear & TIOCM_DTR)
1317a6afd9f3SGreg Kroah-Hartman 		dtr = 0;
1318a6afd9f3SGreg Kroah-Hartman 	MoxaPortLineCtrl(ch, dtr, rts);
1319a6afd9f3SGreg Kroah-Hartman 	mutex_unlock(&moxa_openlock);
1320a6afd9f3SGreg Kroah-Hartman 	return 0;
1321a6afd9f3SGreg Kroah-Hartman }
1322a6afd9f3SGreg Kroah-Hartman 
1323a6afd9f3SGreg Kroah-Hartman static void moxa_set_termios(struct tty_struct *tty,
1324a6afd9f3SGreg Kroah-Hartman 		struct ktermios *old_termios)
1325a6afd9f3SGreg Kroah-Hartman {
1326a6afd9f3SGreg Kroah-Hartman 	struct moxa_port *ch = tty->driver_data;
1327a6afd9f3SGreg Kroah-Hartman 
1328a6afd9f3SGreg Kroah-Hartman 	if (ch == NULL)
1329a6afd9f3SGreg Kroah-Hartman 		return;
1330a6afd9f3SGreg Kroah-Hartman 	moxa_set_tty_param(tty, old_termios);
1331a6afd9f3SGreg Kroah-Hartman 	if (!(old_termios->c_cflag & CLOCAL) && C_CLOCAL(tty))
1332a6afd9f3SGreg Kroah-Hartman 		wake_up_interruptible(&ch->port.open_wait);
1333a6afd9f3SGreg Kroah-Hartman }
1334a6afd9f3SGreg Kroah-Hartman 
1335a6afd9f3SGreg Kroah-Hartman static void moxa_stop(struct tty_struct *tty)
1336a6afd9f3SGreg Kroah-Hartman {
1337a6afd9f3SGreg Kroah-Hartman 	struct moxa_port *ch = tty->driver_data;
1338a6afd9f3SGreg Kroah-Hartman 
1339a6afd9f3SGreg Kroah-Hartman 	if (ch == NULL)
1340a6afd9f3SGreg Kroah-Hartman 		return;
1341a6afd9f3SGreg Kroah-Hartman 	MoxaPortTxDisable(ch);
1342a6afd9f3SGreg Kroah-Hartman 	set_bit(TXSTOPPED, &ch->statusflags);
1343a6afd9f3SGreg Kroah-Hartman }
1344a6afd9f3SGreg Kroah-Hartman 
1345a6afd9f3SGreg Kroah-Hartman 
1346a6afd9f3SGreg Kroah-Hartman static void moxa_start(struct tty_struct *tty)
1347a6afd9f3SGreg Kroah-Hartman {
1348a6afd9f3SGreg Kroah-Hartman 	struct moxa_port *ch = tty->driver_data;
1349a6afd9f3SGreg Kroah-Hartman 
1350a6afd9f3SGreg Kroah-Hartman 	if (ch == NULL)
1351a6afd9f3SGreg Kroah-Hartman 		return;
1352a6afd9f3SGreg Kroah-Hartman 
135358112dfbSDan Carpenter 	if (!test_bit(TXSTOPPED, &ch->statusflags))
1354a6afd9f3SGreg Kroah-Hartman 		return;
1355a6afd9f3SGreg Kroah-Hartman 
1356a6afd9f3SGreg Kroah-Hartman 	MoxaPortTxEnable(ch);
1357a6afd9f3SGreg Kroah-Hartman 	clear_bit(TXSTOPPED, &ch->statusflags);
1358a6afd9f3SGreg Kroah-Hartman }
1359a6afd9f3SGreg Kroah-Hartman 
1360a6afd9f3SGreg Kroah-Hartman static void moxa_hangup(struct tty_struct *tty)
1361a6afd9f3SGreg Kroah-Hartman {
1362a6afd9f3SGreg Kroah-Hartman 	struct moxa_port *ch = tty->driver_data;
1363a6afd9f3SGreg Kroah-Hartman 	tty_port_hangup(&ch->port);
1364a6afd9f3SGreg Kroah-Hartman }
1365a6afd9f3SGreg Kroah-Hartman 
1366a6afd9f3SGreg Kroah-Hartman static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd)
1367a6afd9f3SGreg Kroah-Hartman {
1368a6afd9f3SGreg Kroah-Hartman 	struct tty_struct *tty;
1369a6afd9f3SGreg Kroah-Hartman 	unsigned long flags;
1370a6afd9f3SGreg Kroah-Hartman 	dcd = !!dcd;
1371a6afd9f3SGreg Kroah-Hartman 
1372a6afd9f3SGreg Kroah-Hartman 	spin_lock_irqsave(&p->port.lock, flags);
1373a6afd9f3SGreg Kroah-Hartman 	if (dcd != p->DCDState) {
1374a6afd9f3SGreg Kroah-Hartman         	p->DCDState = dcd;
1375a6afd9f3SGreg Kroah-Hartman         	spin_unlock_irqrestore(&p->port.lock, flags);
1376a6afd9f3SGreg Kroah-Hartman 		tty = tty_port_tty_get(&p->port);
13774bd82136SAlan Cox 		if (tty && !C_CLOCAL(tty) && !dcd)
1378a6afd9f3SGreg Kroah-Hartman 			tty_hangup(tty);
1379a6afd9f3SGreg Kroah-Hartman 		tty_kref_put(tty);
1380a6afd9f3SGreg Kroah-Hartman 	}
1381a6afd9f3SGreg Kroah-Hartman 	else
1382a6afd9f3SGreg Kroah-Hartman 		spin_unlock_irqrestore(&p->port.lock, flags);
1383a6afd9f3SGreg Kroah-Hartman }
1384a6afd9f3SGreg Kroah-Hartman 
1385a6afd9f3SGreg Kroah-Hartman static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
1386a6afd9f3SGreg Kroah-Hartman 		u16 __iomem *ip)
1387a6afd9f3SGreg Kroah-Hartman {
1388a6afd9f3SGreg Kroah-Hartman 	struct tty_struct *tty = tty_port_tty_get(&p->port);
1389a6afd9f3SGreg Kroah-Hartman 	void __iomem *ofsAddr;
1390a6afd9f3SGreg Kroah-Hartman 	unsigned int inited = p->port.flags & ASYNC_INITIALIZED;
1391a6afd9f3SGreg Kroah-Hartman 	u16 intr;
1392a6afd9f3SGreg Kroah-Hartman 
1393a6afd9f3SGreg Kroah-Hartman 	if (tty) {
1394a6afd9f3SGreg Kroah-Hartman 		if (test_bit(EMPTYWAIT, &p->statusflags) &&
1395a6afd9f3SGreg Kroah-Hartman 				MoxaPortTxQueue(p) == 0) {
1396a6afd9f3SGreg Kroah-Hartman 			clear_bit(EMPTYWAIT, &p->statusflags);
1397a6afd9f3SGreg Kroah-Hartman 			tty_wakeup(tty);
1398a6afd9f3SGreg Kroah-Hartman 		}
1399a6afd9f3SGreg Kroah-Hartman 		if (test_bit(LOWWAIT, &p->statusflags) && !tty->stopped &&
1400a6afd9f3SGreg Kroah-Hartman 				MoxaPortTxQueue(p) <= WAKEUP_CHARS) {
1401a6afd9f3SGreg Kroah-Hartman 			clear_bit(LOWWAIT, &p->statusflags);
1402a6afd9f3SGreg Kroah-Hartman 			tty_wakeup(tty);
1403a6afd9f3SGreg Kroah-Hartman 		}
1404a6afd9f3SGreg Kroah-Hartman 
1405a6afd9f3SGreg Kroah-Hartman 		if (inited && !test_bit(TTY_THROTTLED, &tty->flags) &&
1406a6afd9f3SGreg Kroah-Hartman 				MoxaPortRxQueue(p) > 0) { /* RX */
1407a6afd9f3SGreg Kroah-Hartman 			MoxaPortReadData(p);
1408a6afd9f3SGreg Kroah-Hartman 			tty_schedule_flip(tty);
1409a6afd9f3SGreg Kroah-Hartman 		}
1410a6afd9f3SGreg Kroah-Hartman 	} else {
1411a6afd9f3SGreg Kroah-Hartman 		clear_bit(EMPTYWAIT, &p->statusflags);
1412a6afd9f3SGreg Kroah-Hartman 		MoxaPortFlushData(p, 0); /* flush RX */
1413a6afd9f3SGreg Kroah-Hartman 	}
1414a6afd9f3SGreg Kroah-Hartman 
1415a6afd9f3SGreg Kroah-Hartman 	if (!handle) /* nothing else to do */
1416a6afd9f3SGreg Kroah-Hartman 		goto put;
1417a6afd9f3SGreg Kroah-Hartman 
1418a6afd9f3SGreg Kroah-Hartman 	intr = readw(ip); /* port irq status */
1419a6afd9f3SGreg Kroah-Hartman 	if (intr == 0)
1420a6afd9f3SGreg Kroah-Hartman 		goto put;
1421a6afd9f3SGreg Kroah-Hartman 
1422a6afd9f3SGreg Kroah-Hartman 	writew(0, ip); /* ACK port */
1423a6afd9f3SGreg Kroah-Hartman 	ofsAddr = p->tableAddr;
1424a6afd9f3SGreg Kroah-Hartman 	if (intr & IntrTx) /* disable tx intr */
1425a6afd9f3SGreg Kroah-Hartman 		writew(readw(ofsAddr + HostStat) & ~WakeupTx,
1426a6afd9f3SGreg Kroah-Hartman 				ofsAddr + HostStat);
1427a6afd9f3SGreg Kroah-Hartman 
1428a6afd9f3SGreg Kroah-Hartman 	if (!inited)
1429a6afd9f3SGreg Kroah-Hartman 		goto put;
1430a6afd9f3SGreg Kroah-Hartman 
1431a6afd9f3SGreg Kroah-Hartman 	if (tty && (intr & IntrBreak) && !I_IGNBRK(tty)) { /* BREAK */
1432a6afd9f3SGreg Kroah-Hartman 		tty_insert_flip_char(tty, 0, TTY_BREAK);
1433a6afd9f3SGreg Kroah-Hartman 		tty_schedule_flip(tty);
1434a6afd9f3SGreg Kroah-Hartman 	}
1435a6afd9f3SGreg Kroah-Hartman 
1436a6afd9f3SGreg Kroah-Hartman 	if (intr & IntrLine)
1437a6afd9f3SGreg Kroah-Hartman 		moxa_new_dcdstate(p, readb(ofsAddr + FlagStat) & DCD_state);
1438a6afd9f3SGreg Kroah-Hartman put:
1439a6afd9f3SGreg Kroah-Hartman 	tty_kref_put(tty);
1440a6afd9f3SGreg Kroah-Hartman 
1441a6afd9f3SGreg Kroah-Hartman 	return 0;
1442a6afd9f3SGreg Kroah-Hartman }
1443a6afd9f3SGreg Kroah-Hartman 
1444a6afd9f3SGreg Kroah-Hartman static void moxa_poll(unsigned long ignored)
1445a6afd9f3SGreg Kroah-Hartman {
1446a6afd9f3SGreg Kroah-Hartman 	struct moxa_board_conf *brd;
1447a6afd9f3SGreg Kroah-Hartman 	u16 __iomem *ip;
1448a6afd9f3SGreg Kroah-Hartman 	unsigned int card, port, served = 0;
1449a6afd9f3SGreg Kroah-Hartman 
1450a6afd9f3SGreg Kroah-Hartman 	spin_lock(&moxa_lock);
1451a6afd9f3SGreg Kroah-Hartman 	for (card = 0; card < MAX_BOARDS; card++) {
1452a6afd9f3SGreg Kroah-Hartman 		brd = &moxa_boards[card];
1453a6afd9f3SGreg Kroah-Hartman 		if (!brd->ready)
1454a6afd9f3SGreg Kroah-Hartman 			continue;
1455a6afd9f3SGreg Kroah-Hartman 
1456a6afd9f3SGreg Kroah-Hartman 		served++;
1457a6afd9f3SGreg Kroah-Hartman 
1458a6afd9f3SGreg Kroah-Hartman 		ip = NULL;
1459a6afd9f3SGreg Kroah-Hartman 		if (readb(brd->intPend) == 0xff)
1460a6afd9f3SGreg Kroah-Hartman 			ip = brd->intTable + readb(brd->intNdx);
1461a6afd9f3SGreg Kroah-Hartman 
1462a6afd9f3SGreg Kroah-Hartman 		for (port = 0; port < brd->numPorts; port++)
1463a6afd9f3SGreg Kroah-Hartman 			moxa_poll_port(&brd->ports[port], !!ip, ip + port);
1464a6afd9f3SGreg Kroah-Hartman 
1465a6afd9f3SGreg Kroah-Hartman 		if (ip)
1466a6afd9f3SGreg Kroah-Hartman 			writeb(0, brd->intPend); /* ACK */
1467a6afd9f3SGreg Kroah-Hartman 
1468a6afd9f3SGreg Kroah-Hartman 		if (moxaLowWaterChk) {
1469a6afd9f3SGreg Kroah-Hartman 			struct moxa_port *p = brd->ports;
1470a6afd9f3SGreg Kroah-Hartman 			for (port = 0; port < brd->numPorts; port++, p++)
1471a6afd9f3SGreg Kroah-Hartman 				if (p->lowChkFlag) {
1472a6afd9f3SGreg Kroah-Hartman 					p->lowChkFlag = 0;
1473a6afd9f3SGreg Kroah-Hartman 					moxa_low_water_check(p->tableAddr);
1474a6afd9f3SGreg Kroah-Hartman 				}
1475a6afd9f3SGreg Kroah-Hartman 		}
1476a6afd9f3SGreg Kroah-Hartman 	}
1477a6afd9f3SGreg Kroah-Hartman 	moxaLowWaterChk = 0;
1478a6afd9f3SGreg Kroah-Hartman 
1479a6afd9f3SGreg Kroah-Hartman 	if (served)
1480a6afd9f3SGreg Kroah-Hartman 		mod_timer(&moxaTimer, jiffies + HZ / 50);
1481a6afd9f3SGreg Kroah-Hartman 	spin_unlock(&moxa_lock);
1482a6afd9f3SGreg Kroah-Hartman }
1483a6afd9f3SGreg Kroah-Hartman 
1484a6afd9f3SGreg Kroah-Hartman /******************************************************************************/
1485a6afd9f3SGreg Kroah-Hartman 
1486a6afd9f3SGreg Kroah-Hartman static void moxa_set_tty_param(struct tty_struct *tty, struct ktermios *old_termios)
1487a6afd9f3SGreg Kroah-Hartman {
1488adc8d746SAlan Cox 	register struct ktermios *ts = &tty->termios;
1489a6afd9f3SGreg Kroah-Hartman 	struct moxa_port *ch = tty->driver_data;
1490a6afd9f3SGreg Kroah-Hartman 	int rts, cts, txflow, rxflow, xany, baud;
1491a6afd9f3SGreg Kroah-Hartman 
1492a6afd9f3SGreg Kroah-Hartman 	rts = cts = txflow = rxflow = xany = 0;
1493a6afd9f3SGreg Kroah-Hartman 	if (ts->c_cflag & CRTSCTS)
1494a6afd9f3SGreg Kroah-Hartman 		rts = cts = 1;
1495a6afd9f3SGreg Kroah-Hartman 	if (ts->c_iflag & IXON)
1496a6afd9f3SGreg Kroah-Hartman 		txflow = 1;
1497a6afd9f3SGreg Kroah-Hartman 	if (ts->c_iflag & IXOFF)
1498a6afd9f3SGreg Kroah-Hartman 		rxflow = 1;
1499a6afd9f3SGreg Kroah-Hartman 	if (ts->c_iflag & IXANY)
1500a6afd9f3SGreg Kroah-Hartman 		xany = 1;
1501a6afd9f3SGreg Kroah-Hartman 
1502a6afd9f3SGreg Kroah-Hartman 	/* Clear the features we don't support */
1503a6afd9f3SGreg Kroah-Hartman 	ts->c_cflag &= ~CMSPAR;
1504a6afd9f3SGreg Kroah-Hartman 	MoxaPortFlowCtrl(ch, rts, cts, txflow, rxflow, xany);
1505a6afd9f3SGreg Kroah-Hartman 	baud = MoxaPortSetTermio(ch, ts, tty_get_baud_rate(tty));
1506a6afd9f3SGreg Kroah-Hartman 	if (baud == -1)
1507a6afd9f3SGreg Kroah-Hartman 		baud = tty_termios_baud_rate(old_termios);
1508a6afd9f3SGreg Kroah-Hartman 	/* Not put the baud rate into the termios data */
1509a6afd9f3SGreg Kroah-Hartman 	tty_encode_baud_rate(tty, baud, baud);
1510a6afd9f3SGreg Kroah-Hartman }
1511a6afd9f3SGreg Kroah-Hartman 
1512a6afd9f3SGreg Kroah-Hartman /*****************************************************************************
1513a6afd9f3SGreg Kroah-Hartman  *	Driver level functions: 					     *
1514a6afd9f3SGreg Kroah-Hartman  *****************************************************************************/
1515a6afd9f3SGreg Kroah-Hartman 
1516a6afd9f3SGreg Kroah-Hartman static void MoxaPortFlushData(struct moxa_port *port, int mode)
1517a6afd9f3SGreg Kroah-Hartman {
1518a6afd9f3SGreg Kroah-Hartman 	void __iomem *ofsAddr;
1519a6afd9f3SGreg Kroah-Hartman 	if (mode < 0 || mode > 2)
1520a6afd9f3SGreg Kroah-Hartman 		return;
1521a6afd9f3SGreg Kroah-Hartman 	ofsAddr = port->tableAddr;
1522a6afd9f3SGreg Kroah-Hartman 	moxafunc(ofsAddr, FC_FlushQueue, mode);
1523a6afd9f3SGreg Kroah-Hartman 	if (mode != 1) {
1524a6afd9f3SGreg Kroah-Hartman 		port->lowChkFlag = 0;
1525a6afd9f3SGreg Kroah-Hartman 		moxa_low_water_check(ofsAddr);
1526a6afd9f3SGreg Kroah-Hartman 	}
1527a6afd9f3SGreg Kroah-Hartman }
1528a6afd9f3SGreg Kroah-Hartman 
1529a6afd9f3SGreg Kroah-Hartman /*
1530a6afd9f3SGreg Kroah-Hartman  *    Moxa Port Number Description:
1531a6afd9f3SGreg Kroah-Hartman  *
1532a6afd9f3SGreg Kroah-Hartman  *      MOXA serial driver supports up to 4 MOXA-C218/C320 boards. And,
1533a6afd9f3SGreg Kroah-Hartman  *      the port number using in MOXA driver functions will be 0 to 31 for
1534a6afd9f3SGreg Kroah-Hartman  *      first MOXA board, 32 to 63 for second, 64 to 95 for third and 96
1535a6afd9f3SGreg Kroah-Hartman  *      to 127 for fourth. For example, if you setup three MOXA boards,
1536a6afd9f3SGreg Kroah-Hartman  *      first board is C218, second board is C320-16 and third board is
1537a6afd9f3SGreg Kroah-Hartman  *      C320-32. The port number of first board (C218 - 8 ports) is from
1538a6afd9f3SGreg Kroah-Hartman  *      0 to 7. The port number of second board (C320 - 16 ports) is form
1539a6afd9f3SGreg Kroah-Hartman  *      32 to 47. The port number of third board (C320 - 32 ports) is from
1540a6afd9f3SGreg Kroah-Hartman  *      64 to 95. And those port numbers form 8 to 31, 48 to 63 and 96 to
1541a6afd9f3SGreg Kroah-Hartman  *      127 will be invalid.
1542a6afd9f3SGreg Kroah-Hartman  *
1543a6afd9f3SGreg Kroah-Hartman  *
1544a6afd9f3SGreg Kroah-Hartman  *      Moxa Functions Description:
1545a6afd9f3SGreg Kroah-Hartman  *
1546a6afd9f3SGreg Kroah-Hartman  *      Function 1:     Driver initialization routine, this routine must be
1547a6afd9f3SGreg Kroah-Hartman  *                      called when initialized driver.
1548a6afd9f3SGreg Kroah-Hartman  *      Syntax:
1549a6afd9f3SGreg Kroah-Hartman  *      void MoxaDriverInit();
1550a6afd9f3SGreg Kroah-Hartman  *
1551a6afd9f3SGreg Kroah-Hartman  *
1552a6afd9f3SGreg Kroah-Hartman  *      Function 2:     Moxa driver private IOCTL command processing.
1553a6afd9f3SGreg Kroah-Hartman  *      Syntax:
1554a6afd9f3SGreg Kroah-Hartman  *      int  MoxaDriverIoctl(unsigned int cmd, unsigned long arg, int port);
1555a6afd9f3SGreg Kroah-Hartman  *
1556a6afd9f3SGreg Kroah-Hartman  *           unsigned int cmd   : IOCTL command
1557a6afd9f3SGreg Kroah-Hartman  *           unsigned long arg  : IOCTL argument
1558a6afd9f3SGreg Kroah-Hartman  *           int port           : port number (0 - 127)
1559a6afd9f3SGreg Kroah-Hartman  *
1560a6afd9f3SGreg Kroah-Hartman  *           return:    0  (OK)
1561a6afd9f3SGreg Kroah-Hartman  *                      -EINVAL
1562a6afd9f3SGreg Kroah-Hartman  *                      -ENOIOCTLCMD
1563a6afd9f3SGreg Kroah-Hartman  *
1564a6afd9f3SGreg Kroah-Hartman  *
1565a6afd9f3SGreg Kroah-Hartman  *      Function 6:     Enable this port to start Tx/Rx data.
1566a6afd9f3SGreg Kroah-Hartman  *      Syntax:
1567a6afd9f3SGreg Kroah-Hartman  *      void MoxaPortEnable(int port);
1568a6afd9f3SGreg Kroah-Hartman  *           int port           : port number (0 - 127)
1569a6afd9f3SGreg Kroah-Hartman  *
1570a6afd9f3SGreg Kroah-Hartman  *
1571a6afd9f3SGreg Kroah-Hartman  *      Function 7:     Disable this port
1572a6afd9f3SGreg Kroah-Hartman  *      Syntax:
1573a6afd9f3SGreg Kroah-Hartman  *      void MoxaPortDisable(int port);
1574a6afd9f3SGreg Kroah-Hartman  *           int port           : port number (0 - 127)
1575a6afd9f3SGreg Kroah-Hartman  *
1576a6afd9f3SGreg Kroah-Hartman  *
1577a6afd9f3SGreg Kroah-Hartman  *      Function 10:    Setting baud rate of this port.
1578a6afd9f3SGreg Kroah-Hartman  *      Syntax:
1579a6afd9f3SGreg Kroah-Hartman  *      speed_t MoxaPortSetBaud(int port, speed_t baud);
1580a6afd9f3SGreg Kroah-Hartman  *           int port           : port number (0 - 127)
1581a6afd9f3SGreg Kroah-Hartman  *           long baud          : baud rate (50 - 115200)
1582a6afd9f3SGreg Kroah-Hartman  *
1583a6afd9f3SGreg Kroah-Hartman  *           return:    0       : this port is invalid or baud < 50
1584a6afd9f3SGreg Kroah-Hartman  *                      50 - 115200 : the real baud rate set to the port, if
1585a6afd9f3SGreg Kroah-Hartman  *                                    the argument baud is large than maximun
1586a6afd9f3SGreg Kroah-Hartman  *                                    available baud rate, the real setting
1587a6afd9f3SGreg Kroah-Hartman  *                                    baud rate will be the maximun baud rate.
1588a6afd9f3SGreg Kroah-Hartman  *
1589a6afd9f3SGreg Kroah-Hartman  *
1590a6afd9f3SGreg Kroah-Hartman  *      Function 12:    Configure the port.
1591a6afd9f3SGreg Kroah-Hartman  *      Syntax:
1592a6afd9f3SGreg Kroah-Hartman  *      int  MoxaPortSetTermio(int port, struct ktermios *termio, speed_t baud);
1593a6afd9f3SGreg Kroah-Hartman  *           int port           : port number (0 - 127)
1594a6afd9f3SGreg Kroah-Hartman  *           struct ktermios * termio : termio structure pointer
1595a6afd9f3SGreg Kroah-Hartman  *	     speed_t baud	: baud rate
1596a6afd9f3SGreg Kroah-Hartman  *
1597a6afd9f3SGreg Kroah-Hartman  *           return:    -1      : this port is invalid or termio == NULL
1598a6afd9f3SGreg Kroah-Hartman  *                      0       : setting O.K.
1599a6afd9f3SGreg Kroah-Hartman  *
1600a6afd9f3SGreg Kroah-Hartman  *
1601a6afd9f3SGreg Kroah-Hartman  *      Function 13:    Get the DTR/RTS state of this port.
1602a6afd9f3SGreg Kroah-Hartman  *      Syntax:
1603a6afd9f3SGreg Kroah-Hartman  *      int  MoxaPortGetLineOut(int port, int *dtrState, int *rtsState);
1604a6afd9f3SGreg Kroah-Hartman  *           int port           : port number (0 - 127)
1605a6afd9f3SGreg Kroah-Hartman  *           int * dtrState     : pointer to INT to receive the current DTR
1606a6afd9f3SGreg Kroah-Hartman  *                                state. (if NULL, this function will not
1607a6afd9f3SGreg Kroah-Hartman  *                                write to this address)
1608a6afd9f3SGreg Kroah-Hartman  *           int * rtsState     : pointer to INT to receive the current RTS
1609a6afd9f3SGreg Kroah-Hartman  *                                state. (if NULL, this function will not
1610a6afd9f3SGreg Kroah-Hartman  *                                write to this address)
1611a6afd9f3SGreg Kroah-Hartman  *
1612a6afd9f3SGreg Kroah-Hartman  *           return:    -1      : this port is invalid
1613a6afd9f3SGreg Kroah-Hartman  *                      0       : O.K.
1614a6afd9f3SGreg Kroah-Hartman  *
1615a6afd9f3SGreg Kroah-Hartman  *
1616a6afd9f3SGreg Kroah-Hartman  *      Function 14:    Setting the DTR/RTS output state of this port.
1617a6afd9f3SGreg Kroah-Hartman  *      Syntax:
1618a6afd9f3SGreg Kroah-Hartman  *      void MoxaPortLineCtrl(int port, int dtrState, int rtsState);
1619a6afd9f3SGreg Kroah-Hartman  *           int port           : port number (0 - 127)
1620a6afd9f3SGreg Kroah-Hartman  *           int dtrState       : DTR output state (0: off, 1: on)
1621a6afd9f3SGreg Kroah-Hartman  *           int rtsState       : RTS output state (0: off, 1: on)
1622a6afd9f3SGreg Kroah-Hartman  *
1623a6afd9f3SGreg Kroah-Hartman  *
1624a6afd9f3SGreg Kroah-Hartman  *      Function 15:    Setting the flow control of this port.
1625a6afd9f3SGreg Kroah-Hartman  *      Syntax:
1626a6afd9f3SGreg Kroah-Hartman  *      void MoxaPortFlowCtrl(int port, int rtsFlow, int ctsFlow, int rxFlow,
1627a6afd9f3SGreg Kroah-Hartman  *                            int txFlow,int xany);
1628a6afd9f3SGreg Kroah-Hartman  *           int port           : port number (0 - 127)
1629a6afd9f3SGreg Kroah-Hartman  *           int rtsFlow        : H/W RTS flow control (0: no, 1: yes)
1630a6afd9f3SGreg Kroah-Hartman  *           int ctsFlow        : H/W CTS flow control (0: no, 1: yes)
1631a6afd9f3SGreg Kroah-Hartman  *           int rxFlow         : S/W Rx XON/XOFF flow control (0: no, 1: yes)
1632a6afd9f3SGreg Kroah-Hartman  *           int txFlow         : S/W Tx XON/XOFF flow control (0: no, 1: yes)
1633a6afd9f3SGreg Kroah-Hartman  *           int xany           : S/W XANY flow control (0: no, 1: yes)
1634a6afd9f3SGreg Kroah-Hartman  *
1635a6afd9f3SGreg Kroah-Hartman  *
1636a6afd9f3SGreg Kroah-Hartman  *      Function 16:    Get ths line status of this port
1637a6afd9f3SGreg Kroah-Hartman  *      Syntax:
1638a6afd9f3SGreg Kroah-Hartman  *      int  MoxaPortLineStatus(int port);
1639a6afd9f3SGreg Kroah-Hartman  *           int port           : port number (0 - 127)
1640a6afd9f3SGreg Kroah-Hartman  *
1641a6afd9f3SGreg Kroah-Hartman  *           return:    Bit 0 - CTS state (0: off, 1: on)
1642a6afd9f3SGreg Kroah-Hartman  *                      Bit 1 - DSR state (0: off, 1: on)
1643a6afd9f3SGreg Kroah-Hartman  *                      Bit 2 - DCD state (0: off, 1: on)
1644a6afd9f3SGreg Kroah-Hartman  *
1645a6afd9f3SGreg Kroah-Hartman  *
1646a6afd9f3SGreg Kroah-Hartman  *      Function 19:    Flush the Rx/Tx buffer data of this port.
1647a6afd9f3SGreg Kroah-Hartman  *      Syntax:
1648a6afd9f3SGreg Kroah-Hartman  *      void MoxaPortFlushData(int port, int mode);
1649a6afd9f3SGreg Kroah-Hartman  *           int port           : port number (0 - 127)
1650a6afd9f3SGreg Kroah-Hartman  *           int mode
1651a6afd9f3SGreg Kroah-Hartman  *                      0       : flush the Rx buffer
1652a6afd9f3SGreg Kroah-Hartman  *                      1       : flush the Tx buffer
1653a6afd9f3SGreg Kroah-Hartman  *                      2       : flush the Rx and Tx buffer
1654a6afd9f3SGreg Kroah-Hartman  *
1655a6afd9f3SGreg Kroah-Hartman  *
1656a6afd9f3SGreg Kroah-Hartman  *      Function 20:    Write data.
1657a6afd9f3SGreg Kroah-Hartman  *      Syntax:
1658a6afd9f3SGreg Kroah-Hartman  *      int  MoxaPortWriteData(int port, unsigned char * buffer, int length);
1659a6afd9f3SGreg Kroah-Hartman  *           int port           : port number (0 - 127)
1660a6afd9f3SGreg Kroah-Hartman  *           unsigned char * buffer     : pointer to write data buffer.
1661a6afd9f3SGreg Kroah-Hartman  *           int length         : write data length
1662a6afd9f3SGreg Kroah-Hartman  *
1663a6afd9f3SGreg Kroah-Hartman  *           return:    0 - length      : real write data length
1664a6afd9f3SGreg Kroah-Hartman  *
1665a6afd9f3SGreg Kroah-Hartman  *
1666a6afd9f3SGreg Kroah-Hartman  *      Function 21:    Read data.
1667a6afd9f3SGreg Kroah-Hartman  *      Syntax:
1668a6afd9f3SGreg Kroah-Hartman  *      int  MoxaPortReadData(int port, struct tty_struct *tty);
1669a6afd9f3SGreg Kroah-Hartman  *           int port           : port number (0 - 127)
1670a6afd9f3SGreg Kroah-Hartman  *	     struct tty_struct *tty : tty for data
1671a6afd9f3SGreg Kroah-Hartman  *
1672a6afd9f3SGreg Kroah-Hartman  *           return:    0 - length      : real read data length
1673a6afd9f3SGreg Kroah-Hartman  *
1674a6afd9f3SGreg Kroah-Hartman  *
1675a6afd9f3SGreg Kroah-Hartman  *      Function 24:    Get the Tx buffer current queued data bytes
1676a6afd9f3SGreg Kroah-Hartman  *      Syntax:
1677a6afd9f3SGreg Kroah-Hartman  *      int  MoxaPortTxQueue(int port);
1678a6afd9f3SGreg Kroah-Hartman  *           int port           : port number (0 - 127)
1679a6afd9f3SGreg Kroah-Hartman  *
1680a6afd9f3SGreg Kroah-Hartman  *           return:    ..      : Tx buffer current queued data bytes
1681a6afd9f3SGreg Kroah-Hartman  *
1682a6afd9f3SGreg Kroah-Hartman  *
1683a6afd9f3SGreg Kroah-Hartman  *      Function 25:    Get the Tx buffer current free space
1684a6afd9f3SGreg Kroah-Hartman  *      Syntax:
1685a6afd9f3SGreg Kroah-Hartman  *      int  MoxaPortTxFree(int port);
1686a6afd9f3SGreg Kroah-Hartman  *           int port           : port number (0 - 127)
1687a6afd9f3SGreg Kroah-Hartman  *
1688a6afd9f3SGreg Kroah-Hartman  *           return:    ..      : Tx buffer current free space
1689a6afd9f3SGreg Kroah-Hartman  *
1690a6afd9f3SGreg Kroah-Hartman  *
1691a6afd9f3SGreg Kroah-Hartman  *      Function 26:    Get the Rx buffer current queued data bytes
1692a6afd9f3SGreg Kroah-Hartman  *      Syntax:
1693a6afd9f3SGreg Kroah-Hartman  *      int  MoxaPortRxQueue(int port);
1694a6afd9f3SGreg Kroah-Hartman  *           int port           : port number (0 - 127)
1695a6afd9f3SGreg Kroah-Hartman  *
1696a6afd9f3SGreg Kroah-Hartman  *           return:    ..      : Rx buffer current queued data bytes
1697a6afd9f3SGreg Kroah-Hartman  *
1698a6afd9f3SGreg Kroah-Hartman  *
1699a6afd9f3SGreg Kroah-Hartman  *      Function 28:    Disable port data transmission.
1700a6afd9f3SGreg Kroah-Hartman  *      Syntax:
1701a6afd9f3SGreg Kroah-Hartman  *      void MoxaPortTxDisable(int port);
1702a6afd9f3SGreg Kroah-Hartman  *           int port           : port number (0 - 127)
1703a6afd9f3SGreg Kroah-Hartman  *
1704a6afd9f3SGreg Kroah-Hartman  *
1705a6afd9f3SGreg Kroah-Hartman  *      Function 29:    Enable port data transmission.
1706a6afd9f3SGreg Kroah-Hartman  *      Syntax:
1707a6afd9f3SGreg Kroah-Hartman  *      void MoxaPortTxEnable(int port);
1708a6afd9f3SGreg Kroah-Hartman  *           int port           : port number (0 - 127)
1709a6afd9f3SGreg Kroah-Hartman  *
1710a6afd9f3SGreg Kroah-Hartman  *
1711a6afd9f3SGreg Kroah-Hartman  *      Function 31:    Get the received BREAK signal count and reset it.
1712a6afd9f3SGreg Kroah-Hartman  *      Syntax:
1713a6afd9f3SGreg Kroah-Hartman  *      int  MoxaPortResetBrkCnt(int port);
1714a6afd9f3SGreg Kroah-Hartman  *           int port           : port number (0 - 127)
1715a6afd9f3SGreg Kroah-Hartman  *
1716a6afd9f3SGreg Kroah-Hartman  *           return:    0 - ..  : BREAK signal count
1717a6afd9f3SGreg Kroah-Hartman  *
1718a6afd9f3SGreg Kroah-Hartman  *
1719a6afd9f3SGreg Kroah-Hartman  */
1720a6afd9f3SGreg Kroah-Hartman 
1721a6afd9f3SGreg Kroah-Hartman static void MoxaPortEnable(struct moxa_port *port)
1722a6afd9f3SGreg Kroah-Hartman {
1723a6afd9f3SGreg Kroah-Hartman 	void __iomem *ofsAddr;
1724a6afd9f3SGreg Kroah-Hartman 	u16 lowwater = 512;
1725a6afd9f3SGreg Kroah-Hartman 
1726a6afd9f3SGreg Kroah-Hartman 	ofsAddr = port->tableAddr;
1727a6afd9f3SGreg Kroah-Hartman 	writew(lowwater, ofsAddr + Low_water);
1728a6afd9f3SGreg Kroah-Hartman 	if (MOXA_IS_320(port->board))
1729a6afd9f3SGreg Kroah-Hartman 		moxafunc(ofsAddr, FC_SetBreakIrq, 0);
1730a6afd9f3SGreg Kroah-Hartman 	else
1731a6afd9f3SGreg Kroah-Hartman 		writew(readw(ofsAddr + HostStat) | WakeupBreak,
1732a6afd9f3SGreg Kroah-Hartman 				ofsAddr + HostStat);
1733a6afd9f3SGreg Kroah-Hartman 
1734a6afd9f3SGreg Kroah-Hartman 	moxafunc(ofsAddr, FC_SetLineIrq, Magic_code);
1735a6afd9f3SGreg Kroah-Hartman 	moxafunc(ofsAddr, FC_FlushQueue, 2);
1736a6afd9f3SGreg Kroah-Hartman 
1737a6afd9f3SGreg Kroah-Hartman 	moxafunc(ofsAddr, FC_EnableCH, Magic_code);
1738a6afd9f3SGreg Kroah-Hartman 	MoxaPortLineStatus(port);
1739a6afd9f3SGreg Kroah-Hartman }
1740a6afd9f3SGreg Kroah-Hartman 
1741a6afd9f3SGreg Kroah-Hartman static void MoxaPortDisable(struct moxa_port *port)
1742a6afd9f3SGreg Kroah-Hartman {
1743a6afd9f3SGreg Kroah-Hartman 	void __iomem *ofsAddr = port->tableAddr;
1744a6afd9f3SGreg Kroah-Hartman 
1745a6afd9f3SGreg Kroah-Hartman 	moxafunc(ofsAddr, FC_SetFlowCtl, 0);	/* disable flow control */
1746a6afd9f3SGreg Kroah-Hartman 	moxafunc(ofsAddr, FC_ClrLineIrq, Magic_code);
1747a6afd9f3SGreg Kroah-Hartman 	writew(0, ofsAddr + HostStat);
1748a6afd9f3SGreg Kroah-Hartman 	moxafunc(ofsAddr, FC_DisableCH, Magic_code);
1749a6afd9f3SGreg Kroah-Hartman }
1750a6afd9f3SGreg Kroah-Hartman 
1751a6afd9f3SGreg Kroah-Hartman static speed_t MoxaPortSetBaud(struct moxa_port *port, speed_t baud)
1752a6afd9f3SGreg Kroah-Hartman {
1753a6afd9f3SGreg Kroah-Hartman 	void __iomem *ofsAddr = port->tableAddr;
1754a6afd9f3SGreg Kroah-Hartman 	unsigned int clock, val;
1755a6afd9f3SGreg Kroah-Hartman 	speed_t max;
1756a6afd9f3SGreg Kroah-Hartman 
1757a6afd9f3SGreg Kroah-Hartman 	max = MOXA_IS_320(port->board) ? 460800 : 921600;
1758a6afd9f3SGreg Kroah-Hartman 	if (baud < 50)
1759a6afd9f3SGreg Kroah-Hartman 		return 0;
1760a6afd9f3SGreg Kroah-Hartman 	if (baud > max)
1761a6afd9f3SGreg Kroah-Hartman 		baud = max;
1762a6afd9f3SGreg Kroah-Hartman 	clock = 921600;
1763a6afd9f3SGreg Kroah-Hartman 	val = clock / baud;
1764a6afd9f3SGreg Kroah-Hartman 	moxafunc(ofsAddr, FC_SetBaud, val);
1765a6afd9f3SGreg Kroah-Hartman 	baud = clock / val;
1766a6afd9f3SGreg Kroah-Hartman 	return baud;
1767a6afd9f3SGreg Kroah-Hartman }
1768a6afd9f3SGreg Kroah-Hartman 
1769a6afd9f3SGreg Kroah-Hartman static int MoxaPortSetTermio(struct moxa_port *port, struct ktermios *termio,
1770a6afd9f3SGreg Kroah-Hartman 		speed_t baud)
1771a6afd9f3SGreg Kroah-Hartman {
1772a6afd9f3SGreg Kroah-Hartman 	void __iomem *ofsAddr;
1773a6afd9f3SGreg Kroah-Hartman 	tcflag_t mode = 0;
1774a6afd9f3SGreg Kroah-Hartman 
1775a6afd9f3SGreg Kroah-Hartman 	ofsAddr = port->tableAddr;
1776a6afd9f3SGreg Kroah-Hartman 
1777a6afd9f3SGreg Kroah-Hartman 	mode = termio->c_cflag & CSIZE;
1778a6afd9f3SGreg Kroah-Hartman 	if (mode == CS5)
1779a6afd9f3SGreg Kroah-Hartman 		mode = MX_CS5;
1780a6afd9f3SGreg Kroah-Hartman 	else if (mode == CS6)
1781a6afd9f3SGreg Kroah-Hartman 		mode = MX_CS6;
1782a6afd9f3SGreg Kroah-Hartman 	else if (mode == CS7)
1783a6afd9f3SGreg Kroah-Hartman 		mode = MX_CS7;
1784a6afd9f3SGreg Kroah-Hartman 	else if (mode == CS8)
1785a6afd9f3SGreg Kroah-Hartman 		mode = MX_CS8;
1786a6afd9f3SGreg Kroah-Hartman 
1787a6afd9f3SGreg Kroah-Hartman 	if (termio->c_cflag & CSTOPB) {
1788a6afd9f3SGreg Kroah-Hartman 		if (mode == MX_CS5)
1789a6afd9f3SGreg Kroah-Hartman 			mode |= MX_STOP15;
1790a6afd9f3SGreg Kroah-Hartman 		else
1791a6afd9f3SGreg Kroah-Hartman 			mode |= MX_STOP2;
1792a6afd9f3SGreg Kroah-Hartman 	} else
1793a6afd9f3SGreg Kroah-Hartman 		mode |= MX_STOP1;
1794a6afd9f3SGreg Kroah-Hartman 
1795a6afd9f3SGreg Kroah-Hartman 	if (termio->c_cflag & PARENB) {
1796a6afd9f3SGreg Kroah-Hartman 		if (termio->c_cflag & PARODD)
1797a6afd9f3SGreg Kroah-Hartman 			mode |= MX_PARODD;
1798a6afd9f3SGreg Kroah-Hartman 		else
1799a6afd9f3SGreg Kroah-Hartman 			mode |= MX_PAREVEN;
1800a6afd9f3SGreg Kroah-Hartman 	} else
1801a6afd9f3SGreg Kroah-Hartman 		mode |= MX_PARNONE;
1802a6afd9f3SGreg Kroah-Hartman 
1803a6afd9f3SGreg Kroah-Hartman 	moxafunc(ofsAddr, FC_SetDataMode, (u16)mode);
1804a6afd9f3SGreg Kroah-Hartman 
1805a6afd9f3SGreg Kroah-Hartman 	if (MOXA_IS_320(port->board) && baud >= 921600)
1806a6afd9f3SGreg Kroah-Hartman 		return -1;
1807a6afd9f3SGreg Kroah-Hartman 
1808a6afd9f3SGreg Kroah-Hartman 	baud = MoxaPortSetBaud(port, baud);
1809a6afd9f3SGreg Kroah-Hartman 
1810a6afd9f3SGreg Kroah-Hartman 	if (termio->c_iflag & (IXON | IXOFF | IXANY)) {
1811a6afd9f3SGreg Kroah-Hartman 	        spin_lock_irq(&moxafunc_lock);
1812a6afd9f3SGreg Kroah-Hartman 		writeb(termio->c_cc[VSTART], ofsAddr + FuncArg);
1813a6afd9f3SGreg Kroah-Hartman 		writeb(termio->c_cc[VSTOP], ofsAddr + FuncArg1);
1814a6afd9f3SGreg Kroah-Hartman 		writeb(FC_SetXonXoff, ofsAddr + FuncCode);
1815a6afd9f3SGreg Kroah-Hartman 		moxa_wait_finish(ofsAddr);
1816a6afd9f3SGreg Kroah-Hartman 		spin_unlock_irq(&moxafunc_lock);
1817a6afd9f3SGreg Kroah-Hartman 
1818a6afd9f3SGreg Kroah-Hartman 	}
1819a6afd9f3SGreg Kroah-Hartman 	return baud;
1820a6afd9f3SGreg Kroah-Hartman }
1821a6afd9f3SGreg Kroah-Hartman 
1822a6afd9f3SGreg Kroah-Hartman static int MoxaPortGetLineOut(struct moxa_port *port, int *dtrState,
1823a6afd9f3SGreg Kroah-Hartman 		int *rtsState)
1824a6afd9f3SGreg Kroah-Hartman {
1825a6afd9f3SGreg Kroah-Hartman 	if (dtrState)
1826a6afd9f3SGreg Kroah-Hartman 		*dtrState = !!(port->lineCtrl & DTR_ON);
1827a6afd9f3SGreg Kroah-Hartman 	if (rtsState)
1828a6afd9f3SGreg Kroah-Hartman 		*rtsState = !!(port->lineCtrl & RTS_ON);
1829a6afd9f3SGreg Kroah-Hartman 
1830a6afd9f3SGreg Kroah-Hartman 	return 0;
1831a6afd9f3SGreg Kroah-Hartman }
1832a6afd9f3SGreg Kroah-Hartman 
1833a6afd9f3SGreg Kroah-Hartman static void MoxaPortLineCtrl(struct moxa_port *port, int dtr, int rts)
1834a6afd9f3SGreg Kroah-Hartman {
1835a6afd9f3SGreg Kroah-Hartman 	u8 mode = 0;
1836a6afd9f3SGreg Kroah-Hartman 
1837a6afd9f3SGreg Kroah-Hartman 	if (dtr)
1838a6afd9f3SGreg Kroah-Hartman 		mode |= DTR_ON;
1839a6afd9f3SGreg Kroah-Hartman 	if (rts)
1840a6afd9f3SGreg Kroah-Hartman 		mode |= RTS_ON;
1841a6afd9f3SGreg Kroah-Hartman 	port->lineCtrl = mode;
1842a6afd9f3SGreg Kroah-Hartman 	moxafunc(port->tableAddr, FC_LineControl, mode);
1843a6afd9f3SGreg Kroah-Hartman }
1844a6afd9f3SGreg Kroah-Hartman 
1845a6afd9f3SGreg Kroah-Hartman static void MoxaPortFlowCtrl(struct moxa_port *port, int rts, int cts,
1846a6afd9f3SGreg Kroah-Hartman 		int txflow, int rxflow, int txany)
1847a6afd9f3SGreg Kroah-Hartman {
1848a6afd9f3SGreg Kroah-Hartman 	int mode = 0;
1849a6afd9f3SGreg Kroah-Hartman 
1850a6afd9f3SGreg Kroah-Hartman 	if (rts)
1851a6afd9f3SGreg Kroah-Hartman 		mode |= RTS_FlowCtl;
1852a6afd9f3SGreg Kroah-Hartman 	if (cts)
1853a6afd9f3SGreg Kroah-Hartman 		mode |= CTS_FlowCtl;
1854a6afd9f3SGreg Kroah-Hartman 	if (txflow)
1855a6afd9f3SGreg Kroah-Hartman 		mode |= Tx_FlowCtl;
1856a6afd9f3SGreg Kroah-Hartman 	if (rxflow)
1857a6afd9f3SGreg Kroah-Hartman 		mode |= Rx_FlowCtl;
1858a6afd9f3SGreg Kroah-Hartman 	if (txany)
1859a6afd9f3SGreg Kroah-Hartman 		mode |= IXM_IXANY;
1860a6afd9f3SGreg Kroah-Hartman 	moxafunc(port->tableAddr, FC_SetFlowCtl, mode);
1861a6afd9f3SGreg Kroah-Hartman }
1862a6afd9f3SGreg Kroah-Hartman 
1863a6afd9f3SGreg Kroah-Hartman static int MoxaPortLineStatus(struct moxa_port *port)
1864a6afd9f3SGreg Kroah-Hartman {
1865a6afd9f3SGreg Kroah-Hartman 	void __iomem *ofsAddr;
1866a6afd9f3SGreg Kroah-Hartman 	int val;
1867a6afd9f3SGreg Kroah-Hartman 
1868a6afd9f3SGreg Kroah-Hartman 	ofsAddr = port->tableAddr;
1869a6afd9f3SGreg Kroah-Hartman 	if (MOXA_IS_320(port->board))
1870a6afd9f3SGreg Kroah-Hartman 		val = moxafuncret(ofsAddr, FC_LineStatus, 0);
1871a6afd9f3SGreg Kroah-Hartman 	else
1872a6afd9f3SGreg Kroah-Hartman 		val = readw(ofsAddr + FlagStat) >> 4;
1873a6afd9f3SGreg Kroah-Hartman 	val &= 0x0B;
1874a6afd9f3SGreg Kroah-Hartman 	if (val & 8)
1875a6afd9f3SGreg Kroah-Hartman 		val |= 4;
1876a6afd9f3SGreg Kroah-Hartman 	moxa_new_dcdstate(port, val & 8);
1877a6afd9f3SGreg Kroah-Hartman 	val &= 7;
1878a6afd9f3SGreg Kroah-Hartman 	return val;
1879a6afd9f3SGreg Kroah-Hartman }
1880a6afd9f3SGreg Kroah-Hartman 
1881a6afd9f3SGreg Kroah-Hartman static int MoxaPortWriteData(struct tty_struct *tty,
1882a6afd9f3SGreg Kroah-Hartman 		const unsigned char *buffer, int len)
1883a6afd9f3SGreg Kroah-Hartman {
1884a6afd9f3SGreg Kroah-Hartman 	struct moxa_port *port = tty->driver_data;
1885a6afd9f3SGreg Kroah-Hartman 	void __iomem *baseAddr, *ofsAddr, *ofs;
1886a6afd9f3SGreg Kroah-Hartman 	unsigned int c, total;
1887a6afd9f3SGreg Kroah-Hartman 	u16 head, tail, tx_mask, spage, epage;
1888a6afd9f3SGreg Kroah-Hartman 	u16 pageno, pageofs, bufhead;
1889a6afd9f3SGreg Kroah-Hartman 
1890a6afd9f3SGreg Kroah-Hartman 	ofsAddr = port->tableAddr;
1891a6afd9f3SGreg Kroah-Hartman 	baseAddr = port->board->basemem;
1892a6afd9f3SGreg Kroah-Hartman 	tx_mask = readw(ofsAddr + TX_mask);
1893a6afd9f3SGreg Kroah-Hartman 	spage = readw(ofsAddr + Page_txb);
1894a6afd9f3SGreg Kroah-Hartman 	epage = readw(ofsAddr + EndPage_txb);
1895a6afd9f3SGreg Kroah-Hartman 	tail = readw(ofsAddr + TXwptr);
1896a6afd9f3SGreg Kroah-Hartman 	head = readw(ofsAddr + TXrptr);
1897a6afd9f3SGreg Kroah-Hartman 	c = (head > tail) ? (head - tail - 1) : (head - tail + tx_mask);
1898a6afd9f3SGreg Kroah-Hartman 	if (c > len)
1899a6afd9f3SGreg Kroah-Hartman 		c = len;
1900a6afd9f3SGreg Kroah-Hartman 	moxaLog.txcnt[port->port.tty->index] += c;
1901a6afd9f3SGreg Kroah-Hartman 	total = c;
1902a6afd9f3SGreg Kroah-Hartman 	if (spage == epage) {
1903a6afd9f3SGreg Kroah-Hartman 		bufhead = readw(ofsAddr + Ofs_txb);
1904a6afd9f3SGreg Kroah-Hartman 		writew(spage, baseAddr + Control_reg);
1905a6afd9f3SGreg Kroah-Hartman 		while (c > 0) {
1906a6afd9f3SGreg Kroah-Hartman 			if (head > tail)
1907a6afd9f3SGreg Kroah-Hartman 				len = head - tail - 1;
1908a6afd9f3SGreg Kroah-Hartman 			else
1909a6afd9f3SGreg Kroah-Hartman 				len = tx_mask + 1 - tail;
1910a6afd9f3SGreg Kroah-Hartman 			len = (c > len) ? len : c;
1911a6afd9f3SGreg Kroah-Hartman 			ofs = baseAddr + DynPage_addr + bufhead + tail;
1912a6afd9f3SGreg Kroah-Hartman 			memcpy_toio(ofs, buffer, len);
1913a6afd9f3SGreg Kroah-Hartman 			buffer += len;
1914a6afd9f3SGreg Kroah-Hartman 			tail = (tail + len) & tx_mask;
1915a6afd9f3SGreg Kroah-Hartman 			c -= len;
1916a6afd9f3SGreg Kroah-Hartman 		}
1917a6afd9f3SGreg Kroah-Hartman 	} else {
1918a6afd9f3SGreg Kroah-Hartman 		pageno = spage + (tail >> 13);
1919a6afd9f3SGreg Kroah-Hartman 		pageofs = tail & Page_mask;
1920a6afd9f3SGreg Kroah-Hartman 		while (c > 0) {
1921a6afd9f3SGreg Kroah-Hartman 			len = Page_size - pageofs;
1922a6afd9f3SGreg Kroah-Hartman 			if (len > c)
1923a6afd9f3SGreg Kroah-Hartman 				len = c;
1924a6afd9f3SGreg Kroah-Hartman 			writeb(pageno, baseAddr + Control_reg);
1925a6afd9f3SGreg Kroah-Hartman 			ofs = baseAddr + DynPage_addr + pageofs;
1926a6afd9f3SGreg Kroah-Hartman 			memcpy_toio(ofs, buffer, len);
1927a6afd9f3SGreg Kroah-Hartman 			buffer += len;
1928a6afd9f3SGreg Kroah-Hartman 			if (++pageno == epage)
1929a6afd9f3SGreg Kroah-Hartman 				pageno = spage;
1930a6afd9f3SGreg Kroah-Hartman 			pageofs = 0;
1931a6afd9f3SGreg Kroah-Hartman 			c -= len;
1932a6afd9f3SGreg Kroah-Hartman 		}
1933a6afd9f3SGreg Kroah-Hartman 		tail = (tail + total) & tx_mask;
1934a6afd9f3SGreg Kroah-Hartman 	}
1935a6afd9f3SGreg Kroah-Hartman 	writew(tail, ofsAddr + TXwptr);
1936a6afd9f3SGreg Kroah-Hartman 	writeb(1, ofsAddr + CD180TXirq);	/* start to send */
1937a6afd9f3SGreg Kroah-Hartman 	return total;
1938a6afd9f3SGreg Kroah-Hartman }
1939a6afd9f3SGreg Kroah-Hartman 
1940a6afd9f3SGreg Kroah-Hartman static int MoxaPortReadData(struct moxa_port *port)
1941a6afd9f3SGreg Kroah-Hartman {
1942a6afd9f3SGreg Kroah-Hartman 	struct tty_struct *tty = port->port.tty;
1943a6afd9f3SGreg Kroah-Hartman 	unsigned char *dst;
1944a6afd9f3SGreg Kroah-Hartman 	void __iomem *baseAddr, *ofsAddr, *ofs;
1945a6afd9f3SGreg Kroah-Hartman 	unsigned int count, len, total;
1946a6afd9f3SGreg Kroah-Hartman 	u16 tail, rx_mask, spage, epage;
1947a6afd9f3SGreg Kroah-Hartman 	u16 pageno, pageofs, bufhead, head;
1948a6afd9f3SGreg Kroah-Hartman 
1949a6afd9f3SGreg Kroah-Hartman 	ofsAddr = port->tableAddr;
1950a6afd9f3SGreg Kroah-Hartman 	baseAddr = port->board->basemem;
1951a6afd9f3SGreg Kroah-Hartman 	head = readw(ofsAddr + RXrptr);
1952a6afd9f3SGreg Kroah-Hartman 	tail = readw(ofsAddr + RXwptr);
1953a6afd9f3SGreg Kroah-Hartman 	rx_mask = readw(ofsAddr + RX_mask);
1954a6afd9f3SGreg Kroah-Hartman 	spage = readw(ofsAddr + Page_rxb);
1955a6afd9f3SGreg Kroah-Hartman 	epage = readw(ofsAddr + EndPage_rxb);
1956a6afd9f3SGreg Kroah-Hartman 	count = (tail >= head) ? (tail - head) : (tail - head + rx_mask + 1);
1957a6afd9f3SGreg Kroah-Hartman 	if (count == 0)
1958a6afd9f3SGreg Kroah-Hartman 		return 0;
1959a6afd9f3SGreg Kroah-Hartman 
1960a6afd9f3SGreg Kroah-Hartman 	total = count;
1961a6afd9f3SGreg Kroah-Hartman 	moxaLog.rxcnt[tty->index] += total;
1962a6afd9f3SGreg Kroah-Hartman 	if (spage == epage) {
1963a6afd9f3SGreg Kroah-Hartman 		bufhead = readw(ofsAddr + Ofs_rxb);
1964a6afd9f3SGreg Kroah-Hartman 		writew(spage, baseAddr + Control_reg);
1965a6afd9f3SGreg Kroah-Hartman 		while (count > 0) {
1966a6afd9f3SGreg Kroah-Hartman 			ofs = baseAddr + DynPage_addr + bufhead + head;
1967a6afd9f3SGreg Kroah-Hartman 			len = (tail >= head) ? (tail - head) :
1968a6afd9f3SGreg Kroah-Hartman 					(rx_mask + 1 - head);
1969a6afd9f3SGreg Kroah-Hartman 			len = tty_prepare_flip_string(tty, &dst,
1970a6afd9f3SGreg Kroah-Hartman 					min(len, count));
1971a6afd9f3SGreg Kroah-Hartman 			memcpy_fromio(dst, ofs, len);
1972a6afd9f3SGreg Kroah-Hartman 			head = (head + len) & rx_mask;
1973a6afd9f3SGreg Kroah-Hartman 			count -= len;
1974a6afd9f3SGreg Kroah-Hartman 		}
1975a6afd9f3SGreg Kroah-Hartman 	} else {
1976a6afd9f3SGreg Kroah-Hartman 		pageno = spage + (head >> 13);
1977a6afd9f3SGreg Kroah-Hartman 		pageofs = head & Page_mask;
1978a6afd9f3SGreg Kroah-Hartman 		while (count > 0) {
1979a6afd9f3SGreg Kroah-Hartman 			writew(pageno, baseAddr + Control_reg);
1980a6afd9f3SGreg Kroah-Hartman 			ofs = baseAddr + DynPage_addr + pageofs;
1981a6afd9f3SGreg Kroah-Hartman 			len = tty_prepare_flip_string(tty, &dst,
1982a6afd9f3SGreg Kroah-Hartman 					min(Page_size - pageofs, count));
1983a6afd9f3SGreg Kroah-Hartman 			memcpy_fromio(dst, ofs, len);
1984a6afd9f3SGreg Kroah-Hartman 
1985a6afd9f3SGreg Kroah-Hartman 			count -= len;
1986a6afd9f3SGreg Kroah-Hartman 			pageofs = (pageofs + len) & Page_mask;
1987a6afd9f3SGreg Kroah-Hartman 			if (pageofs == 0 && ++pageno == epage)
1988a6afd9f3SGreg Kroah-Hartman 				pageno = spage;
1989a6afd9f3SGreg Kroah-Hartman 		}
1990a6afd9f3SGreg Kroah-Hartman 		head = (head + total) & rx_mask;
1991a6afd9f3SGreg Kroah-Hartman 	}
1992a6afd9f3SGreg Kroah-Hartman 	writew(head, ofsAddr + RXrptr);
1993a6afd9f3SGreg Kroah-Hartman 	if (readb(ofsAddr + FlagStat) & Xoff_state) {
1994a6afd9f3SGreg Kroah-Hartman 		moxaLowWaterChk = 1;
1995a6afd9f3SGreg Kroah-Hartman 		port->lowChkFlag = 1;
1996a6afd9f3SGreg Kroah-Hartman 	}
1997a6afd9f3SGreg Kroah-Hartman 	return total;
1998a6afd9f3SGreg Kroah-Hartman }
1999a6afd9f3SGreg Kroah-Hartman 
2000a6afd9f3SGreg Kroah-Hartman 
2001a6afd9f3SGreg Kroah-Hartman static int MoxaPortTxQueue(struct moxa_port *port)
2002a6afd9f3SGreg Kroah-Hartman {
2003a6afd9f3SGreg Kroah-Hartman 	void __iomem *ofsAddr = port->tableAddr;
2004a6afd9f3SGreg Kroah-Hartman 	u16 rptr, wptr, mask;
2005a6afd9f3SGreg Kroah-Hartman 
2006a6afd9f3SGreg Kroah-Hartman 	rptr = readw(ofsAddr + TXrptr);
2007a6afd9f3SGreg Kroah-Hartman 	wptr = readw(ofsAddr + TXwptr);
2008a6afd9f3SGreg Kroah-Hartman 	mask = readw(ofsAddr + TX_mask);
2009a6afd9f3SGreg Kroah-Hartman 	return (wptr - rptr) & mask;
2010a6afd9f3SGreg Kroah-Hartman }
2011a6afd9f3SGreg Kroah-Hartman 
2012a6afd9f3SGreg Kroah-Hartman static int MoxaPortTxFree(struct moxa_port *port)
2013a6afd9f3SGreg Kroah-Hartman {
2014a6afd9f3SGreg Kroah-Hartman 	void __iomem *ofsAddr = port->tableAddr;
2015a6afd9f3SGreg Kroah-Hartman 	u16 rptr, wptr, mask;
2016a6afd9f3SGreg Kroah-Hartman 
2017a6afd9f3SGreg Kroah-Hartman 	rptr = readw(ofsAddr + TXrptr);
2018a6afd9f3SGreg Kroah-Hartman 	wptr = readw(ofsAddr + TXwptr);
2019a6afd9f3SGreg Kroah-Hartman 	mask = readw(ofsAddr + TX_mask);
2020a6afd9f3SGreg Kroah-Hartman 	return mask - ((wptr - rptr) & mask);
2021a6afd9f3SGreg Kroah-Hartman }
2022a6afd9f3SGreg Kroah-Hartman 
2023a6afd9f3SGreg Kroah-Hartman static int MoxaPortRxQueue(struct moxa_port *port)
2024a6afd9f3SGreg Kroah-Hartman {
2025a6afd9f3SGreg Kroah-Hartman 	void __iomem *ofsAddr = port->tableAddr;
2026a6afd9f3SGreg Kroah-Hartman 	u16 rptr, wptr, mask;
2027a6afd9f3SGreg Kroah-Hartman 
2028a6afd9f3SGreg Kroah-Hartman 	rptr = readw(ofsAddr + RXrptr);
2029a6afd9f3SGreg Kroah-Hartman 	wptr = readw(ofsAddr + RXwptr);
2030a6afd9f3SGreg Kroah-Hartman 	mask = readw(ofsAddr + RX_mask);
2031a6afd9f3SGreg Kroah-Hartman 	return (wptr - rptr) & mask;
2032a6afd9f3SGreg Kroah-Hartman }
2033a6afd9f3SGreg Kroah-Hartman 
2034a6afd9f3SGreg Kroah-Hartman static void MoxaPortTxDisable(struct moxa_port *port)
2035a6afd9f3SGreg Kroah-Hartman {
2036a6afd9f3SGreg Kroah-Hartman 	moxafunc(port->tableAddr, FC_SetXoffState, Magic_code);
2037a6afd9f3SGreg Kroah-Hartman }
2038a6afd9f3SGreg Kroah-Hartman 
2039a6afd9f3SGreg Kroah-Hartman static void MoxaPortTxEnable(struct moxa_port *port)
2040a6afd9f3SGreg Kroah-Hartman {
2041a6afd9f3SGreg Kroah-Hartman 	moxafunc(port->tableAddr, FC_SetXonState, Magic_code);
2042a6afd9f3SGreg Kroah-Hartman }
2043a6afd9f3SGreg Kroah-Hartman 
2044a6afd9f3SGreg Kroah-Hartman static int moxa_get_serial_info(struct moxa_port *info,
2045a6afd9f3SGreg Kroah-Hartman 		struct serial_struct __user *retinfo)
2046a6afd9f3SGreg Kroah-Hartman {
2047a6afd9f3SGreg Kroah-Hartman 	struct serial_struct tmp = {
2048a6afd9f3SGreg Kroah-Hartman 		.type = info->type,
2049a6afd9f3SGreg Kroah-Hartman 		.line = info->port.tty->index,
2050a6afd9f3SGreg Kroah-Hartman 		.flags = info->port.flags,
2051a6afd9f3SGreg Kroah-Hartman 		.baud_base = 921600,
2052a6afd9f3SGreg Kroah-Hartman 		.close_delay = info->port.close_delay
2053a6afd9f3SGreg Kroah-Hartman 	};
2054a6afd9f3SGreg Kroah-Hartman 	return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
2055a6afd9f3SGreg Kroah-Hartman }
2056a6afd9f3SGreg Kroah-Hartman 
2057a6afd9f3SGreg Kroah-Hartman 
2058a6afd9f3SGreg Kroah-Hartman static int moxa_set_serial_info(struct moxa_port *info,
2059a6afd9f3SGreg Kroah-Hartman 		struct serial_struct __user *new_info)
2060a6afd9f3SGreg Kroah-Hartman {
2061a6afd9f3SGreg Kroah-Hartman 	struct serial_struct new_serial;
2062a6afd9f3SGreg Kroah-Hartman 
2063a6afd9f3SGreg Kroah-Hartman 	if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
2064a6afd9f3SGreg Kroah-Hartman 		return -EFAULT;
2065a6afd9f3SGreg Kroah-Hartman 
2066a6afd9f3SGreg Kroah-Hartman 	if (new_serial.irq != 0 || new_serial.port != 0 ||
2067a6afd9f3SGreg Kroah-Hartman 			new_serial.custom_divisor != 0 ||
2068a6afd9f3SGreg Kroah-Hartman 			new_serial.baud_base != 921600)
2069a6afd9f3SGreg Kroah-Hartman 		return -EPERM;
2070a6afd9f3SGreg Kroah-Hartman 
2071a6afd9f3SGreg Kroah-Hartman 	if (!capable(CAP_SYS_ADMIN)) {
2072a6afd9f3SGreg Kroah-Hartman 		if (((new_serial.flags & ~ASYNC_USR_MASK) !=
2073a6afd9f3SGreg Kroah-Hartman 		     (info->port.flags & ~ASYNC_USR_MASK)))
2074a6afd9f3SGreg Kroah-Hartman 			return -EPERM;
2075a6afd9f3SGreg Kroah-Hartman 	} else
2076a6afd9f3SGreg Kroah-Hartman 		info->port.close_delay = new_serial.close_delay * HZ / 100;
2077a6afd9f3SGreg Kroah-Hartman 
2078a6afd9f3SGreg Kroah-Hartman 	new_serial.flags = (new_serial.flags & ~ASYNC_FLAGS);
2079a6afd9f3SGreg Kroah-Hartman 	new_serial.flags |= (info->port.flags & ASYNC_FLAGS);
2080a6afd9f3SGreg Kroah-Hartman 
2081a6afd9f3SGreg Kroah-Hartman 	MoxaSetFifo(info, new_serial.type == PORT_16550A);
2082a6afd9f3SGreg Kroah-Hartman 
2083a6afd9f3SGreg Kroah-Hartman 	info->type = new_serial.type;
2084a6afd9f3SGreg Kroah-Hartman 	return 0;
2085a6afd9f3SGreg Kroah-Hartman }
2086a6afd9f3SGreg Kroah-Hartman 
2087a6afd9f3SGreg Kroah-Hartman 
2088a6afd9f3SGreg Kroah-Hartman 
2089a6afd9f3SGreg Kroah-Hartman /*****************************************************************************
2090a6afd9f3SGreg Kroah-Hartman  *	Static local functions: 					     *
2091a6afd9f3SGreg Kroah-Hartman  *****************************************************************************/
2092a6afd9f3SGreg Kroah-Hartman 
2093a6afd9f3SGreg Kroah-Hartman static void MoxaSetFifo(struct moxa_port *port, int enable)
2094a6afd9f3SGreg Kroah-Hartman {
2095a6afd9f3SGreg Kroah-Hartman 	void __iomem *ofsAddr = port->tableAddr;
2096a6afd9f3SGreg Kroah-Hartman 
2097a6afd9f3SGreg Kroah-Hartman 	if (!enable) {
2098a6afd9f3SGreg Kroah-Hartman 		moxafunc(ofsAddr, FC_SetRxFIFOTrig, 0);
2099a6afd9f3SGreg Kroah-Hartman 		moxafunc(ofsAddr, FC_SetTxFIFOCnt, 1);
2100a6afd9f3SGreg Kroah-Hartman 	} else {
2101a6afd9f3SGreg Kroah-Hartman 		moxafunc(ofsAddr, FC_SetRxFIFOTrig, 3);
2102a6afd9f3SGreg Kroah-Hartman 		moxafunc(ofsAddr, FC_SetTxFIFOCnt, 16);
2103a6afd9f3SGreg Kroah-Hartman 	}
2104a6afd9f3SGreg Kroah-Hartman }
2105