moxa.c revision a8f5cda067e2eeefe49fe386caf0f61fc5c825e0
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           moxa.c  -- MOXA Intellio family multiport serial driver.
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Copyright (C) 1999-2000  Moxa Technologies (support@moxa.com.tw).
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      This code is loosely based on the Linux serial driver, written by
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Linus Torvalds, Theodore T'so and others.
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      This program is free software; you can redistribute it and/or modify
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      it under the terms of the GNU General Public License as published by
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      the Free Software Foundation; either version 2 of the License, or
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      (at your option) any later version.
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    MOXA Intellio Series Driver
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      for             : LINUX
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      date            : 1999/1/7
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      version         : 5.1
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h>
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
28037182346f0991683cc7320a257c3f6089432ceeJiri Slaby#include <linux/firmware.h>
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/signal.h>
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sched.h>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/timer.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty.h>
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_flip.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/major.h>
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fcntl.h>
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ptrace.h>
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/serial.h>
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_driver.h>
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h>
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/bitops.h>
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/system.h>
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h>
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
50037182346f0991683cc7320a257c3f6089432ceeJiri Slaby#include "moxa.h"
51037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
5211324edd4ad34981764b25bed44d46a1507b62e1Jiri Slaby#define MOXA_VERSION		"5.1k"
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
54037182346f0991683cc7320a257c3f6089432ceeJiri Slaby#define MOXA_FW_HDRLEN		32
55037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
5611324edd4ad34981764b25bed44d46a1507b62e1Jiri Slaby#define MOXAMAJOR		172
5711324edd4ad34981764b25bed44d46a1507b62e1Jiri Slaby#define MOXACUMAJOR		173
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5911324edd4ad34981764b25bed44d46a1507b62e1Jiri Slaby#define MAX_BOARDS		4	/* Don't change this value */
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MAX_PORTS_PER_BOARD	32	/* Don't change this value */
6111324edd4ad34981764b25bed44d46a1507b62e1Jiri Slaby#define MAX_PORTS		(MAX_BOARDS * MAX_PORTS_PER_BOARD)
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Define the Moxa PCI vendor and device IDs.
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
6611324edd4ad34981764b25bed44d46a1507b62e1Jiri Slaby#define MOXA_BUS_TYPE_ISA	0
6711324edd4ad34981764b25bed44d46a1507b62e1Jiri Slaby#define MOXA_BUS_TYPE_PCI	1
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum {
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MOXA_BOARD_C218_PCI = 1,
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MOXA_BOARD_C218_ISA,
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MOXA_BOARD_C320_PCI,
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MOXA_BOARD_C320_ISA,
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MOXA_BOARD_CP204J,
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char *moxa_brdname[] =
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"C218 Turbo PCI series",
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"C218 Turbo ISA series",
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"C320 Turbo PCI series",
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"C320 Turbo ISA series",
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"CP-204J series",
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PCI
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pci_device_id moxa_pcibrds[] = {
885ebb4078af0dab866fdf57f84f72b9e9a7e8c6b8Jiri Slaby	{ PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C218),
895ebb4078af0dab866fdf57f84f72b9e9a7e8c6b8Jiri Slaby		.driver_data = MOXA_BOARD_C218_PCI },
905ebb4078af0dab866fdf57f84f72b9e9a7e8c6b8Jiri Slaby	{ PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C320),
915ebb4078af0dab866fdf57f84f72b9e9a7e8c6b8Jiri Slaby		.driver_data = MOXA_BOARD_C320_PCI },
925ebb4078af0dab866fdf57f84f72b9e9a7e8c6b8Jiri Slaby	{ PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP204J),
935ebb4078af0dab866fdf57f84f72b9e9a7e8c6b8Jiri Slaby		.driver_data = MOXA_BOARD_CP204J },
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0 }
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DEVICE_TABLE(pci, moxa_pcibrds);
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_PCI */
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
99037182346f0991683cc7320a257c3f6089432ceeJiri Slabystruct moxa_port;
100037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
1018f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slabystatic struct moxa_board_conf {
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int boardType;
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int numPorts;
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int busType;
1058f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby
106810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	unsigned int ready;
1078f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby
108037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	struct moxa_port *ports;
109037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
1108f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	void __iomem *basemem;
1118f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	void __iomem *intNdx;
1128f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	void __iomem *intPend;
1138f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	void __iomem *intTable;
1148f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby} moxa_boards[MAX_BOARDS];
1158f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby
1168f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slabystruct mxser_mstatus {
1178f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	tcflag_t cflag;
1188f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	int cts;
1198f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	int dsr;
1208f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	int ri;
1218f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	int dcd;
1229dff89cd82af7bccc706fed288b1c33a51c3b937Jiri Slaby};
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1248f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slabystruct moxaq_str {
1258f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	int inq;
1268f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	int outq;
1278f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby};
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1298f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slabystruct moxa_port {
130b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	struct moxa_board_conf *board;
1317bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	struct tty_struct *tty;
1327bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	void __iomem *tableAddr;
1337bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int type;
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int close_delay;
136a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	unsigned int count;
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int asyncflags;
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cflag;
1397bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	unsigned long statusflags;
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wait_queue_head_t open_wait;
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1427bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	u8 DCDState;
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 */
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TXSTOPPED	0x1
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LOWWAIT 	0x2
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define EMPTYWAIT	0x4
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define THROTTLE	0x8
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SERIAL_DO_RESTART
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define WAKEUP_CHARS		256
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ttymajor = MOXAMAJOR;
16474d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slabystatic struct mon_str moxaLog;
16574d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slabystatic unsigned int moxaFuncTout = HZ / 2;
1667bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slabystatic unsigned int moxaLowWaterChk;
167a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slabystatic DEFINE_MUTEX(moxa_openlock);
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Variables for insmod */
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef MODULE
170d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slabystatic unsigned long baseaddr[MAX_BOARDS];
171d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slabystatic unsigned int type[MAX_BOARDS];
172d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slabystatic unsigned int numports[MAX_BOARDS];
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("William Chen");
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("MOXA Intellio Family Multiport Board Device Driver");
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef MODULE
179d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slabymodule_param_array(type, uint, NULL, 0);
180d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri SlabyMODULE_PARM_DESC(type, "card type: C218=2, C320=4");
181d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slabymodule_param_array(baseaddr, ulong, NULL, 0);
182d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri SlabyMODULE_PARM_DESC(baseaddr, "base address");
183d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slabymodule_param_array(numports, uint, NULL, 0);
184d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri SlabyMODULE_PARM_DESC(numports, "numports (ignored for C218)");
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(ttymajor, int, 0);
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * static functions:
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int moxa_open(struct tty_struct *, struct file *);
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_close(struct tty_struct *, struct file *);
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int moxa_write(struct tty_struct *, const unsigned char *, int);
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int moxa_write_room(struct tty_struct *);
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_flush_buffer(struct tty_struct *);
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int moxa_chars_in_buffer(struct tty_struct *);
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_flush_chars(struct tty_struct *);
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_put_char(struct tty_struct *, unsigned char);
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_throttle(struct tty_struct *);
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_unthrottle(struct tty_struct *);
201606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Coxstatic void moxa_set_termios(struct tty_struct *, struct ktermios *);
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_stop(struct tty_struct *);
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_start(struct tty_struct *);
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_hangup(struct tty_struct *);
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int moxa_tiocmget(struct tty_struct *tty, struct file *file);
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int moxa_tiocmset(struct tty_struct *tty, struct file *file,
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 unsigned int set, unsigned int clear);
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_poll(unsigned long);
209db1acaa632870ec87b65e062bc72ca375837a1f6Alan Coxstatic void moxa_set_tty_param(struct tty_struct *, struct ktermios *);
2106f56b658b4e5c4486641ce62f331150954c4de37Jiri Slabystatic void moxa_setup_empty_event(struct tty_struct *);
2116f56b658b4e5c4486641ce62f331150954c4de37Jiri Slabystatic void moxa_shut_down(struct moxa_port *);
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * moxa board interface functions:
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
215b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic void MoxaPortEnable(struct moxa_port *);
216b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic void MoxaPortDisable(struct moxa_port *);
217b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic int MoxaPortSetTermio(struct moxa_port *, struct ktermios *, speed_t);
218b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic int MoxaPortGetLineOut(struct moxa_port *, int *, int *);
219b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic void MoxaPortLineCtrl(struct moxa_port *, int, int);
220b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic void MoxaPortFlowCtrl(struct moxa_port *, int, int, int, int, int);
221b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic int MoxaPortLineStatus(struct moxa_port *);
222b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic void MoxaPortFlushData(struct moxa_port *, int);
2232108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slabystatic int MoxaPortWriteData(struct moxa_port *, const unsigned char *, int);
2247bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slabystatic int MoxaPortReadData(struct moxa_port *);
225b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic int MoxaPortTxQueue(struct moxa_port *);
226b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic int MoxaPortRxQueue(struct moxa_port *);
227b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic int MoxaPortTxFree(struct moxa_port *);
228b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic void MoxaPortTxDisable(struct moxa_port *);
229b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic void MoxaPortTxEnable(struct moxa_port *);
2308f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slabystatic int moxa_get_serial_info(struct moxa_port *, struct serial_struct __user *);
2318f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slabystatic int moxa_set_serial_info(struct moxa_port *, struct serial_struct __user *);
232b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic void MoxaSetFifo(struct moxa_port *port, int enable);
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23474d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby/*
23574d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby * I/O functions
23674d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby */
23774d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby
23874d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slabystatic void moxa_wait_finish(void __iomem *ofsAddr)
23974d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby{
24074d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	unsigned long end = jiffies + moxaFuncTout;
24174d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby
24274d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	while (readw(ofsAddr + FuncCode) != 0)
24374d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		if (time_after(jiffies, end))
24474d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby			return;
24574d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	if (readw(ofsAddr + FuncCode) != 0 && printk_ratelimit())
24674d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		printk(KERN_WARNING "moxa function expired\n");
24774d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby}
24874d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby
24974d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slabystatic void moxafunc(void __iomem *ofsAddr, int cmd, ushort arg)
25074d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby{
25174d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	writew(arg, ofsAddr + FuncArg);
25274d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	writew(cmd, ofsAddr + FuncCode);
25374d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	moxa_wait_finish(ofsAddr);
25474d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby}
25574d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby
2567bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slabystatic void moxa_low_water_check(void __iomem *ofsAddr)
2577bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby{
2587bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	u16 rptr, wptr, mask, len;
2597bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby
2607bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	if (readb(ofsAddr + FlagStat) & Xoff_state) {
2617bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		rptr = readw(ofsAddr + RXrptr);
2627bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		wptr = readw(ofsAddr + RXwptr);
2637bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		mask = readw(ofsAddr + RX_mask);
2647bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		len = (wptr - rptr) & mask;
2657bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		if (len <= Low_water)
2667bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby			moxafunc(ofsAddr, FC_SendXon, 0);
2677bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	}
2687bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby}
2697bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby
27074d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby/*
27174d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby * TTY operations
27274d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby */
27374d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby
27474d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slabystatic int moxa_ioctl(struct tty_struct *tty, struct file *file,
27574d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		      unsigned int cmd, unsigned long arg)
27674d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby{
27774d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	struct moxa_port *ch = tty->driver_data;
27874d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	void __user *argp = (void __user *)arg;
279a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	int status, ret = 0;
28074d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby
28174d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	if (tty->index == MAX_PORTS) {
28274d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		if (cmd != MOXA_GETDATACOUNT && cmd != MOXA_GET_IOQUEUE &&
28374d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby				cmd != MOXA_GETMSTATUS)
28474d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby			return -EINVAL;
28574d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	} else if (!ch)
28674d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		return -ENODEV;
28774d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby
28874d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	switch (cmd) {
28974d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	case MOXA_GETDATACOUNT:
29074d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		moxaLog.tick = jiffies;
291a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		if (copy_to_user(argp, &moxaLog, sizeof(moxaLog)))
292a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby			ret = -EFAULT;
293a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		break;
29474d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	case MOXA_FLUSH_QUEUE:
29574d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		MoxaPortFlushData(ch, arg);
296a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		break;
29774d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	case MOXA_GET_IOQUEUE: {
29874d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		struct moxaq_str __user *argm = argp;
29974d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		struct moxaq_str tmp;
30074d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		struct moxa_port *p;
30174d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		unsigned int i, j;
30274d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby
303a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		mutex_lock(&moxa_openlock);
30474d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		for (i = 0; i < MAX_BOARDS; i++) {
30574d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby			p = moxa_boards[i].ports;
30674d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby			for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
30774d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby				memset(&tmp, 0, sizeof(tmp));
30874d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby				if (moxa_boards[i].ready) {
30974d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby					tmp.inq = MoxaPortRxQueue(p);
31074d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby					tmp.outq = MoxaPortTxQueue(p);
31174d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby				}
312a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby				if (copy_to_user(argm, &tmp, sizeof(tmp))) {
313a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby					mutex_unlock(&moxa_openlock);
31474d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby					return -EFAULT;
315a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby				}
31674d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby			}
31774d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		}
318a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		mutex_unlock(&moxa_openlock);
319a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		break;
32074d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	} case MOXA_GET_OQUEUE:
32174d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		status = MoxaPortTxQueue(ch);
322a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		ret = put_user(status, (unsigned long __user *)argp);
323a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		break;
32474d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	case MOXA_GET_IQUEUE:
32574d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		status = MoxaPortRxQueue(ch);
326a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		ret = put_user(status, (unsigned long __user *)argp);
327a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		break;
32874d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	case MOXA_GETMSTATUS: {
32974d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		struct mxser_mstatus __user *argm = argp;
33074d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		struct mxser_mstatus tmp;
33174d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		struct moxa_port *p;
33274d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		unsigned int i, j;
33374d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby
334a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		mutex_lock(&moxa_openlock);
33574d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		for (i = 0; i < MAX_BOARDS; i++) {
33674d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby			p = moxa_boards[i].ports;
33774d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby			for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
33874d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby				memset(&tmp, 0, sizeof(tmp));
33974d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby				if (!moxa_boards[i].ready)
34074d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby					goto copy;
34174d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby
34274d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby				status = MoxaPortLineStatus(p);
34374d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby				if (status & 1)
34474d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby					tmp.cts = 1;
34574d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby				if (status & 2)
34674d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby					tmp.dsr = 1;
34774d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby				if (status & 4)
34874d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby					tmp.dcd = 1;
34974d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby
35074d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby				if (!p->tty || !p->tty->termios)
35174d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby					tmp.cflag = p->cflag;
35274d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby				else
35374d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby					tmp.cflag = p->tty->termios->c_cflag;
35474d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slabycopy:
355a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby				if (copy_to_user(argm, &tmp, sizeof(tmp))) {
356a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby					mutex_unlock(&moxa_openlock);
35774d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby					return -EFAULT;
358a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby				}
35974d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby			}
36074d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		}
361a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		mutex_unlock(&moxa_openlock);
362a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		break;
36374d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	}
36474d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	case TIOCGSERIAL:
365a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		mutex_lock(&moxa_openlock);
366a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		ret = moxa_get_serial_info(ch, argp);
367a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		mutex_unlock(&moxa_openlock);
368a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		break;
36974d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	case TIOCSSERIAL:
370a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		mutex_lock(&moxa_openlock);
371a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		ret = moxa_set_serial_info(ch, argp);
372a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		mutex_unlock(&moxa_openlock);
373a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		break;
374a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	default:
375a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		ret = -ENOIOCTLCMD;
37674d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	}
377a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	return ret;
37874d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby}
37974d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby
38074d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slabystatic void moxa_break_ctl(struct tty_struct *tty, int state)
38174d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby{
38274d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	struct moxa_port *port = tty->driver_data;
38374d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby
38474d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	moxafunc(port->tableAddr, state ? FC_SendBreak : FC_StopBreak,
38574d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby			Magic_code);
38674d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby}
38774d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby
388b68e31d0ebbcc909d1941f9f230c9d062a3a13d3Jeff Dikestatic const struct tty_operations moxa_ops = {
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.open = moxa_open,
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.close = moxa_close,
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.write = moxa_write,
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.write_room = moxa_write_room,
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.flush_buffer = moxa_flush_buffer,
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.chars_in_buffer = moxa_chars_in_buffer,
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.flush_chars = moxa_flush_chars,
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.put_char = moxa_put_char,
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.ioctl = moxa_ioctl,
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.throttle = moxa_throttle,
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.unthrottle = moxa_unthrottle,
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_termios = moxa_set_termios,
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.stop = moxa_stop,
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.start = moxa_start,
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.hangup = moxa_hangup,
40474d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby	.break_ctl = moxa_break_ctl,
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.tiocmget = moxa_tiocmget,
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.tiocmset = moxa_tiocmset,
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
409aa7e5221fb47badbea618cc62704d6e4a4bcce15Jiri Slabystatic struct tty_driver *moxaDriver;
410aa7e5221fb47badbea618cc62704d6e4a4bcce15Jiri Slabystatic DEFINE_TIMER(moxaTimer, moxa_poll, 0, 0);
41134af946a22724c4e2b204957f2b24b22a0fb121cIngo Molnarstatic DEFINE_SPINLOCK(moxa_lock);
41233f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox
41374d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby/*
41474d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby * HW init
41574d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby */
41674d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby
417037182346f0991683cc7320a257c3f6089432ceeJiri Slabystatic int moxa_check_fw_model(struct moxa_board_conf *brd, u8 model)
418037182346f0991683cc7320a257c3f6089432ceeJiri Slaby{
419037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	switch (brd->boardType) {
420037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	case MOXA_BOARD_C218_ISA:
421037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	case MOXA_BOARD_C218_PCI:
422037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		if (model != 1)
423037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			goto err;
424037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		break;
425037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	case MOXA_BOARD_CP204J:
426037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		if (model != 3)
427037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			goto err;
428037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		break;
429037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	default:
430037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		if (model != 2)
431037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			goto err;
432037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		break;
433037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
434037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	return 0;
435037182346f0991683cc7320a257c3f6089432ceeJiri Slabyerr:
436037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	return -EINVAL;
437037182346f0991683cc7320a257c3f6089432ceeJiri Slaby}
438037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
439037182346f0991683cc7320a257c3f6089432ceeJiri Slabystatic int moxa_check_fw(const void *ptr)
440037182346f0991683cc7320a257c3f6089432ceeJiri Slaby{
441037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	const __le16 *lptr = ptr;
442037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
443037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (*lptr != cpu_to_le16(0x7980))
444037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		return -EINVAL;
445037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
446037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	return 0;
447037182346f0991683cc7320a257c3f6089432ceeJiri Slaby}
448037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
449037182346f0991683cc7320a257c3f6089432ceeJiri Slabystatic int moxa_load_bios(struct moxa_board_conf *brd, const u8 *buf,
450037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		size_t len)
451037182346f0991683cc7320a257c3f6089432ceeJiri Slaby{
452037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	void __iomem *baseAddr = brd->basemem;
453037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	u16 tmp;
454037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
455037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	writeb(HW_reset, baseAddr + Control_reg);	/* reset */
456037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	msleep(10);
457037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	memset_io(baseAddr, 0, 4096);
458037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	memcpy_toio(baseAddr, buf, len);	/* download BIOS */
459037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	writeb(0, baseAddr + Control_reg);	/* restart */
460037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
461037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	msleep(2000);
462037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
463037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	switch (brd->boardType) {
464037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	case MOXA_BOARD_C218_ISA:
465037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	case MOXA_BOARD_C218_PCI:
466037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		tmp = readw(baseAddr + C218_key);
467037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		if (tmp != C218_KeyCode)
468037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			goto err;
469037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		break;
470037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	case MOXA_BOARD_CP204J:
471037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		tmp = readw(baseAddr + C218_key);
472037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		if (tmp != CP204J_KeyCode)
473037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			goto err;
474037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		break;
475037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	default:
476037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		tmp = readw(baseAddr + C320_key);
477037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		if (tmp != C320_KeyCode)
478037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			goto err;
479037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		tmp = readw(baseAddr + C320_status);
480037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		if (tmp != STS_init) {
481037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			printk(KERN_ERR "moxa: bios upload failed -- CPU/Basic "
482037182346f0991683cc7320a257c3f6089432ceeJiri Slaby					"module not found\n");
483037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			return -EIO;
484037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		}
485037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		break;
486037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
487037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
488037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	return 0;
489037182346f0991683cc7320a257c3f6089432ceeJiri Slabyerr:
490037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	printk(KERN_ERR "moxa: bios upload failed -- board not found\n");
491037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	return -EIO;
492037182346f0991683cc7320a257c3f6089432ceeJiri Slaby}
493037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
494037182346f0991683cc7320a257c3f6089432ceeJiri Slabystatic int moxa_load_320b(struct moxa_board_conf *brd, const u8 *ptr,
495037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		size_t len)
496037182346f0991683cc7320a257c3f6089432ceeJiri Slaby{
497037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	void __iomem *baseAddr = brd->basemem;
498037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
499037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (len < 7168) {
500037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		printk(KERN_ERR "moxa: invalid 320 bios -- too short\n");
501037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		return -EINVAL;
502037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
503037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
504037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	writew(len - 7168 - 2, baseAddr + C320bapi_len);
505037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	writeb(1, baseAddr + Control_reg);	/* Select Page 1 */
506037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	memcpy_toio(baseAddr + DynPage_addr, ptr, 7168);
507037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	writeb(2, baseAddr + Control_reg);	/* Select Page 2 */
508037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	memcpy_toio(baseAddr + DynPage_addr, ptr + 7168, len - 7168);
509037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
510037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	return 0;
511037182346f0991683cc7320a257c3f6089432ceeJiri Slaby}
512037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
5135292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slabystatic int moxa_real_load_code(struct moxa_board_conf *brd, const void *ptr,
514037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		size_t len)
515037182346f0991683cc7320a257c3f6089432ceeJiri Slaby{
516037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	void __iomem *baseAddr = brd->basemem;
517037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	const u16 *uptr = ptr;
518037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	size_t wlen, len2, j;
5195292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby	unsigned long key, loadbuf, loadlen, checksum, checksum_ok;
5205292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby	unsigned int i, retry, c320;
521037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	u16 usum, keycode;
522037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
5235292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby	c320 = brd->boardType == MOXA_BOARD_C320_PCI ||
5245292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby			brd->boardType == MOXA_BOARD_C320_ISA;
5255292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby	keycode = (brd->boardType == MOXA_BOARD_CP204J) ? CP204J_KeyCode :
5265292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby				C218_KeyCode;
527037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
5285292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby	switch (brd->boardType) {
5295292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby	case MOXA_BOARD_CP204J:
5305292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby	case MOXA_BOARD_C218_ISA:
5315292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby	case MOXA_BOARD_C218_PCI:
5325292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		key = C218_key;
5335292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		loadbuf = C218_LoadBuf;
5345292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		loadlen = C218DLoad_len;
5355292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		checksum = C218check_sum;
5365292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		checksum_ok = C218chksum_ok;
5375292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		break;
5385292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby	default:
5395292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		key = C320_key;
5405292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		keycode = C320_KeyCode;
5415292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		loadbuf = C320_LoadBuf;
5425292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		loadlen = C320DLoad_len;
5435292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		checksum = C320check_sum;
5445292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		checksum_ok = C320chksum_ok;
5455292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		break;
546037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
547037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
548037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	usum = 0;
549037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	wlen = len >> 1;
550037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	for (i = 0; i < wlen; i++)
551037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		usum += le16_to_cpu(uptr[i]);
552037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	retry = 0;
553037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	do {
554037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		wlen = len >> 1;
555037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		j = 0;
556037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		while (wlen) {
557037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			len2 = (wlen > 2048) ? 2048 : wlen;
558037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			wlen -= len2;
5595292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby			memcpy_toio(baseAddr + loadbuf, ptr + j, len2 << 1);
560037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			j += len2 << 1;
5615292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby
5625292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby			writew(len2, baseAddr + loadlen);
5635292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby			writew(0, baseAddr + key);
5645292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby			for (i = 0; i < 100; i++) {
5655292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby				if (readw(baseAddr + key) == keycode)
566037182346f0991683cc7320a257c3f6089432ceeJiri Slaby					break;
567037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				msleep(10);
568037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			}
5695292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby			if (readw(baseAddr + key) != keycode)
570037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				return -EIO;
571037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		}
5725292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		writew(0, baseAddr + loadlen);
5735292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		writew(usum, baseAddr + checksum);
5745292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		writew(0, baseAddr + key);
5755292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		for (i = 0; i < 100; i++) {
5765292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby			if (readw(baseAddr + key) == keycode)
577037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				break;
578037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			msleep(10);
579037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		}
580037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		retry++;
5815292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby	} while ((readb(baseAddr + checksum_ok) != 1) && (retry < 3));
5825292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby	if (readb(baseAddr + checksum_ok) != 1)
583037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		return -EIO;
584037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
5855292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby	writew(0, baseAddr + key);
586037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	for (i = 0; i < 600; i++) {
587037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		if (readw(baseAddr + Magic_no) == Magic_code)
588037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			break;
589037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		msleep(10);
590037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
591037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (readw(baseAddr + Magic_no) != Magic_code)
592037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		return -EIO;
593037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
5945292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby	if (c320) {
5955292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		if (brd->busType == MOXA_BUS_TYPE_PCI) {	/* ASIC board */
5965292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby			writew(0x3800, baseAddr + TMS320_PORT1);
5975292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby			writew(0x3900, baseAddr + TMS320_PORT2);
5985292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby			writew(28499, baseAddr + TMS320_CLOCK);
5995292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		} else {
6005292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby			writew(0x3200, baseAddr + TMS320_PORT1);
6015292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby			writew(0x3400, baseAddr + TMS320_PORT2);
6025292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby			writew(19999, baseAddr + TMS320_CLOCK);
6035292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		}
604037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
605037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	writew(1, baseAddr + Disable_IRQ);
606037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	writew(0, baseAddr + Magic_no);
607037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	for (i = 0; i < 500; i++) {
608037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		if (readw(baseAddr + Magic_no) == Magic_code)
609037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			break;
610037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		msleep(10);
611037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
612037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (readw(baseAddr + Magic_no) != Magic_code)
613037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		return -EIO;
614037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
6155292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby	if (c320) {
6165292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		j = readw(baseAddr + Module_cnt);
6175292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		if (j <= 0)
6185292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby			return -EIO;
6195292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		brd->numPorts = j * 8;
6205292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		writew(j, baseAddr + Module_no);
6215292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		writew(0, baseAddr + Magic_no);
6225292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		for (i = 0; i < 600; i++) {
6235292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby			if (readw(baseAddr + Magic_no) == Magic_code)
6245292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby				break;
6255292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby			msleep(10);
6265292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		}
6275292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		if (readw(baseAddr + Magic_no) != Magic_code)
6285292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby			return -EIO;
629037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
630037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	brd->intNdx = baseAddr + IRQindex;
631037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	brd->intPend = baseAddr + IRQpending;
632037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	brd->intTable = baseAddr + IRQtable;
633037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
634037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	return 0;
635037182346f0991683cc7320a257c3f6089432ceeJiri Slaby}
636037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
637037182346f0991683cc7320a257c3f6089432ceeJiri Slabystatic int moxa_load_code(struct moxa_board_conf *brd, const void *ptr,
638037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		size_t len)
639037182346f0991683cc7320a257c3f6089432ceeJiri Slaby{
640037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	void __iomem *ofsAddr, *baseAddr = brd->basemem;
641037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	struct moxa_port *port;
642037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	int retval, i;
643037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
644037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (len % 2) {
6455292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		printk(KERN_ERR "moxa: bios length is not even\n");
646037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		return -EINVAL;
647037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
648037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
6495292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby	retval = moxa_real_load_code(brd, ptr, len); /* may change numPorts */
6505292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby	if (retval)
6515292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby		return retval;
6525292bcd38e4bcd147905941b5e37b5b0da1a5577Jiri Slaby
653037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	switch (brd->boardType) {
654037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	case MOXA_BOARD_C218_ISA:
655037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	case MOXA_BOARD_C218_PCI:
656037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	case MOXA_BOARD_CP204J:
657037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		port = brd->ports;
658037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		for (i = 0; i < brd->numPorts; i++, port++) {
659b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby			port->board = brd;
660037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			port->DCDState = 0;
661037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			port->tableAddr = baseAddr + Extern_table +
662037182346f0991683cc7320a257c3f6089432ceeJiri Slaby					Extern_size * i;
663037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			ofsAddr = port->tableAddr;
664037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			writew(C218rx_mask, ofsAddr + RX_mask);
665037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			writew(C218tx_mask, ofsAddr + TX_mask);
666037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			writew(C218rx_spage + i * C218buf_pageno, ofsAddr + Page_rxb);
667037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			writew(readw(ofsAddr + Page_rxb) + C218rx_pageno, ofsAddr + EndPage_rxb);
668037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
669037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			writew(C218tx_spage + i * C218buf_pageno, ofsAddr + Page_txb);
670037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			writew(readw(ofsAddr + Page_txb) + C218tx_pageno, ofsAddr + EndPage_txb);
671037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
672037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		}
673037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		break;
674037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	default:
675037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		port = brd->ports;
676037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		for (i = 0; i < brd->numPorts; i++, port++) {
677b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby			port->board = brd;
678037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			port->DCDState = 0;
679037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			port->tableAddr = baseAddr + Extern_table +
680037182346f0991683cc7320a257c3f6089432ceeJiri Slaby					Extern_size * i;
681037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			ofsAddr = port->tableAddr;
682037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			switch (brd->numPorts) {
683037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			case 8:
684037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p8rx_mask, ofsAddr + RX_mask);
685037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p8tx_mask, ofsAddr + TX_mask);
686037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p8rx_spage + i * C320p8buf_pgno, ofsAddr + Page_rxb);
687037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(readw(ofsAddr + Page_rxb) + C320p8rx_pgno, ofsAddr + EndPage_rxb);
688037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p8tx_spage + i * C320p8buf_pgno, ofsAddr + Page_txb);
689037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(readw(ofsAddr + Page_txb) + C320p8tx_pgno, ofsAddr + EndPage_txb);
690037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
691037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				break;
692037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			case 16:
693037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p16rx_mask, ofsAddr + RX_mask);
694037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p16tx_mask, ofsAddr + TX_mask);
695037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p16rx_spage + i * C320p16buf_pgno, ofsAddr + Page_rxb);
696037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(readw(ofsAddr + Page_rxb) + C320p16rx_pgno, ofsAddr + EndPage_rxb);
697037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p16tx_spage + i * C320p16buf_pgno, ofsAddr + Page_txb);
698037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(readw(ofsAddr + Page_txb) + C320p16tx_pgno, ofsAddr + EndPage_txb);
699037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				break;
700037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
701037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			case 24:
702037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p24rx_mask, ofsAddr + RX_mask);
703037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p24tx_mask, ofsAddr + TX_mask);
704037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p24rx_spage + i * C320p24buf_pgno, ofsAddr + Page_rxb);
705037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(readw(ofsAddr + Page_rxb) + C320p24rx_pgno, ofsAddr + EndPage_rxb);
706037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p24tx_spage + i * C320p24buf_pgno, ofsAddr + Page_txb);
707037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(readw(ofsAddr + Page_txb), ofsAddr + EndPage_txb);
708037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				break;
709037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			case 32:
710037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p32rx_mask, ofsAddr + RX_mask);
711037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p32tx_mask, ofsAddr + TX_mask);
712037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p32tx_ofs, ofsAddr + Ofs_txb);
713037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p32rx_spage + i * C320p32buf_pgno, ofsAddr + Page_rxb);
714037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(readb(ofsAddr + Page_rxb), ofsAddr + EndPage_rxb);
715037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p32tx_spage + i * C320p32buf_pgno, ofsAddr + Page_txb);
716037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(readw(ofsAddr + Page_txb), ofsAddr + EndPage_txb);
717037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				break;
718037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			}
719037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		}
720037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		break;
721037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
722037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	return 0;
723037182346f0991683cc7320a257c3f6089432ceeJiri Slaby}
724037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
725037182346f0991683cc7320a257c3f6089432ceeJiri Slabystatic int moxa_load_fw(struct moxa_board_conf *brd, const struct firmware *fw)
726037182346f0991683cc7320a257c3f6089432ceeJiri Slaby{
727037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	void *ptr = fw->data;
728037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	char rsn[64];
729037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	u16 lens[5];
730037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	size_t len;
731037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	unsigned int a, lenp, lencnt;
732037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	int ret = -EINVAL;
733037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	struct {
734037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		__le32 magic;	/* 0x34303430 */
735037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		u8 reserved1[2];
736037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		u8 type;	/* UNIX = 3 */
737037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		u8 model;	/* C218T=1, C320T=2, CP204=3 */
738037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		u8 reserved2[8];
739037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		__le16 len[5];
740037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	} *hdr = ptr;
741037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
742037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	BUILD_BUG_ON(ARRAY_SIZE(hdr->len) != ARRAY_SIZE(lens));
743037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
744037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (fw->size < MOXA_FW_HDRLEN) {
745037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		strcpy(rsn, "too short (even header won't fit)");
746037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		goto err;
747037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
748037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (hdr->magic != cpu_to_le32(0x30343034)) {
749037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		sprintf(rsn, "bad magic: %.8x", le32_to_cpu(hdr->magic));
750037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		goto err;
751037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
752037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (hdr->type != 3) {
753037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		sprintf(rsn, "not for linux, type is %u", hdr->type);
754037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		goto err;
755037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
756037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (moxa_check_fw_model(brd, hdr->model)) {
757037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		sprintf(rsn, "not for this card, model is %u", hdr->model);
758037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		goto err;
759037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
760037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
761037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	len = MOXA_FW_HDRLEN;
762037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	lencnt = hdr->model == 2 ? 5 : 3;
763037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	for (a = 0; a < ARRAY_SIZE(lens); a++) {
764037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		lens[a] = le16_to_cpu(hdr->len[a]);
765037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		if (lens[a] && len + lens[a] <= fw->size &&
766037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				moxa_check_fw(&fw->data[len]))
767037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			printk(KERN_WARNING "moxa firmware: unexpected input "
768037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				"at offset %u, but going on\n", (u32)len);
769037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		if (!lens[a] && a < lencnt) {
770037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			sprintf(rsn, "too few entries in fw file");
771037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			goto err;
772037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		}
773037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		len += lens[a];
774037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
775037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
776037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (len != fw->size) {
777037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		sprintf(rsn, "bad length: %u (should be %u)", (u32)fw->size,
778037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				(u32)len);
779037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		goto err;
780037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
781037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
782037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	ptr += MOXA_FW_HDRLEN;
783037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	lenp = 0; /* bios */
784037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
785037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	strcpy(rsn, "read above");
786037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
787037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	ret = moxa_load_bios(brd, ptr, lens[lenp]);
788037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (ret)
789037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		goto err;
790037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
791037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	/* we skip the tty section (lens[1]), since we don't need it */
792037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	ptr += lens[lenp] + lens[lenp + 1];
793037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	lenp += 2; /* comm */
794037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
795037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (hdr->model == 2) {
796037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		ret = moxa_load_320b(brd, ptr, lens[lenp]);
797037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		if (ret)
798037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			goto err;
799037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		/* skip another tty */
800037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		ptr += lens[lenp] + lens[lenp + 1];
801037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		lenp += 2;
802037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
803037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
804037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	ret = moxa_load_code(brd, ptr, lens[lenp]);
805037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (ret)
806037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		goto err;
807037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
808037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	return 0;
809037182346f0991683cc7320a257c3f6089432ceeJiri Slabyerr:
810037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	printk(KERN_ERR "firmware failed to load, reason: %s\n", rsn);
811037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	return ret;
812037182346f0991683cc7320a257c3f6089432ceeJiri Slaby}
813037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
814037182346f0991683cc7320a257c3f6089432ceeJiri Slabystatic int moxa_init_board(struct moxa_board_conf *brd, struct device *dev)
815037182346f0991683cc7320a257c3f6089432ceeJiri Slaby{
816037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	const struct firmware *fw;
817037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	const char *file;
818810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	struct moxa_port *p;
819810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	unsigned int i;
820037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	int ret;
821037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
822810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	brd->ports = kcalloc(MAX_PORTS_PER_BOARD, sizeof(*brd->ports),
823810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby			GFP_KERNEL);
824810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	if (brd->ports == NULL) {
825810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby		printk(KERN_ERR "cannot allocate memory for ports\n");
826810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby		ret = -ENOMEM;
827810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby		goto err;
828810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	}
829810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby
830810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	for (i = 0, p = brd->ports; i < MAX_PORTS_PER_BOARD; i++, p++) {
831810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby		p->type = PORT_16550A;
832810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby		p->close_delay = 5 * HZ / 10;
833810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby		p->cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
834810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby		init_waitqueue_head(&p->open_wait);
835810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	}
836810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby
837037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	switch (brd->boardType) {
838037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	case MOXA_BOARD_C218_ISA:
839037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	case MOXA_BOARD_C218_PCI:
840037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		file = "c218tunx.cod";
841037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		break;
842037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	case MOXA_BOARD_CP204J:
843037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		file = "cp204unx.cod";
844037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		break;
845037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	default:
846037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		file = "c320tunx.cod";
847037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		break;
848037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
849037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
850037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	ret = request_firmware(&fw, file, dev);
851037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (ret) {
852037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		printk(KERN_ERR "request_firmware failed\n");
853810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby		goto err_free;
854037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
855037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
856037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	ret = moxa_load_fw(brd, fw);
857037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
858037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	release_firmware(fw);
859810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby
860810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	if (ret)
861810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby		goto err_free;
862810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby
8632a5413416b6b2fd8a5a38601a4fe3b56a52cfb86Jiri Slaby	spin_lock_bh(&moxa_lock);
864810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	brd->ready = 1;
8650bcc4caadc8f5396b52950ee03c67b76875602dfJiri Slaby	if (!timer_pending(&moxaTimer))
8660bcc4caadc8f5396b52950ee03c67b76875602dfJiri Slaby		mod_timer(&moxaTimer, jiffies + HZ / 50);
8672a5413416b6b2fd8a5a38601a4fe3b56a52cfb86Jiri Slaby	spin_unlock_bh(&moxa_lock);
8680bcc4caadc8f5396b52950ee03c67b76875602dfJiri Slaby
869810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	return 0;
870810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slabyerr_free:
871810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	kfree(brd->ports);
872810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slabyerr:
873037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	return ret;
874037182346f0991683cc7320a257c3f6089432ceeJiri Slaby}
875037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
876810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slabystatic void moxa_board_deinit(struct moxa_board_conf *brd)
877810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby{
878a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	unsigned int a, opened;
879a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby
880a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	mutex_lock(&moxa_openlock);
8817bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	spin_lock_bh(&moxa_lock);
882810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	brd->ready = 0;
8837bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	spin_unlock_bh(&moxa_lock);
884a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby
885a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	/* pci hot-un-plug support */
886a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	for (a = 0; a < brd->numPorts; a++)
887a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		if (brd->ports[a].asyncflags & ASYNC_INITIALIZED)
888a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby			tty_hangup(brd->ports[a].tty);
889a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	while (1) {
890a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		opened = 0;
891a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		for (a = 0; a < brd->numPorts; a++)
892a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby			if (brd->ports[a].asyncflags & ASYNC_INITIALIZED)
893a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby				opened++;
894a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		mutex_unlock(&moxa_openlock);
895a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		if (!opened)
896a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby			break;
897a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		msleep(50);
898a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		mutex_lock(&moxa_openlock);
899a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	}
900a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby
901810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	iounmap(brd->basemem);
902810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	brd->basemem = NULL;
903810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	kfree(brd->ports);
904810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby}
905810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PCI
9079cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slabystatic int __devinit moxa_pci_probe(struct pci_dev *pdev,
9089cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby		const struct pci_device_id *ent)
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9109cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby	struct moxa_board_conf *board;
9119cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby	unsigned int i;
9129cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby	int board_type = ent->driver_data;
9139cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby	int retval;
9149cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby
9159cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby	retval = pci_enable_device(pdev);
9167aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby	if (retval) {
9177aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby		dev_err(&pdev->dev, "can't enable pci device\n");
9189cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby		goto err;
9197aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby	}
9209cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby
9219cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby	for (i = 0; i < MAX_BOARDS; i++)
9229cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby		if (moxa_boards[i].basemem == NULL)
9239cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby			break;
9249cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby
9259cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby	retval = -ENODEV;
9269cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby	if (i >= MAX_BOARDS) {
9277aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby		dev_warn(&pdev->dev, "more than %u MOXA Intellio family boards "
9289cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby				"found. Board is ignored.\n", MAX_BOARDS);
9299cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby		goto err;
9309cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby	}
9319cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby
9329cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby	board = &moxa_boards[i];
933e46a5e3ff06b70690d567bdc81faf6c1c32e742fJiri Slaby
934e46a5e3ff06b70690d567bdc81faf6c1c32e742fJiri Slaby	retval = pci_request_region(pdev, 2, "moxa-base");
935e46a5e3ff06b70690d567bdc81faf6c1c32e742fJiri Slaby	if (retval) {
936e46a5e3ff06b70690d567bdc81faf6c1c32e742fJiri Slaby		dev_err(&pdev->dev, "can't request pci region 2\n");
937e46a5e3ff06b70690d567bdc81faf6c1c32e742fJiri Slaby		goto err;
938e46a5e3ff06b70690d567bdc81faf6c1c32e742fJiri Slaby	}
939e46a5e3ff06b70690d567bdc81faf6c1c32e742fJiri Slaby
940e46a5e3ff06b70690d567bdc81faf6c1c32e742fJiri Slaby	board->basemem = ioremap(pci_resource_start(pdev, 2), 0x4000);
9417aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby	if (board->basemem == NULL) {
9427aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby		dev_err(&pdev->dev, "can't remap io space 2\n");
943e46a5e3ff06b70690d567bdc81faf6c1c32e742fJiri Slaby		goto err_reg;
9447aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby	}
9459cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	board->boardType = board_type;
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (board_type) {
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case MOXA_BOARD_C218_ISA:
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case MOXA_BOARD_C218_PCI:
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		board->numPorts = 8;
9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case MOXA_BOARD_CP204J:
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		board->numPorts = 4;
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		board->numPorts = 0;
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	board->busType = MOXA_BUS_TYPE_PCI;
961a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby
962037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	retval = moxa_init_board(board, &pdev->dev);
963037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (retval)
964037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		goto err_base;
965037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
9669cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby	pci_set_drvdata(pdev, board);
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (0);
969037182346f0991683cc7320a257c3f6089432ceeJiri Slabyerr_base:
970037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	iounmap(board->basemem);
971037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	board->basemem = NULL;
972e46a5e3ff06b70690d567bdc81faf6c1c32e742fJiri Slabyerr_reg:
973e46a5e3ff06b70690d567bdc81faf6c1c32e742fJiri Slaby	pci_release_region(pdev, 2);
9749cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slabyerr:
9759cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby	return retval;
9769cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby}
9779cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby
9789cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slabystatic void __devexit moxa_pci_remove(struct pci_dev *pdev)
9799cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby{
9809cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby	struct moxa_board_conf *brd = pci_get_drvdata(pdev);
9819cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby
982810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	moxa_board_deinit(brd);
983810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby
984e46a5e3ff06b70690d567bdc81faf6c1c32e742fJiri Slaby	pci_release_region(pdev, 2);
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
986a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby
987a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slabystatic struct pci_driver moxa_pci_driver = {
988a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby	.name = "moxa",
989a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby	.id_table = moxa_pcibrds,
990a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby	.probe = moxa_pci_probe,
991a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby	.remove = __devexit_p(moxa_pci_remove)
992a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby};
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_PCI */
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init moxa_init(void)
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
997810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	unsigned int isabrds = 0;
998d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby	int retval = 0;
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10007aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby	printk(KERN_INFO "MOXA Intellio family driver version %s\n",
10017aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby			MOXA_VERSION);
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxaDriver = alloc_tty_driver(MAX_PORTS + 1);
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!moxaDriver)
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxaDriver->owner = THIS_MODULE;
10079b4e3b13b147e9b737de63188a9ae740eaa8c36dSergey Vlasov	moxaDriver->name = "ttyMX";
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxaDriver->major = ttymajor;
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxaDriver->minor_start = 0;
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxaDriver->type = TTY_DRIVER_TYPE_SERIAL;
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxaDriver->subtype = SERIAL_TYPE_NORMAL;
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxaDriver->init_termios = tty_std_termios;
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxaDriver->init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
1014606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox	moxaDriver->init_termios.c_ispeed = 9600;
1015606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox	moxaDriver->init_termios.c_ospeed = 9600;
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxaDriver->flags = TTY_DRIVER_REAL_RAW;
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tty_set_operations(moxaDriver, &moxa_ops);
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10197aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby	pr_debug("Moxa tty devices major number = %d\n", ttymajor);
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tty_register_driver(moxaDriver)) {
10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "Couldn't install MOXA Smartio family driver !\n");
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		put_tty_driver(moxaDriver);
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1027d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby	/* Find the boards defined from module args. */
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef MODULE
1029d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby	{
1030d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby	struct moxa_board_conf *brd = moxa_boards;
1031810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	unsigned int i;
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < MAX_BOARDS; i++) {
1033d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby		if (!baseaddr[i])
1034d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby			break;
1035d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby		if (type[i] == MOXA_BOARD_C218_ISA ||
1036d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby				type[i] == MOXA_BOARD_C320_ISA) {
10377aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby			pr_debug("Moxa board %2d: %s board(baseAddr=%lx)\n",
1038d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby					isabrds + 1, moxa_brdname[type[i] - 1],
1039d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby					baseaddr[i]);
1040d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby			brd->boardType = type[i];
1041d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby			brd->numPorts = type[i] == MOXA_BOARD_C218_ISA ? 8 :
1042d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby					numports[i];
1043d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby			brd->busType = MOXA_BUS_TYPE_ISA;
1044d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby			brd->basemem = ioremap(baseaddr[i], 0x4000);
1045d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby			if (!brd->basemem) {
1046d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby				printk(KERN_ERR "moxa: can't remap %lx\n",
1047d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby						baseaddr[i]);
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				continue;
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
1050037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			if (moxa_init_board(brd, NULL)) {
1051037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				iounmap(brd->basemem);
1052037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				brd->basemem = NULL;
1053037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				continue;
1054037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			}
1055d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby
1056d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby			brd++;
1057d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby			isabrds++;
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1060d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby	}
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1062a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PCI
1064a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby	retval = pci_register_driver(&moxa_pci_driver);
1065a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby	if (retval) {
1066a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby		printk(KERN_ERR "Can't register moxa pci driver!\n");
1067d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby		if (isabrds)
1068a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby			retval = 0;
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1071a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby
1072a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby	return retval;
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit moxa_exit(void)
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10799cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby#ifdef CONFIG_PCI
1080a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby	pci_unregister_driver(&moxa_pci_driver);
10819cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby#endif
1082a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby
1083810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	for (i = 0; i < MAX_BOARDS; i++) /* ISA boards */
1084810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby		if (moxa_boards[i].ready)
1085810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby			moxa_board_deinit(&moxa_boards[i]);
10862a5413416b6b2fd8a5a38601a4fe3b56a52cfb86Jiri Slaby
10872a5413416b6b2fd8a5a38601a4fe3b56a52cfb86Jiri Slaby	del_timer_sync(&moxaTimer);
10882a5413416b6b2fd8a5a38601a4fe3b56a52cfb86Jiri Slaby
10892a5413416b6b2fd8a5a38601a4fe3b56a52cfb86Jiri Slaby	if (tty_unregister_driver(moxaDriver))
10902a5413416b6b2fd8a5a38601a4fe3b56a52cfb86Jiri Slaby		printk(KERN_ERR "Couldn't unregister MOXA Intellio family "
10912a5413416b6b2fd8a5a38601a4fe3b56a52cfb86Jiri Slaby				"serial driver\n");
10922a5413416b6b2fd8a5a38601a4fe3b56a52cfb86Jiri Slaby	put_tty_driver(moxaDriver);
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(moxa_init);
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(moxa_exit);
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1098a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slabystatic void moxa_close_port(struct moxa_port *ch)
1099a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby{
1100a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	moxa_shut_down(ch);
1101a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	MoxaPortFlushData(ch, 2);
1102a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
1103a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	ch->tty->driver_data = NULL;
1104a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	ch->tty = NULL;
1105a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby}
1106a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby
1107a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slabystatic int moxa_block_till_ready(struct tty_struct *tty, struct file *filp,
1108a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby			    struct moxa_port *ch)
1109a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby{
1110a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	DEFINE_WAIT(wait);
1111a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	int retval = 0;
1112a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	u8 dcd;
1113a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby
1114a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	while (1) {
1115a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		prepare_to_wait(&ch->open_wait, &wait, TASK_INTERRUPTIBLE);
1116a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		if (tty_hung_up_p(filp)) {
1117a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby#ifdef SERIAL_DO_RESTART
1118a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby			retval = -ERESTARTSYS;
1119a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby#else
1120a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby			retval = -EAGAIN;
1121a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby#endif
1122a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby			break;
1123a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		}
1124a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		spin_lock_bh(&moxa_lock);
1125a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		dcd = ch->DCDState;
1126a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		spin_unlock_bh(&moxa_lock);
1127a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		if (dcd)
1128a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby			break;
1129a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby
1130a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		if (signal_pending(current)) {
1131a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby			retval = -ERESTARTSYS;
1132a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby			break;
1133a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		}
1134a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		schedule();
1135a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	}
1136a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	finish_wait(&ch->open_wait, &wait);
1137a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby
1138a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	return retval;
1139a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby}
1140a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int moxa_open(struct tty_struct *tty, struct file *filp)
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1143810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	struct moxa_board_conf *brd;
11448f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	struct moxa_port *ch;
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int port;
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval;
11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
114811324edd4ad34981764b25bed44d46a1507b62e1Jiri Slaby	port = tty->index;
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (port == MAX_PORTS) {
115074d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		return capable(CAP_SYS_ADMIN) ? 0 : -EPERM;
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1152a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	if (mutex_lock_interruptible(&moxa_openlock))
1153a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		return -ERESTARTSYS;
1154810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	brd = &moxa_boards[port / MAX_PORTS_PER_BOARD];
1155a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	if (!brd->ready) {
1156a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		mutex_unlock(&moxa_openlock);
1157810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby		return -ENODEV;
1158a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	}
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1160810ab09b2f3a4e9a6f553e3d1e84a27f4074de9cJiri Slaby	ch = &brd->ports[port % MAX_PORTS_PER_BOARD];
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ch->count++;
11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tty->driver_data = ch;
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ch->tty = tty;
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(ch->asyncflags & ASYNC_INITIALIZED)) {
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ch->statusflags = 0;
1166db1acaa632870ec87b65e062bc72ca375837a1f6Alan Cox		moxa_set_tty_param(tty, tty->termios);
1167b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby		MoxaPortLineCtrl(ch, 1, 1);
1168b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby		MoxaPortEnable(ch);
1169a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		MoxaSetFifo(ch, ch->type == PORT_16550A);
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ch->asyncflags |= ASYNC_INITIALIZED;
11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1172a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	mutex_unlock(&moxa_openlock);
11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1174a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	retval = 0;
1175a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	if (!(filp->f_flags & O_NONBLOCK) && !C_CLOCAL(tty))
1176a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		retval = moxa_block_till_ready(tty, filp, ch);
1177a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	mutex_lock(&moxa_openlock);
1178a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	if (retval) {
1179a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		if (ch->count) /* 0 means already hung up... */
1180a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby			if (--ch->count == 0)
1181a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby				moxa_close_port(ch);
1182a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	} else
1183a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
1184a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	mutex_unlock(&moxa_openlock);
11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1186a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	return retval;
11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_close(struct tty_struct *tty, struct file *filp)
11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11918f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	struct moxa_port *ch;
11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int port;
11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
119411324edd4ad34981764b25bed44d46a1507b62e1Jiri Slaby	port = tty->index;
1195a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	if (port == MAX_PORTS || tty_hung_up_p(filp))
11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1198a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	mutex_lock(&moxa_openlock);
1199a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	ch = tty->driver_data;
1200a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	if (ch == NULL)
1201a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		goto unlock;
1202a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	if (tty->count == 1 && ch->count != 1) {
12037aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby		printk(KERN_WARNING "moxa_close: bad serial port count; "
12047aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby			"tty->count is 1, ch->count is %d\n", ch->count);
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ch->count = 1;
12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (--ch->count < 0) {
12087aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby		printk(KERN_WARNING "moxa_close: bad serial port count, "
12097aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby			"device=%s\n", tty->name);
12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ch->count = 0;
12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1212a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	if (ch->count)
1213a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		goto unlock;
12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ch->cflag = tty->termios->c_cflag;
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ch->asyncflags & ASYNC_INITIALIZED) {
12176f56b658b4e5c4486641ce62f331150954c4de37Jiri Slaby		moxa_setup_empty_event(tty);
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tty_wait_until_sent(tty, 30 * HZ);	/* 30 seconds timeout */
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1221a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	moxa_close_port(ch);
1222a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slabyunlock:
1223a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	mutex_unlock(&moxa_openlock);
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int moxa_write(struct tty_struct *tty,
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      const unsigned char *buf, int count)
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1229b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	struct moxa_port *ch = tty->driver_data;
1230b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	int len;
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ch == NULL)
1233b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby		return 0;
123433f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox
12357bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	spin_lock_bh(&moxa_lock);
12362108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby	len = MoxaPortWriteData(ch, buf, count);
12377bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	spin_unlock_bh(&moxa_lock);
12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*********************************************
12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ( !(ch->statusflags & LOWWAIT) &&
12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	     ((len != count) || (MoxaPortTxFree(port) <= 100)) )
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	************************************************/
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ch->statusflags |= LOWWAIT;
12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (len);
12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int moxa_write_room(struct tty_struct *tty)
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12498f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	struct moxa_port *ch;
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tty->stopped)
12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (0);
1253b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	ch = tty->driver_data;
12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ch == NULL)
12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (0);
1256b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	return MoxaPortTxFree(ch);
12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_flush_buffer(struct tty_struct *tty)
12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1261b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	struct moxa_port *ch = tty->driver_data;
12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ch == NULL)
12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
1265b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	MoxaPortFlushData(ch, 1);
12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tty_wakeup(tty);
12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int moxa_chars_in_buffer(struct tty_struct *tty)
12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1271b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	struct moxa_port *ch = tty->driver_data;
12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int chars;
12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Sigh...I have to check if driver_data is NULL here, because
12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * if an open() fails, the TTY subsystem eventually calls
12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * tty_wait_until_sent(), which calls the driver's chars_in_buffer()
12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * routine.  And since the open() failed, we return 0 here.  TDJ
12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ch == NULL)
12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (0);
1282b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	chars = MoxaPortTxQueue(ch);
12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (chars) {
12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Make it possible to wakeup anything waiting for output
12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * in tty_ioctl.c, etc.
12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(ch->statusflags & EMPTYWAIT))
12896f56b658b4e5c4486641ce62f331150954c4de37Jiri Slaby			moxa_setup_empty_event(tty);
12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (chars);
12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_flush_chars(struct tty_struct *tty)
12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Don't think I need this, because this is called to empty the TX
12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * buffer for the 16450, 16550, etc.
12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_put_char(struct tty_struct *tty, unsigned char c)
13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1304b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	struct moxa_port *ch = tty->driver_data;
13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ch == NULL)
13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
13087bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	spin_lock_bh(&moxa_lock);
1309b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	MoxaPortWriteData(ch, &c, 1);
13107bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	spin_unlock_bh(&moxa_lock);
13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/************************************************
13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ( !(ch->statusflags & LOWWAIT) && (MoxaPortTxFree(port) <= 100) )
13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*************************************************/
13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ch->statusflags |= LOWWAIT;
13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int moxa_tiocmget(struct tty_struct *tty, struct file *file)
13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1319a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	struct moxa_port *ch;
13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int flag = 0, dtr, rts;
13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1322a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	mutex_lock(&moxa_openlock);
1323a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	ch = tty->driver_data;
1324a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	if (!ch) {
1325a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		mutex_unlock(&moxa_openlock);
132674d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		return -EINVAL;
1327a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	}
13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1329b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	MoxaPortGetLineOut(ch, &dtr, &rts);
13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dtr)
13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flag |= TIOCM_DTR;
13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rts)
13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flag |= TIOCM_RTS;
1334b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	dtr = MoxaPortLineStatus(ch);
13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dtr & 1)
13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flag |= TIOCM_CTS;
13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dtr & 2)
13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flag |= TIOCM_DSR;
13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dtr & 4)
13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flag |= TIOCM_CD;
1341a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	mutex_unlock(&moxa_openlock);
13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return flag;
13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int moxa_tiocmset(struct tty_struct *tty, struct file *file,
13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 unsigned int set, unsigned int clear)
13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1348a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	struct moxa_port *ch;
13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int port;
13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int dtr, rts;
13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
135211324edd4ad34981764b25bed44d46a1507b62e1Jiri Slaby	port = tty->index;
1353a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	mutex_lock(&moxa_openlock);
1354a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	ch = tty->driver_data;
1355a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	if (!ch) {
1356a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		mutex_unlock(&moxa_openlock);
135774d7d97b9e2a090a4b1812b5074ac6c539234ebbJiri Slaby		return -EINVAL;
1358a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	}
13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1360b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	MoxaPortGetLineOut(ch, &dtr, &rts);
13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (set & TIOCM_RTS)
13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rts = 1;
13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (set & TIOCM_DTR)
13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dtr = 1;
13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clear & TIOCM_RTS)
13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rts = 0;
13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clear & TIOCM_DTR)
13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dtr = 0;
1369b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	MoxaPortLineCtrl(ch, dtr, rts);
1370a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	mutex_unlock(&moxa_openlock);
13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_throttle(struct tty_struct *tty)
13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13768f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ch->statusflags |= THROTTLE;
13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_unthrottle(struct tty_struct *tty)
13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13838f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ch->statusflags &= ~THROTTLE;
13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_set_termios(struct tty_struct *tty,
1389606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox			     struct ktermios *old_termios)
13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13918f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ch == NULL)
13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
1395db1acaa632870ec87b65e062bc72ca375837a1f6Alan Cox	moxa_set_tty_param(tty, old_termios);
13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(old_termios->c_cflag & CLOCAL) &&
13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (tty->termios->c_cflag & CLOCAL))
13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		wake_up_interruptible(&ch->open_wait);
13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_stop(struct tty_struct *tty)
14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14038f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ch == NULL)
14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
1407b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	MoxaPortTxDisable(ch);
14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ch->statusflags |= TXSTOPPED;
14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_start(struct tty_struct *tty)
14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14148f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ch == NULL)
14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(ch->statusflags & TXSTOPPED))
14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1422b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	MoxaPortTxEnable(ch);
14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ch->statusflags &= ~TXSTOPPED;
14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_hangup(struct tty_struct *tty)
14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1428a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	struct moxa_port *ch;
14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1430a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	mutex_lock(&moxa_openlock);
1431a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	ch = tty->driver_data;
1432a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	if (ch == NULL) {
1433a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		mutex_unlock(&moxa_openlock);
1434a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		return;
1435a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	}
14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ch->count = 0;
1437a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	moxa_close_port(ch);
1438a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	mutex_unlock(&moxa_openlock);
1439a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby
14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wake_up_interruptible(&ch->open_wait);
14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14437bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slabystatic void moxa_new_dcdstate(struct moxa_port *p, u8 dcd)
14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14457bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	dcd = !!dcd;
14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14477bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	if ((dcd != p->DCDState) && p->tty && C_CLOCAL(p->tty)) {
1448a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby		if (!dcd)
14497bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby			tty_hangup(p->tty);
14507bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	}
14517bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	p->DCDState = dcd;
14527bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby}
14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14547bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slabystatic int moxa_poll_port(struct moxa_port *p, unsigned int handle,
14557bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		u16 __iomem *ip)
14567bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby{
14577bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	struct tty_struct *tty = p->tty;
14587bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	void __iomem *ofsAddr;
14597bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	unsigned int inited = p->asyncflags & ASYNC_INITIALIZED;
14607bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	u16 intr;
14617bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby
14627bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	if (tty) {
14637bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		if ((p->statusflags & EMPTYWAIT) &&
14647bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby				MoxaPortTxQueue(p) == 0) {
14657bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby			p->statusflags &= ~EMPTYWAIT;
14667bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby			tty_wakeup(tty);
14677bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		}
14687bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		if ((p->statusflags & LOWWAIT) && !tty->stopped &&
14697bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby				MoxaPortTxQueue(p) <= WAKEUP_CHARS) {
14707bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby			p->statusflags &= ~LOWWAIT;
14717bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby			tty_wakeup(tty);
14727bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		}
14737bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby
14747bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		if (inited && !(p->statusflags & THROTTLE) &&
14757bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby				MoxaPortRxQueue(p) > 0) { /* RX */
14767bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby			MoxaPortReadData(p);
14777bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby			tty_schedule_flip(tty);
14787bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		}
14797bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	} else {
14807bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		p->statusflags &= ~EMPTYWAIT;
14817bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		MoxaPortFlushData(p, 0); /* flush RX */
14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14830bcc4caadc8f5396b52950ee03c67b76875602dfJiri Slaby
14847bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	if (!handle) /* nothing else to do */
14857bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		return 0;
14867bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby
14877bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	intr = readw(ip); /* port irq status */
14887bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	if (intr == 0)
14897bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		return 0;
14907bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby
14917bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	writew(0, ip); /* ACK port */
14927bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	ofsAddr = p->tableAddr;
14937bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	if (intr & IntrTx) /* disable tx intr */
14947bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		writew(readw(ofsAddr + HostStat) & ~WakeupTx,
14957bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby				ofsAddr + HostStat);
14967bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby
14977bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	if (!inited)
14987bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		return 0;
14997bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby
15007bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	if (tty && (intr & IntrBreak) && !I_IGNBRK(tty)) { /* BREAK */
15017bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		tty_insert_flip_char(tty, 0, TTY_BREAK);
15027bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		tty_schedule_flip(tty);
15037bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	}
15047bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby
15057bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	if (intr & IntrLine)
15067bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		moxa_new_dcdstate(p, readb(ofsAddr + FlagStat) & DCD_state);
15077bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby
15087bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	return 0;
15097bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby}
15107bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby
15117bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slabystatic void moxa_poll(unsigned long ignored)
15127bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby{
15137bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	struct moxa_board_conf *brd;
15147bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	u16 __iomem *ip;
15152a5413416b6b2fd8a5a38601a4fe3b56a52cfb86Jiri Slaby	unsigned int card, port, served = 0;
15167bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby
15177bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	spin_lock(&moxa_lock);
15181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (card = 0; card < MAX_BOARDS; card++) {
15197bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		brd = &moxa_boards[card];
15207bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		if (!brd->ready)
15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
15227bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby
15232a5413416b6b2fd8a5a38601a4fe3b56a52cfb86Jiri Slaby		served++;
15242a5413416b6b2fd8a5a38601a4fe3b56a52cfb86Jiri Slaby
15257bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		ip = NULL;
15267bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		if (readb(brd->intPend) == 0xff)
15277bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby			ip = brd->intTable + readb(brd->intNdx);
15287bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby
15297bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		for (port = 0; port < brd->numPorts; port++)
15307bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby			moxa_poll_port(&brd->ports[port], !!ip, ip + port);
15317bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby
15327bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		if (ip)
15337bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby			writeb(0, brd->intPend); /* ACK */
15347bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby
15357bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby		if (moxaLowWaterChk) {
15367bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby			struct moxa_port *p = brd->ports;
15377bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby			for (port = 0; port < brd->numPorts; port++, p++)
15387bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby				if (p->lowChkFlag) {
15397bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby					p->lowChkFlag = 0;
15407bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby					moxa_low_water_check(p->tableAddr);
15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15447bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	moxaLowWaterChk = 0;
15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15462a5413416b6b2fd8a5a38601a4fe3b56a52cfb86Jiri Slaby	if (served)
15472a5413416b6b2fd8a5a38601a4fe3b56a52cfb86Jiri Slaby		mod_timer(&moxaTimer, jiffies + HZ / 50);
15482a5413416b6b2fd8a5a38601a4fe3b56a52cfb86Jiri Slaby	spin_unlock(&moxa_lock);
15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/******************************************************************************/
15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1553db1acaa632870ec87b65e062bc72ca375837a1f6Alan Coxstatic void moxa_set_tty_param(struct tty_struct *tty, struct ktermios *old_termios)
15541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1555606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox	register struct ktermios *ts;
15568f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	struct moxa_port *ch;
1557db1acaa632870ec87b65e062bc72ca375837a1f6Alan Cox	int rts, cts, txflow, rxflow, xany, baud;
15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15598f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	ch = (struct moxa_port *) tty->driver_data;
15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ts = tty->termios;
15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rts = cts = txflow = rxflow = xany = 0;
15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ts->c_cflag & CRTSCTS)
15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rts = cts = 1;
15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ts->c_iflag & IXON)
15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		txflow = 1;
15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ts->c_iflag & IXOFF)
15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rxflow = 1;
15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ts->c_iflag & IXANY)
15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		xany = 1;
1570db1acaa632870ec87b65e062bc72ca375837a1f6Alan Cox
1571db1acaa632870ec87b65e062bc72ca375837a1f6Alan Cox	/* Clear the features we don't support */
1572db1acaa632870ec87b65e062bc72ca375837a1f6Alan Cox	ts->c_cflag &= ~CMSPAR;
1573b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	MoxaPortFlowCtrl(ch, rts, cts, txflow, rxflow, xany);
1574b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	baud = MoxaPortSetTermio(ch, ts, tty_get_baud_rate(tty));
1575db1acaa632870ec87b65e062bc72ca375837a1f6Alan Cox	if (baud == -1)
1576db1acaa632870ec87b65e062bc72ca375837a1f6Alan Cox		baud = tty_termios_baud_rate(old_termios);
1577db1acaa632870ec87b65e062bc72ca375837a1f6Alan Cox	/* Not put the baud rate into the termios data */
1578db1acaa632870ec87b65e062bc72ca375837a1f6Alan Cox	tty_encode_baud_rate(tty, baud, baud);
15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15816f56b658b4e5c4486641ce62f331150954c4de37Jiri Slabystatic void moxa_setup_empty_event(struct tty_struct *tty)
15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15838f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	struct moxa_port *ch = tty->driver_data;
15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15857bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	spin_lock_bh(&moxa_lock);
15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ch->statusflags |= EMPTYWAIT;
15877bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	spin_unlock_bh(&moxa_lock);
15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15906f56b658b4e5c4486641ce62f331150954c4de37Jiri Slabystatic void moxa_shut_down(struct moxa_port *ch)
15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1592a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	struct tty_struct *tp = ch->tty;
15931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(ch->asyncflags & ASYNC_INITIALIZED))
15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1597b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	MoxaPortDisable(ch);
15981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * If we're a modem control device and HUPCL is on, drop RTS & DTR.
16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1602a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	if (C_HUPCL(tp))
1603b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby		MoxaPortLineCtrl(ch, 0, 0);
16041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1605a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	spin_lock_bh(&moxa_lock);
16061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ch->asyncflags &= ~ASYNC_INITIALIZED;
1607a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	spin_unlock_bh(&moxa_lock);
16081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************
16111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Driver level functions: 					     *
16121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *****************************************************************************/
16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1614b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic void MoxaPortFlushData(struct moxa_port *port, int mode)
16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *ofsAddr;
16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((mode < 0) || (mode > 2))
16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
1619b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	ofsAddr = port->tableAddr;
16201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxafunc(ofsAddr, FC_FlushQueue, mode);
16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mode != 1) {
1622b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby		port->lowChkFlag = 0;
16236f56b658b4e5c4486641ce62f331150954c4de37Jiri Slaby		moxa_low_water_check(ofsAddr);
16241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
16251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************
16281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Port level functions:						     *
16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	2.  MoxaPortEnable(int port);					     *
16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	3.  MoxaPortDisable(int port);					     *
16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	4.  MoxaPortGetMaxBaud(int port);				     *
16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	6.  MoxaPortSetBaud(int port, long baud);			     *
16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	8.  MoxaPortSetTermio(int port, unsigned char *termio); 	     *
16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	9.  MoxaPortGetLineOut(int port, int *dtrState, int *rtsState);      *
16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	10. MoxaPortLineCtrl(int port, int dtrState, int rtsState);	     *
16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	11. MoxaPortFlowCtrl(int port, int rts, int cts, int rx, int tx,int xany);    *
16371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	12. MoxaPortLineStatus(int port);				     *
16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	15. MoxaPortFlushData(int port, int mode);	                     *
16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	16. MoxaPortWriteData(int port, unsigned char * buffer, int length); *
164033f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox *	17. MoxaPortReadData(int port, struct tty_struct *tty); 	     *
16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	20. MoxaPortTxQueue(int port);					     *
16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	21. MoxaPortTxFree(int port);					     *
16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	22. MoxaPortRxQueue(int port);					     *
16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	24. MoxaPortTxDisable(int port);				     *
16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	25. MoxaPortTxEnable(int port); 				     *
16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	27. MoxaPortResetBrkCnt(int port);				     *
16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *****************************************************************************/
16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
16491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Moxa Port Number Description:
16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      MOXA serial driver supports up to 4 MOXA-C218/C320 boards. And,
16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      the port number using in MOXA driver functions will be 0 to 31 for
16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      first MOXA board, 32 to 63 for second, 64 to 95 for third and 96
16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      to 127 for fourth. For example, if you setup three MOXA boards,
16551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      first board is C218, second board is C320-16 and third board is
16561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      C320-32. The port number of first board (C218 - 8 ports) is from
16571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      0 to 7. The port number of second board (C320 - 16 ports) is form
16581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      32 to 47. The port number of third board (C320 - 32 ports) is from
16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      64 to 95. And those port numbers form 8 to 31, 48 to 63 and 96 to
16601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      127 will be invalid.
16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Moxa Functions Description:
16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 1:     Driver initialization routine, this routine must be
16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                      called when initialized driver.
16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      void MoxaDriverInit();
16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 2:     Moxa driver private IOCTL command processing.
16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      int  MoxaDriverIoctl(unsigned int cmd, unsigned long arg, int port);
16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           unsigned int cmd   : IOCTL command
16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           unsigned long arg  : IOCTL argument
16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           return:    0  (OK)
16801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                      -EINVAL
16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                      -ENOIOCTLCMD
16821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 6:     Enable this port to start Tx/Rx data.
16851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
16861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      void MoxaPortEnable(int port);
16871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
16881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 7:     Disable this port
16911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
16921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      void MoxaPortDisable(int port);
16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
16941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 8:     Get the maximun available baud rate of this port.
16971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
16981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      long MoxaPortGetMaxBaud(int port);
16991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           return:    0       : this port is invalid
17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                      38400/57600/115200 bps
17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
17051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 10:    Setting baud rate of this port.
17061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
17071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      long MoxaPortSetBaud(int port, long baud);
17081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           long baud          : baud rate (50 - 115200)
17101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
17111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           return:    0       : this port is invalid or baud < 50
17121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                      50 - 115200 : the real baud rate set to the port, if
17131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                                    the argument baud is large than maximun
17141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                                    available baud rate, the real setting
17151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                                    baud rate will be the maximun baud rate.
17161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
17171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
17181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 12:    Configure the port.
17191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
1720606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox *      int  MoxaPortSetTermio(int port, struct ktermios *termio, speed_t baud);
17211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
1722606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox *           struct ktermios * termio : termio structure pointer
1723c7bce3097c0f9bbed76ee6fd03742f2624031a45Alan Cox *	     speed_t baud	: baud rate
17241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
17251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           return:    -1      : this port is invalid or termio == NULL
17261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                      0       : setting O.K.
17271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 13:    Get the DTR/RTS state of this port.
17301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
17311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      int  MoxaPortGetLineOut(int port, int *dtrState, int *rtsState);
17321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
17331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int * dtrState     : pointer to INT to receive the current DTR
17341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                                state. (if NULL, this function will not
17351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                                write to this address)
17361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int * rtsState     : pointer to INT to receive the current RTS
17371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                                state. (if NULL, this function will not
17381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                                write to this address)
17391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
17401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           return:    -1      : this port is invalid
17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                      0       : O.K.
17421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
17441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 14:    Setting the DTR/RTS output state of this port.
17451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
17461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      void MoxaPortLineCtrl(int port, int dtrState, int rtsState);
17471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int dtrState       : DTR output state (0: off, 1: on)
17491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int rtsState       : RTS output state (0: off, 1: on)
17501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
17511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
17521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 15:    Setting the flow control of this port.
17531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
17541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      void MoxaPortFlowCtrl(int port, int rtsFlow, int ctsFlow, int rxFlow,
17551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                            int txFlow,int xany);
17561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
17571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int rtsFlow        : H/W RTS flow control (0: no, 1: yes)
17581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int ctsFlow        : H/W CTS flow control (0: no, 1: yes)
17591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int rxFlow         : S/W Rx XON/XOFF flow control (0: no, 1: yes)
17601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int txFlow         : S/W Tx XON/XOFF flow control (0: no, 1: yes)
17611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int xany           : S/W XANY flow control (0: no, 1: yes)
17621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
17631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
17641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 16:    Get ths line status of this port
17651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
17661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      int  MoxaPortLineStatus(int port);
17671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
17681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
17691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           return:    Bit 0 - CTS state (0: off, 1: on)
17701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                      Bit 1 - DSR state (0: off, 1: on)
17711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                      Bit 2 - DCD state (0: off, 1: on)
17721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
17731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
17741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 19:    Flush the Rx/Tx buffer data of this port.
17751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
17761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      void MoxaPortFlushData(int port, int mode);
17771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
17781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int mode
17791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                      0       : flush the Rx buffer
17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                      1       : flush the Tx buffer
17811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                      2       : flush the Rx and Tx buffer
17821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
17841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 20:    Write data.
17851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      int  MoxaPortWriteData(int port, unsigned char * buffer, int length);
17871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           unsigned char * buffer     : pointer to write data buffer.
17891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int length         : write data length
17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
17911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           return:    0 - length      : real write data length
17921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
17931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
17941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 21:    Read data.
17951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
179633f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox *      int  MoxaPortReadData(int port, struct tty_struct *tty);
17971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
179833f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox *	     struct tty_struct *tty : tty for data
17991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           return:    0 - length      : real read data length
18011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 24:    Get the Tx buffer current queued data bytes
18041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
18051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      int  MoxaPortTxQueue(int port);
18061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
18071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           return:    ..      : Tx buffer current queued data bytes
18091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 25:    Get the Tx buffer current free space
18121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
18131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      int  MoxaPortTxFree(int port);
18141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
18151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           return:    ..      : Tx buffer current free space
18171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 26:    Get the Rx buffer current queued data bytes
18201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
18211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      int  MoxaPortRxQueue(int port);
18221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
18231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           return:    ..      : Rx buffer current queued data bytes
18251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 28:    Disable port data transmission.
18281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
18291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      void MoxaPortTxDisable(int port);
18301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
18311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 29:    Enable port data transmission.
18341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
18351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      void MoxaPortTxEnable(int port);
18361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
18371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 31:    Get the received BREAK signal count and reset it.
18401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
18411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      int  MoxaPortResetBrkCnt(int port);
18421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
18431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           return:    0 - ..  : BREAK signal count
18451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
18481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1849b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic void MoxaPortEnable(struct moxa_port *port)
18501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
18511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *ofsAddr;
18521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	short lowwater = 512;
18531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1854b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	ofsAddr = port->tableAddr;
18551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writew(lowwater, ofsAddr + Low_water);
1856b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	if (port->board->boardType == MOXA_BOARD_C320_ISA ||
1857b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	    port->board->boardType == MOXA_BOARD_C320_PCI) {
18581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		moxafunc(ofsAddr, FC_SetBreakIrq, 0);
18591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
18601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writew(readw(ofsAddr + HostStat) | WakeupBreak, ofsAddr + HostStat);
18611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
18621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxafunc(ofsAddr, FC_SetLineIrq, Magic_code);
18641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxafunc(ofsAddr, FC_FlushQueue, 2);
18651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxafunc(ofsAddr, FC_EnableCH, Magic_code);
18671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MoxaPortLineStatus(port);
18681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1870b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic void MoxaPortDisable(struct moxa_port *port)
18711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1872b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	void __iomem *ofsAddr = port->tableAddr;
18731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxafunc(ofsAddr, FC_SetFlowCtl, 0);	/* disable flow control */
18751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxafunc(ofsAddr, FC_ClrLineIrq, Magic_code);
18761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writew(0, ofsAddr + HostStat);
18771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxafunc(ofsAddr, FC_DisableCH, Magic_code);
18781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1880b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic long MoxaPortGetMaxBaud(struct moxa_port *port)
18811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1882b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	if (port->board->boardType == MOXA_BOARD_C320_ISA ||
1883b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby			port->board->boardType == MOXA_BOARD_C320_PCI)
18841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (460800L);
18851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
18861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (921600L);
18871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1890b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic long MoxaPortSetBaud(struct moxa_port *port, long baud)
18911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
18921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *ofsAddr;
18931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	long max, clock;
18941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int val;
18951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((baud < 50L) || ((max = MoxaPortGetMaxBaud(port)) == 0))
18971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (0);
1898b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	ofsAddr = port->tableAddr;
18991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (baud > max)
19001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		baud = max;
19011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (max == 38400L)
19021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		clock = 614400L;	/* for 9.8304 Mhz : max. 38400 bps */
19031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (max == 57600L)
19041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		clock = 691200L;	/* for 11.0592 Mhz : max. 57600 bps */
19051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
19061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		clock = 921600L;	/* for 14.7456 Mhz : max. 115200 bps */
19071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = clock / baud;
19081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxafunc(ofsAddr, FC_SetBaud, val);
19091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	baud = clock / val;
19101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (baud);
19111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
19121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1913b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic int MoxaPortSetTermio(struct moxa_port *port, struct ktermios *termio,
1914b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby		speed_t baud)
19151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
19161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *ofsAddr;
19171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcflag_t cflag;
19181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcflag_t mode = 0;
19191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1920b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	ofsAddr = port->tableAddr;
19211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cflag = termio->c_cflag;	/* termio->c_cflag */
19221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mode = termio->c_cflag & CSIZE;
19241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mode == CS5)
19251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mode = MX_CS5;
19261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (mode == CS6)
19271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mode = MX_CS6;
19281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (mode == CS7)
19291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mode = MX_CS7;
19301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (mode == CS8)
19311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mode = MX_CS8;
19321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (termio->c_cflag & CSTOPB) {
19341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (mode == MX_CS5)
19351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mode |= MX_STOP15;
19361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
19371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mode |= MX_STOP2;
19381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
19391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mode |= MX_STOP1;
19401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (termio->c_cflag & PARENB) {
19421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (termio->c_cflag & PARODD)
19431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mode |= MX_PARODD;
19441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
19451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mode |= MX_PAREVEN;
19461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
19471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mode |= MX_PARNONE;
19481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxafunc(ofsAddr, FC_SetDataMode, (ushort) mode);
19501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1951b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	if (port->board->boardType == MOXA_BOARD_C320_ISA ||
1952b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby			port->board->boardType == MOXA_BOARD_C320_PCI) {
1953c7bce3097c0f9bbed76ee6fd03742f2624031a45Alan Cox		if (baud >= 921600L)
19541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return (-1);
19551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1956db1acaa632870ec87b65e062bc72ca375837a1f6Alan Cox	baud = MoxaPortSetBaud(port, baud);
19571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (termio->c_iflag & (IXON | IXOFF | IXANY)) {
19591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writeb(termio->c_cc[VSTART], ofsAddr + FuncArg);
19601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writeb(termio->c_cc[VSTOP], ofsAddr + FuncArg1);
19611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writeb(FC_SetXonXoff, ofsAddr + FuncCode);
19626f56b658b4e5c4486641ce62f331150954c4de37Jiri Slaby		moxa_wait_finish(ofsAddr);
19631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1965db1acaa632870ec87b65e062bc72ca375837a1f6Alan Cox	return (baud);
19661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
19671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1968b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic int MoxaPortGetLineOut(struct moxa_port *port, int *dtrState,
1969b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby		int *rtsState)
19701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
19711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1972b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	if (dtrState)
1973b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby		*dtrState = !!(port->lineCtrl & DTR_ON);
1974b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	if (rtsState)
1975b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby		*rtsState = !!(port->lineCtrl & RTS_ON);
1976b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby
19771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (0);
19781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
19791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1980b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic void MoxaPortLineCtrl(struct moxa_port *port, int dtr, int rts)
19811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1982b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	int mode = 0;
19831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dtr)
19851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mode |= DTR_ON;
19861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rts)
19871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mode |= RTS_ON;
1988b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	port->lineCtrl = mode;
1989b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	moxafunc(port->tableAddr, FC_LineControl, mode);
19901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
19911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1992b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic void MoxaPortFlowCtrl(struct moxa_port *port, int rts, int cts,
1993b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby		int txflow, int rxflow, int txany)
19941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1995b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	int mode = 0;
19961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rts)
19981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mode |= RTS_FlowCtl;
19991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cts)
20001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mode |= CTS_FlowCtl;
20011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (txflow)
20021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mode |= Tx_FlowCtl;
20031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rxflow)
20041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mode |= Rx_FlowCtl;
20051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (txany)
20061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mode |= IXM_IXANY;
2007b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	moxafunc(port->tableAddr, FC_SetFlowCtl, mode);
20081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2010b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic int MoxaPortLineStatus(struct moxa_port *port)
20111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
20121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *ofsAddr;
20131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int val;
20141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2015b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	ofsAddr = port->tableAddr;
2016b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	if (port->board->boardType == MOXA_BOARD_C320_ISA ||
2017b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby			port->board->boardType == MOXA_BOARD_C320_PCI) {
20181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		moxafunc(ofsAddr, FC_LineStatus, 0);
20191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val = readw(ofsAddr + FuncArg);
20201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
20211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val = readw(ofsAddr + FlagStat) >> 4;
20221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
20231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val &= 0x0B;
20247bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	if (val & 8)
20251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val |= 4;
2026a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	spin_lock_bh(&moxa_lock);
20277bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	moxa_new_dcdstate(port, val & 8);
2028a8f5cda067e2eeefe49fe386caf0f61fc5c825e0Jiri Slaby	spin_unlock_bh(&moxa_lock);
20291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val &= 7;
20307bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	return val;
20311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20332108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slabystatic int MoxaPortWriteData(struct moxa_port *port,
20342108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby		const unsigned char *buffer, int len)
20351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
20361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *baseAddr, *ofsAddr, *ofs;
20372108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby	unsigned int c, total;
20382108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby	u16 head, tail, tx_mask, spage, epage;
20392108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby	u16 pageno, pageofs, bufhead;
20401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2041b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	ofsAddr = port->tableAddr;
2042b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	baseAddr = port->board->basemem;
20431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tx_mask = readw(ofsAddr + TX_mask);
20441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spage = readw(ofsAddr + Page_txb);
20451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	epage = readw(ofsAddr + EndPage_txb);
20461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tail = readw(ofsAddr + TXwptr);
20471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	head = readw(ofsAddr + TXrptr);
20482108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby	c = (head > tail) ? (head - tail - 1) : (head - tail + tx_mask);
20491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (c > len)
20501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		c = len;
2051b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	moxaLog.txcnt[port->tty->index] += c;
20521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	total = c;
20531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (spage == epage) {
20541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bufhead = readw(ofsAddr + Ofs_txb);
20551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writew(spage, baseAddr + Control_reg);
20561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (c > 0) {
20571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (head > tail)
20581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				len = head - tail - 1;
20591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else
20601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				len = tx_mask + 1 - tail;
20611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			len = (c > len) ? len : c;
20621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ofs = baseAddr + DynPage_addr + bufhead + tail;
20632108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby			memcpy_toio(ofs, buffer, len);
20642108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby			buffer += len;
20651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tail = (tail + len) & tx_mask;
20661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			c -= len;
20671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
20681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
20691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pageno = spage + (tail >> 13);
20701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pageofs = tail & Page_mask;
20712108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby		while (c > 0) {
20722108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby			len = Page_size - pageofs;
20732108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby			if (len > c)
20742108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby				len = c;
20751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			writeb(pageno, baseAddr + Control_reg);
20761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ofs = baseAddr + DynPage_addr + pageofs;
20772108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby			memcpy_toio(ofs, buffer, len);
20782108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby			buffer += len;
20791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (++pageno == epage)
20801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pageno = spage;
20811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pageofs = 0;
20822108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby			c -= len;
20832108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby		}
20842108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby		tail = (tail + total) & tx_mask;
20851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
20862108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby	writew(tail, ofsAddr + TXwptr);
20871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writeb(1, ofsAddr + CD180TXirq);	/* start to send */
20882108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby	return total;
20891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20917bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slabystatic int MoxaPortReadData(struct moxa_port *port)
20921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
20937bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	struct tty_struct *tty = port->tty;
20942108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby	unsigned char *dst;
20951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *baseAddr, *ofsAddr, *ofs;
20962108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby	unsigned int count, len, total;
20972108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby	u16 tail, rx_mask, spage, epage;
20982108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby	u16 pageno, pageofs, bufhead, head;
20991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2100b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	ofsAddr = port->tableAddr;
2101b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	baseAddr = port->board->basemem;
21021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	head = readw(ofsAddr + RXrptr);
21031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tail = readw(ofsAddr + RXwptr);
21041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rx_mask = readw(ofsAddr + RX_mask);
21051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spage = readw(ofsAddr + Page_rxb);
21061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	epage = readw(ofsAddr + EndPage_rxb);
21072108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby	count = (tail >= head) ? (tail - head) : (tail - head + rx_mask + 1);
21081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (count == 0)
210933f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox		return 0;
21101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
211133f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox	total = count;
21127bcf97d1dd88135b58c7adb7c3bfebab55b21a20Jiri Slaby	moxaLog.rxcnt[tty->index] += total;
21131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (spage == epage) {
21141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bufhead = readw(ofsAddr + Ofs_rxb);
21151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writew(spage, baseAddr + Control_reg);
21161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (count > 0) {
21171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ofs = baseAddr + DynPage_addr + bufhead + head;
21182108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby			len = (tail >= head) ? (tail - head) :
21192108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby					(rx_mask + 1 - head);
21202108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby			len = tty_prepare_flip_string(tty, &dst,
21212108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby					min(len, count));
21222108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby			memcpy_fromio(dst, ofs, len);
21231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			head = (head + len) & rx_mask;
21241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			count -= len;
21251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
21261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
21271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pageno = spage + (head >> 13);
21281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pageofs = head & Page_mask;
21292108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby		while (count > 0) {
21301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			writew(pageno, baseAddr + Control_reg);
21311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ofs = baseAddr + DynPage_addr + pageofs;
21322108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby			len = tty_prepare_flip_string(tty, &dst,
21332108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby					min(Page_size - pageofs, count));
21342108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby			memcpy_fromio(dst, ofs, len);
21352108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby
21362108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby			count -= len;
21372108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby			pageofs = (pageofs + len) & Page_mask;
21382108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby			if (pageofs == 0 && ++pageno == epage)
21391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pageno = spage;
21402108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby		}
21412108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby		head = (head + total) & rx_mask;
21421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
21432108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby	writew(head, ofsAddr + RXrptr);
21442108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby	if (readb(ofsAddr + FlagStat) & Xoff_state) {
21451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		moxaLowWaterChk = 1;
2146b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby		port->lowChkFlag = 1;
21471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
21482108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby	return total;
21491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
21501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2152b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic int MoxaPortTxQueue(struct moxa_port *port)
21531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2154b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	void __iomem *ofsAddr = port->tableAddr;
21552108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby	u16 rptr, wptr, mask;
21561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rptr = readw(ofsAddr + TXrptr);
21581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wptr = readw(ofsAddr + TXwptr);
21591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mask = readw(ofsAddr + TX_mask);
21602108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby	return (wptr - rptr) & mask;
21611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
21621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2163b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic int MoxaPortTxFree(struct moxa_port *port)
21641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2165b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	void __iomem *ofsAddr = port->tableAddr;
21662108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby	u16 rptr, wptr, mask;
21671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rptr = readw(ofsAddr + TXrptr);
21691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wptr = readw(ofsAddr + TXwptr);
21701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mask = readw(ofsAddr + TX_mask);
21712108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby	return mask - ((wptr - rptr) & mask);
21721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
21731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2174b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic int MoxaPortRxQueue(struct moxa_port *port)
21751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2176b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	void __iomem *ofsAddr = port->tableAddr;
21772108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby	u16 rptr, wptr, mask;
21781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rptr = readw(ofsAddr + RXrptr);
21801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wptr = readw(ofsAddr + RXwptr);
21811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mask = readw(ofsAddr + RX_mask);
21822108eba5c531c12f5ae2ed2ef4cee7bf4246897bJiri Slaby	return (wptr - rptr) & mask;
21831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
21841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2185b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic void MoxaPortTxDisable(struct moxa_port *port)
21861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2187b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	moxafunc(port->tableAddr, FC_SetXoffState, Magic_code);
21881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
21891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2190b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic void MoxaPortTxEnable(struct moxa_port *port)
21911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2192b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	moxafunc(port->tableAddr, FC_SetXonState, Magic_code);
21931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
21941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21958f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slabystatic int moxa_get_serial_info(struct moxa_port *info,
21961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				struct serial_struct __user *retinfo)
21971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
21981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct serial_struct tmp;
21991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(&tmp, 0, sizeof(tmp));
22011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp.type = info->type;
2202b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	tmp.line = info->tty->index;
22031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp.port = 0;
22041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp.irq = 0;
22051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp.flags = info->asyncflags;
22061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp.baud_base = 921600;
22071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp.close_delay = info->close_delay;
22081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp.custom_divisor = 0;
22091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp.hub6 = 0;
22101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
22111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
22121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (0);
22131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
22141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22168f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slabystatic int moxa_set_serial_info(struct moxa_port *info,
22171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				struct serial_struct __user *new_info)
22181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
22191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct serial_struct new_serial;
22201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(copy_from_user(&new_serial, new_info, sizeof(new_serial)))
22221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
22231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((new_serial.irq != 0) ||
22251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (new_serial.port != 0) ||
22261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds//           (new_serial.type != info->type) ||
22271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (new_serial.custom_divisor != 0) ||
22281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (new_serial.baud_base != 921600))
22291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (-EPERM);
22301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!capable(CAP_SYS_ADMIN)) {
22321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (((new_serial.flags & ~ASYNC_USR_MASK) !=
22331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     (info->asyncflags & ~ASYNC_USR_MASK)))
22341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return (-EPERM);
22351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
22361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info->close_delay = new_serial.close_delay * HZ / 100;
22371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
22381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	new_serial.flags = (new_serial.flags & ~ASYNC_FLAGS);
22401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	new_serial.flags |= (info->asyncflags & ASYNC_FLAGS);
22411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (new_serial.type == PORT_16550A) {
2243b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby		MoxaSetFifo(info, 1);
22441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
2245b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby		MoxaSetFifo(info, 0);
22461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
22471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->type = new_serial.type;
22491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (0);
22501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
22511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************
22551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Static local functions: 					     *
22561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *****************************************************************************/
22571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2258b4173f45758a5b5185acb302c507289e661d9419Jiri Slabystatic void MoxaSetFifo(struct moxa_port *port, int enable)
22591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2260b4173f45758a5b5185acb302c507289e661d9419Jiri Slaby	void __iomem *ofsAddr = port->tableAddr;
22611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!enable) {
22631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		moxafunc(ofsAddr, FC_SetRxFIFOTrig, 0);
22641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		moxafunc(ofsAddr, FC_SetTxFIFOCnt, 1);
22651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
22661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		moxafunc(ofsAddr, FC_SetRxFIFOTrig, 3);
22671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		moxafunc(ofsAddr, FC_SetTxFIFOCnt, 16);
22681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
22691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2270