moxa.c revision 037182346f0991683cc7320a257c3f6089432cee
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>
4595e0791480af8347460d0cbe34a46eca7e77d0d0Jiri Slaby#include <linux/completion.h>
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/system.h>
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h>
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
51037182346f0991683cc7320a257c3f6089432ceeJiri Slaby#include "moxa.h"
52037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
5311324edd4ad34981764b25bed44d46a1507b62e1Jiri Slaby#define MOXA_VERSION		"5.1k"
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
55037182346f0991683cc7320a257c3f6089432ceeJiri Slaby#define MOXA_FW_HDRLEN		32
56037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
5711324edd4ad34981764b25bed44d46a1507b62e1Jiri Slaby#define MOXAMAJOR		172
5811324edd4ad34981764b25bed44d46a1507b62e1Jiri Slaby#define MOXACUMAJOR		173
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6011324edd4ad34981764b25bed44d46a1507b62e1Jiri Slaby#define MAX_BOARDS		4	/* Don't change this value */
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MAX_PORTS_PER_BOARD	32	/* Don't change this value */
6211324edd4ad34981764b25bed44d46a1507b62e1Jiri Slaby#define MAX_PORTS		(MAX_BOARDS * MAX_PORTS_PER_BOARD)
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Define the Moxa PCI vendor and device IDs.
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
6711324edd4ad34981764b25bed44d46a1507b62e1Jiri Slaby#define MOXA_BUS_TYPE_ISA	0
6811324edd4ad34981764b25bed44d46a1507b62e1Jiri Slaby#define MOXA_BUS_TYPE_PCI	1
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum {
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MOXA_BOARD_C218_PCI = 1,
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MOXA_BOARD_C218_ISA,
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MOXA_BOARD_C320_PCI,
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MOXA_BOARD_C320_ISA,
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MOXA_BOARD_CP204J,
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char *moxa_brdname[] =
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"C218 Turbo PCI series",
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"C218 Turbo ISA series",
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"C320 Turbo PCI series",
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"C320 Turbo ISA series",
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"CP-204J series",
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PCI
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pci_device_id moxa_pcibrds[] = {
895ebb4078af0dab866fdf57f84f72b9e9a7e8c6b8Jiri Slaby	{ PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C218),
905ebb4078af0dab866fdf57f84f72b9e9a7e8c6b8Jiri Slaby		.driver_data = MOXA_BOARD_C218_PCI },
915ebb4078af0dab866fdf57f84f72b9e9a7e8c6b8Jiri Slaby	{ PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C320),
925ebb4078af0dab866fdf57f84f72b9e9a7e8c6b8Jiri Slaby		.driver_data = MOXA_BOARD_C320_PCI },
935ebb4078af0dab866fdf57f84f72b9e9a7e8c6b8Jiri Slaby	{ PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP204J),
945ebb4078af0dab866fdf57f84f72b9e9a7e8c6b8Jiri Slaby		.driver_data = MOXA_BOARD_CP204J },
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0 }
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DEVICE_TABLE(pci, moxa_pcibrds);
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_PCI */
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
100037182346f0991683cc7320a257c3f6089432ceeJiri Slabystruct moxa_port;
101037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
1028f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slabystatic struct moxa_board_conf {
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int boardType;
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int numPorts;
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int busType;
1068f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby
1078f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	int loadstat;
1088f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby
109037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	struct moxa_port *ports;
110037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
1118f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	void __iomem *basemem;
1128f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	void __iomem *intNdx;
1138f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	void __iomem *intPend;
1148f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	void __iomem *intTable;
1158f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby} moxa_boards[MAX_BOARDS];
1168f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby
1178f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slabystruct mxser_mstatus {
1188f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	tcflag_t cflag;
1198f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	int cts;
1208f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	int dsr;
1218f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	int ri;
1228f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	int dcd;
1239dff89cd82af7bccc706fed288b1c33a51c3b937Jiri Slaby};
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1258f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slabystruct moxaq_str {
1268f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	int inq;
1278f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	int outq;
1288f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby};
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1308f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slabystruct moxa_port {
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int type;
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int port;
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int close_delay;
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned short closing_wait;
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int count;
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int blocked_open;
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	long event; /* long req'd for set_bit --RR */
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int asyncflags;
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long statusflags;
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tty_struct *tty;
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cflag;
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wait_queue_head_t open_wait;
14395e0791480af8347460d0cbe34a46eca7e77d0d0Jiri Slaby	struct completion close_wait;
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1458f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	struct timer_list emptyTimer;
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1478f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	char chkPort;
1488f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	char lineCtrl;
1498f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	void __iomem *tableAddr;
1508f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	long curBaud;
1518f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	char DCDState;
1528f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	char lowChkFlag;
1538f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby
1548f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	ushort breakCnt;
1558f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby};
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* statusflags */
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TXSTOPPED	0x1
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LOWWAIT 	0x2
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define EMPTYWAIT	0x4
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define THROTTLE	0x8
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SERIAL_DO_RESTART
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define WAKEUP_CHARS		256
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ttymajor = MOXAMAJOR;
168037182346f0991683cc7320a257c3f6089432ceeJiri Slabystatic int moxaCard;
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Variables for insmod */
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef MODULE
171d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slabystatic unsigned long baseaddr[MAX_BOARDS];
172d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slabystatic unsigned int type[MAX_BOARDS];
173d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slabystatic unsigned int numports[MAX_BOARDS];
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("William Chen");
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("MOXA Intellio Family Multiport Board Device Driver");
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef MODULE
180d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slabymodule_param_array(type, uint, NULL, 0);
181d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri SlabyMODULE_PARM_DESC(type, "card type: C218=2, C320=4");
182d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slabymodule_param_array(baseaddr, ulong, NULL, 0);
183d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri SlabyMODULE_PARM_DESC(baseaddr, "base address");
184d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slabymodule_param_array(numports, uint, NULL, 0);
185d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri SlabyMODULE_PARM_DESC(numports, "numports (ignored for C218)");
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(ttymajor, int, 0);
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * static functions:
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int moxa_open(struct tty_struct *, struct file *);
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_close(struct tty_struct *, struct file *);
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int moxa_write(struct tty_struct *, const unsigned char *, int);
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int moxa_write_room(struct tty_struct *);
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_flush_buffer(struct tty_struct *);
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int moxa_chars_in_buffer(struct tty_struct *);
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_flush_chars(struct tty_struct *);
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_put_char(struct tty_struct *, unsigned char);
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int moxa_ioctl(struct tty_struct *, struct file *, unsigned int, unsigned long);
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_throttle(struct tty_struct *);
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_unthrottle(struct tty_struct *);
203606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Coxstatic void moxa_set_termios(struct tty_struct *, struct ktermios *);
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_stop(struct tty_struct *);
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_start(struct tty_struct *);
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_hangup(struct tty_struct *);
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int moxa_tiocmget(struct tty_struct *tty, struct file *file);
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int moxa_tiocmset(struct tty_struct *tty, struct file *file,
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 unsigned int set, unsigned int clear);
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_poll(unsigned long);
211db1acaa632870ec87b65e062bc72ca375837a1f6Alan Coxstatic void moxa_set_tty_param(struct tty_struct *, struct ktermios *);
2126f56b658b4e5c4486641ce62f331150954c4de37Jiri Slabystatic int moxa_block_till_ready(struct tty_struct *, struct file *,
2138f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby			    struct moxa_port *);
2146f56b658b4e5c4486641ce62f331150954c4de37Jiri Slabystatic void moxa_setup_empty_event(struct tty_struct *);
2156f56b658b4e5c4486641ce62f331150954c4de37Jiri Slabystatic void moxa_check_xmit_empty(unsigned long);
2166f56b658b4e5c4486641ce62f331150954c4de37Jiri Slabystatic void moxa_shut_down(struct moxa_port *);
2176f56b658b4e5c4486641ce62f331150954c4de37Jiri Slabystatic void moxa_receive_data(struct moxa_port *);
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * moxa board interface functions:
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int MoxaDriverIoctl(unsigned int, unsigned long, int);
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int MoxaDriverPoll(void);
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int MoxaPortsOfCard(int);
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int MoxaPortIsValid(int);
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void MoxaPortEnable(int);
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void MoxaPortDisable(int);
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic long MoxaPortGetMaxBaud(int);
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic long MoxaPortSetBaud(int, long);
229606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Coxstatic int MoxaPortSetTermio(int, struct ktermios *, speed_t);
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int MoxaPortGetLineOut(int, int *, int *);
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void MoxaPortLineCtrl(int, int, int);
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void MoxaPortFlowCtrl(int, int, int, int, int, int);
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int MoxaPortLineStatus(int);
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int MoxaPortDCDChange(int);
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int MoxaPortDCDON(int);
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void MoxaPortFlushData(int, int);
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int MoxaPortWriteData(int, unsigned char *, int);
23833f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Coxstatic int MoxaPortReadData(int, struct tty_struct *tty);
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int MoxaPortTxQueue(int);
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int MoxaPortRxQueue(int);
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int MoxaPortTxFree(int);
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void MoxaPortTxDisable(int);
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void MoxaPortTxEnable(int);
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int MoxaPortResetBrkCnt(int);
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void MoxaPortSendBreak(int, int);
2468f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slabystatic int moxa_get_serial_info(struct moxa_port *, struct serial_struct __user *);
2478f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slabystatic int moxa_set_serial_info(struct moxa_port *, struct serial_struct __user *);
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void MoxaSetFifo(int port, int enable);
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
250b68e31d0ebbcc909d1941f9f230c9d062a3a13d3Jeff Dikestatic const struct tty_operations moxa_ops = {
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.open = moxa_open,
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.close = moxa_close,
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.write = moxa_write,
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.write_room = moxa_write_room,
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.flush_buffer = moxa_flush_buffer,
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.chars_in_buffer = moxa_chars_in_buffer,
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.flush_chars = moxa_flush_chars,
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.put_char = moxa_put_char,
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.ioctl = moxa_ioctl,
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.throttle = moxa_throttle,
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.unthrottle = moxa_unthrottle,
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_termios = moxa_set_termios,
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.stop = moxa_stop,
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.start = moxa_start,
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.hangup = moxa_hangup,
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.tiocmget = moxa_tiocmget,
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.tiocmset = moxa_tiocmset,
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
270aa7e5221fb47badbea618cc62704d6e4a4bcce15Jiri Slabystatic struct tty_driver *moxaDriver;
2718f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slabystatic struct moxa_port moxa_ports[MAX_PORTS];
272aa7e5221fb47badbea618cc62704d6e4a4bcce15Jiri Slabystatic DEFINE_TIMER(moxaTimer, moxa_poll, 0, 0);
27334af946a22724c4e2b204957f2b24b22a0fb121cIngo Molnarstatic DEFINE_SPINLOCK(moxa_lock);
27433f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox
275037182346f0991683cc7320a257c3f6089432ceeJiri Slabystatic int moxa_check_fw_model(struct moxa_board_conf *brd, u8 model)
276037182346f0991683cc7320a257c3f6089432ceeJiri Slaby{
277037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	switch (brd->boardType) {
278037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	case MOXA_BOARD_C218_ISA:
279037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	case MOXA_BOARD_C218_PCI:
280037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		if (model != 1)
281037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			goto err;
282037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		break;
283037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	case MOXA_BOARD_CP204J:
284037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		if (model != 3)
285037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			goto err;
286037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		break;
287037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	default:
288037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		if (model != 2)
289037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			goto err;
290037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		break;
291037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
292037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	return 0;
293037182346f0991683cc7320a257c3f6089432ceeJiri Slabyerr:
294037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	return -EINVAL;
295037182346f0991683cc7320a257c3f6089432ceeJiri Slaby}
296037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
297037182346f0991683cc7320a257c3f6089432ceeJiri Slabystatic int moxa_check_fw(const void *ptr)
298037182346f0991683cc7320a257c3f6089432ceeJiri Slaby{
299037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	const __le16 *lptr = ptr;
300037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
301037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (*lptr != cpu_to_le16(0x7980))
302037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		return -EINVAL;
303037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
304037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	return 0;
305037182346f0991683cc7320a257c3f6089432ceeJiri Slaby}
306037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
307037182346f0991683cc7320a257c3f6089432ceeJiri Slabystatic int moxa_load_bios(struct moxa_board_conf *brd, const u8 *buf,
308037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		size_t len)
309037182346f0991683cc7320a257c3f6089432ceeJiri Slaby{
310037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	void __iomem *baseAddr = brd->basemem;
311037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	u16 tmp;
312037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
313037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	writeb(HW_reset, baseAddr + Control_reg);	/* reset */
314037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	msleep(10);
315037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	memset_io(baseAddr, 0, 4096);
316037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	memcpy_toio(baseAddr, buf, len);	/* download BIOS */
317037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	writeb(0, baseAddr + Control_reg);	/* restart */
318037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
319037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	msleep(2000);
320037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
321037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	switch (brd->boardType) {
322037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	case MOXA_BOARD_C218_ISA:
323037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	case MOXA_BOARD_C218_PCI:
324037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		tmp = readw(baseAddr + C218_key);
325037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		if (tmp != C218_KeyCode)
326037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			goto err;
327037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		break;
328037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	case MOXA_BOARD_CP204J:
329037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		tmp = readw(baseAddr + C218_key);
330037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		if (tmp != CP204J_KeyCode)
331037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			goto err;
332037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		break;
333037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	default:
334037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		tmp = readw(baseAddr + C320_key);
335037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		if (tmp != C320_KeyCode)
336037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			goto err;
337037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		tmp = readw(baseAddr + C320_status);
338037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		if (tmp != STS_init) {
339037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			printk(KERN_ERR "moxa: bios upload failed -- CPU/Basic "
340037182346f0991683cc7320a257c3f6089432ceeJiri Slaby					"module not found\n");
341037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			return -EIO;
342037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		}
343037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		break;
344037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
345037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
346037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	return 0;
347037182346f0991683cc7320a257c3f6089432ceeJiri Slabyerr:
348037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	printk(KERN_ERR "moxa: bios upload failed -- board not found\n");
349037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	return -EIO;
350037182346f0991683cc7320a257c3f6089432ceeJiri Slaby}
351037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
352037182346f0991683cc7320a257c3f6089432ceeJiri Slabystatic int moxa_load_320b(struct moxa_board_conf *brd, const u8 *ptr,
353037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		size_t len)
354037182346f0991683cc7320a257c3f6089432ceeJiri Slaby{
355037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	void __iomem *baseAddr = brd->basemem;
356037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
357037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (len < 7168) {
358037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		printk(KERN_ERR "moxa: invalid 320 bios -- too short\n");
359037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		return -EINVAL;
360037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
361037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
362037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	writew(len - 7168 - 2, baseAddr + C320bapi_len);
363037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	writeb(1, baseAddr + Control_reg);	/* Select Page 1 */
364037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	memcpy_toio(baseAddr + DynPage_addr, ptr, 7168);
365037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	writeb(2, baseAddr + Control_reg);	/* Select Page 2 */
366037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	memcpy_toio(baseAddr + DynPage_addr, ptr + 7168, len - 7168);
367037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
368037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	return 0;
369037182346f0991683cc7320a257c3f6089432ceeJiri Slaby}
370037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
371037182346f0991683cc7320a257c3f6089432ceeJiri Slabystatic int moxa_load_c218(struct moxa_board_conf *brd, const void *ptr,
372037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		size_t len)
373037182346f0991683cc7320a257c3f6089432ceeJiri Slaby{
374037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	void __iomem *baseAddr = brd->basemem;
375037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	const u16 *uptr = ptr;
376037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	size_t wlen, len2, j;
377037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	unsigned int i, retry;
378037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	u16 usum, keycode;
379037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
380037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (brd->boardType == MOXA_BOARD_CP204J)
381037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		keycode = CP204J_KeyCode;
382037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	else
383037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		keycode = C218_KeyCode;
384037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	usum = 0;
385037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	wlen = len >> 1;
386037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	for (i = 0; i < wlen; i++)
387037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		usum += le16_to_cpu(uptr[i]);
388037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	retry = 0;
389037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	do {
390037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		wlen = len >> 1;
391037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		j = 0;
392037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		while (wlen) {
393037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			len2 = (wlen > 2048) ? 2048 : wlen;
394037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			wlen -= len2;
395037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			memcpy_toio(baseAddr + C218_LoadBuf, ptr + j,
396037182346f0991683cc7320a257c3f6089432ceeJiri Slaby					len2 << 1);
397037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			j += len2 << 1;
398037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
399037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			writew(len2, baseAddr + C218DLoad_len);
400037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			writew(0, baseAddr + C218_key);
401037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			for (i = 0; i < 100; i++) {
402037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				if (readw(baseAddr + C218_key) == keycode)
403037182346f0991683cc7320a257c3f6089432ceeJiri Slaby					break;
404037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				msleep(10);
405037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			}
406037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			if (readw(baseAddr + C218_key) != keycode)
407037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				return -EIO;
408037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		}
409037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		writew(0, baseAddr + C218DLoad_len);
410037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		writew(usum, baseAddr + C218check_sum);
411037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		writew(0, baseAddr + C218_key);
412037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		for (i = 0; i < 100; i++) {
413037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			if (readw(baseAddr + C218_key) == keycode)
414037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				break;
415037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			msleep(10);
416037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		}
417037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		retry++;
418037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	} while ((readb(baseAddr + C218chksum_ok) != 1) && (retry < 3));
419037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (readb(baseAddr + C218chksum_ok) != 1)
420037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		return -EIO;
421037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
422037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	writew(0, baseAddr + C218_key);
423037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	for (i = 0; i < 100; i++) {
424037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		if (readw(baseAddr + Magic_no) == Magic_code)
425037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			break;
426037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		msleep(10);
427037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
428037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (readw(baseAddr + Magic_no) != Magic_code)
429037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		return -EIO;
430037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
431037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	writew(1, baseAddr + Disable_IRQ);
432037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	writew(0, baseAddr + Magic_no);
433037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	for (i = 0; i < 100; i++) {
434037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		if (readw(baseAddr + Magic_no) == Magic_code)
435037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			break;
436037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		msleep(10);
437037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
438037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (readw(baseAddr + Magic_no) != Magic_code)
439037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		return -EIO;
440037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
441037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	moxaCard = 1;
442037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	brd->intNdx = baseAddr + IRQindex;
443037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	brd->intPend = baseAddr + IRQpending;
444037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	brd->intTable = baseAddr + IRQtable;
445037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
446037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	return 0;
447037182346f0991683cc7320a257c3f6089432ceeJiri Slaby}
448037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
449037182346f0991683cc7320a257c3f6089432ceeJiri Slabystatic int moxa_load_c320(struct moxa_board_conf *brd, const void *ptr,
450037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		size_t len)
451037182346f0991683cc7320a257c3f6089432ceeJiri Slaby{
452037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	void __iomem *baseAddr = brd->basemem;
453037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	const u16 *uptr = ptr;
454037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	size_t wlen, len2, j;
455037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	unsigned int i, retry;
456037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	u16 usum;
457037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
458037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	usum = 0;
459037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	wlen = len >> 1;
460037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	for (i = 0; i < wlen; i++)
461037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		usum += le16_to_cpu(uptr[i]);
462037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	retry = 0;
463037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	do {
464037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		wlen = len >> 1;
465037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		j = 0;
466037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		while (wlen) {
467037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			len2 = (wlen > 2048) ? 2048 : wlen;
468037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			wlen -= len2;
469037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			memcpy_toio(baseAddr + C320_LoadBuf, ptr + j,
470037182346f0991683cc7320a257c3f6089432ceeJiri Slaby					len2 << 1);
471037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			j += len2 << 1;
472037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			writew(len2, baseAddr + C320DLoad_len);
473037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			writew(0, baseAddr + C320_key);
474037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			for (i = 0; i < 10; i++) {
475037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				if (readw(baseAddr + C320_key) == C320_KeyCode)
476037182346f0991683cc7320a257c3f6089432ceeJiri Slaby					break;
477037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				msleep(10);
478037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			}
479037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			if (readw(baseAddr + C320_key) != C320_KeyCode)
480037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				return -EIO;
481037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		}
482037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		writew(0, baseAddr + C320DLoad_len);
483037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		writew(usum, baseAddr + C320check_sum);
484037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		writew(0, baseAddr + C320_key);
485037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		for (i = 0; i < 10; i++) {
486037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			if (readw(baseAddr + C320_key) == C320_KeyCode)
487037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				break;
488037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			msleep(10);
489037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		}
490037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		retry++;
491037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	} while ((readb(baseAddr + C320chksum_ok) != 1) && (retry < 3));
492037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (readb(baseAddr + C320chksum_ok) != 1)
493037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		return -EIO;
494037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
495037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	writew(0, baseAddr + C320_key);
496037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	for (i = 0; i < 600; i++) {
497037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		if (readw(baseAddr + Magic_no) == Magic_code)
498037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			break;
499037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		msleep(10);
500037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
501037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (readw(baseAddr + Magic_no) != Magic_code)
502037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		return -EIO;
503037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
504037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (brd->busType == MOXA_BUS_TYPE_PCI) {	/* ASIC board */
505037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		writew(0x3800, baseAddr + TMS320_PORT1);
506037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		writew(0x3900, baseAddr + TMS320_PORT2);
507037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		writew(28499, baseAddr + TMS320_CLOCK);
508037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	} else {
509037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		writew(0x3200, baseAddr + TMS320_PORT1);
510037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		writew(0x3400, baseAddr + TMS320_PORT2);
511037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		writew(19999, baseAddr + TMS320_CLOCK);
512037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
513037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	writew(1, baseAddr + Disable_IRQ);
514037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	writew(0, baseAddr + Magic_no);
515037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	for (i = 0; i < 500; i++) {
516037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		if (readw(baseAddr + Magic_no) == Magic_code)
517037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			break;
518037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		msleep(10);
519037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
520037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (readw(baseAddr + Magic_no) != Magic_code)
521037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		return -EIO;
522037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
523037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	j = readw(baseAddr + Module_cnt);
524037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (j <= 0)
525037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		return -EIO;
526037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	brd->numPorts = j * 8;
527037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	writew(j, baseAddr + Module_no);
528037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	writew(0, baseAddr + Magic_no);
529037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	for (i = 0; i < 600; i++) {
530037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		if (readw(baseAddr + Magic_no) == Magic_code)
531037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			break;
532037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		msleep(10);
533037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
534037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (readw(baseAddr + Magic_no) != Magic_code)
535037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		return -EIO;
536037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	moxaCard = 1;
537037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	brd->intNdx = baseAddr + IRQindex;
538037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	brd->intPend = baseAddr + IRQpending;
539037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	brd->intTable = baseAddr + IRQtable;
540037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
541037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	return 0;
542037182346f0991683cc7320a257c3f6089432ceeJiri Slaby}
543037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
544037182346f0991683cc7320a257c3f6089432ceeJiri Slabystatic int moxa_load_code(struct moxa_board_conf *brd, const void *ptr,
545037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		size_t len)
546037182346f0991683cc7320a257c3f6089432ceeJiri Slaby{
547037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	void __iomem *ofsAddr, *baseAddr = brd->basemem;
548037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	struct moxa_port *port;
549037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	int retval, i;
550037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
551037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (len % 2) {
552037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		printk(KERN_ERR "moxa: C2XX bios length is not even\n");
553037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		return -EINVAL;
554037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
555037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
556037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	switch (brd->boardType) {
557037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	case MOXA_BOARD_C218_ISA:
558037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	case MOXA_BOARD_C218_PCI:
559037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	case MOXA_BOARD_CP204J:
560037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		retval = moxa_load_c218(brd, ptr, len);
561037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		if (retval)
562037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			return retval;
563037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		port = brd->ports;
564037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		for (i = 0; i < brd->numPorts; i++, port++) {
565037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			port->chkPort = 1;
566037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			port->curBaud = 9600L;
567037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			port->DCDState = 0;
568037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			port->tableAddr = baseAddr + Extern_table +
569037182346f0991683cc7320a257c3f6089432ceeJiri Slaby					Extern_size * i;
570037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			ofsAddr = port->tableAddr;
571037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			writew(C218rx_mask, ofsAddr + RX_mask);
572037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			writew(C218tx_mask, ofsAddr + TX_mask);
573037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			writew(C218rx_spage + i * C218buf_pageno, ofsAddr + Page_rxb);
574037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			writew(readw(ofsAddr + Page_rxb) + C218rx_pageno, ofsAddr + EndPage_rxb);
575037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
576037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			writew(C218tx_spage + i * C218buf_pageno, ofsAddr + Page_txb);
577037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			writew(readw(ofsAddr + Page_txb) + C218tx_pageno, ofsAddr + EndPage_txb);
578037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
579037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		}
580037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		break;
581037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	default:
582037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		retval = moxa_load_c320(brd, ptr, len); /* fills in numPorts */
583037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		if (retval)
584037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			return retval;
585037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		port = brd->ports;
586037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		for (i = 0; i < brd->numPorts; i++, port++) {
587037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			port->chkPort = 1;
588037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			port->curBaud = 9600L;
589037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			port->DCDState = 0;
590037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			port->tableAddr = baseAddr + Extern_table +
591037182346f0991683cc7320a257c3f6089432ceeJiri Slaby					Extern_size * i;
592037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			ofsAddr = port->tableAddr;
593037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			switch (brd->numPorts) {
594037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			case 8:
595037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p8rx_mask, ofsAddr + RX_mask);
596037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p8tx_mask, ofsAddr + TX_mask);
597037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p8rx_spage + i * C320p8buf_pgno, ofsAddr + Page_rxb);
598037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(readw(ofsAddr + Page_rxb) + C320p8rx_pgno, ofsAddr + EndPage_rxb);
599037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p8tx_spage + i * C320p8buf_pgno, ofsAddr + Page_txb);
600037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(readw(ofsAddr + Page_txb) + C320p8tx_pgno, ofsAddr + EndPage_txb);
601037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
602037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				break;
603037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			case 16:
604037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p16rx_mask, ofsAddr + RX_mask);
605037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p16tx_mask, ofsAddr + TX_mask);
606037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p16rx_spage + i * C320p16buf_pgno, ofsAddr + Page_rxb);
607037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(readw(ofsAddr + Page_rxb) + C320p16rx_pgno, ofsAddr + EndPage_rxb);
608037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p16tx_spage + i * C320p16buf_pgno, ofsAddr + Page_txb);
609037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(readw(ofsAddr + Page_txb) + C320p16tx_pgno, ofsAddr + EndPage_txb);
610037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				break;
611037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
612037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			case 24:
613037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p24rx_mask, ofsAddr + RX_mask);
614037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p24tx_mask, ofsAddr + TX_mask);
615037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p24rx_spage + i * C320p24buf_pgno, ofsAddr + Page_rxb);
616037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(readw(ofsAddr + Page_rxb) + C320p24rx_pgno, ofsAddr + EndPage_rxb);
617037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p24tx_spage + i * C320p24buf_pgno, ofsAddr + Page_txb);
618037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(readw(ofsAddr + Page_txb), ofsAddr + EndPage_txb);
619037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				break;
620037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			case 32:
621037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p32rx_mask, ofsAddr + RX_mask);
622037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p32tx_mask, ofsAddr + TX_mask);
623037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p32tx_ofs, ofsAddr + Ofs_txb);
624037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p32rx_spage + i * C320p32buf_pgno, ofsAddr + Page_rxb);
625037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(readb(ofsAddr + Page_rxb), ofsAddr + EndPage_rxb);
626037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(C320p32tx_spage + i * C320p32buf_pgno, ofsAddr + Page_txb);
627037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				writew(readw(ofsAddr + Page_txb), ofsAddr + EndPage_txb);
628037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				break;
629037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			}
630037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		}
631037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		break;
632037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
633037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	brd->loadstat = 1;
634037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	return 0;
635037182346f0991683cc7320a257c3f6089432ceeJiri Slaby}
636037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
637037182346f0991683cc7320a257c3f6089432ceeJiri Slabystatic int moxa_load_fw(struct moxa_board_conf *brd, const struct firmware *fw)
638037182346f0991683cc7320a257c3f6089432ceeJiri Slaby{
639037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	void *ptr = fw->data;
640037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	char rsn[64];
641037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	u16 lens[5];
642037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	size_t len;
643037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	unsigned int a, lenp, lencnt;
644037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	int ret = -EINVAL;
645037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	struct {
646037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		__le32 magic;	/* 0x34303430 */
647037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		u8 reserved1[2];
648037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		u8 type;	/* UNIX = 3 */
649037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		u8 model;	/* C218T=1, C320T=2, CP204=3 */
650037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		u8 reserved2[8];
651037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		__le16 len[5];
652037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	} *hdr = ptr;
653037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
654037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	BUILD_BUG_ON(ARRAY_SIZE(hdr->len) != ARRAY_SIZE(lens));
655037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
656037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (fw->size < MOXA_FW_HDRLEN) {
657037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		strcpy(rsn, "too short (even header won't fit)");
658037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		goto err;
659037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
660037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (hdr->magic != cpu_to_le32(0x30343034)) {
661037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		sprintf(rsn, "bad magic: %.8x", le32_to_cpu(hdr->magic));
662037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		goto err;
663037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
664037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (hdr->type != 3) {
665037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		sprintf(rsn, "not for linux, type is %u", hdr->type);
666037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		goto err;
667037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
668037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (moxa_check_fw_model(brd, hdr->model)) {
669037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		sprintf(rsn, "not for this card, model is %u", hdr->model);
670037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		goto err;
671037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
672037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
673037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	len = MOXA_FW_HDRLEN;
674037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	lencnt = hdr->model == 2 ? 5 : 3;
675037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	for (a = 0; a < ARRAY_SIZE(lens); a++) {
676037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		lens[a] = le16_to_cpu(hdr->len[a]);
677037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		if (lens[a] && len + lens[a] <= fw->size &&
678037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				moxa_check_fw(&fw->data[len]))
679037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			printk(KERN_WARNING "moxa firmware: unexpected input "
680037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				"at offset %u, but going on\n", (u32)len);
681037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		if (!lens[a] && a < lencnt) {
682037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			sprintf(rsn, "too few entries in fw file");
683037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			goto err;
684037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		}
685037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		len += lens[a];
686037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
687037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
688037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (len != fw->size) {
689037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		sprintf(rsn, "bad length: %u (should be %u)", (u32)fw->size,
690037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				(u32)len);
691037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		goto err;
692037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
693037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
694037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	ptr += MOXA_FW_HDRLEN;
695037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	lenp = 0; /* bios */
696037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
697037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	strcpy(rsn, "read above");
698037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
699037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	ret = moxa_load_bios(brd, ptr, lens[lenp]);
700037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (ret)
701037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		goto err;
702037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
703037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	/* we skip the tty section (lens[1]), since we don't need it */
704037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	ptr += lens[lenp] + lens[lenp + 1];
705037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	lenp += 2; /* comm */
706037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
707037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (hdr->model == 2) {
708037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		ret = moxa_load_320b(brd, ptr, lens[lenp]);
709037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		if (ret)
710037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			goto err;
711037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		/* skip another tty */
712037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		ptr += lens[lenp] + lens[lenp + 1];
713037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		lenp += 2;
714037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
715037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
716037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	ret = moxa_load_code(brd, ptr, lens[lenp]);
717037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (ret)
718037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		goto err;
719037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
720037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	return 0;
721037182346f0991683cc7320a257c3f6089432ceeJiri Slabyerr:
722037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	printk(KERN_ERR "firmware failed to load, reason: %s\n", rsn);
723037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	return ret;
724037182346f0991683cc7320a257c3f6089432ceeJiri Slaby}
725037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
726037182346f0991683cc7320a257c3f6089432ceeJiri Slabystatic int moxa_init_board(struct moxa_board_conf *brd, struct device *dev)
727037182346f0991683cc7320a257c3f6089432ceeJiri Slaby{
728037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	const struct firmware *fw;
729037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	const char *file;
730037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	int ret;
731037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
732037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	switch (brd->boardType) {
733037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	case MOXA_BOARD_C218_ISA:
734037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	case MOXA_BOARD_C218_PCI:
735037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		file = "c218tunx.cod";
736037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		break;
737037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	case MOXA_BOARD_CP204J:
738037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		file = "cp204unx.cod";
739037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		break;
740037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	default:
741037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		file = "c320tunx.cod";
742037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		break;
743037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
744037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
745037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	ret = request_firmware(&fw, file, dev);
746037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (ret) {
747037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		printk(KERN_ERR "request_firmware failed\n");
748037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		goto end;
749037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
750037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
751037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	ret = moxa_load_fw(brd, fw);
752037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
753037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	release_firmware(fw);
754037182346f0991683cc7320a257c3f6089432ceeJiri Slabyend:
755037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	return ret;
756037182346f0991683cc7320a257c3f6089432ceeJiri Slaby}
757037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PCI
7599cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slabystatic int __devinit moxa_pci_probe(struct pci_dev *pdev,
7609cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby		const struct pci_device_id *ent)
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7629cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby	struct moxa_board_conf *board;
7639cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby	unsigned int i;
7649cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby	int board_type = ent->driver_data;
7659cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby	int retval;
7669cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby
7679cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby	retval = pci_enable_device(pdev);
7687aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby	if (retval) {
7697aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby		dev_err(&pdev->dev, "can't enable pci device\n");
7709cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby		goto err;
7717aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby	}
7729cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby
7739cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby	for (i = 0; i < MAX_BOARDS; i++)
7749cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby		if (moxa_boards[i].basemem == NULL)
7759cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby			break;
7769cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby
7779cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby	retval = -ENODEV;
7789cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby	if (i >= MAX_BOARDS) {
7797aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby		dev_warn(&pdev->dev, "more than %u MOXA Intellio family boards "
7809cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby				"found. Board is ignored.\n", MAX_BOARDS);
7819cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby		goto err;
7829cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby	}
7839cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby
7849cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby	board = &moxa_boards[i];
785037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	board->ports = &moxa_ports[i * MAX_PORTS_PER_BOARD];
786e46a5e3ff06b70690d567bdc81faf6c1c32e742fJiri Slaby
787e46a5e3ff06b70690d567bdc81faf6c1c32e742fJiri Slaby	retval = pci_request_region(pdev, 2, "moxa-base");
788e46a5e3ff06b70690d567bdc81faf6c1c32e742fJiri Slaby	if (retval) {
789e46a5e3ff06b70690d567bdc81faf6c1c32e742fJiri Slaby		dev_err(&pdev->dev, "can't request pci region 2\n");
790e46a5e3ff06b70690d567bdc81faf6c1c32e742fJiri Slaby		goto err;
791e46a5e3ff06b70690d567bdc81faf6c1c32e742fJiri Slaby	}
792e46a5e3ff06b70690d567bdc81faf6c1c32e742fJiri Slaby
793e46a5e3ff06b70690d567bdc81faf6c1c32e742fJiri Slaby	board->basemem = ioremap(pci_resource_start(pdev, 2), 0x4000);
7947aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby	if (board->basemem == NULL) {
7957aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby		dev_err(&pdev->dev, "can't remap io space 2\n");
796e46a5e3ff06b70690d567bdc81faf6c1c32e742fJiri Slaby		goto err_reg;
7977aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby	}
7989cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	board->boardType = board_type;
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (board_type) {
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case MOXA_BOARD_C218_ISA:
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case MOXA_BOARD_C218_PCI:
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		board->numPorts = 8;
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case MOXA_BOARD_CP204J:
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		board->numPorts = 4;
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		board->numPorts = 0;
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	board->busType = MOXA_BUS_TYPE_PCI;
814a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby
815037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	retval = moxa_init_board(board, &pdev->dev);
816037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (retval)
817037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		goto err_base;
818037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
8199cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby	pci_set_drvdata(pdev, board);
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (0);
822037182346f0991683cc7320a257c3f6089432ceeJiri Slabyerr_base:
823037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	iounmap(board->basemem);
824037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	board->basemem = NULL;
825e46a5e3ff06b70690d567bdc81faf6c1c32e742fJiri Slabyerr_reg:
826e46a5e3ff06b70690d567bdc81faf6c1c32e742fJiri Slaby	pci_release_region(pdev, 2);
8279cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slabyerr:
8289cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby	return retval;
8299cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby}
8309cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby
8319cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slabystatic void __devexit moxa_pci_remove(struct pci_dev *pdev)
8329cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby{
8339cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby	struct moxa_board_conf *brd = pci_get_drvdata(pdev);
8349cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby
835e46a5e3ff06b70690d567bdc81faf6c1c32e742fJiri Slaby	iounmap(brd->basemem);
8369cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby	brd->basemem = NULL;
837e46a5e3ff06b70690d567bdc81faf6c1c32e742fJiri Slaby	pci_release_region(pdev, 2);
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
839a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby
840a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slabystatic struct pci_driver moxa_pci_driver = {
841a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby	.name = "moxa",
842a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby	.id_table = moxa_pcibrds,
843a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby	.probe = moxa_pci_probe,
844a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby	.remove = __devexit_p(moxa_pci_remove)
845a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby};
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_PCI */
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init moxa_init(void)
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8508f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	struct moxa_port *ch;
851d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby	unsigned int i, isabrds = 0;
852d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby	int retval = 0;
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8547aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby	printk(KERN_INFO "MOXA Intellio family driver version %s\n",
8557aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby			MOXA_VERSION);
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxaDriver = alloc_tty_driver(MAX_PORTS + 1);
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!moxaDriver)
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxaDriver->owner = THIS_MODULE;
8619b4e3b13b147e9b737de63188a9ae740eaa8c36dSergey Vlasov	moxaDriver->name = "ttyMX";
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxaDriver->major = ttymajor;
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxaDriver->minor_start = 0;
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxaDriver->type = TTY_DRIVER_TYPE_SERIAL;
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxaDriver->subtype = SERIAL_TYPE_NORMAL;
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxaDriver->init_termios = tty_std_termios;
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxaDriver->init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
868606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox	moxaDriver->init_termios.c_ispeed = 9600;
869606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox	moxaDriver->init_termios.c_ospeed = 9600;
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxaDriver->flags = TTY_DRIVER_REAL_RAW;
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tty_set_operations(moxaDriver, &moxa_ops);
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8738f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	for (i = 0, ch = moxa_ports; i < MAX_PORTS; i++, ch++) {
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ch->type = PORT_16550A;
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ch->port = i;
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ch->close_delay = 5 * HZ / 10;
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ch->closing_wait = 30 * HZ;
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ch->cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		init_waitqueue_head(&ch->open_wait);
88095e0791480af8347460d0cbe34a46eca7e77d0d0Jiri Slaby		init_completion(&ch->close_wait);
8818f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby
8826f56b658b4e5c4486641ce62f331150954c4de37Jiri Slaby		setup_timer(&ch->emptyTimer, moxa_check_xmit_empty,
8838f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby				(unsigned long)ch);
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8867aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby	pr_debug("Moxa tty devices major number = %d\n", ttymajor);
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tty_register_driver(moxaDriver)) {
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "Couldn't install MOXA Smartio family driver !\n");
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		put_tty_driver(moxaDriver);
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
894aa7e5221fb47badbea618cc62704d6e4a4bcce15Jiri Slaby	mod_timer(&moxaTimer, jiffies + HZ / 50);
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
896d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby	/* Find the boards defined from module args. */
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef MODULE
898d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby	{
899d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby	struct moxa_board_conf *brd = moxa_boards;
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < MAX_BOARDS; i++) {
901d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby		if (!baseaddr[i])
902d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby			break;
903d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby		if (type[i] == MOXA_BOARD_C218_ISA ||
904d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby				type[i] == MOXA_BOARD_C320_ISA) {
9057aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby			pr_debug("Moxa board %2d: %s board(baseAddr=%lx)\n",
906d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby					isabrds + 1, moxa_brdname[type[i] - 1],
907d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby					baseaddr[i]);
908d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby			brd->boardType = type[i];
909037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			brd->ports = &moxa_ports[isabrds * MAX_PORTS_PER_BOARD];
910d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby			brd->numPorts = type[i] == MOXA_BOARD_C218_ISA ? 8 :
911d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby					numports[i];
912d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby			brd->busType = MOXA_BUS_TYPE_ISA;
913d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby			brd->basemem = ioremap(baseaddr[i], 0x4000);
914d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby			if (!brd->basemem) {
915d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby				printk(KERN_ERR "moxa: can't remap %lx\n",
916d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby						baseaddr[i]);
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				continue;
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
919037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			if (moxa_init_board(brd, NULL)) {
920037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				iounmap(brd->basemem);
921037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				brd->basemem = NULL;
922037182346f0991683cc7320a257c3f6089432ceeJiri Slaby				continue;
923037182346f0991683cc7320a257c3f6089432ceeJiri Slaby			}
924d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby
925d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby			brd++;
926d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby			isabrds++;
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
929d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby	}
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
931a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PCI
933a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby	retval = pci_register_driver(&moxa_pci_driver);
934a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby	if (retval) {
935a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby		printk(KERN_ERR "Can't register moxa pci driver!\n");
936d353eca4e0480fddcb088c4692e1edba0a82eac9Jiri Slaby		if (isabrds)
937a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby			retval = 0;
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
940a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby
941a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby	return retval;
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit moxa_exit(void)
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
948c251ae0d7514563c7fdace0d390175454761228bJiri Slaby	del_timer_sync(&moxaTimer);
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < MAX_PORTS; i++)
9518f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby		del_timer_sync(&moxa_ports[i].emptyTimer);
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tty_unregister_driver(moxaDriver))
9547aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby		printk(KERN_ERR "Couldn't unregister MOXA Intellio family "
9557aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby				"serial driver\n");
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	put_tty_driver(moxaDriver);
95786fbf1486a44a4bce4fdcbe3665a7d8a62ba958aJiri Slaby
9589cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby#ifdef CONFIG_PCI
959a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby	pci_unregister_driver(&moxa_pci_driver);
9609cde5bf027556bd1e58caa14bfe8cdba64192eddJiri Slaby#endif
961a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby
962a784bf7c195f9eca1188562c54952e4bf9791437Jiri Slaby	for (i = 0; i < MAX_BOARDS; i++)
9638f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby		if (moxa_boards[i].basemem)
9648f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby			iounmap(moxa_boards[i].basemem);
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(moxa_init);
9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(moxa_exit);
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int moxa_open(struct tty_struct *tty, struct file *filp)
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9728f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	struct moxa_port *ch;
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int port;
9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval;
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
97611324edd4ad34981764b25bed44d46a1507b62e1Jiri Slaby	port = tty->index;
9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (port == MAX_PORTS) {
9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (0);
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!MoxaPortIsValid(port)) {
9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tty->driver_data = NULL;
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (-ENODEV);
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9858f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	ch = &moxa_ports[port];
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ch->count++;
9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tty->driver_data = ch;
9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ch->tty = tty;
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(ch->asyncflags & ASYNC_INITIALIZED)) {
9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ch->statusflags = 0;
991db1acaa632870ec87b65e062bc72ca375837a1f6Alan Cox		moxa_set_tty_param(tty, tty->termios);
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MoxaPortLineCtrl(ch->port, 1, 1);
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MoxaPortEnable(ch->port);
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ch->asyncflags |= ASYNC_INITIALIZED;
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9966f56b658b4e5c4486641ce62f331150954c4de37Jiri Slaby	retval = moxa_block_till_ready(tty, filp, ch);
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxa_unthrottle(tty);
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ch->type == PORT_16550A) {
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MoxaSetFifo(ch->port, 1);
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MoxaSetFifo(ch->port, 0);
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (retval);
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_close(struct tty_struct *tty, struct file *filp)
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10118f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	struct moxa_port *ch;
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int port;
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
101411324edd4ad34981764b25bed44d46a1507b62e1Jiri Slaby	port = tty->index;
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (port == MAX_PORTS) {
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!MoxaPortIsValid(port)) {
10197aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby		pr_debug("Invalid portno in moxa_close\n");
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tty->driver_data = NULL;
10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tty->driver_data == NULL) {
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tty_hung_up_p(filp)) {
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10298f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	ch = (struct moxa_port *) tty->driver_data;
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((tty->count == 1) && (ch->count != 1)) {
10327aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby		printk(KERN_WARNING "moxa_close: bad serial port count; "
10337aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby			"tty->count is 1, ch->count is %d\n", ch->count);
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ch->count = 1;
10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (--ch->count < 0) {
10377aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby		printk(KERN_WARNING "moxa_close: bad serial port count, "
10387aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby			"device=%s\n", tty->name);
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ch->count = 0;
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ch->count) {
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ch->asyncflags |= ASYNC_CLOSING;
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ch->cflag = tty->termios->c_cflag;
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ch->asyncflags & ASYNC_INITIALIZED) {
10486f56b658b4e5c4486641ce62f331150954c4de37Jiri Slaby		moxa_setup_empty_event(tty);
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tty_wait_until_sent(tty, 30 * HZ);	/* 30 seconds timeout */
10508f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby		del_timer_sync(&moxa_ports[ch->port].emptyTimer);
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10526f56b658b4e5c4486641ce62f331150954c4de37Jiri Slaby	moxa_shut_down(ch);
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MoxaPortFlushData(port, 2);
10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tty->driver->flush_buffer)
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tty->driver->flush_buffer(tty);
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tty_ldisc_flush(tty);
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tty->closing = 0;
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ch->event = 0;
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ch->tty = NULL;
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ch->blocked_open) {
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ch->close_delay) {
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			msleep_interruptible(jiffies_to_msecs(ch->close_delay));
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		wake_up_interruptible(&ch->open_wait);
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
106995e0791480af8347460d0cbe34a46eca7e77d0d0Jiri Slaby	complete_all(&ch->close_wait);
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int moxa_write(struct tty_struct *tty,
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      const unsigned char *buf, int count)
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10758f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	struct moxa_port *ch;
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int len, port;
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10798f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	ch = (struct moxa_port *) tty->driver_data;
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ch == NULL)
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (0);
10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port = ch->port;
108333f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox
108433f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox	spin_lock_irqsave(&moxa_lock, flags);
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = MoxaPortWriteData(port, (unsigned char *) buf, count);
108633f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox	spin_unlock_irqrestore(&moxa_lock, flags);
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*********************************************
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ( !(ch->statusflags & LOWWAIT) &&
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	     ((len != count) || (MoxaPortTxFree(port) <= 100)) )
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	************************************************/
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ch->statusflags |= LOWWAIT;
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (len);
10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int moxa_write_room(struct tty_struct *tty)
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10988f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	struct moxa_port *ch;
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tty->stopped)
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (0);
11028f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	ch = (struct moxa_port *) tty->driver_data;
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ch == NULL)
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (0);
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (MoxaPortTxFree(ch->port));
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_flush_buffer(struct tty_struct *tty)
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11108f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ch == NULL)
11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MoxaPortFlushData(ch->port, 1);
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tty_wakeup(tty);
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int moxa_chars_in_buffer(struct tty_struct *tty)
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int chars;
11218f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Sigh...I have to check if driver_data is NULL here, because
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * if an open() fails, the TTY subsystem eventually calls
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * tty_wait_until_sent(), which calls the driver's chars_in_buffer()
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * routine.  And since the open() failed, we return 0 here.  TDJ
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ch == NULL)
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (0);
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	chars = MoxaPortTxQueue(ch->port);
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (chars) {
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Make it possible to wakeup anything waiting for output
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * in tty_ioctl.c, etc.
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(ch->statusflags & EMPTYWAIT))
11386f56b658b4e5c4486641ce62f331150954c4de37Jiri Slaby			moxa_setup_empty_event(tty);
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (chars);
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_flush_chars(struct tty_struct *tty)
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Don't think I need this, because this is called to empty the TX
11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * buffer for the 16450, 16550, etc.
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_put_char(struct tty_struct *tty, unsigned char c)
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11538f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	struct moxa_port *ch;
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int port;
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11578f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	ch = (struct moxa_port *) tty->driver_data;
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ch == NULL)
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port = ch->port;
116133f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox	spin_lock_irqsave(&moxa_lock, flags);
1162f204d2672044f0f7061d645f0f59f8535b63d106Jiri Slaby	MoxaPortWriteData(port, &c, 1);
116333f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox	spin_unlock_irqrestore(&moxa_lock, flags);
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/************************************************
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ( !(ch->statusflags & LOWWAIT) && (MoxaPortTxFree(port) <= 100) )
11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*************************************************/
11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ch->statusflags |= LOWWAIT;
11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int moxa_tiocmget(struct tty_struct *tty, struct file *file)
11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11728f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int port;
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int flag = 0, dtr, rts;
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
117611324edd4ad34981764b25bed44d46a1507b62e1Jiri Slaby	port = tty->index;
11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((port != MAX_PORTS) && (!ch))
11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (-EINVAL);
11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MoxaPortGetLineOut(ch->port, &dtr, &rts);
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dtr)
11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flag |= TIOCM_DTR;
11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rts)
11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flag |= TIOCM_RTS;
11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dtr = MoxaPortLineStatus(ch->port);
11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dtr & 1)
11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flag |= TIOCM_CTS;
11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dtr & 2)
11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flag |= TIOCM_DSR;
11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dtr & 4)
11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flag |= TIOCM_CD;
11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return flag;
11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int moxa_tiocmset(struct tty_struct *tty, struct file *file,
11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 unsigned int set, unsigned int clear)
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11988f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int port;
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int dtr, rts;
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
120211324edd4ad34981764b25bed44d46a1507b62e1Jiri Slaby	port = tty->index;
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((port != MAX_PORTS) && (!ch))
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (-EINVAL);
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MoxaPortGetLineOut(ch->port, &dtr, &rts);
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (set & TIOCM_RTS)
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rts = 1;
12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (set & TIOCM_DTR)
12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dtr = 1;
12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clear & TIOCM_RTS)
12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rts = 0;
12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clear & TIOCM_DTR)
12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dtr = 0;
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MoxaPortLineCtrl(ch->port, dtr, rts);
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int moxa_ioctl(struct tty_struct *tty, struct file *file,
12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      unsigned int cmd, unsigned long arg)
12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12228f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register int port;
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __user *argp = (void __user *)arg;
12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval;
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
122711324edd4ad34981764b25bed44d46a1507b62e1Jiri Slaby	port = tty->index;
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((port != MAX_PORTS) && (!ch))
12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (-EINVAL);
12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd) {
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TCSBRK:		/* SVID version: non-zero arg --> no break */
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = tty_check_change(tty);
12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (retval)
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return (retval);
12366f56b658b4e5c4486641ce62f331150954c4de37Jiri Slaby		moxa_setup_empty_event(tty);
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tty_wait_until_sent(tty, 0);
12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!arg)
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			MoxaPortSendBreak(ch->port, 0);
12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (0);
12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TCSBRKP:		/* support for POSIX tcsendbreak() */
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = tty_check_change(tty);
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (retval)
12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return (retval);
12456f56b658b4e5c4486641ce62f331150954c4de37Jiri Slaby		moxa_setup_empty_event(tty);
12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tty_wait_until_sent(tty, 0);
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MoxaPortSendBreak(ch->port, arg);
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (0);
12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TIOCGSOFTCAR:
12509e9fc313ffa3cb92f7f81a8e076566bc9d582351Jiri Slaby		return put_user(C_CLOCAL(tty) ? 1 : 0, (int __user *)argp);
12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TIOCSSOFTCAR:
12529e9fc313ffa3cb92f7f81a8e076566bc9d582351Jiri Slaby		if (get_user(retval, (int __user *)argp))
12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EFAULT;
12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		arg = retval;
12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) |
12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 (arg ? CLOCAL : 0));
12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (C_CLOCAL(tty))
12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ch->asyncflags &= ~ASYNC_CHECK_CD;
12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ch->asyncflags |= ASYNC_CHECK_CD;
12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (0);
12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TIOCGSERIAL:
12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return moxa_get_serial_info(ch, argp);
12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TIOCSSERIAL:
12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return moxa_set_serial_info(ch, argp);
12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = MoxaDriverIoctl(cmd, arg, port);
12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (retval);
12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_throttle(struct tty_struct *tty)
12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12758f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ch->statusflags |= THROTTLE;
12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_unthrottle(struct tty_struct *tty)
12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12828f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ch->statusflags &= ~THROTTLE;
12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_set_termios(struct tty_struct *tty,
1288606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox			     struct ktermios *old_termios)
12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12908f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ch == NULL)
12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
1294db1acaa632870ec87b65e062bc72ca375837a1f6Alan Cox	moxa_set_tty_param(tty, old_termios);
12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(old_termios->c_cflag & CLOCAL) &&
12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (tty->termios->c_cflag & CLOCAL))
12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		wake_up_interruptible(&ch->open_wait);
12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_stop(struct tty_struct *tty)
13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13028f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ch == NULL)
13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MoxaPortTxDisable(ch->port);
13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ch->statusflags |= TXSTOPPED;
13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_start(struct tty_struct *tty)
13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13138f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ch == NULL)
13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(ch->statusflags & TXSTOPPED))
13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MoxaPortTxEnable(ch->port);
13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ch->statusflags &= ~TXSTOPPED;
13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_hangup(struct tty_struct *tty)
13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13278f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxa_flush_buffer(tty);
13306f56b658b4e5c4486641ce62f331150954c4de37Jiri Slaby	moxa_shut_down(ch);
13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ch->event = 0;
13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ch->count = 0;
13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ch->tty = NULL;
13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wake_up_interruptible(&ch->open_wait);
13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxa_poll(unsigned long ignored)
13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register int card;
13418f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	struct moxa_port *ch;
13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tty_struct *tp;
13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, ports;
13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	del_timer(&moxaTimer);
13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (MoxaDriverPoll() < 0) {
1348aa7e5221fb47badbea618cc62704d6e4a4bcce15Jiri Slaby		mod_timer(&moxaTimer, jiffies + HZ / 50);
13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (card = 0; card < MAX_BOARDS; card++) {
13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((ports = MoxaPortsOfCard(card)) <= 0)
13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
13548f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby		ch = &moxa_ports[card * MAX_PORTS_PER_BOARD];
13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < ports; i++, ch++) {
13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ((ch->asyncflags & ASYNC_INITIALIZED) == 0)
13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				continue;
13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!(ch->statusflags & THROTTLE) &&
13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    (MoxaPortRxQueue(ch->port) > 0))
13606f56b658b4e5c4486641ce62f331150954c4de37Jiri Slaby				moxa_receive_data(ch);
13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ((tp = ch->tty) == 0)
13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				continue;
13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ch->statusflags & LOWWAIT) {
13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (MoxaPortTxQueue(ch->port) <= WAKEUP_CHARS) {
13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (!tp->stopped) {
13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						ch->statusflags &= ~LOWWAIT;
13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						tty_wakeup(tp);
13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!I_IGNBRK(tp) && (MoxaPortResetBrkCnt(ch->port) > 0)) {
13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				tty_insert_flip_char(tp, 0, TTY_BREAK);
13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				tty_schedule_flip(tp);
13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (MoxaPortDCDChange(ch->port)) {
13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (ch->asyncflags & ASYNC_CHECK_CD) {
13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (MoxaPortDCDON(ch->port))
13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						wake_up_interruptible(&ch->open_wait);
13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					else {
1380ba196df3d6432c5c20429e8e447c5db7abedb8f3Jiri Slaby						tty_hangup(tp);
1381ba196df3d6432c5c20429e8e447c5db7abedb8f3Jiri Slaby						wake_up_interruptible(&ch->open_wait);
1382ba196df3d6432c5c20429e8e447c5db7abedb8f3Jiri Slaby						ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1389aa7e5221fb47badbea618cc62704d6e4a4bcce15Jiri Slaby	mod_timer(&moxaTimer, jiffies + HZ / 50);
13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/******************************************************************************/
13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1394db1acaa632870ec87b65e062bc72ca375837a1f6Alan Coxstatic void moxa_set_tty_param(struct tty_struct *tty, struct ktermios *old_termios)
13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1396606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox	register struct ktermios *ts;
13978f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	struct moxa_port *ch;
1398db1acaa632870ec87b65e062bc72ca375837a1f6Alan Cox	int rts, cts, txflow, rxflow, xany, baud;
13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14008f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	ch = (struct moxa_port *) tty->driver_data;
14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ts = tty->termios;
14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ts->c_cflag & CLOCAL)
14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ch->asyncflags &= ~ASYNC_CHECK_CD;
14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ch->asyncflags |= ASYNC_CHECK_CD;
14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rts = cts = txflow = rxflow = xany = 0;
14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ts->c_cflag & CRTSCTS)
14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rts = cts = 1;
14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ts->c_iflag & IXON)
14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		txflow = 1;
14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ts->c_iflag & IXOFF)
14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rxflow = 1;
14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ts->c_iflag & IXANY)
14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		xany = 1;
1415db1acaa632870ec87b65e062bc72ca375837a1f6Alan Cox
1416db1acaa632870ec87b65e062bc72ca375837a1f6Alan Cox	/* Clear the features we don't support */
1417db1acaa632870ec87b65e062bc72ca375837a1f6Alan Cox	ts->c_cflag &= ~CMSPAR;
14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MoxaPortFlowCtrl(ch->port, rts, cts, txflow, rxflow, xany);
1419db1acaa632870ec87b65e062bc72ca375837a1f6Alan Cox	baud = MoxaPortSetTermio(ch->port, ts, tty_get_baud_rate(tty));
1420db1acaa632870ec87b65e062bc72ca375837a1f6Alan Cox	if (baud == -1)
1421db1acaa632870ec87b65e062bc72ca375837a1f6Alan Cox		baud = tty_termios_baud_rate(old_termios);
1422db1acaa632870ec87b65e062bc72ca375837a1f6Alan Cox	/* Not put the baud rate into the termios data */
1423db1acaa632870ec87b65e062bc72ca375837a1f6Alan Cox	tty_encode_baud_rate(tty, baud, baud);
14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14266f56b658b4e5c4486641ce62f331150954c4de37Jiri Slabystatic int moxa_block_till_ready(struct tty_struct *tty, struct file *filp,
14278f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby			    struct moxa_port *ch)
14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DECLARE_WAITQUEUE(wait,current);
14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval;
14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int do_clocal = C_CLOCAL(tty);
14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * If the device is in the middle of being closed, then block
14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * until it's done, and then try again.
14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tty_hung_up_p(filp) || (ch->asyncflags & ASYNC_CLOSING)) {
14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ch->asyncflags & ASYNC_CLOSING)
144095e0791480af8347460d0cbe34a46eca7e77d0d0Jiri Slaby			wait_for_completion_interruptible(&ch->close_wait);
14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef SERIAL_DO_RESTART
14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ch->asyncflags & ASYNC_HUP_NOTIFY)
14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return (-EAGAIN);
14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return (-ERESTARTSYS);
14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (-EAGAIN);
14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * If non-blocking mode is set, then make the check up front
14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * and then exit.
14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (filp->f_flags & O_NONBLOCK) {
14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (0);
14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Block waiting for the carrier detect and the line to become free
14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = 0;
14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	add_wait_queue(&ch->open_wait, &wait);
14637aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby	pr_debug("block_til_ready before block: ttys%d, count = %d\n",
14647aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby		ch->port, ch->count);
146533f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox	spin_lock_irqsave(&moxa_lock, flags);
14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!tty_hung_up_p(filp))
14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ch->count--;
14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ch->blocked_open++;
146933f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox	spin_unlock_irqrestore(&moxa_lock, flags);
147033f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox
14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (1) {
14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_current_state(TASK_INTERRUPTIBLE);
14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tty_hung_up_p(filp) ||
14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    !(ch->asyncflags & ASYNC_INITIALIZED)) {
14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef SERIAL_DO_RESTART
14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ch->asyncflags & ASYNC_HUP_NOTIFY)
14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				retval = -EAGAIN;
14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else
14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				retval = -ERESTARTSYS;
14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			retval = -EAGAIN;
14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(ch->asyncflags & ASYNC_CLOSING) && (do_clocal ||
14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						MoxaPortDCDON(ch->port)))
14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (signal_pending(current)) {
14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			retval = -ERESTARTSYS;
14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		schedule();
14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_current_state(TASK_RUNNING);
14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	remove_wait_queue(&ch->open_wait, &wait);
149733f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox
149833f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox	spin_lock_irqsave(&moxa_lock, flags);
14991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!tty_hung_up_p(filp))
15001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ch->count++;
15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ch->blocked_open--;
150233f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox	spin_unlock_irqrestore(&moxa_lock, flags);
15037aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby	pr_debug("block_til_ready after blocking: ttys%d, count = %d\n",
15047aeb95daf37dbd72f63cdd52d86a8b5d89e59394Jiri Slaby		ch->port, ch->count);
15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval)
15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (retval);
150733f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox	/* FIXME: review to see if we need to use set_bit on these */
15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
150933f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox	return 0;
15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15126f56b658b4e5c4486641ce62f331150954c4de37Jiri Slabystatic void moxa_setup_empty_event(struct tty_struct *tty)
15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15148f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	struct moxa_port *ch = tty->driver_data;
15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
151733f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox	spin_lock_irqsave(&moxa_lock, flags);
15181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ch->statusflags |= EMPTYWAIT;
15198f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	mod_timer(&moxa_ports[ch->port].emptyTimer, jiffies + HZ);
152033f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox	spin_unlock_irqrestore(&moxa_lock, flags);
15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15236f56b658b4e5c4486641ce62f331150954c4de37Jiri Slabystatic void moxa_check_xmit_empty(unsigned long data)
15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15258f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	struct moxa_port *ch;
15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15278f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	ch = (struct moxa_port *) data;
15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ch->tty && (ch->statusflags & EMPTYWAIT)) {
15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (MoxaPortTxQueue(ch->port) == 0) {
15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ch->statusflags &= ~EMPTYWAIT;
15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tty_wakeup(ch->tty);
15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1534c43422053bea7a5ce09f18d0c50a606fe1a549f4Jiri Slaby		mod_timer(&moxa_ports[ch->port].emptyTimer,
1535c43422053bea7a5ce09f18d0c50a606fe1a549f4Jiri Slaby				round_jiffies(jiffies + HZ));
15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ch->statusflags &= ~EMPTYWAIT;
15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15406f56b658b4e5c4486641ce62f331150954c4de37Jiri Slabystatic void moxa_shut_down(struct moxa_port *ch)
15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tty_struct *tp;
15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(ch->asyncflags & ASYNC_INITIALIZED))
15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tp = ch->tty;
15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MoxaPortDisable(ch->port);
15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * If we're a modem control device and HUPCL is on, drop RTS & DTR.
15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
15541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tp->termios->c_cflag & HUPCL)
15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MoxaPortLineCtrl(ch->port, 0, 0);
15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ch->asyncflags &= ~ASYNC_INITIALIZED;
15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15606f56b658b4e5c4486641ce62f331150954c4de37Jiri Slabystatic void moxa_receive_data(struct moxa_port *ch)
15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tty_struct *tp;
1563606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox	struct ktermios *ts;
15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ts = NULL;
15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tp = ch->tty;
15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tp)
15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ts = tp->termios;
15701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/**************************************************
1571037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if ( !tp || !ts || !(ts->c_cflag & CREAD) ) {
1572037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	*****************************************************/
1573037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	if (!tp || !ts) {
1574037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		MoxaPortFlushData(ch->port, 0);
1575037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		return;
1576037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	}
1577037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	spin_lock_irqsave(&moxa_lock, flags);
1578037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	MoxaPortReadData(ch->port, tp);
1579037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	spin_unlock_irqrestore(&moxa_lock, flags);
1580037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	tty_schedule_flip(tp);
1581037182346f0991683cc7320a257c3f6089432ceeJiri Slaby}
15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Query
15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct mon_str {
15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int tick;
15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rxcnt[MAX_PORTS];
15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int txcnt[MAX_PORTS];
15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define 	DCD_changed	0x01
15941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define 	DCD_oldstate	0x80
15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int moxaLowWaterChk;
15979dff89cd82af7bccc706fed288b1c33a51c3b937Jiri Slabystatic struct mon_str moxaLog;
15989fa372a850b9ffcb177eb9ac0b75963b2f9af233Jiri Slabystatic int moxaFuncTout = HZ / 2;
15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxafunc(void __iomem *, int, ushort);
16016f56b658b4e5c4486641ce62f331150954c4de37Jiri Slabystatic void moxa_wait_finish(void __iomem *);
16026f56b658b4e5c4486641ce62f331150954c4de37Jiri Slabystatic void moxa_low_water_check(void __iomem *);
16031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************
16051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Driver level functions: 					     *
16061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	2. MoxaDriverIoctl(unsigned int cmd, unsigned long arg, int port);   *
16071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	3. MoxaDriverPoll(void);					     *
16081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *****************************************************************************/
16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MOXA		0x400
16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MOXA_GET_IQUEUE 	(MOXA + 1)	/* get input buffered count */
16111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MOXA_GET_OQUEUE 	(MOXA + 2)	/* get output buffered count */
16121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MOXA_GETDATACOUNT       (MOXA + 23)
16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MOXA_GET_IOQUEUE	(MOXA + 27)
16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MOXA_FLUSH_QUEUE	(MOXA + 28)
16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MOXA_GET_CONF		(MOXA + 35)	/* configuration */
16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MOXA_GET_MAJOR          (MOXA + 63)
16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MOXA_GET_CUMAJOR        (MOXA + 64)
16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MOXA_GETMSTATUS         (MOXA + 65)
16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid MoxaPortFlushData(int port, int mode)
16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *ofsAddr;
16231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((mode < 0) || (mode > 2))
16241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
16258f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	ofsAddr = moxa_ports[port].tableAddr;
16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxafunc(ofsAddr, FC_FlushQueue, mode);
16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mode != 1) {
16288f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby		moxa_ports[port].lowChkFlag = 0;
16296f56b658b4e5c4486641ce62f331150954c4de37Jiri Slaby		moxa_low_water_check(ofsAddr);
16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint MoxaDriverIoctl(unsigned int cmd, unsigned long arg, int port)
16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int status;
16371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int MoxaPortTxQueue(int), MoxaPortRxQueue(int);
16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __user *argp = (void __user *)arg;
16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
164011324edd4ad34981764b25bed44d46a1507b62e1Jiri Slaby	if (port == MAX_PORTS) {
1641037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		if ((cmd != MOXA_GET_CONF) && (cmd != MOXA_GETDATACOUNT) &&
1642037182346f0991683cc7320a257c3f6089432ceeJiri Slaby		    (cmd != MOXA_GET_IOQUEUE) && (cmd != MOXA_GET_MAJOR) &&
16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    (cmd != MOXA_GET_CUMAJOR) && (cmd != MOXA_GETMSTATUS))
16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return (-EINVAL);
16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd) {
16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case MOXA_GETDATACOUNT:
16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		moxaLog.tick = jiffies;
16499dff89cd82af7bccc706fed288b1c33a51c3b937Jiri Slaby		if(copy_to_user(argp, &moxaLog, sizeof(struct mon_str)))
16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EFAULT;
16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (0);
16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case MOXA_FLUSH_QUEUE:
16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MoxaPortFlushData(port, arg);
16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (0);
16558f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	case MOXA_GET_IOQUEUE: {
16568f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby		struct moxaq_str __user *argm = argp;
1657181d6f4fac7f01ede95284954ea1231939dca0d9Jiri Slaby		struct moxaq_str tmp;
16588f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby
16598f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby		for (i = 0; i < MAX_PORTS; i++, argm++) {
1660181d6f4fac7f01ede95284954ea1231939dca0d9Jiri Slaby			memset(&tmp, 0, sizeof(tmp));
1661181d6f4fac7f01ede95284954ea1231939dca0d9Jiri Slaby			if (moxa_ports[i].chkPort) {
1662181d6f4fac7f01ede95284954ea1231939dca0d9Jiri Slaby				tmp.inq = MoxaPortRxQueue(i);
1663181d6f4fac7f01ede95284954ea1231939dca0d9Jiri Slaby				tmp.outq = MoxaPortTxQueue(i);
16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
1665181d6f4fac7f01ede95284954ea1231939dca0d9Jiri Slaby			if (copy_to_user(argm, &tmp, sizeof(tmp)))
16668f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby				return -EFAULT;
16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (0);
16698f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	} case MOXA_GET_OQUEUE:
16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i = MoxaPortTxQueue(port);
16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return put_user(i, (unsigned long __user *)argp);
16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case MOXA_GET_IQUEUE:
16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i = MoxaPortRxQueue(port);
16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return put_user(i, (unsigned long __user *)argp);
16751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case MOXA_GET_MAJOR:
16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if(copy_to_user(argp, &ttymajor, sizeof(int)))
16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EFAULT;
16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
16791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case MOXA_GET_CUMAJOR:
16801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i = 0;
16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if(copy_to_user(argp, &i, sizeof(int)))
16821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EFAULT;
16831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
16848f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	case MOXA_GETMSTATUS: {
16858f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby		struct mxser_mstatus __user *argm = argp;
1686181d6f4fac7f01ede95284954ea1231939dca0d9Jiri Slaby		struct mxser_mstatus tmp;
16878f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby		struct moxa_port *p;
16888f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby
16898f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby		for (i = 0; i < MAX_PORTS; i++, argm++) {
16908f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby			p = &moxa_ports[i];
1691181d6f4fac7f01ede95284954ea1231939dca0d9Jiri Slaby			memset(&tmp, 0, sizeof(tmp));
16928f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby			if (!p->chkPort) {
16938f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby				goto copy;
16941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
16958f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby				status = MoxaPortLineStatus(p->port);
16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (status & 1)
1697181d6f4fac7f01ede95284954ea1231939dca0d9Jiri Slaby					tmp.cts = 1;
16981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (status & 2)
1699181d6f4fac7f01ede95284954ea1231939dca0d9Jiri Slaby					tmp.dsr = 1;
17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (status & 4)
1701181d6f4fac7f01ede95284954ea1231939dca0d9Jiri Slaby					tmp.dcd = 1;
17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17048f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby			if (!p->tty || !p->tty->termios)
1705181d6f4fac7f01ede95284954ea1231939dca0d9Jiri Slaby				tmp.cflag = p->cflag;
17061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else
1707181d6f4fac7f01ede95284954ea1231939dca0d9Jiri Slaby				tmp.cflag = p->tty->termios->c_cflag;
17088f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slabycopy:
1709181d6f4fac7f01ede95284954ea1231939dca0d9Jiri Slaby			if (copy_to_user(argm, &tmp, sizeof(tmp)))
17108f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby				return -EFAULT;
17111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
17121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
17131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1715037182346f0991683cc7320a257c3f6089432ceeJiri Slaby
1716037182346f0991683cc7320a257c3f6089432ceeJiri Slaby	return -ENOIOCTLCMD;
17171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint MoxaDriverPoll(void)
17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
17218f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	struct moxa_board_conf *brd;
17221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register ushort temp;
17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register int card;
17241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *ofsAddr;
17251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *ip;
17261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int port, p, ports;
17271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (moxaCard == 0)
17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (-1);
17301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (card = 0; card < MAX_BOARDS; card++) {
17318f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby		brd = &moxa_boards[card];
17328f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	        if (brd->loadstat == 0)
173301cfaf0d12ae5fa092cc916ca4066ee1598e857dDirk Eibach			continue;
17348f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby		if ((ports = brd->numPorts) == 0)
17351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
17368f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby		if (readb(brd->intPend) == 0xff) {
17378f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby			ip = brd->intTable + readb(brd->intNdx);
17381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			p = card * MAX_PORTS_PER_BOARD;
17391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ports <<= 1;
17401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (port = 0; port < ports; port += 2, p++) {
17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if ((temp = readw(ip + port)) != 0) {
17421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					writew(0, ip + port);
17438f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby					ofsAddr = moxa_ports[p].tableAddr;
17441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (temp & IntrTx)
17451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						writew(readw(ofsAddr + HostStat) & ~WakeupTx, ofsAddr + HostStat);
17461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (temp & IntrBreak) {
17478f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby						moxa_ports[p].breakCnt++;
17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
17491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (temp & IntrLine) {
17501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						if (readb(ofsAddr + FlagStat) & DCD_state) {
17518f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby							if ((moxa_ports[p].DCDState & DCD_oldstate) == 0)
17528f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby								moxa_ports[p].DCDState = (DCD_oldstate |
17531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds										   DCD_changed);
17541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						} else {
17558f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby							if (moxa_ports[p].DCDState & DCD_oldstate)
17568f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby								moxa_ports[p].DCDState = DCD_changed;
17571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						}
17581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
17591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
17601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
17618f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby			writeb(0, brd->intPend);
17621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
17631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (moxaLowWaterChk) {
17641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			p = card * MAX_PORTS_PER_BOARD;
17651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (port = 0; port < ports; port++, p++) {
17668f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby				if (moxa_ports[p].lowChkFlag) {
17678f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby					moxa_ports[p].lowChkFlag = 0;
17688f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby					ofsAddr = moxa_ports[p].tableAddr;
17696f56b658b4e5c4486641ce62f331150954c4de37Jiri Slaby					moxa_low_water_check(ofsAddr);
17701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
17711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
17721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
17731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxaLowWaterChk = 0;
17751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (0);
17761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************
17791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Card level function:						     *
17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	1. MoxaPortsOfCard(int cardno); 				     *
17811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *****************************************************************************/
17821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint MoxaPortsOfCard(int cardno)
17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
17841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (moxa_boards[cardno].boardType == 0)
17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (0);
17871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (moxa_boards[cardno].numPorts);
17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************
17911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Port level functions:						     *
17921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	1.  MoxaPortIsValid(int port);					     *
17931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	2.  MoxaPortEnable(int port);					     *
17941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	3.  MoxaPortDisable(int port);					     *
17951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	4.  MoxaPortGetMaxBaud(int port);				     *
17961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	6.  MoxaPortSetBaud(int port, long baud);			     *
17971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	8.  MoxaPortSetTermio(int port, unsigned char *termio); 	     *
17981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	9.  MoxaPortGetLineOut(int port, int *dtrState, int *rtsState);      *
17991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	10. MoxaPortLineCtrl(int port, int dtrState, int rtsState);	     *
18001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	11. MoxaPortFlowCtrl(int port, int rts, int cts, int rx, int tx,int xany);    *
18011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	12. MoxaPortLineStatus(int port);				     *
18021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	13. MoxaPortDCDChange(int port);				     *
18031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	14. MoxaPortDCDON(int port);					     *
18041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	15. MoxaPortFlushData(int port, int mode);	                     *
18051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	16. MoxaPortWriteData(int port, unsigned char * buffer, int length); *
180633f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox *	17. MoxaPortReadData(int port, struct tty_struct *tty); 	     *
18071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	20. MoxaPortTxQueue(int port);					     *
18081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	21. MoxaPortTxFree(int port);					     *
18091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	22. MoxaPortRxQueue(int port);					     *
18101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	24. MoxaPortTxDisable(int port);				     *
18111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	25. MoxaPortTxEnable(int port); 				     *
18121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	27. MoxaPortResetBrkCnt(int port);				     *
18131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	30. MoxaPortSendBreak(int port, int ticks);			     *
18141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *****************************************************************************/
18151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
18161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Moxa Port Number Description:
18171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      MOXA serial driver supports up to 4 MOXA-C218/C320 boards. And,
18191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      the port number using in MOXA driver functions will be 0 to 31 for
18201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      first MOXA board, 32 to 63 for second, 64 to 95 for third and 96
18211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      to 127 for fourth. For example, if you setup three MOXA boards,
18221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      first board is C218, second board is C320-16 and third board is
18231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      C320-32. The port number of first board (C218 - 8 ports) is from
18241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      0 to 7. The port number of second board (C320 - 16 ports) is form
18251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      32 to 47. The port number of third board (C320 - 32 ports) is from
18261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      64 to 95. And those port numbers form 8 to 31, 48 to 63 and 96 to
18271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      127 will be invalid.
18281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Moxa Functions Description:
18311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 1:     Driver initialization routine, this routine must be
18331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                      called when initialized driver.
18341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
18351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      void MoxaDriverInit();
18361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 2:     Moxa driver private IOCTL command processing.
18391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
18401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      int  MoxaDriverIoctl(unsigned int cmd, unsigned long arg, int port);
18411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           unsigned int cmd   : IOCTL command
18431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           unsigned long arg  : IOCTL argument
18441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
18451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           return:    0  (OK)
18471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                      -EINVAL
18481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                      -ENOIOCTLCMD
18491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 3:     Moxa driver polling process routine.
18521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
18531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      int  MoxaDriverPoll(void);
18541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           return:    0       ; polling O.K.
18561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                      -1      : no any Moxa card.
18571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 4:     Get the ports of this card.
18601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
18611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      int  MoxaPortsOfCard(int cardno);
18621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int cardno         : card number (0 - 3)
18641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           return:    0       : this card is invalid
18661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                      8/16/24/32
18671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 5:     Check this port is valid or invalid
18701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
18711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      int  MoxaPortIsValid(int port);
18721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127, ref port description)
18731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           return:    0       : this port is invalid
18751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                      1       : this port is valid
18761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 6:     Enable this port to start Tx/Rx data.
18791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
18801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      void MoxaPortEnable(int port);
18811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
18821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 7:     Disable this port
18851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
18861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      void MoxaPortDisable(int port);
18871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
18881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 8:     Get the maximun available baud rate of this port.
18911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
18921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      long MoxaPortGetMaxBaud(int port);
18931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
18941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           return:    0       : this port is invalid
18961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                      38400/57600/115200 bps
18971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 10:    Setting baud rate of this port.
19001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
19011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      long MoxaPortSetBaud(int port, long baud);
19021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
19031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           long baud          : baud rate (50 - 115200)
19041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
19051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           return:    0       : this port is invalid or baud < 50
19061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                      50 - 115200 : the real baud rate set to the port, if
19071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                                    the argument baud is large than maximun
19081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                                    available baud rate, the real setting
19091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                                    baud rate will be the maximun baud rate.
19101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
19111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
19121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 12:    Configure the port.
19131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
1914606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox *      int  MoxaPortSetTermio(int port, struct ktermios *termio, speed_t baud);
19151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
1916606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox *           struct ktermios * termio : termio structure pointer
1917c7bce3097c0f9bbed76ee6fd03742f2624031a45Alan Cox *	     speed_t baud	: baud rate
19181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
19191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           return:    -1      : this port is invalid or termio == NULL
19201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                      0       : setting O.K.
19211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
19221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
19231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 13:    Get the DTR/RTS state of this port.
19241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
19251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      int  MoxaPortGetLineOut(int port, int *dtrState, int *rtsState);
19261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
19271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int * dtrState     : pointer to INT to receive the current DTR
19281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                                state. (if NULL, this function will not
19291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                                write to this address)
19301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int * rtsState     : pointer to INT to receive the current RTS
19311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                                state. (if NULL, this function will not
19321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                                write to this address)
19331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
19341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           return:    -1      : this port is invalid
19351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                      0       : O.K.
19361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
19371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
19381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 14:    Setting the DTR/RTS output state of this port.
19391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
19401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      void MoxaPortLineCtrl(int port, int dtrState, int rtsState);
19411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
19421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int dtrState       : DTR output state (0: off, 1: on)
19431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int rtsState       : RTS output state (0: off, 1: on)
19441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
19451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
19461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 15:    Setting the flow control of this port.
19471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
19481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      void MoxaPortFlowCtrl(int port, int rtsFlow, int ctsFlow, int rxFlow,
19491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                            int txFlow,int xany);
19501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
19511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int rtsFlow        : H/W RTS flow control (0: no, 1: yes)
19521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int ctsFlow        : H/W CTS flow control (0: no, 1: yes)
19531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int rxFlow         : S/W Rx XON/XOFF flow control (0: no, 1: yes)
19541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int txFlow         : S/W Tx XON/XOFF flow control (0: no, 1: yes)
19551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int xany           : S/W XANY flow control (0: no, 1: yes)
19561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
19571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
19581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 16:    Get ths line status of this port
19591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
19601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      int  MoxaPortLineStatus(int port);
19611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
19621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
19631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           return:    Bit 0 - CTS state (0: off, 1: on)
19641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                      Bit 1 - DSR state (0: off, 1: on)
19651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                      Bit 2 - DCD state (0: off, 1: on)
19661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
19671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
19681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 17:    Check the DCD state has changed since the last read
19691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                      of this function.
19701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
19711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      int  MoxaPortDCDChange(int port);
19721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
19731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
19741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           return:    0       : no changed
19751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                      1       : DCD has changed
19761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
19771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
19781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 18:    Check ths current DCD state is ON or not.
19791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
19801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      int  MoxaPortDCDON(int port);
19811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
19821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
19831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           return:    0       : DCD off
19841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                      1       : DCD on
19851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
19861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
19871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 19:    Flush the Rx/Tx buffer data of this port.
19881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
19891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      void MoxaPortFlushData(int port, int mode);
19901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
19911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int mode
19921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                      0       : flush the Rx buffer
19931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                      1       : flush the Tx buffer
19941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                      2       : flush the Rx and Tx buffer
19951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
19961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
19971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 20:    Write data.
19981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
19991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      int  MoxaPortWriteData(int port, unsigned char * buffer, int length);
20001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
20011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           unsigned char * buffer     : pointer to write data buffer.
20021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int length         : write data length
20031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
20041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           return:    0 - length      : real write data length
20051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
20061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
20071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 21:    Read data.
20081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
200933f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox *      int  MoxaPortReadData(int port, struct tty_struct *tty);
20101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
201133f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox *	     struct tty_struct *tty : tty for data
20121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
20131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           return:    0 - length      : real read data length
20141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
20151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
20161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 24:    Get the Tx buffer current queued data bytes
20171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
20181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      int  MoxaPortTxQueue(int port);
20191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
20201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
20211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           return:    ..      : Tx buffer current queued data bytes
20221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
20231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
20241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 25:    Get the Tx buffer current free space
20251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
20261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      int  MoxaPortTxFree(int port);
20271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
20281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
20291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           return:    ..      : Tx buffer current free space
20301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
20311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
20321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 26:    Get the Rx buffer current queued data bytes
20331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
20341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      int  MoxaPortRxQueue(int port);
20351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
20361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
20371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           return:    ..      : Rx buffer current queued data bytes
20381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
20391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
20401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 28:    Disable port data transmission.
20411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
20421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      void MoxaPortTxDisable(int port);
20431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
20441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
20451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
20461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 29:    Enable port data transmission.
20471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
20481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      void MoxaPortTxEnable(int port);
20491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
20501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
20511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
20521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 31:    Get the received BREAK signal count and reset it.
20531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
20541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      int  MoxaPortResetBrkCnt(int port);
20551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
20561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
20571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           return:    0 - ..  : BREAK signal count
20581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
20591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
20601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Function 34:    Send out a BREAK signal.
20611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Syntax:
20621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      void MoxaPortSendBreak(int port, int ms100);
20631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int port           : port number (0 - 127)
20641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           int ms100          : break signal time interval.
20651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                                unit: 100 mini-second. if ms100 == 0, it will
20661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                                send out a about 250 ms BREAK signal.
20671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
20681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
20691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint MoxaPortIsValid(int port)
20701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
20711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (moxaCard == 0)
20721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (0);
20738f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	if (moxa_ports[port].chkPort == 0)
20741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (0);
20751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (1);
20761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid MoxaPortEnable(int port)
20791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
20801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *ofsAddr;
20811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int MoxaPortLineStatus(int);
20821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	short lowwater = 512;
20831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20848f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	ofsAddr = moxa_ports[port].tableAddr;
20851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writew(lowwater, ofsAddr + Low_water);
20868f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	moxa_ports[port].breakCnt = 0;
20871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) ||
20881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI)) {
20891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		moxafunc(ofsAddr, FC_SetBreakIrq, 0);
20901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
20911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writew(readw(ofsAddr + HostStat) | WakeupBreak, ofsAddr + HostStat);
20921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
20931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxafunc(ofsAddr, FC_SetLineIrq, Magic_code);
20951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxafunc(ofsAddr, FC_FlushQueue, 2);
20961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxafunc(ofsAddr, FC_EnableCH, Magic_code);
20981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MoxaPortLineStatus(port);
20991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
21001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid MoxaPortDisable(int port)
21021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
21038f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	void __iomem *ofsAddr = moxa_ports[port].tableAddr;
21041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxafunc(ofsAddr, FC_SetFlowCtl, 0);	/* disable flow control */
21061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxafunc(ofsAddr, FC_ClrLineIrq, Magic_code);
21071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writew(0, ofsAddr + HostStat);
21081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxafunc(ofsAddr, FC_DisableCH, Magic_code);
21091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
21101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldslong MoxaPortGetMaxBaud(int port)
21121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
21131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) ||
21141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI))
21151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (460800L);
21161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
21171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (921600L);
21181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
21191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldslong MoxaPortSetBaud(int port, long baud)
21221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
21231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *ofsAddr;
21241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	long max, clock;
21251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int val;
21261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((baud < 50L) || ((max = MoxaPortGetMaxBaud(port)) == 0))
21281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (0);
21298f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	ofsAddr = moxa_ports[port].tableAddr;
21301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (baud > max)
21311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		baud = max;
21321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (max == 38400L)
21331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		clock = 614400L;	/* for 9.8304 Mhz : max. 38400 bps */
21341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (max == 57600L)
21351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		clock = 691200L;	/* for 11.0592 Mhz : max. 57600 bps */
21361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
21371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		clock = 921600L;	/* for 14.7456 Mhz : max. 115200 bps */
21381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = clock / baud;
21391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxafunc(ofsAddr, FC_SetBaud, val);
21401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	baud = clock / val;
21418f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	moxa_ports[port].curBaud = baud;
21421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (baud);
21431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
21441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2145606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Coxint MoxaPortSetTermio(int port, struct ktermios *termio, speed_t baud)
21461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
21471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *ofsAddr;
21481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcflag_t cflag;
21491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcflag_t mode = 0;
21501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21518f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	if (moxa_ports[port].chkPort == 0 || termio == 0)
21521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (-1);
21538f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	ofsAddr = moxa_ports[port].tableAddr;
21541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cflag = termio->c_cflag;	/* termio->c_cflag */
21551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mode = termio->c_cflag & CSIZE;
21571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mode == CS5)
21581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mode = MX_CS5;
21591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (mode == CS6)
21601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mode = MX_CS6;
21611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (mode == CS7)
21621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mode = MX_CS7;
21631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (mode == CS8)
21641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mode = MX_CS8;
21651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (termio->c_cflag & CSTOPB) {
21671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (mode == MX_CS5)
21681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mode |= MX_STOP15;
21691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
21701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mode |= MX_STOP2;
21711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
21721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mode |= MX_STOP1;
21731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (termio->c_cflag & PARENB) {
21751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (termio->c_cflag & PARODD)
21761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mode |= MX_PARODD;
21771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
21781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mode |= MX_PAREVEN;
21791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
21801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mode |= MX_PARNONE;
21811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxafunc(ofsAddr, FC_SetDataMode, (ushort) mode);
21831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) ||
21851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI)) {
2186c7bce3097c0f9bbed76ee6fd03742f2624031a45Alan Cox		if (baud >= 921600L)
21871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return (-1);
21881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2189db1acaa632870ec87b65e062bc72ca375837a1f6Alan Cox	baud = MoxaPortSetBaud(port, baud);
21901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (termio->c_iflag & (IXON | IXOFF | IXANY)) {
21921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writeb(termio->c_cc[VSTART], ofsAddr + FuncArg);
21931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writeb(termio->c_cc[VSTOP], ofsAddr + FuncArg1);
21941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writeb(FC_SetXonXoff, ofsAddr + FuncCode);
21956f56b658b4e5c4486641ce62f331150954c4de37Jiri Slaby		moxa_wait_finish(ofsAddr);
21961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2198db1acaa632870ec87b65e062bc72ca375837a1f6Alan Cox	return (baud);
21991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
22001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint MoxaPortGetLineOut(int port, int *dtrState, int *rtsState)
22021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
22031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!MoxaPortIsValid(port))
22051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (-1);
22061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dtrState) {
22078f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby		if (moxa_ports[port].lineCtrl & DTR_ON)
22081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*dtrState = 1;
22091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
22101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*dtrState = 0;
22111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
22121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rtsState) {
22138f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby		if (moxa_ports[port].lineCtrl & RTS_ON)
22141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*rtsState = 1;
22151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
22161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*rtsState = 0;
22171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
22181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (0);
22191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
22201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid MoxaPortLineCtrl(int port, int dtr, int rts)
22221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
22231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *ofsAddr;
22241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int mode;
22251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22268f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	ofsAddr = moxa_ports[port].tableAddr;
22271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mode = 0;
22281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dtr)
22291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mode |= DTR_ON;
22301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rts)
22311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mode |= RTS_ON;
22328f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	moxa_ports[port].lineCtrl = mode;
22331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxafunc(ofsAddr, FC_LineControl, mode);
22341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
22351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid MoxaPortFlowCtrl(int port, int rts, int cts, int txflow, int rxflow, int txany)
22371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
22381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *ofsAddr;
22391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int mode;
22401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22418f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	ofsAddr = moxa_ports[port].tableAddr;
22421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mode = 0;
22431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rts)
22441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mode |= RTS_FlowCtl;
22451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cts)
22461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mode |= CTS_FlowCtl;
22471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (txflow)
22481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mode |= Tx_FlowCtl;
22491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rxflow)
22501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mode |= Rx_FlowCtl;
22511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (txany)
22521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mode |= IXM_IXANY;
22531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxafunc(ofsAddr, FC_SetFlowCtl, mode);
22541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
22551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint MoxaPortLineStatus(int port)
22571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
22581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *ofsAddr;
22591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int val;
22601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22618f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	ofsAddr = moxa_ports[port].tableAddr;
22621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) ||
22631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI)) {
22641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		moxafunc(ofsAddr, FC_LineStatus, 0);
22651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val = readw(ofsAddr + FuncArg);
22661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
22671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val = readw(ofsAddr + FlagStat) >> 4;
22681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
22691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val &= 0x0B;
22701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (val & 8) {
22711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val |= 4;
22728f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby		if ((moxa_ports[port].DCDState & DCD_oldstate) == 0)
22738f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby			moxa_ports[port].DCDState = (DCD_oldstate | DCD_changed);
22741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
22758f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby		if (moxa_ports[port].DCDState & DCD_oldstate)
22768f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby			moxa_ports[port].DCDState = DCD_changed;
22771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
22781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val &= 7;
22791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (val);
22801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
22811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint MoxaPortDCDChange(int port)
22831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
22841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int n;
22851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22868f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	if (moxa_ports[port].chkPort == 0)
22871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (0);
22888f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	n = moxa_ports[port].DCDState;
22898f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	moxa_ports[port].DCDState &= ~DCD_changed;
22901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	n &= DCD_changed;
22911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (n);
22921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
22931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint MoxaPortDCDON(int port)
22951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
22961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int n;
22971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22988f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	if (moxa_ports[port].chkPort == 0)
22991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (0);
23008f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	if (moxa_ports[port].DCDState & DCD_oldstate)
23011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		n = 1;
23021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
23031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		n = 0;
23041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (n);
23051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
23061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint MoxaPortWriteData(int port, unsigned char * buffer, int len)
23081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
23091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int c, total, i;
23101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ushort tail;
23111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cnt;
23121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ushort head, tx_mask, spage, epage;
23131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ushort pageno, pageofs, bufhead;
23141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *baseAddr, *ofsAddr, *ofs;
23151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23168f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	ofsAddr = moxa_ports[port].tableAddr;
23178f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	baseAddr = moxa_boards[port / MAX_PORTS_PER_BOARD].basemem;
23181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tx_mask = readw(ofsAddr + TX_mask);
23191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spage = readw(ofsAddr + Page_txb);
23201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	epage = readw(ofsAddr + EndPage_txb);
23211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tail = readw(ofsAddr + TXwptr);
23221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	head = readw(ofsAddr + TXrptr);
23231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	c = (head > tail) ? (head - tail - 1)
23241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    : (head - tail + tx_mask);
23251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (c > len)
23261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		c = len;
23271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxaLog.txcnt[port] += c;
23281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	total = c;
23291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (spage == epage) {
23301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bufhead = readw(ofsAddr + Ofs_txb);
23311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writew(spage, baseAddr + Control_reg);
23321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (c > 0) {
23331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (head > tail)
23341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				len = head - tail - 1;
23351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else
23361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				len = tx_mask + 1 - tail;
23371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			len = (c > len) ? len : c;
23381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ofs = baseAddr + DynPage_addr + bufhead + tail;
23391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (i = 0; i < len; i++)
23401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				writeb(*buffer++, ofs + i);
23411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tail = (tail + len) & tx_mask;
23421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			c -= len;
23431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
23441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writew(tail, ofsAddr + TXwptr);
23451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
23461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		len = c;
23471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pageno = spage + (tail >> 13);
23481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pageofs = tail & Page_mask;
23491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		do {
23501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cnt = Page_size - pageofs;
23511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (cnt > c)
23521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				cnt = c;
23531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			c -= cnt;
23541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			writeb(pageno, baseAddr + Control_reg);
23551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ofs = baseAddr + DynPage_addr + pageofs;
23561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (i = 0; i < cnt; i++)
23571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				writeb(*buffer++, ofs + i);
23581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (c == 0) {
23591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				writew((tail + len) & tx_mask, ofsAddr + TXwptr);
23601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
23611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
23621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (++pageno == epage)
23631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pageno = spage;
23641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pageofs = 0;
23651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} while (1);
23661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
23671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writeb(1, ofsAddr + CD180TXirq);	/* start to send */
23681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (total);
23691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
23701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
237133f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Coxint MoxaPortReadData(int port, struct tty_struct *tty)
23721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
23731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register ushort head, pageofs;
23741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, count, cnt, len, total, remain;
23751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ushort tail, rx_mask, spage, epage;
23761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ushort pageno, bufhead;
23771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *baseAddr, *ofsAddr, *ofs;
23781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23798f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	ofsAddr = moxa_ports[port].tableAddr;
23808f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	baseAddr = moxa_boards[port / MAX_PORTS_PER_BOARD].basemem;
23811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	head = readw(ofsAddr + RXrptr);
23821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tail = readw(ofsAddr + RXwptr);
23831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rx_mask = readw(ofsAddr + RX_mask);
23841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spage = readw(ofsAddr + Page_rxb);
23851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	epage = readw(ofsAddr + EndPage_rxb);
23861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	count = (tail >= head) ? (tail - head)
23871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    : (tail - head + rx_mask + 1);
23881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (count == 0)
238933f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox		return 0;
23901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
239133f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox	total = count;
23921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	remain = count - total;
23931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxaLog.rxcnt[port] += total;
23941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	count = total;
23951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (spage == epage) {
23961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bufhead = readw(ofsAddr + Ofs_rxb);
23971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writew(spage, baseAddr + Control_reg);
23981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (count > 0) {
23991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (tail >= head)
24001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				len = tail - head;
24011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else
24021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				len = rx_mask + 1 - head;
24031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			len = (count > len) ? len : count;
24041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ofs = baseAddr + DynPage_addr + bufhead + head;
24051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (i = 0; i < len; i++)
240633f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox				tty_insert_flip_char(tty, readb(ofs + i), TTY_NORMAL);
24071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			head = (head + len) & rx_mask;
24081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			count -= len;
24091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
24101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writew(head, ofsAddr + RXrptr);
24111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
24121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		len = count;
24131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pageno = spage + (head >> 13);
24141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pageofs = head & Page_mask;
24151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		do {
24161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cnt = Page_size - pageofs;
24171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (cnt > count)
24181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				cnt = count;
24191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			count -= cnt;
24201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			writew(pageno, baseAddr + Control_reg);
24211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ofs = baseAddr + DynPage_addr + pageofs;
24221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (i = 0; i < cnt; i++)
242333f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox				tty_insert_flip_char(tty, readb(ofs + i), TTY_NORMAL);
24241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (count == 0) {
24251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				writew((head + len) & rx_mask, ofsAddr + RXrptr);
24261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
24271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
24281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (++pageno == epage)
24291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pageno = spage;
24301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pageofs = 0;
24311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} while (1);
24321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
24331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((readb(ofsAddr + FlagStat) & Xoff_state) && (remain < LowWater)) {
24341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		moxaLowWaterChk = 1;
24358f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby		moxa_ports[port].lowChkFlag = 1;
24361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
24371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (total);
24381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
24391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint MoxaPortTxQueue(int port)
24421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
24431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *ofsAddr;
24441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ushort rptr, wptr, mask;
24451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int len;
24461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24478f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	ofsAddr = moxa_ports[port].tableAddr;
24481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rptr = readw(ofsAddr + TXrptr);
24491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wptr = readw(ofsAddr + TXwptr);
24501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mask = readw(ofsAddr + TX_mask);
24511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = (wptr - rptr) & mask;
24521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (len);
24531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
24541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint MoxaPortTxFree(int port)
24561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
24571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *ofsAddr;
24581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ushort rptr, wptr, mask;
24591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int len;
24601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24618f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	ofsAddr = moxa_ports[port].tableAddr;
24621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rptr = readw(ofsAddr + TXrptr);
24631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wptr = readw(ofsAddr + TXwptr);
24641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mask = readw(ofsAddr + TX_mask);
24651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = mask - ((wptr - rptr) & mask);
24661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (len);
24671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
24681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint MoxaPortRxQueue(int port)
24701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
24711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *ofsAddr;
24721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ushort rptr, wptr, mask;
24731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int len;
24741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24758f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	ofsAddr = moxa_ports[port].tableAddr;
24761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rptr = readw(ofsAddr + RXrptr);
24771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wptr = readw(ofsAddr + RXwptr);
24781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mask = readw(ofsAddr + RX_mask);
24791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = (wptr - rptr) & mask;
24801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (len);
24811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
24821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid MoxaPortTxDisable(int port)
24851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
24861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *ofsAddr;
24871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24888f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	ofsAddr = moxa_ports[port].tableAddr;
24891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxafunc(ofsAddr, FC_SetXoffState, Magic_code);
24901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
24911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid MoxaPortTxEnable(int port)
24931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
24941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *ofsAddr;
24951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24968f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	ofsAddr = moxa_ports[port].tableAddr;
24971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxafunc(ofsAddr, FC_SetXonState, Magic_code);
24981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
24991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint MoxaPortResetBrkCnt(int port)
25021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
25031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ushort cnt;
25048f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	cnt = moxa_ports[port].breakCnt;
25058f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	moxa_ports[port].breakCnt = 0;
25061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (cnt);
25071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
25081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid MoxaPortSendBreak(int port, int ms100)
25111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
25121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *ofsAddr;
25131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25148f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	ofsAddr = moxa_ports[port].tableAddr;
25151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ms100) {
25161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		moxafunc(ofsAddr, FC_SendBreak, Magic_code);
251724c032f1dd393c995545ecefa8c1585ae9ef6b37Jiri Slaby		msleep(ms100 * 10);
25181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
25191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		moxafunc(ofsAddr, FC_SendBreak, Magic_code);
252024c032f1dd393c995545ecefa8c1585ae9ef6b37Jiri Slaby		msleep(250);
25211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
25221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	moxafunc(ofsAddr, FC_StopBreak, Magic_code);
25231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
25241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25258f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slabystatic int moxa_get_serial_info(struct moxa_port *info,
25261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				struct serial_struct __user *retinfo)
25271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
25281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct serial_struct tmp;
25291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(&tmp, 0, sizeof(tmp));
25311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp.type = info->type;
25321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp.line = info->port;
25331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp.port = 0;
25341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp.irq = 0;
25351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp.flags = info->asyncflags;
25361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp.baud_base = 921600;
25371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp.close_delay = info->close_delay;
25381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp.closing_wait = info->closing_wait;
25391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp.custom_divisor = 0;
25401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp.hub6 = 0;
25411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
25421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
25431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (0);
25441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
25451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25478f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slabystatic int moxa_set_serial_info(struct moxa_port *info,
25481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				struct serial_struct __user *new_info)
25491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
25501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct serial_struct new_serial;
25511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(copy_from_user(&new_serial, new_info, sizeof(new_serial)))
25531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
25541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((new_serial.irq != 0) ||
25561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (new_serial.port != 0) ||
25571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds//           (new_serial.type != info->type) ||
25581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (new_serial.custom_divisor != 0) ||
25591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (new_serial.baud_base != 921600))
25601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (-EPERM);
25611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!capable(CAP_SYS_ADMIN)) {
25631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (((new_serial.flags & ~ASYNC_USR_MASK) !=
25641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     (info->asyncflags & ~ASYNC_USR_MASK)))
25651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return (-EPERM);
25661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
25671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info->close_delay = new_serial.close_delay * HZ / 100;
25681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info->closing_wait = new_serial.closing_wait * HZ / 100;
25691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
25701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	new_serial.flags = (new_serial.flags & ~ASYNC_FLAGS);
25721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	new_serial.flags |= (info->asyncflags & ASYNC_FLAGS);
25731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (new_serial.type == PORT_16550A) {
25751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MoxaSetFifo(info->port, 1);
25761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
25771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MoxaSetFifo(info->port, 0);
25781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
25791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->type = new_serial.type;
25811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (0);
25821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
25831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************
25871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Static local functions: 					     *
25881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *****************************************************************************/
25891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void moxafunc(void __iomem *ofsAddr, int cmd, ushort arg)
25901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
25911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writew(arg, ofsAddr + FuncArg);
25931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writew(cmd, ofsAddr + FuncCode);
25946f56b658b4e5c4486641ce62f331150954c4de37Jiri Slaby	moxa_wait_finish(ofsAddr);
25951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
25961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25976f56b658b4e5c4486641ce62f331150954c4de37Jiri Slabystatic void moxa_wait_finish(void __iomem *ofsAddr)
25981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
25991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long i, j;
26001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i = jiffies;
26021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (readw(ofsAddr + FuncCode) != 0) {
26031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		j = jiffies;
26041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((j - i) > moxaFuncTout) {
26051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
26061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
26071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
26081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
26091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26106f56b658b4e5c4486641ce62f331150954c4de37Jiri Slabystatic void moxa_low_water_check(void __iomem *ofsAddr)
26111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
26121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int len;
26131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ushort rptr, wptr, mask;
26141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (readb(ofsAddr + FlagStat) & Xoff_state) {
26161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rptr = readw(ofsAddr + RXrptr);
26171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		wptr = readw(ofsAddr + RXwptr);
26181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mask = readw(ofsAddr + RX_mask);
26191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		len = (wptr - rptr) & mask;
26201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (len <= Low_water)
26211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			moxafunc(ofsAddr, FC_SendXon, 0);
26221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
26231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
26241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void MoxaSetFifo(int port, int enable)
26261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
26278f8ecbad09b48e5fe44a8d7f5344e802e9c231c8Jiri Slaby	void __iomem *ofsAddr = moxa_ports[port].tableAddr;
26281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!enable) {
26301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		moxafunc(ofsAddr, FC_SetRxFIFOTrig, 0);
26311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		moxafunc(ofsAddr, FC_SetTxFIFOCnt, 1);
26321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
26331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		moxafunc(ofsAddr, FC_SetRxFIFOTrig, 3);
26341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		moxafunc(ofsAddr, FC_SetTxFIFOCnt, 16);
26351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
26361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2637