11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           moxa.c  -- MOXA Intellio family multiport serial driver.
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5b9705b603d1d29471aa2977e6310f4f9a4e85925Jiri Slaby *      Copyright (C) 1999-2000  Moxa Technologies (support@moxa.com).
6b9705b603d1d29471aa2977e6310f4f9a4e85925Jiri Slaby *      Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com>
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      This code is loosely based on the Linux serial driver, written by
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Linus Torvalds, Theodore T'so and others.
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      This program is free software; you can redistribute it and/or modify
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      it under the terms of the GNU General Public License as published by
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      the Free Software Foundation; either version 2 of the License, or
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      (at your option) any later version.
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    MOXA Intellio Series Driver
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      for             : LINUX
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      date            : 1999/1/7
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      version         : 5.1
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h>
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
29037182346f0991683cc7320a257c3f6089432ceeJiri Slaby#include <linux/firmware.h>
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/signal.h>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sched.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/timer.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_flip.h>
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/major.h>
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fcntl.h>
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ptrace.h>
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/serial.h>
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_driver.h>
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h>
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/bitops.h>
465a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
475a3c6b251d587715f8b87a50216e4c085c655777Manuel Zerpies#include <linux/ratelimit.h>
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h>
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
52037182346f0991683cc7320a257c3f6089432ceeJiri Slaby#include "moxa.h"
53037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
54b9705b603d1d29471aa2977e6310f4f9a4e85925Jiri Slaby#define MOXA_VERSION		"6.0k"
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
56037182346f0991683cc7320a257c3f6089432ceeJiri Slaby#define MOXA_FW_HDRLEN		32
57037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
5811324edd4ad34981764b25bed44d46a1507b62e1Jiri Slaby#define MOXAMAJOR		172
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6011324edd4ad34981764b25bed44d46a1507b62e1Jiri Slaby#define MAX_BOARDS		4	/* Don't change this value */
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MAX_PORTS_PER_BOARD	32	/* Don't change this value */
6211324edd4ad34981764b25bed44d46a1507b62e1Jiri Slaby#define MAX_PORTS		(MAX_BOARDS * MAX_PORTS_PER_BOARD)
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6408d01c792568ba07d2bcf5202dbc8484dbff6747Jiri Slaby#define MOXA_IS_320(brd) ((brd)->boardType == MOXA_BOARD_C320_ISA || \
6508d01c792568ba07d2bcf5202dbc8484dbff6747Jiri Slaby		(brd)->boardType == MOXA_BOARD_C320_PCI)
6608d01c792568ba07d2bcf5202dbc8484dbff6747Jiri Slaby
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Define the Moxa PCI vendor and device IDs.
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
7011324edd4ad34981764b25bed44d46a1507b62e1Jiri Slaby#define MOXA_BUS_TYPE_ISA	0
7111324edd4ad34981764b25bed44d46a1507b62e1Jiri Slaby#define MOXA_BUS_TYPE_PCI	1
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum {
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MOXA_BOARD_C218_PCI = 1,
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MOXA_BOARD_C218_ISA,
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MOXA_BOARD_C320_PCI,
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MOXA_BOARD_C320_ISA,
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MOXA_BOARD_CP204J,
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char *moxa_brdname[] =
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"C218 Turbo PCI series",
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"C218 Turbo ISA series",
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"C320 Turbo PCI series",
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"C320 Turbo ISA series",
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"CP-204J series",
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PCI
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pci_device_id moxa_pcibrds[] = {
925ebb4078af0dab866fdf57f84f72b9e9a7e8c6b8Jiri Slaby	{ PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C218),
935ebb4078af0dab866fdf57f84f72b9e9a7e8c6b8Jiri Slaby		.driver_data = MOXA_BOARD_C218_PCI },
945ebb4078af0dab866fdf57f84f72b9e9a7e8c6b8Jiri Slaby	{ PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C320),
955ebb4078af0dab866fdf57f84f72b9e9a7e8c6b8Jiri Slaby		.driver_data = MOXA_BOARD_C320_PCI },
965ebb4078af0dab866fdf57f84f72b9e9a7e8c6b8Jiri Slaby	{ PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP204J),
975ebb4078af0dab866fdf57f84f72b9e9a7e8c6b8Jiri Slaby		.driver_data = MOXA_BOARD_CP204J },
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0 }
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DEVICE_TABLE(pci, moxa_pcibrds);
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_PCI */
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
103037182346f0991683cc7320a257c3f6089432ceeJiri Slabystruct moxa_port;
104037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
1058f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slabystatic struct moxa_board_conf {
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int boardType;
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int numPorts;
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int busType;
1098f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby
110810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	unsigned int ready;
1118f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby
112037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	struct moxa_port *ports;
113037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
1148f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	void __iomem *basemem;
1158f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	void __iomem *intNdx;
1168f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	void __iomem *intPend;
1178f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	void __iomem *intTable;
1188f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby} moxa_boards[MAX_BOARDS];
1198f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby
1208f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slabystruct mxser_mstatus {
1218f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	tcflag_t cflag;
1228f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	int cts;
1238f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	int dsr;
1248f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	int ri;
1258f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	int dcd;
1269dff89cd82af7bccc706fed288b1c33a51c3b937Jiri Slaby};
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1288f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slabystruct moxaq_str {
1298f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	int inq;
1308f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	int outq;
1318f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby};
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1338f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slabystruct moxa_port {
1349de6a51fee08f9e7020074738150441305e83af2Alan Cox	struct tty_port port;
135b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	struct moxa_board_conf *board;
1367bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	void __iomem *tableAddr;
1377bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int type;
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cflag;
1407bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	unsigned long statusflags;
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1428482bcd58530ad5857d7187854132f2b846db681Alan Cox	u8 DCDState;		/* Protected by the port lock */
1437bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	u8 lineCtrl;
1447bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	u8 lowChkFlag;
1458f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby};
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14774d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slabystruct mon_str {
14874d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	int tick;
14974d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	int rxcnt[MAX_PORTS];
15074d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	int txcnt[MAX_PORTS];
15174d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby};
15274d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* statusflags */
154a808ac0c4a2c5d81ba38a2a76d4ddc1de40d1539Alan Cox#define TXSTOPPED	1
155a808ac0c4a2c5d81ba38a2a76d4ddc1de40d1539Alan Cox#define LOWWAIT 	2
156a808ac0c4a2c5d81ba38a2a76d4ddc1de40d1539Alan Cox#define EMPTYWAIT	3
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SERIAL_DO_RESTART
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define WAKEUP_CHARS		256
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ttymajor = MOXAMAJOR;
16374d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slabystatic struct mon_str moxaLog;
16474d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slabystatic unsigned int moxaFuncTout = HZ / 2;
1657bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slabystatic unsigned int moxaLowWaterChk;
166a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slabystatic DEFINE_MUTEX(moxa_openlock);
167e8c62103fd5fecc8d2086bae244b32d089892175Alan Coxstatic DEFINE_SPINLOCK(moxa_lock);
168c6fc826e4c51d2c54913c2a6d800159a2c7dac4bRakib Mullick
169d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slabystatic unsigned long baseaddr[MAX_BOARDS];
170d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slabystatic unsigned int type[MAX_BOARDS];
171d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slabystatic unsigned int numports[MAX_BOARDS];
172793be8984fb979ae8887609862842cbb1f60bfafJiri Slabystatic struct tty_port moxa_service_port;
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("William Chen");
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("MOXA Intellio Family Multiport Board Device Driver");
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
177e6c4ef984ebbd1a0458503417da91f3de47cbbe0Ben HutchingsMODULE_FIRMWARE("c218tunx.cod");
178e6c4ef984ebbd1a0458503417da91f3de47cbbe0Ben HutchingsMODULE_FIRMWARE("cp204unx.cod");
179e6c4ef984ebbd1a0458503417da91f3de47cbbe0Ben HutchingsMODULE_FIRMWARE("c320tunx.cod");
180c6fc826e4c51d2c54913c2a6d800159a2c7dac4bRakib Mullick
181d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slabymodule_param_array(type, uint, NULL, 0);
182d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri SlabyMODULE_PARM_DESC(type, "card type: C218=2, C320=4");
183d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slabymodule_param_array(baseaddr, ulong, NULL, 0);
184d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri SlabyMODULE_PARM_DESC(baseaddr, "base address");
185d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slabymodule_param_array(numports, uint, NULL, 0);
186d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri SlabyMODULE_PARM_DESC(numports, "numports (ignored for C218)");
187c6fc826e4c51d2c54913c2a6d800159a2c7dac4bRakib Mullick
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(ttymajor, int, 0);
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * static functions:
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int moxa_open(struct tty_struct *, struct file *);
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_close(struct tty_struct *, struct file *);
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int moxa_write(struct tty_struct *, const unsigned char *, int);
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int moxa_write_room(struct tty_struct *);
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_flush_buffer(struct tty_struct *);
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int moxa_chars_in_buffer(struct tty_struct *);
199606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Coxstatic void moxa_set_termios(struct tty_struct *, struct ktermios *);
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_stop(struct tty_struct *);
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_start(struct tty_struct *);
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_hangup(struct tty_struct *);
20360b33c133ca0b7c0b6072c87234b63fee6e80558Alan Coxstatic int moxa_tiocmget(struct tty_struct *tty);
20420b9d17715017ae4dd4ec87fabc36d33b9de708eAlan Coxstatic int moxa_tiocmset(struct tty_struct *tty,
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 unsigned int set, unsigned int clear);
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_poll(unsigned long);
207db1acaa632870ec87b65e062bc72ca375837a1f6Alan Coxstatic void moxa_set_tty_param(struct tty_struct *, struct ktermios *);
208f176178ba09d27cc33988435e2c9fe078b44998cAlan Coxstatic void moxa_shutdown(struct tty_port *);
20931f35939d1d9bcfb3099b32c67b896d2792603f9Alan Coxstatic int moxa_carrier_raised(struct tty_port *);
210f176178ba09d27cc33988435e2c9fe078b44998cAlan Coxstatic void moxa_dtr_rts(struct tty_port *, int);
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * moxa board interface functions:
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
214b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic void MoxaPortEnable(struct moxa_port *);
215b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic void MoxaPortDisable(struct moxa_port *);
216b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic int MoxaPortSetTermio(struct moxa_port *, struct ktermios *, speed_t);
217b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic int MoxaPortGetLineOut(struct moxa_port *, int *, int *);
218b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic void MoxaPortLineCtrl(struct moxa_port *, int, int);
219b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic void MoxaPortFlowCtrl(struct moxa_port *, int, int, int, int, int);
220b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic int MoxaPortLineStatus(struct moxa_port *);
221b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic void MoxaPortFlushData(struct moxa_port *, int);
222d450b5a0196b6442cf3f29fc611d9c8daa56b559Alan Coxstatic int MoxaPortWriteData(struct tty_struct *, const unsigned char *, int);
2237bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slabystatic int MoxaPortReadData(struct moxa_port *);
224b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic int MoxaPortTxQueue(struct moxa_port *);
225b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic int MoxaPortRxQueue(struct moxa_port *);
226b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic int MoxaPortTxFree(struct moxa_port *);
227b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic void MoxaPortTxDisable(struct moxa_port *);
228b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic void MoxaPortTxEnable(struct moxa_port *);
2298f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slabystatic int moxa_get_serial_info(struct moxa_port *, struct serial_struct __user *);
2308f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slabystatic int moxa_set_serial_info(struct moxa_port *, struct serial_struct __user *);
231b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic void MoxaSetFifo(struct moxa_port *port, int enable);
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23374d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby/*
23474d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby * I/O functions
23574d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby */
23674d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby
237a808ac0c4a2c5d81ba38a2a76d4ddc1de40d1539Alan Coxstatic DEFINE_SPINLOCK(moxafunc_lock);
238a808ac0c4a2c5d81ba38a2a76d4ddc1de40d1539Alan Cox
23974d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slabystatic void moxa_wait_finish(void __iomem *ofsAddr)
24074d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby{
24174d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	unsigned long end = jiffies + moxaFuncTout;
24274d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby
24374d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	while (readw(ofsAddr + FuncCode) != 0)
24474d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		if (time_after(jiffies, end))
24574d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby			return;
2465a3c6b251d587715f8b87a50216e4c085c655777Manuel Zerpies	if (readw(ofsAddr + FuncCode) != 0)
2475a3c6b251d587715f8b87a50216e4c085c655777Manuel Zerpies		printk_ratelimited(KERN_WARNING "moxa function expired\n");
24874d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby}
24974d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby
250eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slabystatic void moxafunc(void __iomem *ofsAddr, u16 cmd, u16 arg)
25174d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby{
252f5c5a36d27ae6d9e03c2f1b7890942bf84e92c5bAlan Cox        unsigned long flags;
253f5c5a36d27ae6d9e03c2f1b7890942bf84e92c5bAlan Cox        spin_lock_irqsave(&moxafunc_lock, flags);
25474d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	writew(arg, ofsAddr + FuncArg);
25574d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	writew(cmd, ofsAddr + FuncCode);
25674d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	moxa_wait_finish(ofsAddr);
257f5c5a36d27ae6d9e03c2f1b7890942bf84e92c5bAlan Cox	spin_unlock_irqrestore(&moxafunc_lock, flags);
258f5c5a36d27ae6d9e03c2f1b7890942bf84e92c5bAlan Cox}
259f5c5a36d27ae6d9e03c2f1b7890942bf84e92c5bAlan Cox
260f5c5a36d27ae6d9e03c2f1b7890942bf84e92c5bAlan Coxstatic int moxafuncret(void __iomem *ofsAddr, u16 cmd, u16 arg)
261f5c5a36d27ae6d9e03c2f1b7890942bf84e92c5bAlan Cox{
262f5c5a36d27ae6d9e03c2f1b7890942bf84e92c5bAlan Cox        unsigned long flags;
263f5c5a36d27ae6d9e03c2f1b7890942bf84e92c5bAlan Cox        u16 ret;
264f5c5a36d27ae6d9e03c2f1b7890942bf84e92c5bAlan Cox        spin_lock_irqsave(&moxafunc_lock, flags);
265f5c5a36d27ae6d9e03c2f1b7890942bf84e92c5bAlan Cox	writew(arg, ofsAddr + FuncArg);
266f5c5a36d27ae6d9e03c2f1b7890942bf84e92c5bAlan Cox	writew(cmd, ofsAddr + FuncCode);
267f5c5a36d27ae6d9e03c2f1b7890942bf84e92c5bAlan Cox	moxa_wait_finish(ofsAddr);
268f5c5a36d27ae6d9e03c2f1b7890942bf84e92c5bAlan Cox	ret = readw(ofsAddr + FuncArg);
269f5c5a36d27ae6d9e03c2f1b7890942bf84e92c5bAlan Cox	spin_unlock_irqrestore(&moxafunc_lock, flags);
270f5c5a36d27ae6d9e03c2f1b7890942bf84e92c5bAlan Cox	return ret;
27174d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby}
27274d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby
2737bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slabystatic void moxa_low_water_check(void __iomem *ofsAddr)
2747bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby{
2757bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	u16 rptr, wptr, mask, len;
2767bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby
2777bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	if (readb(ofsAddr + FlagStat) & Xoff_state) {
2787bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		rptr = readw(ofsAddr + RXrptr);
2797bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		wptr = readw(ofsAddr + RXwptr);
2807bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		mask = readw(ofsAddr + RX_mask);
2817bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		len = (wptr - rptr) & mask;
2827bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		if (len <= Low_water)
2837bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby			moxafunc(ofsAddr, FC_SendXon, 0);
2847bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	}
2857bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby}
2867bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby
28774d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby/*
28874d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby * TTY operations
28974d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby */
29074d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby
2916caa76b7786891b42b66a0e61e2c2fff2c884620Alan Coxstatic int moxa_ioctl(struct tty_struct *tty,
29274d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		      unsigned int cmd, unsigned long arg)
29374d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby{
29474d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	struct moxa_port *ch = tty->driver_data;
29574d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	void __user *argp = (void __user *)arg;
296a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	int status, ret = 0;
29774d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby
29874d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	if (tty->index == MAX_PORTS) {
29974d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		if (cmd != MOXA_GETDATACOUNT && cmd != MOXA_GET_IOQUEUE &&
30074d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby				cmd != MOXA_GETMSTATUS)
30174d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby			return -EINVAL;
30274d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	} else if (!ch)
30374d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		return -ENODEV;
30474d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby
30574d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	switch (cmd) {
30674d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	case MOXA_GETDATACOUNT:
30774d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		moxaLog.tick = jiffies;
308a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		if (copy_to_user(argp, &moxaLog, sizeof(moxaLog)))
309a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby			ret = -EFAULT;
310a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		break;
31174d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	case MOXA_FLUSH_QUEUE:
31274d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		MoxaPortFlushData(ch, arg);
313a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		break;
31474d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	case MOXA_GET_IOQUEUE: {
31574d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		struct moxaq_str __user *argm = argp;
31674d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		struct moxaq_str tmp;
31774d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		struct moxa_port *p;
31874d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		unsigned int i, j;
31974d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby
32074d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		for (i = 0; i < MAX_BOARDS; i++) {
32174d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby			p = moxa_boards[i].ports;
32274d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby			for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
32374d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby				memset(&tmp, 0, sizeof(tmp));
324e8c62103fd5fecc8d2086bae244b32d089892175Alan Cox				spin_lock_bh(&moxa_lock);
32574d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby				if (moxa_boards[i].ready) {
32674d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby					tmp.inq = MoxaPortRxQueue(p);
32774d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby					tmp.outq = MoxaPortTxQueue(p);
32874d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby				}
329e8c62103fd5fecc8d2086bae244b32d089892175Alan Cox				spin_unlock_bh(&moxa_lock);
330e8c62103fd5fecc8d2086bae244b32d089892175Alan Cox				if (copy_to_user(argm, &tmp, sizeof(tmp)))
33174d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby					return -EFAULT;
33274d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby			}
33374d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		}
334a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		break;
33574d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	} case MOXA_GET_OQUEUE:
33674d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		status = MoxaPortTxQueue(ch);
337a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		ret = put_user(status, (unsigned long __user *)argp);
338a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		break;
33974d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	case MOXA_GET_IQUEUE:
34074d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		status = MoxaPortRxQueue(ch);
341a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		ret = put_user(status, (unsigned long __user *)argp);
342a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		break;
34374d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	case MOXA_GETMSTATUS: {
34474d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		struct mxser_mstatus __user *argm = argp;
34574d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		struct mxser_mstatus tmp;
34674d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		struct moxa_port *p;
34774d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		unsigned int i, j;
34874d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby
34974d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		for (i = 0; i < MAX_BOARDS; i++) {
35074d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby			p = moxa_boards[i].ports;
35174d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby			for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
352d450b5a0196b6442cf3f29fc611d9c8daa56b559Alan Cox				struct tty_struct *ttyp;
35374d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby				memset(&tmp, 0, sizeof(tmp));
354e8c62103fd5fecc8d2086bae244b32d089892175Alan Cox				spin_lock_bh(&moxa_lock);
355e8c62103fd5fecc8d2086bae244b32d089892175Alan Cox				if (!moxa_boards[i].ready) {
356e8c62103fd5fecc8d2086bae244b32d089892175Alan Cox				        spin_unlock_bh(&moxa_lock);
35774d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby					goto copy;
358e8c62103fd5fecc8d2086bae244b32d089892175Alan Cox                                }
35974d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby
36074d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby				status = MoxaPortLineStatus(p);
361e8c62103fd5fecc8d2086bae244b32d089892175Alan Cox				spin_unlock_bh(&moxa_lock);
362e8c62103fd5fecc8d2086bae244b32d089892175Alan Cox
36374d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby				if (status & 1)
36474d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby					tmp.cts = 1;
36574d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby				if (status & 2)
36674d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby					tmp.dsr = 1;
36774d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby				if (status & 4)
36874d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby					tmp.dcd = 1;
36974d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby
370d450b5a0196b6442cf3f29fc611d9c8daa56b559Alan Cox				ttyp = tty_port_tty_get(&p->port);
371adc8d746caa67fff4b53ba3e5163a6cbacc3b523Alan Cox				if (!ttyp)
37274d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby					tmp.cflag = p->cflag;
37374d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby				else
374adc8d746caa67fff4b53ba3e5163a6cbacc3b523Alan Cox					tmp.cflag = ttyp->termios.c_cflag;
375df43daaae926c3710eda911ec048808c904572feJulia Lawall				tty_kref_put(ttyp);
37674d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slabycopy:
377e8c62103fd5fecc8d2086bae244b32d089892175Alan Cox				if (copy_to_user(argm, &tmp, sizeof(tmp)))
37874d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby					return -EFAULT;
37974d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby			}
38074d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		}
381a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		break;
38274d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	}
38374d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	case TIOCGSERIAL:
384a808ac0c4a2c5d81ba38a2a76d4ddc1de40d1539Alan Cox	        mutex_lock(&ch->port.mutex);
385a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		ret = moxa_get_serial_info(ch, argp);
386a808ac0c4a2c5d81ba38a2a76d4ddc1de40d1539Alan Cox		mutex_unlock(&ch->port.mutex);
387a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		break;
38874d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	case TIOCSSERIAL:
389a808ac0c4a2c5d81ba38a2a76d4ddc1de40d1539Alan Cox	        mutex_lock(&ch->port.mutex);
390a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		ret = moxa_set_serial_info(ch, argp);
391a808ac0c4a2c5d81ba38a2a76d4ddc1de40d1539Alan Cox		mutex_unlock(&ch->port.mutex);
392a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		break;
393a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	default:
394a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		ret = -ENOIOCTLCMD;
39574d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	}
396a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	return ret;
39774d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby}
39874d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby
3999e98966c7bb94355689478bc84cc3e0c190f977eAlan Coxstatic int moxa_break_ctl(struct tty_struct *tty, int state)
40074d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby{
40174d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	struct moxa_port *port = tty->driver_data;
40274d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby
40374d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	moxafunc(port->tableAddr, state ? FC_SendBreak : FC_StopBreak,
40474d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby			Magic_code);
4059e98966c7bb94355689478bc84cc3e0c190f977eAlan Cox	return 0;
40674d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby}
40774d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby
408b68e31d0ebbcc909d1941f9f230c9d062a3a13d3Jeff Dikestatic const struct tty_operations moxa_ops = {
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.open = moxa_open,
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.close = moxa_close,
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.write = moxa_write,
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.write_room = moxa_write_room,
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.flush_buffer = moxa_flush_buffer,
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.chars_in_buffer = moxa_chars_in_buffer,
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.ioctl = moxa_ioctl,
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_termios = moxa_set_termios,
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.stop = moxa_stop,
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.start = moxa_start,
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.hangup = moxa_hangup,
42074d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	.break_ctl = moxa_break_ctl,
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.tiocmget = moxa_tiocmget,
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.tiocmset = moxa_tiocmset,
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42531f35939d1d9bcfb3099b32c67b896d2792603f9Alan Coxstatic const struct tty_port_operations moxa_port_ops = {
42631f35939d1d9bcfb3099b32c67b896d2792603f9Alan Cox	.carrier_raised = moxa_carrier_raised,
427f176178ba09d27cc33988435e2c9fe078b44998cAlan Cox	.dtr_rts = moxa_dtr_rts,
428f176178ba09d27cc33988435e2c9fe078b44998cAlan Cox	.shutdown = moxa_shutdown,
42931f35939d1d9bcfb3099b32c67b896d2792603f9Alan Cox};
43031f35939d1d9bcfb3099b32c67b896d2792603f9Alan Cox
431aa7e5221fb47badbea618cc62704d6e4a4bcce15Jiri Slabystatic struct tty_driver *moxaDriver;
432aa7e5221fb47badbea618cc62704d6e4a4bcce15Jiri Slabystatic DEFINE_TIMER(moxaTimer, moxa_poll, 0, 0);
43333f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox
43474d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby/*
43574d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby * HW init
43674d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby */
43774d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby
438037182346f0991683cc7320a257c3f6089432ceeJiri Slabystatic int moxa_check_fw_model(struct moxa_board_conf *brd, u8 model)
439037182346f0991683cc7320a257c3f6089432ceeJiri Slaby{
440037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	switch (brd->boardType) {
441037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	case MOXA_BOARD_C218_ISA:
442037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	case MOXA_BOARD_C218_PCI:
443037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		if (model != 1)
444037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			goto err;
445037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		break;
446037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	case MOXA_BOARD_CP204J:
447037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		if (model != 3)
448037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			goto err;
449037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		break;
450037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	default:
451037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		if (model != 2)
452037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			goto err;
453037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		break;
454037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
455037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	return 0;
456037182346f0991683cc7320a257c3f6089432ceeJiri Slabyerr:
457037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	return -EINVAL;
458037182346f0991683cc7320a257c3f6089432ceeJiri Slaby}
459037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
460037182346f0991683cc7320a257c3f6089432ceeJiri Slabystatic int moxa_check_fw(const void *ptr)
461037182346f0991683cc7320a257c3f6089432ceeJiri Slaby{
462037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	const __le16 *lptr = ptr;
463037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
464037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (*lptr != cpu_to_le16(0x7980))
465037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		return -EINVAL;
466037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
467037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	return 0;
468037182346f0991683cc7320a257c3f6089432ceeJiri Slaby}
469037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
470037182346f0991683cc7320a257c3f6089432ceeJiri Slabystatic int moxa_load_bios(struct moxa_board_conf *brd, const u8 *buf,
471037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		size_t len)
472037182346f0991683cc7320a257c3f6089432ceeJiri Slaby{
473037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	void __iomem *baseAddr = brd->basemem;
474037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	u16 tmp;
475037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
476037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	writeb(HW_reset, baseAddr + Control_reg);	/* reset */
477037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	msleep(10);
478037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	memset_io(baseAddr, 0, 4096);
479037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	memcpy_toio(baseAddr, buf, len);	/* download BIOS */
480037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	writeb(0, baseAddr + Control_reg);	/* restart */
481037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
482037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	msleep(2000);
483037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
484037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	switch (brd->boardType) {
485037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	case MOXA_BOARD_C218_ISA:
486037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	case MOXA_BOARD_C218_PCI:
487037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		tmp = readw(baseAddr + C218_key);
488037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		if (tmp != C218_KeyCode)
489037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			goto err;
490037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		break;
491037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	case MOXA_BOARD_CP204J:
492037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		tmp = readw(baseAddr + C218_key);
493037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		if (tmp != CP204J_KeyCode)
494037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			goto err;
495037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		break;
496037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	default:
497037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		tmp = readw(baseAddr + C320_key);
498037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		if (tmp != C320_KeyCode)
499037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			goto err;
500037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		tmp = readw(baseAddr + C320_status);
501037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		if (tmp != STS_init) {
502eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby			printk(KERN_ERR "MOXA: bios upload failed -- CPU/Basic "
503037182346f0991683cc7320a257c3f6089432ceeJiri Slaby					"module not found\n");
504037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			return -EIO;
505037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		}
506037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		break;
507037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
508037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
509037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	return 0;
510037182346f0991683cc7320a257c3f6089432ceeJiri Slabyerr:
511eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby	printk(KERN_ERR "MOXA: bios upload failed -- board not found\n");
512037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	return -EIO;
513037182346f0991683cc7320a257c3f6089432ceeJiri Slaby}
514037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
515037182346f0991683cc7320a257c3f6089432ceeJiri Slabystatic int moxa_load_320b(struct moxa_board_conf *brd, const u8 *ptr,
516037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		size_t len)
517037182346f0991683cc7320a257c3f6089432ceeJiri Slaby{
518037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	void __iomem *baseAddr = brd->basemem;
519037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
520037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (len < 7168) {
521eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby		printk(KERN_ERR "MOXA: invalid 320 bios -- too short\n");
522037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		return -EINVAL;
523037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
524037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
525037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	writew(len - 7168 - 2, baseAddr + C320bapi_len);
526037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	writeb(1, baseAddr + Control_reg);	/* Select Page 1 */
527037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	memcpy_toio(baseAddr + DynPage_addr, ptr, 7168);
528037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	writeb(2, baseAddr + Control_reg);	/* Select Page 2 */
529037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	memcpy_toio(baseAddr + DynPage_addr, ptr + 7168, len - 7168);
530037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
531037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	return 0;
532037182346f0991683cc7320a257c3f6089432ceeJiri Slaby}
533037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
5345292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slabystatic int moxa_real_load_code(struct moxa_board_conf *brd, const void *ptr,
535037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		size_t len)
536037182346f0991683cc7320a257c3f6089432ceeJiri Slaby{
537037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	void __iomem *baseAddr = brd->basemem;
538b46f69cd24b9020433f8f153e7d9194b5bfdf5e2Harvey Harrison	const __le16 *uptr = ptr;
539037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	size_t wlen, len2, j;
5405292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby	unsigned long key, loadbuf, loadlen, checksum, checksum_ok;
54108d01c792568ba07d2bcf5202dbc8484dbff6747Jiri Slaby	unsigned int i, retry;
542037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	u16 usum, keycode;
543037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
5445292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby	keycode = (brd->boardType == MOXA_BOARD_CP204J) ? CP204J_KeyCode :
5455292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby				C218_KeyCode;
546037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
5475292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby	switch (brd->boardType) {
5485292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby	case MOXA_BOARD_CP204J:
5495292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby	case MOXA_BOARD_C218_ISA:
5505292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby	case MOXA_BOARD_C218_PCI:
5515292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		key = C218_key;
5525292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		loadbuf = C218_LoadBuf;
5535292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		loadlen = C218DLoad_len;
5545292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		checksum = C218check_sum;
5555292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		checksum_ok = C218chksum_ok;
5565292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		break;
5575292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby	default:
5585292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		key = C320_key;
5595292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		keycode = C320_KeyCode;
5605292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		loadbuf = C320_LoadBuf;
5615292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		loadlen = C320DLoad_len;
5625292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		checksum = C320check_sum;
5635292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		checksum_ok = C320chksum_ok;
5645292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		break;
565037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
566037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
567037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	usum = 0;
568037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	wlen = len >> 1;
569037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	for (i = 0; i < wlen; i++)
570037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		usum += le16_to_cpu(uptr[i]);
571037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	retry = 0;
572037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	do {
573037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		wlen = len >> 1;
574037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		j = 0;
575037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		while (wlen) {
576037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			len2 = (wlen > 2048) ? 2048 : wlen;
577037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			wlen -= len2;
5785292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby			memcpy_toio(baseAddr + loadbuf, ptr + j, len2 << 1);
579037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			j += len2 << 1;
5805292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby
5815292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby			writew(len2, baseAddr + loadlen);
5825292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby			writew(0, baseAddr + key);
5835292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby			for (i = 0; i < 100; i++) {
5845292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby				if (readw(baseAddr + key) == keycode)
585037182346f0991683cc7320a257c3f6089432ceeJiri Slaby					break;
586037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				msleep(10);
587037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			}
5885292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby			if (readw(baseAddr + key) != keycode)
589037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				return -EIO;
590037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		}
5915292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		writew(0, baseAddr + loadlen);
5925292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		writew(usum, baseAddr + checksum);
5935292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		writew(0, baseAddr + key);
5945292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		for (i = 0; i < 100; i++) {
5955292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby			if (readw(baseAddr + key) == keycode)
596037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				break;
597037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			msleep(10);
598037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		}
599037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		retry++;
6005292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby	} while ((readb(baseAddr + checksum_ok) != 1) && (retry < 3));
6015292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby	if (readb(baseAddr + checksum_ok) != 1)
602037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		return -EIO;
603037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
6045292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby	writew(0, baseAddr + key);
605037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	for (i = 0; i < 600; i++) {
606037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		if (readw(baseAddr + Magic_no) == Magic_code)
607037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			break;
608037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		msleep(10);
609037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
610037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (readw(baseAddr + Magic_no) != Magic_code)
611037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		return -EIO;
612037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
61308d01c792568ba07d2bcf5202dbc8484dbff6747Jiri Slaby	if (MOXA_IS_320(brd)) {
6145292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		if (brd->busType == MOXA_BUS_TYPE_PCI) {	/* ASIC board */
6155292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby			writew(0x3800, baseAddr + TMS320_PORT1);
6165292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby			writew(0x3900, baseAddr + TMS320_PORT2);
6175292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby			writew(28499, baseAddr + TMS320_CLOCK);
6185292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		} else {
6195292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby			writew(0x3200, baseAddr + TMS320_PORT1);
6205292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby			writew(0x3400, baseAddr + TMS320_PORT2);
6215292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby			writew(19999, baseAddr + TMS320_CLOCK);
6225292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		}
623037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
624037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	writew(1, baseAddr + Disable_IRQ);
625037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	writew(0, baseAddr + Magic_no);
626037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	for (i = 0; i < 500; i++) {
627037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		if (readw(baseAddr + Magic_no) == Magic_code)
628037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			break;
629037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		msleep(10);
630037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
631037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (readw(baseAddr + Magic_no) != Magic_code)
632037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		return -EIO;
633037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
63408d01c792568ba07d2bcf5202dbc8484dbff6747Jiri Slaby	if (MOXA_IS_320(brd)) {
6355292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		j = readw(baseAddr + Module_cnt);
6365292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		if (j <= 0)
6375292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby			return -EIO;
6385292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		brd->numPorts = j * 8;
6395292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		writew(j, baseAddr + Module_no);
6405292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		writew(0, baseAddr + Magic_no);
6415292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		for (i = 0; i < 600; i++) {
6425292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby			if (readw(baseAddr + Magic_no) == Magic_code)
6435292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby				break;
6445292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby			msleep(10);
6455292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		}
6465292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		if (readw(baseAddr + Magic_no) != Magic_code)
6475292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby			return -EIO;
648037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
649037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	brd->intNdx = baseAddr + IRQindex;
650037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	brd->intPend = baseAddr + IRQpending;
651037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	brd->intTable = baseAddr + IRQtable;
652037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
653037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	return 0;
654037182346f0991683cc7320a257c3f6089432ceeJiri Slaby}
655037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
656037182346f0991683cc7320a257c3f6089432ceeJiri Slabystatic int moxa_load_code(struct moxa_board_conf *brd, const void *ptr,
657037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		size_t len)
658037182346f0991683cc7320a257c3f6089432ceeJiri Slaby{
659037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	void __iomem *ofsAddr, *baseAddr = brd->basemem;
660037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	struct moxa_port *port;
661037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	int retval, i;
662037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
663037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (len % 2) {
664eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby		printk(KERN_ERR "MOXA: bios length is not even\n");
665037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		return -EINVAL;
666037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
667037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
6685292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby	retval = moxa_real_load_code(brd, ptr, len); /* may change numPorts */
6695292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby	if (retval)
6705292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		return retval;
6715292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby
672037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	switch (brd->boardType) {
673037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	case MOXA_BOARD_C218_ISA:
674037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	case MOXA_BOARD_C218_PCI:
675037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	case MOXA_BOARD_CP204J:
676037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		port = brd->ports;
677037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		for (i = 0; i < brd->numPorts; i++, port++) {
678b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby			port->board = brd;
679037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			port->DCDState = 0;
680037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			port->tableAddr = baseAddr + Extern_table +
681037182346f0991683cc7320a257c3f6089432ceeJiri Slaby					Extern_size * i;
682037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			ofsAddr = port->tableAddr;
683037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			writew(C218rx_mask, ofsAddr + RX_mask);
684037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			writew(C218tx_mask, ofsAddr + TX_mask);
685037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			writew(C218rx_spage + i * C218buf_pageno, ofsAddr + Page_rxb);
686037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			writew(readw(ofsAddr + Page_rxb) + C218rx_pageno, ofsAddr + EndPage_rxb);
687037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
688037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			writew(C218tx_spage + i * C218buf_pageno, ofsAddr + Page_txb);
689037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			writew(readw(ofsAddr + Page_txb) + C218tx_pageno, ofsAddr + EndPage_txb);
690037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
691037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		}
692037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		break;
693037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	default:
694037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		port = brd->ports;
695037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		for (i = 0; i < brd->numPorts; i++, port++) {
696b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby			port->board = brd;
697037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			port->DCDState = 0;
698037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			port->tableAddr = baseAddr + Extern_table +
699037182346f0991683cc7320a257c3f6089432ceeJiri Slaby					Extern_size * i;
700037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			ofsAddr = port->tableAddr;
701037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			switch (brd->numPorts) {
702037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			case 8:
703037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p8rx_mask, ofsAddr + RX_mask);
704037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p8tx_mask, ofsAddr + TX_mask);
705037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p8rx_spage + i * C320p8buf_pgno, ofsAddr + Page_rxb);
706037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(readw(ofsAddr + Page_rxb) + C320p8rx_pgno, ofsAddr + EndPage_rxb);
707037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p8tx_spage + i * C320p8buf_pgno, ofsAddr + Page_txb);
708037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(readw(ofsAddr + Page_txb) + C320p8tx_pgno, ofsAddr + EndPage_txb);
709037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
710037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				break;
711037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			case 16:
712037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p16rx_mask, ofsAddr + RX_mask);
713037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p16tx_mask, ofsAddr + TX_mask);
714037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p16rx_spage + i * C320p16buf_pgno, ofsAddr + Page_rxb);
715037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(readw(ofsAddr + Page_rxb) + C320p16rx_pgno, ofsAddr + EndPage_rxb);
716037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p16tx_spage + i * C320p16buf_pgno, ofsAddr + Page_txb);
717037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(readw(ofsAddr + Page_txb) + C320p16tx_pgno, ofsAddr + EndPage_txb);
718037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				break;
719037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
720037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			case 24:
721037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p24rx_mask, ofsAddr + RX_mask);
722037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p24tx_mask, ofsAddr + TX_mask);
723037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p24rx_spage + i * C320p24buf_pgno, ofsAddr + Page_rxb);
724037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(readw(ofsAddr + Page_rxb) + C320p24rx_pgno, ofsAddr + EndPage_rxb);
725037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p24tx_spage + i * C320p24buf_pgno, ofsAddr + Page_txb);
726037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(readw(ofsAddr + Page_txb), ofsAddr + EndPage_txb);
727037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				break;
728037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			case 32:
729037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p32rx_mask, ofsAddr + RX_mask);
730037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p32tx_mask, ofsAddr + TX_mask);
731037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p32tx_ofs, ofsAddr + Ofs_txb);
732037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p32rx_spage + i * C320p32buf_pgno, ofsAddr + Page_rxb);
733037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(readb(ofsAddr + Page_rxb), ofsAddr + EndPage_rxb);
734037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p32tx_spage + i * C320p32buf_pgno, ofsAddr + Page_txb);
735037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(readw(ofsAddr + Page_txb), ofsAddr + EndPage_txb);
736037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				break;
737037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			}
738037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		}
739037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		break;
740037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
741037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	return 0;
742037182346f0991683cc7320a257c3f6089432ceeJiri Slaby}
743037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
744037182346f0991683cc7320a257c3f6089432ceeJiri Slabystatic int moxa_load_fw(struct moxa_board_conf *brd, const struct firmware *fw)
745037182346f0991683cc7320a257c3f6089432ceeJiri Slaby{
7462bca76e89bc43f86136080536858048ebffab3e3David Howells	const void *ptr = fw->data;
747037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	char rsn[64];
748037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	u16 lens[5];
749037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	size_t len;
750037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	unsigned int a, lenp, lencnt;
751037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	int ret = -EINVAL;
752037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	struct {
753037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		__le32 magic;	/* 0x34303430 */
754037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		u8 reserved1[2];
755037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		u8 type;	/* UNIX = 3 */
756037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		u8 model;	/* C218T=1, C320T=2, CP204=3 */
757037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		u8 reserved2[8];
758037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		__le16 len[5];
7592bca76e89bc43f86136080536858048ebffab3e3David Howells	} const *hdr = ptr;
760037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
761037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	BUILD_BUG_ON(ARRAY_SIZE(hdr->len) != ARRAY_SIZE(lens));
762037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
763037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (fw->size < MOXA_FW_HDRLEN) {
764037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		strcpy(rsn, "too short (even header won't fit)");
765037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		goto err;
766037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
767037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (hdr->magic != cpu_to_le32(0x30343034)) {
768037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		sprintf(rsn, "bad magic: %.8x", le32_to_cpu(hdr->magic));
769037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		goto err;
770037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
771037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (hdr->type != 3) {
772037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		sprintf(rsn, "not for linux, type is %u", hdr->type);
773037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		goto err;
774037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
775037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (moxa_check_fw_model(brd, hdr->model)) {
776037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		sprintf(rsn, "not for this card, model is %u", hdr->model);
777037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		goto err;
778037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
779037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
780037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	len = MOXA_FW_HDRLEN;
781037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	lencnt = hdr->model == 2 ? 5 : 3;
782037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	for (a = 0; a < ARRAY_SIZE(lens); a++) {
783037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		lens[a] = le16_to_cpu(hdr->len[a]);
784037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		if (lens[a] && len + lens[a] <= fw->size &&
785037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				moxa_check_fw(&fw->data[len]))
786eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby			printk(KERN_WARNING "MOXA firmware: unexpected input "
787037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				"at offset %u, but going on\n", (u32)len);
788037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		if (!lens[a] && a < lencnt) {
789037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			sprintf(rsn, "too few entries in fw file");
790037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			goto err;
791037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		}
792037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		len += lens[a];
793037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
794037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
795037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (len != fw->size) {
796037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		sprintf(rsn, "bad length: %u (should be %u)", (u32)fw->size,
797037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				(u32)len);
798037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		goto err;
799037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
800037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
801037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	ptr += MOXA_FW_HDRLEN;
802037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	lenp = 0; /* bios */
803037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
804037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	strcpy(rsn, "read above");
805037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
806037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	ret = moxa_load_bios(brd, ptr, lens[lenp]);
807037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (ret)
808037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		goto err;
809037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
810037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	/* we skip the tty section (lens[1]), since we don't need it */
811037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	ptr += lens[lenp] + lens[lenp + 1];
812037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	lenp += 2; /* comm */
813037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
814037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (hdr->model == 2) {
815037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		ret = moxa_load_320b(brd, ptr, lens[lenp]);
816037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		if (ret)
817037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			goto err;
818037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		/* skip another tty */
819037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		ptr += lens[lenp] + lens[lenp + 1];
820037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		lenp += 2;
821037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
822037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
823037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	ret = moxa_load_code(brd, ptr, lens[lenp]);
824037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (ret)
825037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		goto err;
826037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
827037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	return 0;
828037182346f0991683cc7320a257c3f6089432ceeJiri Slabyerr:
829037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	printk(KERN_ERR "firmware failed to load, reason: %s\n", rsn);
830037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	return ret;
831037182346f0991683cc7320a257c3f6089432ceeJiri Slaby}
832037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
833037182346f0991683cc7320a257c3f6089432ceeJiri Slabystatic int moxa_init_board(struct moxa_board_conf *brd, struct device *dev)
834037182346f0991683cc7320a257c3f6089432ceeJiri Slaby{
835037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	const struct firmware *fw;
836037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	const char *file;
837810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	struct moxa_port *p;
838793be8984fb979ae8887609862842cbb1f60bfafJiri Slaby	unsigned int i, first_idx;
839037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	int ret;
840037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
841810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	brd->ports = kcalloc(MAX_PORTS_PER_BOARD, sizeof(*brd->ports),
842810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby			GFP_KERNEL);
843810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	if (brd->ports == NULL) {
844810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby		printk(KERN_ERR "cannot allocate memory for ports\n");
845810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby		ret = -ENOMEM;
846810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby		goto err;
847810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	}
848810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby
849810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	for (i = 0, p = brd->ports; i < MAX_PORTS_PER_BOARD; i++, p++) {
85044b7d1b37f786c61d0e382b6f72f605f73de284bAlan Cox		tty_port_init(&p->port);
85131f35939d1d9bcfb3099b32c67b896d2792603f9Alan Cox		p->port.ops = &moxa_port_ops;
852810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby		p->type = PORT_16550A;
853810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby		p->cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
854810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	}
855810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby
856037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	switch (brd->boardType) {
857037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	case MOXA_BOARD_C218_ISA:
858037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	case MOXA_BOARD_C218_PCI:
859037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		file = "c218tunx.cod";
860037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		break;
861037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	case MOXA_BOARD_CP204J:
862037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		file = "cp204unx.cod";
863037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		break;
864037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	default:
865037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		file = "c320tunx.cod";
866037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		break;
867037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
868037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
869037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	ret = request_firmware(&fw, file, dev);
870037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (ret) {
871ec09cd562135158dcb8a6c08e5a9efa36febedb1Jiri Slaby		printk(KERN_ERR "MOXA: request_firmware failed. Make sure "
872ec09cd562135158dcb8a6c08e5a9efa36febedb1Jiri Slaby				"you've placed '%s' file into your firmware "
873ec09cd562135158dcb8a6c08e5a9efa36febedb1Jiri Slaby				"loader directory (e.g. /lib/firmware)\n",
874ec09cd562135158dcb8a6c08e5a9efa36febedb1Jiri Slaby				file);
875810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby		goto err_free;
876037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
877037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
878037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	ret = moxa_load_fw(brd, fw);
879037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
880037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	release_firmware(fw);
881810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby
882810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	if (ret)
883810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby		goto err_free;
884810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby
8852a5413416b6b2fd8a5a38601a4fe3b56a52cfb86Jiri Slaby	spin_lock_bh(&moxa_lock);
886810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	brd->ready = 1;
8870bcc4caadc8f5396b52950ee03c67b76875602dfJiri Slaby	if (!timer_pending(&moxaTimer))
8880bcc4caadc8f5396b52950ee03c67b76875602dfJiri Slaby		mod_timer(&moxaTimer, jiffies + HZ / 50);
8892a5413416b6b2fd8a5a38601a4fe3b56a52cfb86Jiri Slaby	spin_unlock_bh(&moxa_lock);
8900bcc4caadc8f5396b52950ee03c67b76875602dfJiri Slaby
891793be8984fb979ae8887609862842cbb1f60bfafJiri Slaby	first_idx = (brd - moxa_boards) * MAX_PORTS_PER_BOARD;
892793be8984fb979ae8887609862842cbb1f60bfafJiri Slaby	for (i = 0; i < brd->numPorts; i++)
893793be8984fb979ae8887609862842cbb1f60bfafJiri Slaby		tty_port_register_device(&brd->ports[i].port, moxaDriver,
894793be8984fb979ae8887609862842cbb1f60bfafJiri Slaby				first_idx + i, dev);
895793be8984fb979ae8887609862842cbb1f60bfafJiri Slaby
896810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	return 0;
897810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slabyerr_free:
898191c5f10275cfbb36802edadbdb10c73537327b4Jiri Slaby	for (i = 0; i < MAX_PORTS_PER_BOARD; i++)
899191c5f10275cfbb36802edadbdb10c73537327b4Jiri Slaby		tty_port_destroy(&brd->ports[i].port);
900810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	kfree(brd->ports);
901810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slabyerr:
902037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	return ret;
903037182346f0991683cc7320a257c3f6089432ceeJiri Slaby}
904037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
905810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slabystatic void moxa_board_deinit(struct moxa_board_conf *brd)
906810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby{
907793be8984fb979ae8887609862842cbb1f60bfafJiri Slaby	unsigned int a, opened, first_idx;
908a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby
909a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	mutex_lock(&moxa_openlock);
9107bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	spin_lock_bh(&moxa_lock);
911810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	brd->ready = 0;
9127bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	spin_unlock_bh(&moxa_lock);
913a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby
914a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	/* pci hot-un-plug support */
915a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	for (a = 0; a < brd->numPorts; a++)
916aa27a094e2c2e0cc59914e56113b860f524f4479Jiri Slaby		if (brd->ports[a].port.flags & ASYNC_INITIALIZED)
917aa27a094e2c2e0cc59914e56113b860f524f4479Jiri Slaby			tty_port_tty_hangup(&brd->ports[a].port, false);
918aa27a094e2c2e0cc59914e56113b860f524f4479Jiri Slaby
919191c5f10275cfbb36802edadbdb10c73537327b4Jiri Slaby	for (a = 0; a < MAX_PORTS_PER_BOARD; a++)
920191c5f10275cfbb36802edadbdb10c73537327b4Jiri Slaby		tty_port_destroy(&brd->ports[a].port);
921aa27a094e2c2e0cc59914e56113b860f524f4479Jiri Slaby
922a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	while (1) {
923a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		opened = 0;
924a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		for (a = 0; a < brd->numPorts; a++)
9259de6a51fee08f9e7020074738150441305e83af2Alan Cox			if (brd->ports[a].port.flags & ASYNC_INITIALIZED)
926a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby				opened++;
927a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		mutex_unlock(&moxa_openlock);
928a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		if (!opened)
929a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby			break;
930a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		msleep(50);
931a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		mutex_lock(&moxa_openlock);
932a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	}
933a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby
934793be8984fb979ae8887609862842cbb1f60bfafJiri Slaby	first_idx = (brd - moxa_boards) * MAX_PORTS_PER_BOARD;
935793be8984fb979ae8887609862842cbb1f60bfafJiri Slaby	for (a = 0; a < brd->numPorts; a++)
936793be8984fb979ae8887609862842cbb1f60bfafJiri Slaby		tty_unregister_device(moxaDriver, first_idx + a);
937793be8984fb979ae8887609862842cbb1f60bfafJiri Slaby
938810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	iounmap(brd->basemem);
939810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	brd->basemem = NULL;
940810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	kfree(brd->ports);
941810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby}
942810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PCI
9449671f09921d93e722a28ae9610d478e092ac5466Bill Pembertonstatic int moxa_pci_probe(struct pci_dev *pdev,
9459cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby		const struct pci_device_id *ent)
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9479cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby	struct moxa_board_conf *board;
9489cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby	unsigned int i;
9499cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby	int board_type = ent->driver_data;
9509cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby	int retval;
9519cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby
9529cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby	retval = pci_enable_device(pdev);
9537aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby	if (retval) {
9547aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby		dev_err(&pdev->dev, "can't enable pci device\n");
9559cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby		goto err;
9567aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby	}
9579cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby
9589cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby	for (i = 0; i < MAX_BOARDS; i++)
9599cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby		if (moxa_boards[i].basemem == NULL)
9609cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby			break;
9619cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby
9629cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby	retval = -ENODEV;
9639cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby	if (i >= MAX_BOARDS) {
9647aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby		dev_warn(&pdev->dev, "more than %u MOXA Intellio family boards "
9659cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby				"found. Board is ignored.\n", MAX_BOARDS);
9669cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby		goto err;
9679cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby	}
9689cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby
9699cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby	board = &moxa_boards[i];
970e46a5e3ff06b70690d567bdc81faf6c1c32e742fJiri Slaby
971e46a5e3ff06b70690d567bdc81faf6c1c32e742fJiri Slaby	retval = pci_request_region(pdev, 2, "moxa-base");
972e46a5e3ff06b70690d567bdc81faf6c1c32e742fJiri Slaby	if (retval) {
973e46a5e3ff06b70690d567bdc81faf6c1c32e742fJiri Slaby		dev_err(&pdev->dev, "can't request pci region 2\n");
974e46a5e3ff06b70690d567bdc81faf6c1c32e742fJiri Slaby		goto err;
975e46a5e3ff06b70690d567bdc81faf6c1c32e742fJiri Slaby	}
976e46a5e3ff06b70690d567bdc81faf6c1c32e742fJiri Slaby
97724cb233520f01971d6d873cb52c64bbbb0665ac0Alan Cox	board->basemem = ioremap_nocache(pci_resource_start(pdev, 2), 0x4000);
9787aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby	if (board->basemem == NULL) {
9797aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby		dev_err(&pdev->dev, "can't remap io space 2\n");
980386d95b3ad6f6dad61d0be379873dca66595c1e4Julia Lawall		retval = -ENOMEM;
981e46a5e3ff06b70690d567bdc81faf6c1c32e742fJiri Slaby		goto err_reg;
9827aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby	}
9839cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	board->boardType = board_type;
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (board_type) {
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case MOXA_BOARD_C218_ISA:
9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case MOXA_BOARD_C218_PCI:
9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		board->numPorts = 8;
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case MOXA_BOARD_CP204J:
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		board->numPorts = 4;
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		board->numPorts = 0;
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	board->busType = MOXA_BUS_TYPE_PCI;
999a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby
1000037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	retval = moxa_init_board(board, &pdev->dev);
1001037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (retval)
1002037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		goto err_base;
1003037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
10049cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby	pci_set_drvdata(pdev, board);
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1006bb9f910a1153101a2f92620f1e7d0fda786c9812Jiri Slaby	dev_info(&pdev->dev, "board '%s' ready (%u ports, firmware loaded)\n",
1007bb9f910a1153101a2f92620f1e7d0fda786c9812Jiri Slaby			moxa_brdname[board_type - 1], board->numPorts);
1008bb9f910a1153101a2f92620f1e7d0fda786c9812Jiri Slaby
1009eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby	return 0;
1010037182346f0991683cc7320a257c3f6089432ceeJiri Slabyerr_base:
1011037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	iounmap(board->basemem);
1012037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	board->basemem = NULL;
1013e46a5e3ff06b70690d567bdc81faf6c1c32e742fJiri Slabyerr_reg:
1014e46a5e3ff06b70690d567bdc81faf6c1c32e742fJiri Slaby	pci_release_region(pdev, 2);
10159cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slabyerr:
10169cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby	return retval;
10179cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby}
10189cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby
1019ae8d8a146725a966bd7c59c94f4d0016dcf7a04fBill Pembertonstatic void moxa_pci_remove(struct pci_dev *pdev)
10209cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby{
10219cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby	struct moxa_board_conf *brd = pci_get_drvdata(pdev);
10229cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby
1023810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	moxa_board_deinit(brd);
1024810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby
1025e46a5e3ff06b70690d567bdc81faf6c1c32e742fJiri Slaby	pci_release_region(pdev, 2);
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1027a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby
1028a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slabystatic struct pci_driver moxa_pci_driver = {
1029a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby	.name = "moxa",
1030a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby	.id_table = moxa_pcibrds,
1031a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby	.probe = moxa_pci_probe,
103291116cba5da0c33f3093b804e487bea02b830bfbBill Pemberton	.remove = moxa_pci_remove
1033a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby};
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_PCI */
10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init moxa_init(void)
10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1038810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	unsigned int isabrds = 0;
1039d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby	int retval = 0;
1040c6fc826e4c51d2c54913c2a6d800159a2c7dac4bRakib Mullick	struct moxa_board_conf *brd = moxa_boards;
1041c6fc826e4c51d2c54913c2a6d800159a2c7dac4bRakib Mullick	unsigned int i;
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10437aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby	printk(KERN_INFO "MOXA Intellio family driver version %s\n",
10447aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby			MOXA_VERSION);
1045793be8984fb979ae8887609862842cbb1f60bfafJiri Slaby
1046793be8984fb979ae8887609862842cbb1f60bfafJiri Slaby	tty_port_init(&moxa_service_port);
1047793be8984fb979ae8887609862842cbb1f60bfafJiri Slaby
1048793be8984fb979ae8887609862842cbb1f60bfafJiri Slaby	moxaDriver = tty_alloc_driver(MAX_PORTS + 1,
1049793be8984fb979ae8887609862842cbb1f60bfafJiri Slaby			TTY_DRIVER_REAL_RAW |
1050793be8984fb979ae8887609862842cbb1f60bfafJiri Slaby			TTY_DRIVER_DYNAMIC_DEV);
1051c3a6344ae475763b6fb0fb2ec3639004f500d0f1Dan Carpenter	if (IS_ERR(moxaDriver))
1052c3a6344ae475763b6fb0fb2ec3639004f500d0f1Dan Carpenter		return PTR_ERR(moxaDriver);
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10549b4e3b13b147e9b737de63188a9ae740eaa8c36dSergey Vlasov	moxaDriver->name = "ttyMX";
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxaDriver->major = ttymajor;
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxaDriver->minor_start = 0;
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxaDriver->type = TTY_DRIVER_TYPE_SERIAL;
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxaDriver->subtype = SERIAL_TYPE_NORMAL;
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxaDriver->init_termios = tty_std_termios;
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxaDriver->init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
1061606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox	moxaDriver->init_termios.c_ispeed = 9600;
1062606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox	moxaDriver->init_termios.c_ospeed = 9600;
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tty_set_operations(moxaDriver, &moxa_ops);
1064793be8984fb979ae8887609862842cbb1f60bfafJiri Slaby	/* Having one more port only for ioctls is ugly */
1065793be8984fb979ae8887609862842cbb1f60bfafJiri Slaby	tty_port_link_device(&moxa_service_port, moxaDriver, MAX_PORTS);
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tty_register_driver(moxaDriver)) {
1068eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby		printk(KERN_ERR "can't register MOXA Smartio tty driver!\n");
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		put_tty_driver(moxaDriver);
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1073d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby	/* Find the boards defined from module args. */
1074c6fc826e4c51d2c54913c2a6d800159a2c7dac4bRakib Mullick
10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < MAX_BOARDS; i++) {
1076d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby		if (!baseaddr[i])
1077d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby			break;
1078d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby		if (type[i] == MOXA_BOARD_C218_ISA ||
1079d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby				type[i] == MOXA_BOARD_C320_ISA) {
10807aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby			pr_debug("Moxa board %2d: %s board(baseAddr=%lx)\n",
1081d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby					isabrds + 1, moxa_brdname[type[i] - 1],
1082d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby					baseaddr[i]);
1083d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby			brd->boardType = type[i];
1084d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby			brd->numPorts = type[i] == MOXA_BOARD_C218_ISA ? 8 :
1085d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby					numports[i];
1086d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby			brd->busType = MOXA_BUS_TYPE_ISA;
108724cb233520f01971d6d873cb52c64bbbb0665ac0Alan Cox			brd->basemem = ioremap_nocache(baseaddr[i], 0x4000);
1088d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby			if (!brd->basemem) {
1089eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby				printk(KERN_ERR "MOXA: can't remap %lx\n",
1090d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby						baseaddr[i]);
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				continue;
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
1093037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			if (moxa_init_board(brd, NULL)) {
1094037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				iounmap(brd->basemem);
1095037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				brd->basemem = NULL;
1096037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				continue;
1097037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			}
1098d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby
1099e0525393baf07b1bb6e537ddbe7dfae3621649dfHans Wennborg			printk(KERN_INFO "MOXA isa board found at 0x%.8lx and "
1100bb9f910a1153101a2f92620f1e7d0fda786c9812Jiri Slaby					"ready (%u ports, firmware loaded)\n",
1101bb9f910a1153101a2f92620f1e7d0fda786c9812Jiri Slaby					baseaddr[i], brd->numPorts);
1102bb9f910a1153101a2f92620f1e7d0fda786c9812Jiri Slaby
1103d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby			brd++;
1104d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby			isabrds++;
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1107a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PCI
1109a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby	retval = pci_register_driver(&moxa_pci_driver);
1110a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby	if (retval) {
1111eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby		printk(KERN_ERR "Can't register MOXA pci driver!\n");
1112d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby		if (isabrds)
1113a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby			retval = 0;
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1116a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby
1117a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby	return retval;
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit moxa_exit(void)
11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1122eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby	unsigned int i;
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11249cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby#ifdef CONFIG_PCI
1125a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby	pci_unregister_driver(&moxa_pci_driver);
11269cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby#endif
1127a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby
1128810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	for (i = 0; i < MAX_BOARDS; i++) /* ISA boards */
1129810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby		if (moxa_boards[i].ready)
1130810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby			moxa_board_deinit(&moxa_boards[i]);
11312a5413416b6b2fd8a5a38601a4fe3b56a52cfb86Jiri Slaby
11322a5413416b6b2fd8a5a38601a4fe3b56a52cfb86Jiri Slaby	del_timer_sync(&moxaTimer);
11332a5413416b6b2fd8a5a38601a4fe3b56a52cfb86Jiri Slaby
11342a5413416b6b2fd8a5a38601a4fe3b56a52cfb86Jiri Slaby	if (tty_unregister_driver(moxaDriver))
11352a5413416b6b2fd8a5a38601a4fe3b56a52cfb86Jiri Slaby		printk(KERN_ERR "Couldn't unregister MOXA Intellio family "
11362a5413416b6b2fd8a5a38601a4fe3b56a52cfb86Jiri Slaby				"serial driver\n");
11372a5413416b6b2fd8a5a38601a4fe3b56a52cfb86Jiri Slaby	put_tty_driver(moxaDriver);
11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(moxa_init);
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(moxa_exit);
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1143f176178ba09d27cc33988435e2c9fe078b44998cAlan Coxstatic void moxa_shutdown(struct tty_port *port)
1144a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby{
1145f176178ba09d27cc33988435e2c9fe078b44998cAlan Cox	struct moxa_port *ch = container_of(port, struct moxa_port, port);
1146f176178ba09d27cc33988435e2c9fe078b44998cAlan Cox        MoxaPortDisable(ch);
1147a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	MoxaPortFlushData(ch, 2);
1148a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby}
1149a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby
115031f35939d1d9bcfb3099b32c67b896d2792603f9Alan Coxstatic int moxa_carrier_raised(struct tty_port *port)
115131f35939d1d9bcfb3099b32c67b896d2792603f9Alan Cox{
115231f35939d1d9bcfb3099b32c67b896d2792603f9Alan Cox	struct moxa_port *ch = container_of(port, struct moxa_port, port);
115331f35939d1d9bcfb3099b32c67b896d2792603f9Alan Cox	int dcd;
115431f35939d1d9bcfb3099b32c67b896d2792603f9Alan Cox
11558482bcd58530ad5857d7187854132f2b846db681Alan Cox	spin_lock_irq(&port->lock);
115631f35939d1d9bcfb3099b32c67b896d2792603f9Alan Cox	dcd = ch->DCDState;
11578482bcd58530ad5857d7187854132f2b846db681Alan Cox	spin_unlock_irq(&port->lock);
115831f35939d1d9bcfb3099b32c67b896d2792603f9Alan Cox	return dcd;
115931f35939d1d9bcfb3099b32c67b896d2792603f9Alan Cox}
116031f35939d1d9bcfb3099b32c67b896d2792603f9Alan Cox
1161f176178ba09d27cc33988435e2c9fe078b44998cAlan Coxstatic void moxa_dtr_rts(struct tty_port *port, int onoff)
1162a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby{
1163f176178ba09d27cc33988435e2c9fe078b44998cAlan Cox	struct moxa_port *ch = container_of(port, struct moxa_port, port);
1164f176178ba09d27cc33988435e2c9fe078b44998cAlan Cox	MoxaPortLineCtrl(ch, onoff, onoff);
1165a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby}
1166a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby
1167f176178ba09d27cc33988435e2c9fe078b44998cAlan Cox
11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int moxa_open(struct tty_struct *tty, struct file *filp)
11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1170810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	struct moxa_board_conf *brd;
11718f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	struct moxa_port *ch;
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int port;
11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
117411324edd4ad34981764b25bed44d46a1507b62e1Jiri Slaby	port = tty->index;
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (port == MAX_PORTS) {
117674d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		return capable(CAP_SYS_ADMIN) ? 0 : -EPERM;
11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1178a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	if (mutex_lock_interruptible(&moxa_openlock))
1179a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		return -ERESTARTSYS;
1180810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	brd = &moxa_boards[port / MAX_PORTS_PER_BOARD];
1181a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	if (!brd->ready) {
1182a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		mutex_unlock(&moxa_openlock);
1183810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby		return -ENODEV;
1184a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	}
11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1186f0e8527726b9e56649b9eafde3bc0fbc4dd2dd47Dirk Eibach	if (port % MAX_PORTS_PER_BOARD >= brd->numPorts) {
1187f0e8527726b9e56649b9eafde3bc0fbc4dd2dd47Dirk Eibach		mutex_unlock(&moxa_openlock);
1188f0e8527726b9e56649b9eafde3bc0fbc4dd2dd47Dirk Eibach		return -ENODEV;
1189f0e8527726b9e56649b9eafde3bc0fbc4dd2dd47Dirk Eibach	}
1190f0e8527726b9e56649b9eafde3bc0fbc4dd2dd47Dirk Eibach
1191810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	ch = &brd->ports[port % MAX_PORTS_PER_BOARD];
11929de6a51fee08f9e7020074738150441305e83af2Alan Cox	ch->port.count++;
11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tty->driver_data = ch;
1194d450b5a0196b6442cf3f29fc611d9c8daa56b559Alan Cox	tty_port_tty_set(&ch->port, tty);
1195f176178ba09d27cc33988435e2c9fe078b44998cAlan Cox	mutex_lock(&ch->port.mutex);
11969de6a51fee08f9e7020074738150441305e83af2Alan Cox	if (!(ch->port.flags & ASYNC_INITIALIZED)) {
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ch->statusflags = 0;
1198adc8d746caa67fff4b53ba3e5163a6cbacc3b523Alan Cox		moxa_set_tty_param(tty, &tty->termios);
1199b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby		MoxaPortLineCtrl(ch, 1, 1);
1200b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby		MoxaPortEnable(ch);
1201a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		MoxaSetFifo(ch, ch->type == PORT_16550A);
12029de6a51fee08f9e7020074738150441305e83af2Alan Cox		ch->port.flags |= ASYNC_INITIALIZED;
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1204f176178ba09d27cc33988435e2c9fe078b44998cAlan Cox	mutex_unlock(&ch->port.mutex);
1205a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	mutex_unlock(&moxa_openlock);
12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12077c31bdb6b2a7118150df1668444fd1b7f1df3b85Jiri Slaby	return tty_port_block_til_ready(&ch->port, tty, filp);
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_close(struct tty_struct *tty, struct file *filp)
12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1212f176178ba09d27cc33988435e2c9fe078b44998cAlan Cox	struct moxa_port *ch = tty->driver_data;
1213adc8d746caa67fff4b53ba3e5163a6cbacc3b523Alan Cox	ch->cflag = tty->termios.c_cflag;
1214f176178ba09d27cc33988435e2c9fe078b44998cAlan Cox	tty_port_close(&ch->port, tty, filp);
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int moxa_write(struct tty_struct *tty,
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      const unsigned char *buf, int count)
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1220b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	struct moxa_port *ch = tty->driver_data;
12210ad7c9af3e1cbb97082062266705d6cb5fb207eeJiri Slaby	unsigned long flags;
1222b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	int len;
12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ch == NULL)
1225b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby		return 0;
122633f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox
12270ad7c9af3e1cbb97082062266705d6cb5fb207eeJiri Slaby	spin_lock_irqsave(&moxa_lock, flags);
1228d450b5a0196b6442cf3f29fc611d9c8daa56b559Alan Cox	len = MoxaPortWriteData(tty, buf, count);
12290ad7c9af3e1cbb97082062266705d6cb5fb207eeJiri Slaby	spin_unlock_irqrestore(&moxa_lock, flags);
12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1231a808ac0c4a2c5d81ba38a2a76d4ddc1de40d1539Alan Cox	set_bit(LOWWAIT, &ch->statusflags);
1232eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby	return len;
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int moxa_write_room(struct tty_struct *tty)
12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12378f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	struct moxa_port *ch;
12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tty->stopped)
1240eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby		return 0;
1241b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	ch = tty->driver_data;
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ch == NULL)
1243eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby		return 0;
1244b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	return MoxaPortTxFree(ch);
12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_flush_buffer(struct tty_struct *tty)
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1249b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	struct moxa_port *ch = tty->driver_data;
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ch == NULL)
12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
1253b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	MoxaPortFlushData(ch, 1);
12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tty_wakeup(tty);
12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int moxa_chars_in_buffer(struct tty_struct *tty)
12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1259b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	struct moxa_port *ch = tty->driver_data;
12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int chars;
12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1262b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	chars = MoxaPortTxQueue(ch);
1263f710ebd7f70801e31751f2c49fe4b92a477d24ebAlan Cox	if (chars)
12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Make it possible to wakeup anything waiting for output
12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * in tty_ioctl.c, etc.
12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
1268f710ebd7f70801e31751f2c49fe4b92a477d24ebAlan Cox        	set_bit(EMPTYWAIT, &ch->statusflags);
1269eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby	return chars;
12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
127260b33c133ca0b7c0b6072c87234b63fee6e80558Alan Coxstatic int moxa_tiocmget(struct tty_struct *tty)
12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12748482bcd58530ad5857d7187854132f2b846db681Alan Cox	struct moxa_port *ch = tty->driver_data;
12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int flag = 0, dtr, rts;
12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1277b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	MoxaPortGetLineOut(ch, &dtr, &rts);
12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dtr)
12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flag |= TIOCM_DTR;
12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rts)
12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flag |= TIOCM_RTS;
1282b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	dtr = MoxaPortLineStatus(ch);
12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dtr & 1)
12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flag |= TIOCM_CTS;
12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dtr & 2)
12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flag |= TIOCM_DSR;
12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dtr & 4)
12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flag |= TIOCM_CD;
12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return flag;
12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
129220b9d17715017ae4dd4ec87fabc36d33b9de708eAlan Coxstatic int moxa_tiocmset(struct tty_struct *tty,
12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 unsigned int set, unsigned int clear)
12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1295a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	struct moxa_port *ch;
12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int dtr, rts;
12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1298a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	mutex_lock(&moxa_openlock);
1299a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	ch = tty->driver_data;
1300a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	if (!ch) {
1301a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		mutex_unlock(&moxa_openlock);
130274d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		return -EINVAL;
1303a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	}
13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1305b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	MoxaPortGetLineOut(ch, &dtr, &rts);
13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (set & TIOCM_RTS)
13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rts = 1;
13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (set & TIOCM_DTR)
13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dtr = 1;
13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clear & TIOCM_RTS)
13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rts = 0;
13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clear & TIOCM_DTR)
13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dtr = 0;
1314b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	MoxaPortLineCtrl(ch, dtr, rts);
1315a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	mutex_unlock(&moxa_openlock);
13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_set_termios(struct tty_struct *tty,
1320eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby		struct ktermios *old_termios)
13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1322eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby	struct moxa_port *ch = tty->driver_data;
13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ch == NULL)
13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
1326db1acaa632870ec87b65e062bc72ca375837a1f6Alan Cox	moxa_set_tty_param(tty, old_termios);
1327eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby	if (!(old_termios->c_cflag & CLOCAL) && C_CLOCAL(tty))
13289de6a51fee08f9e7020074738150441305e83af2Alan Cox		wake_up_interruptible(&ch->port.open_wait);
13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_stop(struct tty_struct *tty)
13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1333eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby	struct moxa_port *ch = tty->driver_data;
13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ch == NULL)
13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
1337b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	MoxaPortTxDisable(ch);
1338a808ac0c4a2c5d81ba38a2a76d4ddc1de40d1539Alan Cox	set_bit(TXSTOPPED, &ch->statusflags);
13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_start(struct tty_struct *tty)
13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1344eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby	struct moxa_port *ch = tty->driver_data;
13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ch == NULL)
13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
134958112dfbfe02d803566a2c6c8bd97b5fa3c62cdcDan Carpenter	if (!test_bit(TXSTOPPED, &ch->statusflags))
13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1352b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	MoxaPortTxEnable(ch);
1353a808ac0c4a2c5d81ba38a2a76d4ddc1de40d1539Alan Cox	clear_bit(TXSTOPPED, &ch->statusflags);
13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_hangup(struct tty_struct *tty)
13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1358a808ac0c4a2c5d81ba38a2a76d4ddc1de40d1539Alan Cox	struct moxa_port *ch = tty->driver_data;
1359f176178ba09d27cc33988435e2c9fe078b44998cAlan Cox	tty_port_hangup(&ch->port);
13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13627bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slabystatic void moxa_new_dcdstate(struct moxa_port *p, u8 dcd)
13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13648482bcd58530ad5857d7187854132f2b846db681Alan Cox	unsigned long flags;
13657bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	dcd = !!dcd;
13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13678482bcd58530ad5857d7187854132f2b846db681Alan Cox	spin_lock_irqsave(&p->port.lock, flags);
1368d450b5a0196b6442cf3f29fc611d9c8daa56b559Alan Cox	if (dcd != p->DCDState) {
13698482bcd58530ad5857d7187854132f2b846db681Alan Cox        	p->DCDState = dcd;
13708482bcd58530ad5857d7187854132f2b846db681Alan Cox        	spin_unlock_irqrestore(&p->port.lock, flags);
1371aa27a094e2c2e0cc59914e56113b860f524f4479Jiri Slaby		if (!dcd)
1372aa27a094e2c2e0cc59914e56113b860f524f4479Jiri Slaby			tty_port_tty_hangup(&p->port, true);
13737bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	}
13748482bcd58530ad5857d7187854132f2b846db681Alan Cox	else
13758482bcd58530ad5857d7187854132f2b846db681Alan Cox		spin_unlock_irqrestore(&p->port.lock, flags);
13767bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby}
13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13787bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slabystatic int moxa_poll_port(struct moxa_port *p, unsigned int handle,
13797bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		u16 __iomem *ip)
13807bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby{
1381d450b5a0196b6442cf3f29fc611d9c8daa56b559Alan Cox	struct tty_struct *tty = tty_port_tty_get(&p->port);
13827bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	void __iomem *ofsAddr;
13839de6a51fee08f9e7020074738150441305e83af2Alan Cox	unsigned int inited = p->port.flags & ASYNC_INITIALIZED;
13847bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	u16 intr;
13857bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby
13867bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	if (tty) {
1387a808ac0c4a2c5d81ba38a2a76d4ddc1de40d1539Alan Cox		if (test_bit(EMPTYWAIT, &p->statusflags) &&
13887bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby				MoxaPortTxQueue(p) == 0) {
1389a808ac0c4a2c5d81ba38a2a76d4ddc1de40d1539Alan Cox			clear_bit(EMPTYWAIT, &p->statusflags);
13907bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby			tty_wakeup(tty);
13917bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		}
1392a808ac0c4a2c5d81ba38a2a76d4ddc1de40d1539Alan Cox		if (test_bit(LOWWAIT, &p->statusflags) && !tty->stopped &&
13937bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby				MoxaPortTxQueue(p) <= WAKEUP_CHARS) {
1394a808ac0c4a2c5d81ba38a2a76d4ddc1de40d1539Alan Cox			clear_bit(LOWWAIT, &p->statusflags);
13957bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby			tty_wakeup(tty);
13967bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		}
13977bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby
1398f9b412a8c9adb17d50922f91962e8b1e48789430Alan Cox		if (inited && !test_bit(TTY_THROTTLED, &tty->flags) &&
13997bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby				MoxaPortRxQueue(p) > 0) { /* RX */
14007bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby			MoxaPortReadData(p);
14016732c8bb8671acbdac6cdc93dd72ddd581dd5e25Jiri Slaby			tty_schedule_flip(&p->port);
14027bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		}
14037bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	} else {
1404a808ac0c4a2c5d81ba38a2a76d4ddc1de40d1539Alan Cox		clear_bit(EMPTYWAIT, &p->statusflags);
14057bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		MoxaPortFlushData(p, 0); /* flush RX */
14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14070bcc4caadc8f5396b52950ee03c67b76875602dfJiri Slaby
14087bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	if (!handle) /* nothing else to do */
14090e0fd7d73ed130583dca16405b029f56bf65109fJiri Slaby		goto put;
14107bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby
14117bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	intr = readw(ip); /* port irq status */
14127bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	if (intr == 0)
14130e0fd7d73ed130583dca16405b029f56bf65109fJiri Slaby		goto put;
14147bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby
14157bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	writew(0, ip); /* ACK port */
14167bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	ofsAddr = p->tableAddr;
14177bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	if (intr & IntrTx) /* disable tx intr */
14187bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		writew(readw(ofsAddr + HostStat) & ~WakeupTx,
14197bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby				ofsAddr + HostStat);
14207bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby
14217bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	if (!inited)
14220e0fd7d73ed130583dca16405b029f56bf65109fJiri Slaby		goto put;
14237bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby
14247bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	if (tty && (intr & IntrBreak) && !I_IGNBRK(tty)) { /* BREAK */
142592a19f9cec9a80ad93c06e115822deb729e2c6adJiri Slaby		tty_insert_flip_char(&p->port, 0, TTY_BREAK);
14266732c8bb8671acbdac6cdc93dd72ddd581dd5e25Jiri Slaby		tty_schedule_flip(&p->port);
14277bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	}
14287bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby
14297bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	if (intr & IntrLine)
14307bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		moxa_new_dcdstate(p, readb(ofsAddr + FlagStat) & DCD_state);
14310e0fd7d73ed130583dca16405b029f56bf65109fJiri Slabyput:
14320e0fd7d73ed130583dca16405b029f56bf65109fJiri Slaby	tty_kref_put(tty);
14337bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby
14347bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	return 0;
14357bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby}
14367bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby
14377bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slabystatic void moxa_poll(unsigned long ignored)
14387bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby{
14397bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	struct moxa_board_conf *brd;
14407bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	u16 __iomem *ip;
14412a5413416b6b2fd8a5a38601a4fe3b56a52cfb86Jiri Slaby	unsigned int card, port, served = 0;
14427bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby
14437bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	spin_lock(&moxa_lock);
14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (card = 0; card < MAX_BOARDS; card++) {
14457bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		brd = &moxa_boards[card];
14467bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		if (!brd->ready)
14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
14487bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby
14492a5413416b6b2fd8a5a38601a4fe3b56a52cfb86Jiri Slaby		served++;
14502a5413416b6b2fd8a5a38601a4fe3b56a52cfb86Jiri Slaby
14517bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		ip = NULL;
14527bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		if (readb(brd->intPend) == 0xff)
14537bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby			ip = brd->intTable + readb(brd->intNdx);
14547bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby
14557bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		for (port = 0; port < brd->numPorts; port++)
14567bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby			moxa_poll_port(&brd->ports[port], !!ip, ip + port);
14577bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby
14587bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		if (ip)
14597bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby			writeb(0, brd->intPend); /* ACK */
14607bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby
14617bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		if (moxaLowWaterChk) {
14627bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby			struct moxa_port *p = brd->ports;
14637bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby			for (port = 0; port < brd->numPorts; port++, p++)
14647bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby				if (p->lowChkFlag) {
14657bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby					p->lowChkFlag = 0;
14667bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby					moxa_low_water_check(p->tableAddr);
14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14707bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	moxaLowWaterChk = 0;
14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14722a5413416b6b2fd8a5a38601a4fe3b56a52cfb86Jiri Slaby	if (served)
14732a5413416b6b2fd8a5a38601a4fe3b56a52cfb86Jiri Slaby		mod_timer(&moxaTimer, jiffies + HZ / 50);
14742a5413416b6b2fd8a5a38601a4fe3b56a52cfb86Jiri Slaby	spin_unlock(&moxa_lock);
14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/******************************************************************************/
14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1479db1acaa632870ec87b65e062bc72ca375837a1f6Alan Coxstatic void moxa_set_tty_param(struct tty_struct *tty, struct ktermios *old_termios)
14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1481adc8d746caa67fff4b53ba3e5163a6cbacc3b523Alan Cox	register struct ktermios *ts = &tty->termios;
1482eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby	struct moxa_port *ch = tty->driver_data;
1483db1acaa632870ec87b65e062bc72ca375837a1f6Alan Cox	int rts, cts, txflow, rxflow, xany, baud;
14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rts = cts = txflow = rxflow = xany = 0;
14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ts->c_cflag & CRTSCTS)
14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rts = cts = 1;
14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ts->c_iflag & IXON)
14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		txflow = 1;
14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ts->c_iflag & IXOFF)
14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rxflow = 1;
14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ts->c_iflag & IXANY)
14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		xany = 1;
1494db1acaa632870ec87b65e062bc72ca375837a1f6Alan Cox
1495db1acaa632870ec87b65e062bc72ca375837a1f6Alan Cox	/* Clear the features we don't support */
1496db1acaa632870ec87b65e062bc72ca375837a1f6Alan Cox	ts->c_cflag &= ~CMSPAR;
1497b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	MoxaPortFlowCtrl(ch, rts, cts, txflow, rxflow, xany);
1498b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	baud = MoxaPortSetTermio(ch, ts, tty_get_baud_rate(tty));
1499db1acaa632870ec87b65e062bc72ca375837a1f6Alan Cox	if (baud == -1)
1500db1acaa632870ec87b65e062bc72ca375837a1f6Alan Cox		baud = tty_termios_baud_rate(old_termios);
1501db1acaa632870ec87b65e062bc72ca375837a1f6Alan Cox	/* Not put the baud rate into the termios data */
1502db1acaa632870ec87b65e062bc72ca375837a1f6Alan Cox	tty_encode_baud_rate(tty, baud, baud);
15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************
15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Driver level functions: 					     *
15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *****************************************************************************/
15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1509b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic void MoxaPortFlushData(struct moxa_port *port, int mode)
15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *ofsAddr;
1512eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby	if (mode < 0 || mode > 2)
15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
1514b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	ofsAddr = port->tableAddr;
15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxafunc(ofsAddr, FC_FlushQueue, mode);
15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mode != 1) {
1517b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby		port->lowChkFlag = 0;
15186f56b658b4e5c4486641ce62f331150954c4de37Jiri Slaby		moxa_low_water_check(ofsAddr);
15191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Moxa Port Number Description:
15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
15251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      MOXA serial driver supports up to 4 MOXA-C218/C320 boards. And,
15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      the port number using in MOXA driver functions will be 0 to 31 for
15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      first MOXA board, 32 to 63 for second, 64 to 95 for third and 96
15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      to 127 for fourth. For example, if you setup three MOXA boards,
15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      first board is C218, second board is C320-16 and third board is
15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      C320-32. The port number of first board (C218 - 8 ports) is from
15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      0 to 7. The port number of second board (C320 - 16 ports) is form
15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      32 to 47. The port number of third board (C320 - 32 ports) is from
15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      64 to 95. And those port numbers form 8 to 31, 48 to 63 and 96 to
15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      127 will be invalid.
15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Moxa Functions Description:
15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 1:     Driver initialization routine, this routine must be
15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                      called when initialized driver.
15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      void MoxaDriverInit();
15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 2:     Moxa driver private IOCTL command processing.
15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      int  MoxaDriverIoctl(unsigned int cmd, unsigned long arg, int port);
15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           unsigned int cmd   : IOCTL command
15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           unsigned long arg  : IOCTL argument
15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           return:    0  (OK)
15541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                      -EINVAL
15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                      -ENOIOCTLCMD
15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 6:     Enable this port to start Tx/Rx data.
15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      void MoxaPortEnable(int port);
15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 7:     Disable this port
15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      void MoxaPortDisable(int port);
15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
15701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 10:    Setting baud rate of this port.
15711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
157208d01c792568ba07d2bcf5202dbc8484dbff6747Jiri Slaby *      speed_t MoxaPortSetBaud(int port, speed_t baud);
15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           long baud          : baud rate (50 - 115200)
15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           return:    0       : this port is invalid or baud < 50
15771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                      50 - 115200 : the real baud rate set to the port, if
15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                                    the argument baud is large than maximun
15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                                    available baud rate, the real setting
15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                                    baud rate will be the maximun baud rate.
15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 12:    Configure the port.
15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
1585606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox *      int  MoxaPortSetTermio(int port, struct ktermios *termio, speed_t baud);
15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
1587606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox *           struct ktermios * termio : termio structure pointer
1588c7bce3097c0f9bbed76ee6fd03742f2624031a45Alan Cox *	     speed_t baud	: baud rate
15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           return:    -1      : this port is invalid or termio == NULL
15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                      0       : setting O.K.
15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
15931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
15941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 13:    Get the DTR/RTS state of this port.
15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      int  MoxaPortGetLineOut(int port, int *dtrState, int *rtsState);
15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
15981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int * dtrState     : pointer to INT to receive the current DTR
15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                                state. (if NULL, this function will not
16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                                write to this address)
16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int * rtsState     : pointer to INT to receive the current RTS
16021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                                state. (if NULL, this function will not
16031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                                write to this address)
16041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           return:    -1      : this port is invalid
16061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                      0       : O.K.
16071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 14:    Setting the DTR/RTS output state of this port.
16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
16111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      void MoxaPortLineCtrl(int port, int dtrState, int rtsState);
16121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int dtrState       : DTR output state (0: off, 1: on)
16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int rtsState       : RTS output state (0: off, 1: on)
16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 15:    Setting the flow control of this port.
16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      void MoxaPortFlowCtrl(int port, int rtsFlow, int ctsFlow, int rxFlow,
16201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                            int txFlow,int xany);
16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
16221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int rtsFlow        : H/W RTS flow control (0: no, 1: yes)
16231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int ctsFlow        : H/W CTS flow control (0: no, 1: yes)
16241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int rxFlow         : S/W Rx XON/XOFF flow control (0: no, 1: yes)
16251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int txFlow         : S/W Tx XON/XOFF flow control (0: no, 1: yes)
16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int xany           : S/W XANY flow control (0: no, 1: yes)
16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 16:    Get ths line status of this port
16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      int  MoxaPortLineStatus(int port);
16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           return:    Bit 0 - CTS state (0: off, 1: on)
16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                      Bit 1 - DSR state (0: off, 1: on)
16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                      Bit 2 - DCD state (0: off, 1: on)
16371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 19:    Flush the Rx/Tx buffer data of this port.
16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      void MoxaPortFlushData(int port, int mode);
16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int mode
16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                      0       : flush the Rx buffer
16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                      1       : flush the Tx buffer
16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                      2       : flush the Rx and Tx buffer
16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 20:    Write data.
16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      int  MoxaPortWriteData(int port, unsigned char * buffer, int length);
16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           unsigned char * buffer     : pointer to write data buffer.
16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int length         : write data length
16551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           return:    0 - length      : real write data length
16571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 21:    Read data.
16601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
166133f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox *      int  MoxaPortReadData(int port, struct tty_struct *tty);
16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
166333f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox *	     struct tty_struct *tty : tty for data
16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           return:    0 - length      : real read data length
16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 24:    Get the Tx buffer current queued data bytes
16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      int  MoxaPortTxQueue(int port);
16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           return:    ..      : Tx buffer current queued data bytes
16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 25:    Get the Tx buffer current free space
16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      int  MoxaPortTxFree(int port);
16791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
16801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           return:    ..      : Tx buffer current free space
16821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 26:    Get the Rx buffer current queued data bytes
16851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
16861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      int  MoxaPortRxQueue(int port);
16871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
16881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           return:    ..      : Rx buffer current queued data bytes
16901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 28:    Disable port data transmission.
16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
16941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      void MoxaPortTxDisable(int port);
16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 29:    Enable port data transmission.
16991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      void MoxaPortTxEnable(int port);
17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 31:    Get the received BREAK signal count and reset it.
17051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
17061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      int  MoxaPortResetBrkCnt(int port);
17071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
17081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           return:    0 - ..  : BREAK signal count
17101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
17111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
17121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
17131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1714b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic void MoxaPortEnable(struct moxa_port *port)
17151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
17161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *ofsAddr;
1717eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby	u16 lowwater = 512;
17181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1719b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	ofsAddr = port->tableAddr;
17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writew(lowwater, ofsAddr + Low_water);
172108d01c792568ba07d2bcf5202dbc8484dbff6747Jiri Slaby	if (MOXA_IS_320(port->board))
17221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		moxafunc(ofsAddr, FC_SetBreakIrq, 0);
1723eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby	else
1724eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby		writew(readw(ofsAddr + HostStat) | WakeupBreak,
1725eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby				ofsAddr + HostStat);
17261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxafunc(ofsAddr, FC_SetLineIrq, Magic_code);
17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxafunc(ofsAddr, FC_FlushQueue, 2);
17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxafunc(ofsAddr, FC_EnableCH, Magic_code);
17311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MoxaPortLineStatus(port);
17321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1734b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic void MoxaPortDisable(struct moxa_port *port)
17351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1736b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	void __iomem *ofsAddr = port->tableAddr;
17371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxafunc(ofsAddr, FC_SetFlowCtl, 0);	/* disable flow control */
17391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxafunc(ofsAddr, FC_ClrLineIrq, Magic_code);
17401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writew(0, ofsAddr + HostStat);
17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxafunc(ofsAddr, FC_DisableCH, Magic_code);
17421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
174408d01c792568ba07d2bcf5202dbc8484dbff6747Jiri Slabystatic speed_t MoxaPortSetBaud(struct moxa_port *port, speed_t baud)
17451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
174608d01c792568ba07d2bcf5202dbc8484dbff6747Jiri Slaby	void __iomem *ofsAddr = port->tableAddr;
174708d01c792568ba07d2bcf5202dbc8484dbff6747Jiri Slaby	unsigned int clock, val;
174808d01c792568ba07d2bcf5202dbc8484dbff6747Jiri Slaby	speed_t max;
17491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
175008d01c792568ba07d2bcf5202dbc8484dbff6747Jiri Slaby	max = MOXA_IS_320(port->board) ? 460800 : 921600;
175108d01c792568ba07d2bcf5202dbc8484dbff6747Jiri Slaby	if (baud < 50)
1752eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby		return 0;
17531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (baud > max)
17541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		baud = max;
175508d01c792568ba07d2bcf5202dbc8484dbff6747Jiri Slaby	clock = 921600;
17561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = clock / baud;
17571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxafunc(ofsAddr, FC_SetBaud, val);
17581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	baud = clock / val;
1759eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby	return baud;
17601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1762b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic int MoxaPortSetTermio(struct moxa_port *port, struct ktermios *termio,
1763b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby		speed_t baud)
17641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
17651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *ofsAddr;
17661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcflag_t mode = 0;
17671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1768b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	ofsAddr = port->tableAddr;
17691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mode = termio->c_cflag & CSIZE;
17711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mode == CS5)
17721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mode = MX_CS5;
17731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (mode == CS6)
17741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mode = MX_CS6;
17751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (mode == CS7)
17761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mode = MX_CS7;
17771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (mode == CS8)
17781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mode = MX_CS8;
17791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (termio->c_cflag & CSTOPB) {
17811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (mode == MX_CS5)
17821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mode |= MX_STOP15;
17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
17841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mode |= MX_STOP2;
17851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mode |= MX_STOP1;
17871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (termio->c_cflag & PARENB) {
17891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (termio->c_cflag & PARODD)
17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mode |= MX_PARODD;
17911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
17921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mode |= MX_PAREVEN;
17931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
17941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mode |= MX_PARNONE;
17951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1796eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby	moxafunc(ofsAddr, FC_SetDataMode, (u16)mode);
17971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
179808d01c792568ba07d2bcf5202dbc8484dbff6747Jiri Slaby	if (MOXA_IS_320(port->board) && baud >= 921600)
179908d01c792568ba07d2bcf5202dbc8484dbff6747Jiri Slaby		return -1;
180008d01c792568ba07d2bcf5202dbc8484dbff6747Jiri Slaby
1801db1acaa632870ec87b65e062bc72ca375837a1f6Alan Cox	baud = MoxaPortSetBaud(port, baud);
18021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (termio->c_iflag & (IXON | IXOFF | IXANY)) {
1804f5c5a36d27ae6d9e03c2f1b7890942bf84e92c5bAlan Cox	        spin_lock_irq(&moxafunc_lock);
18051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writeb(termio->c_cc[VSTART], ofsAddr + FuncArg);
18061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writeb(termio->c_cc[VSTOP], ofsAddr + FuncArg1);
18071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writeb(FC_SetXonXoff, ofsAddr + FuncCode);
18086f56b658b4e5c4486641ce62f331150954c4de37Jiri Slaby		moxa_wait_finish(ofsAddr);
1809a808ac0c4a2c5d81ba38a2a76d4ddc1de40d1539Alan Cox		spin_unlock_irq(&moxafunc_lock);
18101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1812eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby	return baud;
18131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1815b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic int MoxaPortGetLineOut(struct moxa_port *port, int *dtrState,
1816b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby		int *rtsState)
18171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1818b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	if (dtrState)
1819b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby		*dtrState = !!(port->lineCtrl & DTR_ON);
1820b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	if (rtsState)
1821b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby		*rtsState = !!(port->lineCtrl & RTS_ON);
1822b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby
1823eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby	return 0;
18241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1826b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic void MoxaPortLineCtrl(struct moxa_port *port, int dtr, int rts)
18271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1828eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby	u8 mode = 0;
18291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dtr)
18311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mode |= DTR_ON;
18321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rts)
18331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mode |= RTS_ON;
1834b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	port->lineCtrl = mode;
1835b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	moxafunc(port->tableAddr, FC_LineControl, mode);
18361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1838b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic void MoxaPortFlowCtrl(struct moxa_port *port, int rts, int cts,
1839b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby		int txflow, int rxflow, int txany)
18401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1841b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	int mode = 0;
18421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rts)
18441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mode |= RTS_FlowCtl;
18451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cts)
18461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mode |= CTS_FlowCtl;
18471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (txflow)
18481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mode |= Tx_FlowCtl;
18491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rxflow)
18501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mode |= Rx_FlowCtl;
18511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (txany)
18521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mode |= IXM_IXANY;
1853b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	moxafunc(port->tableAddr, FC_SetFlowCtl, mode);
18541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1856b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic int MoxaPortLineStatus(struct moxa_port *port)
18571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
18581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *ofsAddr;
18591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int val;
18601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1861b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	ofsAddr = port->tableAddr;
1862f5c5a36d27ae6d9e03c2f1b7890942bf84e92c5bAlan Cox	if (MOXA_IS_320(port->board))
1863f5c5a36d27ae6d9e03c2f1b7890942bf84e92c5bAlan Cox		val = moxafuncret(ofsAddr, FC_LineStatus, 0);
1864f5c5a36d27ae6d9e03c2f1b7890942bf84e92c5bAlan Cox	else
18651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val = readw(ofsAddr + FlagStat) >> 4;
18661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val &= 0x0B;
18677bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	if (val & 8)
18681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val |= 4;
18697bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	moxa_new_dcdstate(port, val & 8);
18701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val &= 7;
18717bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	return val;
18721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1874d450b5a0196b6442cf3f29fc611d9c8daa56b559Alan Coxstatic int MoxaPortWriteData(struct tty_struct *tty,
18752108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby		const unsigned char *buffer, int len)
18761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1877d450b5a0196b6442cf3f29fc611d9c8daa56b559Alan Cox	struct moxa_port *port = tty->driver_data;
18781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *baseAddr, *ofsAddr, *ofs;
18792108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby	unsigned int c, total;
18802108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby	u16 head, tail, tx_mask, spage, epage;
18812108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby	u16 pageno, pageofs, bufhead;
18821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1883b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	ofsAddr = port->tableAddr;
1884b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	baseAddr = port->board->basemem;
18851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tx_mask = readw(ofsAddr + TX_mask);
18861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spage = readw(ofsAddr + Page_txb);
18871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	epage = readw(ofsAddr + EndPage_txb);
18881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tail = readw(ofsAddr + TXwptr);
18891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	head = readw(ofsAddr + TXrptr);
18902108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby	c = (head > tail) ? (head - tail - 1) : (head - tail + tx_mask);
18911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (c > len)
18921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		c = len;
18939de6a51fee08f9e7020074738150441305e83af2Alan Cox	moxaLog.txcnt[port->port.tty->index] += c;
18941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	total = c;
18951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (spage == epage) {
18961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bufhead = readw(ofsAddr + Ofs_txb);
18971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writew(spage, baseAddr + Control_reg);
18981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (c > 0) {
18991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (head > tail)
19001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				len = head - tail - 1;
19011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else
19021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				len = tx_mask + 1 - tail;
19031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			len = (c > len) ? len : c;
19041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ofs = baseAddr + DynPage_addr + bufhead + tail;
19052108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby			memcpy_toio(ofs, buffer, len);
19062108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby			buffer += len;
19071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tail = (tail + len) & tx_mask;
19081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			c -= len;
19091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
19101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
19111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pageno = spage + (tail >> 13);
19121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pageofs = tail & Page_mask;
19132108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby		while (c > 0) {
19142108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby			len = Page_size - pageofs;
19152108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby			if (len > c)
19162108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby				len = c;
19171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			writeb(pageno, baseAddr + Control_reg);
19181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ofs = baseAddr + DynPage_addr + pageofs;
19192108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby			memcpy_toio(ofs, buffer, len);
19202108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby			buffer += len;
19211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (++pageno == epage)
19221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pageno = spage;
19231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pageofs = 0;
19242108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby			c -= len;
19252108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby		}
19262108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby		tail = (tail + total) & tx_mask;
19271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
19282108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby	writew(tail, ofsAddr + TXwptr);
19291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writeb(1, ofsAddr + CD180TXirq);	/* start to send */
19302108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby	return total;
19311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
19321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19337bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slabystatic int MoxaPortReadData(struct moxa_port *port)
19341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
19359de6a51fee08f9e7020074738150441305e83af2Alan Cox	struct tty_struct *tty = port->port.tty;
19362108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby	unsigned char *dst;
19371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *baseAddr, *ofsAddr, *ofs;
19382108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby	unsigned int count, len, total;
19392108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby	u16 tail, rx_mask, spage, epage;
19402108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby	u16 pageno, pageofs, bufhead, head;
19411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1942b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	ofsAddr = port->tableAddr;
1943b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	baseAddr = port->board->basemem;
19441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	head = readw(ofsAddr + RXrptr);
19451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tail = readw(ofsAddr + RXwptr);
19461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rx_mask = readw(ofsAddr + RX_mask);
19471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spage = readw(ofsAddr + Page_rxb);
19481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	epage = readw(ofsAddr + EndPage_rxb);
19492108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby	count = (tail >= head) ? (tail - head) : (tail - head + rx_mask + 1);
19501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (count == 0)
195133f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox		return 0;
19521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
195333f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox	total = count;
19547bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	moxaLog.rxcnt[tty->index] += total;
19551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (spage == epage) {
19561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bufhead = readw(ofsAddr + Ofs_rxb);
19571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writew(spage, baseAddr + Control_reg);
19581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (count > 0) {
19591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ofs = baseAddr + DynPage_addr + bufhead + head;
19602108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby			len = (tail >= head) ? (tail - head) :
19612108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby					(rx_mask + 1 - head);
19622f69335710884ae6112fc8196ebe29b5cda7b79bJiri Slaby			len = tty_prepare_flip_string(&port->port, &dst,
19632108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby					min(len, count));
19642108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby			memcpy_fromio(dst, ofs, len);
19651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			head = (head + len) & rx_mask;
19661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			count -= len;
19671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
19681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
19691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pageno = spage + (head >> 13);
19701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pageofs = head & Page_mask;
19712108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby		while (count > 0) {
19721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			writew(pageno, baseAddr + Control_reg);
19731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ofs = baseAddr + DynPage_addr + pageofs;
19742f69335710884ae6112fc8196ebe29b5cda7b79bJiri Slaby			len = tty_prepare_flip_string(&port->port, &dst,
19752108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby					min(Page_size - pageofs, count));
19762108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby			memcpy_fromio(dst, ofs, len);
19772108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby
19782108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby			count -= len;
19792108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby			pageofs = (pageofs + len) & Page_mask;
19802108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby			if (pageofs == 0 && ++pageno == epage)
19811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pageno = spage;
19822108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby		}
19832108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby		head = (head + total) & rx_mask;
19841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
19852108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby	writew(head, ofsAddr + RXrptr);
19862108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby	if (readb(ofsAddr + FlagStat) & Xoff_state) {
19871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		moxaLowWaterChk = 1;
1988b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby		port->lowChkFlag = 1;
19891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
19902108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby	return total;
19911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
19921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1994b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic int MoxaPortTxQueue(struct moxa_port *port)
19951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1996b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	void __iomem *ofsAddr = port->tableAddr;
19972108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby	u16 rptr, wptr, mask;
19981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rptr = readw(ofsAddr + TXrptr);
20001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wptr = readw(ofsAddr + TXwptr);
20011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mask = readw(ofsAddr + TX_mask);
20022108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby	return (wptr - rptr) & mask;
20031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2005b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic int MoxaPortTxFree(struct moxa_port *port)
20061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2007b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	void __iomem *ofsAddr = port->tableAddr;
20082108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby	u16 rptr, wptr, mask;
20091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rptr = readw(ofsAddr + TXrptr);
20111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wptr = readw(ofsAddr + TXwptr);
20121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mask = readw(ofsAddr + TX_mask);
20132108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby	return mask - ((wptr - rptr) & mask);
20141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2016b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic int MoxaPortRxQueue(struct moxa_port *port)
20171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2018b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	void __iomem *ofsAddr = port->tableAddr;
20192108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby	u16 rptr, wptr, mask;
20201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rptr = readw(ofsAddr + RXrptr);
20221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wptr = readw(ofsAddr + RXwptr);
20231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mask = readw(ofsAddr + RX_mask);
20242108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby	return (wptr - rptr) & mask;
20251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2027b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic void MoxaPortTxDisable(struct moxa_port *port)
20281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2029b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	moxafunc(port->tableAddr, FC_SetXoffState, Magic_code);
20301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2032b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic void MoxaPortTxEnable(struct moxa_port *port)
20331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2034b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	moxafunc(port->tableAddr, FC_SetXonState, Magic_code);
20351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20378f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slabystatic int moxa_get_serial_info(struct moxa_port *info,
2038eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby		struct serial_struct __user *retinfo)
20391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2040eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby	struct serial_struct tmp = {
2041eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby		.type = info->type,
20429de6a51fee08f9e7020074738150441305e83af2Alan Cox		.line = info->port.tty->index,
20439de6a51fee08f9e7020074738150441305e83af2Alan Cox		.flags = info->port.flags,
2044eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby		.baud_base = 921600,
204544b7d1b37f786c61d0e382b6f72f605f73de284bAlan Cox		.close_delay = info->port.close_delay
2046eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby	};
2047eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby	return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
20481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20518f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slabystatic int moxa_set_serial_info(struct moxa_port *info,
2052eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby		struct serial_struct __user *new_info)
20531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
20541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct serial_struct new_serial;
20551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2056eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby	if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
20571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
20581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2059eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby	if (new_serial.irq != 0 || new_serial.port != 0 ||
2060eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby			new_serial.custom_divisor != 0 ||
2061eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby			new_serial.baud_base != 921600)
2062eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby		return -EPERM;
20631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!capable(CAP_SYS_ADMIN)) {
20651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (((new_serial.flags & ~ASYNC_USR_MASK) !=
20669de6a51fee08f9e7020074738150441305e83af2Alan Cox		     (info->port.flags & ~ASYNC_USR_MASK)))
2067eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby			return -EPERM;
2068eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby	} else
206944b7d1b37f786c61d0e382b6f72f605f73de284bAlan Cox		info->port.close_delay = new_serial.close_delay * HZ / 100;
20701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	new_serial.flags = (new_serial.flags & ~ASYNC_FLAGS);
20729de6a51fee08f9e7020074738150441305e83af2Alan Cox	new_serial.flags |= (info->port.flags & ASYNC_FLAGS);
20731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2074eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby	MoxaSetFifo(info, new_serial.type == PORT_16550A);
20751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->type = new_serial.type;
2077eaa95a8da6366c34d3a61e93109e5f8f8a4e72a0Jiri Slaby	return 0;
20781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************
20831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Static local functions: 					     *
20841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *****************************************************************************/
20851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2086b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic void MoxaSetFifo(struct moxa_port *port, int enable)
20871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2088b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	void __iomem *ofsAddr = port->tableAddr;
20891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!enable) {
20911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		moxafunc(ofsAddr, FC_SetRxFIFOTrig, 0);
20921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		moxafunc(ofsAddr, FC_SetTxFIFOCnt, 1);
20931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
20941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		moxafunc(ofsAddr, FC_SetRxFIFOTrig, 3);
20951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		moxafunc(ofsAddr, FC_SetTxFIFOCnt, 16);
20961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
20971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2098