diff options
Diffstat (limited to 'drivers/char/moxa.c')
| -rw-r--r-- | drivers/char/moxa.c | 2092 | 
1 files changed, 0 insertions, 2092 deletions
diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c deleted file mode 100644 index 107b0bd58d1..00000000000 --- a/drivers/char/moxa.c +++ /dev/null @@ -1,2092 +0,0 @@ -/*****************************************************************************/ -/* - *           moxa.c  -- MOXA Intellio family multiport serial driver. - * - *      Copyright (C) 1999-2000  Moxa Technologies (support@moxa.com). - *      Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com> - * - *      This code is loosely based on the Linux serial driver, written by - *      Linus Torvalds, Theodore T'so and others. - * - *      This program is free software; you can redistribute it and/or modify - *      it under the terms of the GNU General Public License as published by - *      the Free Software Foundation; either version 2 of the License, or - *      (at your option) any later version. - */ - -/* - *    MOXA Intellio Series Driver - *      for             : LINUX - *      date            : 1999/1/7 - *      version         : 5.1 - */ - -#include <linux/module.h> -#include <linux/types.h> -#include <linux/mm.h> -#include <linux/ioport.h> -#include <linux/errno.h> -#include <linux/firmware.h> -#include <linux/signal.h> -#include <linux/sched.h> -#include <linux/timer.h> -#include <linux/interrupt.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> -#include <linux/major.h> -#include <linux/string.h> -#include <linux/fcntl.h> -#include <linux/ptrace.h> -#include <linux/serial.h> -#include <linux/tty_driver.h> -#include <linux/delay.h> -#include <linux/pci.h> -#include <linux/init.h> -#include <linux/bitops.h> -#include <linux/slab.h> - -#include <asm/system.h> -#include <asm/io.h> -#include <asm/uaccess.h> - -#include "moxa.h" - -#define MOXA_VERSION		"6.0k" - -#define MOXA_FW_HDRLEN		32 - -#define MOXAMAJOR		172 - -#define MAX_BOARDS		4	/* Don't change this value */ -#define MAX_PORTS_PER_BOARD	32	/* Don't change this value */ -#define MAX_PORTS		(MAX_BOARDS * MAX_PORTS_PER_BOARD) - -#define MOXA_IS_320(brd) ((brd)->boardType == MOXA_BOARD_C320_ISA || \ -		(brd)->boardType == MOXA_BOARD_C320_PCI) - -/* - *    Define the Moxa PCI vendor and device IDs. - */ -#define MOXA_BUS_TYPE_ISA	0 -#define MOXA_BUS_TYPE_PCI	1 - -enum { -	MOXA_BOARD_C218_PCI = 1, -	MOXA_BOARD_C218_ISA, -	MOXA_BOARD_C320_PCI, -	MOXA_BOARD_C320_ISA, -	MOXA_BOARD_CP204J, -}; - -static char *moxa_brdname[] = -{ -	"C218 Turbo PCI series", -	"C218 Turbo ISA series", -	"C320 Turbo PCI series", -	"C320 Turbo ISA series", -	"CP-204J series", -}; - -#ifdef CONFIG_PCI -static struct pci_device_id moxa_pcibrds[] = { -	{ PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C218), -		.driver_data = MOXA_BOARD_C218_PCI }, -	{ PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C320), -		.driver_data = MOXA_BOARD_C320_PCI }, -	{ PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP204J), -		.driver_data = MOXA_BOARD_CP204J }, -	{ 0 } -}; -MODULE_DEVICE_TABLE(pci, moxa_pcibrds); -#endif /* CONFIG_PCI */ - -struct moxa_port; - -static struct moxa_board_conf { -	int boardType; -	int numPorts; -	int busType; - -	unsigned int ready; - -	struct moxa_port *ports; - -	void __iomem *basemem; -	void __iomem *intNdx; -	void __iomem *intPend; -	void __iomem *intTable; -} moxa_boards[MAX_BOARDS]; - -struct mxser_mstatus { -	tcflag_t cflag; -	int cts; -	int dsr; -	int ri; -	int dcd; -}; - -struct moxaq_str { -	int inq; -	int outq; -}; - -struct moxa_port { -	struct tty_port port; -	struct moxa_board_conf *board; -	void __iomem *tableAddr; - -	int type; -	int cflag; -	unsigned long statusflags; - -	u8 DCDState;		/* Protected by the port lock */ -	u8 lineCtrl; -	u8 lowChkFlag; -}; - -struct mon_str { -	int tick; -	int rxcnt[MAX_PORTS]; -	int txcnt[MAX_PORTS]; -}; - -/* statusflags */ -#define TXSTOPPED	1 -#define LOWWAIT 	2 -#define EMPTYWAIT	3 - -#define SERIAL_DO_RESTART - -#define WAKEUP_CHARS		256 - -static int ttymajor = MOXAMAJOR; -static struct mon_str moxaLog; -static unsigned int moxaFuncTout = HZ / 2; -static unsigned int moxaLowWaterChk; -static DEFINE_MUTEX(moxa_openlock); -static DEFINE_SPINLOCK(moxa_lock); - -static unsigned long baseaddr[MAX_BOARDS]; -static unsigned int type[MAX_BOARDS]; -static unsigned int numports[MAX_BOARDS]; - -MODULE_AUTHOR("William Chen"); -MODULE_DESCRIPTION("MOXA Intellio Family Multiport Board Device Driver"); -MODULE_LICENSE("GPL"); -MODULE_FIRMWARE("c218tunx.cod"); -MODULE_FIRMWARE("cp204unx.cod"); -MODULE_FIRMWARE("c320tunx.cod"); - -module_param_array(type, uint, NULL, 0); -MODULE_PARM_DESC(type, "card type: C218=2, C320=4"); -module_param_array(baseaddr, ulong, NULL, 0); -MODULE_PARM_DESC(baseaddr, "base address"); -module_param_array(numports, uint, NULL, 0); -MODULE_PARM_DESC(numports, "numports (ignored for C218)"); - -module_param(ttymajor, int, 0); - -/* - * static functions: - */ -static int moxa_open(struct tty_struct *, struct file *); -static void moxa_close(struct tty_struct *, struct file *); -static int moxa_write(struct tty_struct *, const unsigned char *, int); -static int moxa_write_room(struct tty_struct *); -static void moxa_flush_buffer(struct tty_struct *); -static int moxa_chars_in_buffer(struct tty_struct *); -static void moxa_set_termios(struct tty_struct *, struct ktermios *); -static void moxa_stop(struct tty_struct *); -static void moxa_start(struct tty_struct *); -static void moxa_hangup(struct tty_struct *); -static int moxa_tiocmget(struct tty_struct *tty, struct file *file); -static int moxa_tiocmset(struct tty_struct *tty, struct file *file, -			 unsigned int set, unsigned int clear); -static void moxa_poll(unsigned long); -static void moxa_set_tty_param(struct tty_struct *, struct ktermios *); -static void moxa_shutdown(struct tty_port *); -static int moxa_carrier_raised(struct tty_port *); -static void moxa_dtr_rts(struct tty_port *, int); -/* - * moxa board interface functions: - */ -static void MoxaPortEnable(struct moxa_port *); -static void MoxaPortDisable(struct moxa_port *); -static int MoxaPortSetTermio(struct moxa_port *, struct ktermios *, speed_t); -static int MoxaPortGetLineOut(struct moxa_port *, int *, int *); -static void MoxaPortLineCtrl(struct moxa_port *, int, int); -static void MoxaPortFlowCtrl(struct moxa_port *, int, int, int, int, int); -static int MoxaPortLineStatus(struct moxa_port *); -static void MoxaPortFlushData(struct moxa_port *, int); -static int MoxaPortWriteData(struct tty_struct *, const unsigned char *, int); -static int MoxaPortReadData(struct moxa_port *); -static int MoxaPortTxQueue(struct moxa_port *); -static int MoxaPortRxQueue(struct moxa_port *); -static int MoxaPortTxFree(struct moxa_port *); -static void MoxaPortTxDisable(struct moxa_port *); -static void MoxaPortTxEnable(struct moxa_port *); -static int moxa_get_serial_info(struct moxa_port *, struct serial_struct __user *); -static int moxa_set_serial_info(struct moxa_port *, struct serial_struct __user *); -static void MoxaSetFifo(struct moxa_port *port, int enable); - -/* - * I/O functions - */ - -static DEFINE_SPINLOCK(moxafunc_lock); - -static void moxa_wait_finish(void __iomem *ofsAddr) -{ -	unsigned long end = jiffies + moxaFuncTout; - -	while (readw(ofsAddr + FuncCode) != 0) -		if (time_after(jiffies, end)) -			return; -	if (readw(ofsAddr + FuncCode) != 0 && printk_ratelimit()) -		printk(KERN_WARNING "moxa function expired\n"); -} - -static void moxafunc(void __iomem *ofsAddr, u16 cmd, u16 arg) -{ -        unsigned long flags; -        spin_lock_irqsave(&moxafunc_lock, flags); -	writew(arg, ofsAddr + FuncArg); -	writew(cmd, ofsAddr + FuncCode); -	moxa_wait_finish(ofsAddr); -	spin_unlock_irqrestore(&moxafunc_lock, flags); -} - -static int moxafuncret(void __iomem *ofsAddr, u16 cmd, u16 arg) -{ -        unsigned long flags; -        u16 ret; -        spin_lock_irqsave(&moxafunc_lock, flags); -	writew(arg, ofsAddr + FuncArg); -	writew(cmd, ofsAddr + FuncCode); -	moxa_wait_finish(ofsAddr); -	ret = readw(ofsAddr + FuncArg); -	spin_unlock_irqrestore(&moxafunc_lock, flags); -	return ret; -} - -static void moxa_low_water_check(void __iomem *ofsAddr) -{ -	u16 rptr, wptr, mask, len; - -	if (readb(ofsAddr + FlagStat) & Xoff_state) { -		rptr = readw(ofsAddr + RXrptr); -		wptr = readw(ofsAddr + RXwptr); -		mask = readw(ofsAddr + RX_mask); -		len = (wptr - rptr) & mask; -		if (len <= Low_water) -			moxafunc(ofsAddr, FC_SendXon, 0); -	} -} - -/* - * TTY operations - */ - -static int moxa_ioctl(struct tty_struct *tty, struct file *file, -		      unsigned int cmd, unsigned long arg) -{ -	struct moxa_port *ch = tty->driver_data; -	void __user *argp = (void __user *)arg; -	int status, ret = 0; - -	if (tty->index == MAX_PORTS) { -		if (cmd != MOXA_GETDATACOUNT && cmd != MOXA_GET_IOQUEUE && -				cmd != MOXA_GETMSTATUS) -			return -EINVAL; -	} else if (!ch) -		return -ENODEV; - -	switch (cmd) { -	case MOXA_GETDATACOUNT: -		moxaLog.tick = jiffies; -		if (copy_to_user(argp, &moxaLog, sizeof(moxaLog))) -			ret = -EFAULT; -		break; -	case MOXA_FLUSH_QUEUE: -		MoxaPortFlushData(ch, arg); -		break; -	case MOXA_GET_IOQUEUE: { -		struct moxaq_str __user *argm = argp; -		struct moxaq_str tmp; -		struct moxa_port *p; -		unsigned int i, j; - -		for (i = 0; i < MAX_BOARDS; i++) { -			p = moxa_boards[i].ports; -			for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) { -				memset(&tmp, 0, sizeof(tmp)); -				spin_lock_bh(&moxa_lock); -				if (moxa_boards[i].ready) { -					tmp.inq = MoxaPortRxQueue(p); -					tmp.outq = MoxaPortTxQueue(p); -				} -				spin_unlock_bh(&moxa_lock); -				if (copy_to_user(argm, &tmp, sizeof(tmp))) -					return -EFAULT; -			} -		} -		break; -	} case MOXA_GET_OQUEUE: -		status = MoxaPortTxQueue(ch); -		ret = put_user(status, (unsigned long __user *)argp); -		break; -	case MOXA_GET_IQUEUE: -		status = MoxaPortRxQueue(ch); -		ret = put_user(status, (unsigned long __user *)argp); -		break; -	case MOXA_GETMSTATUS: { -		struct mxser_mstatus __user *argm = argp; -		struct mxser_mstatus tmp; -		struct moxa_port *p; -		unsigned int i, j; - -		for (i = 0; i < MAX_BOARDS; i++) { -			p = moxa_boards[i].ports; -			for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) { -				struct tty_struct *ttyp; -				memset(&tmp, 0, sizeof(tmp)); -				spin_lock_bh(&moxa_lock); -				if (!moxa_boards[i].ready) { -				        spin_unlock_bh(&moxa_lock); -					goto copy; -                                } - -				status = MoxaPortLineStatus(p); -				spin_unlock_bh(&moxa_lock); - -				if (status & 1) -					tmp.cts = 1; -				if (status & 2) -					tmp.dsr = 1; -				if (status & 4) -					tmp.dcd = 1; - -				ttyp = tty_port_tty_get(&p->port); -				if (!ttyp || !ttyp->termios) -					tmp.cflag = p->cflag; -				else -					tmp.cflag = ttyp->termios->c_cflag; -				tty_kref_put(tty); -copy: -				if (copy_to_user(argm, &tmp, sizeof(tmp))) -					return -EFAULT; -			} -		} -		break; -	} -	case TIOCGSERIAL: -	        mutex_lock(&ch->port.mutex); -		ret = moxa_get_serial_info(ch, argp); -		mutex_unlock(&ch->port.mutex); -		break; -	case TIOCSSERIAL: -	        mutex_lock(&ch->port.mutex); -		ret = moxa_set_serial_info(ch, argp); -		mutex_unlock(&ch->port.mutex); -		break; -	default: -		ret = -ENOIOCTLCMD; -	} -	return ret; -} - -static int moxa_break_ctl(struct tty_struct *tty, int state) -{ -	struct moxa_port *port = tty->driver_data; - -	moxafunc(port->tableAddr, state ? FC_SendBreak : FC_StopBreak, -			Magic_code); -	return 0; -} - -static const struct tty_operations moxa_ops = { -	.open = moxa_open, -	.close = moxa_close, -	.write = moxa_write, -	.write_room = moxa_write_room, -	.flush_buffer = moxa_flush_buffer, -	.chars_in_buffer = moxa_chars_in_buffer, -	.ioctl = moxa_ioctl, -	.set_termios = moxa_set_termios, -	.stop = moxa_stop, -	.start = moxa_start, -	.hangup = moxa_hangup, -	.break_ctl = moxa_break_ctl, -	.tiocmget = moxa_tiocmget, -	.tiocmset = moxa_tiocmset, -}; - -static const struct tty_port_operations moxa_port_ops = { -	.carrier_raised = moxa_carrier_raised, -	.dtr_rts = moxa_dtr_rts, -	.shutdown = moxa_shutdown, -}; - -static struct tty_driver *moxaDriver; -static DEFINE_TIMER(moxaTimer, moxa_poll, 0, 0); - -/* - * HW init - */ - -static int moxa_check_fw_model(struct moxa_board_conf *brd, u8 model) -{ -	switch (brd->boardType) { -	case MOXA_BOARD_C218_ISA: -	case MOXA_BOARD_C218_PCI: -		if (model != 1) -			goto err; -		break; -	case MOXA_BOARD_CP204J: -		if (model != 3) -			goto err; -		break; -	default: -		if (model != 2) -			goto err; -		break; -	} -	return 0; -err: -	return -EINVAL; -} - -static int moxa_check_fw(const void *ptr) -{ -	const __le16 *lptr = ptr; - -	if (*lptr != cpu_to_le16(0x7980)) -		return -EINVAL; - -	return 0; -} - -static int moxa_load_bios(struct moxa_board_conf *brd, const u8 *buf, -		size_t len) -{ -	void __iomem *baseAddr = brd->basemem; -	u16 tmp; - -	writeb(HW_reset, baseAddr + Control_reg);	/* reset */ -	msleep(10); -	memset_io(baseAddr, 0, 4096); -	memcpy_toio(baseAddr, buf, len);	/* download BIOS */ -	writeb(0, baseAddr + Control_reg);	/* restart */ - -	msleep(2000); - -	switch (brd->boardType) { -	case MOXA_BOARD_C218_ISA: -	case MOXA_BOARD_C218_PCI: -		tmp = readw(baseAddr + C218_key); -		if (tmp != C218_KeyCode) -			goto err; -		break; -	case MOXA_BOARD_CP204J: -		tmp = readw(baseAddr + C218_key); -		if (tmp != CP204J_KeyCode) -			goto err; -		break; -	default: -		tmp = readw(baseAddr + C320_key); -		if (tmp != C320_KeyCode) -			goto err; -		tmp = readw(baseAddr + C320_status); -		if (tmp != STS_init) { -			printk(KERN_ERR "MOXA: bios upload failed -- CPU/Basic " -					"module not found\n"); -			return -EIO; -		} -		break; -	} - -	return 0; -err: -	printk(KERN_ERR "MOXA: bios upload failed -- board not found\n"); -	return -EIO; -} - -static int moxa_load_320b(struct moxa_board_conf *brd, const u8 *ptr, -		size_t len) -{ -	void __iomem *baseAddr = brd->basemem; - -	if (len < 7168) { -		printk(KERN_ERR "MOXA: invalid 320 bios -- too short\n"); -		return -EINVAL; -	} - -	writew(len - 7168 - 2, baseAddr + C320bapi_len); -	writeb(1, baseAddr + Control_reg);	/* Select Page 1 */ -	memcpy_toio(baseAddr + DynPage_addr, ptr, 7168); -	writeb(2, baseAddr + Control_reg);	/* Select Page 2 */ -	memcpy_toio(baseAddr + DynPage_addr, ptr + 7168, len - 7168); - -	return 0; -} - -static int moxa_real_load_code(struct moxa_board_conf *brd, const void *ptr, -		size_t len) -{ -	void __iomem *baseAddr = brd->basemem; -	const __le16 *uptr = ptr; -	size_t wlen, len2, j; -	unsigned long key, loadbuf, loadlen, checksum, checksum_ok; -	unsigned int i, retry; -	u16 usum, keycode; - -	keycode = (brd->boardType == MOXA_BOARD_CP204J) ? CP204J_KeyCode : -				C218_KeyCode; - -	switch (brd->boardType) { -	case MOXA_BOARD_CP204J: -	case MOXA_BOARD_C218_ISA: -	case MOXA_BOARD_C218_PCI: -		key = C218_key; -		loadbuf = C218_LoadBuf; -		loadlen = C218DLoad_len; -		checksum = C218check_sum; -		checksum_ok = C218chksum_ok; -		break; -	default: -		key = C320_key; -		keycode = C320_KeyCode; -		loadbuf = C320_LoadBuf; -		loadlen = C320DLoad_len; -		checksum = C320check_sum; -		checksum_ok = C320chksum_ok; -		break; -	} - -	usum = 0; -	wlen = len >> 1; -	for (i = 0; i < wlen; i++) -		usum += le16_to_cpu(uptr[i]); -	retry = 0; -	do { -		wlen = len >> 1; -		j = 0; -		while (wlen) { -			len2 = (wlen > 2048) ? 2048 : wlen; -			wlen -= len2; -			memcpy_toio(baseAddr + loadbuf, ptr + j, len2 << 1); -			j += len2 << 1; - -			writew(len2, baseAddr + loadlen); -			writew(0, baseAddr + key); -			for (i = 0; i < 100; i++) { -				if (readw(baseAddr + key) == keycode) -					break; -				msleep(10); -			} -			if (readw(baseAddr + key) != keycode) -				return -EIO; -		} -		writew(0, baseAddr + loadlen); -		writew(usum, baseAddr + checksum); -		writew(0, baseAddr + key); -		for (i = 0; i < 100; i++) { -			if (readw(baseAddr + key) == keycode) -				break; -			msleep(10); -		} -		retry++; -	} while ((readb(baseAddr + checksum_ok) != 1) && (retry < 3)); -	if (readb(baseAddr + checksum_ok) != 1) -		return -EIO; - -	writew(0, baseAddr + key); -	for (i = 0; i < 600; i++) { -		if (readw(baseAddr + Magic_no) == Magic_code) -			break; -		msleep(10); -	} -	if (readw(baseAddr + Magic_no) != Magic_code) -		return -EIO; - -	if (MOXA_IS_320(brd)) { -		if (brd->busType == MOXA_BUS_TYPE_PCI) {	/* ASIC board */ -			writew(0x3800, baseAddr + TMS320_PORT1); -			writew(0x3900, baseAddr + TMS320_PORT2); -			writew(28499, baseAddr + TMS320_CLOCK); -		} else { -			writew(0x3200, baseAddr + TMS320_PORT1); -			writew(0x3400, baseAddr + TMS320_PORT2); -			writew(19999, baseAddr + TMS320_CLOCK); -		} -	} -	writew(1, baseAddr + Disable_IRQ); -	writew(0, baseAddr + Magic_no); -	for (i = 0; i < 500; i++) { -		if (readw(baseAddr + Magic_no) == Magic_code) -			break; -		msleep(10); -	} -	if (readw(baseAddr + Magic_no) != Magic_code) -		return -EIO; - -	if (MOXA_IS_320(brd)) { -		j = readw(baseAddr + Module_cnt); -		if (j <= 0) -			return -EIO; -		brd->numPorts = j * 8; -		writew(j, baseAddr + Module_no); -		writew(0, baseAddr + Magic_no); -		for (i = 0; i < 600; i++) { -			if (readw(baseAddr + Magic_no) == Magic_code) -				break; -			msleep(10); -		} -		if (readw(baseAddr + Magic_no) != Magic_code) -			return -EIO; -	} -	brd->intNdx = baseAddr + IRQindex; -	brd->intPend = baseAddr + IRQpending; -	brd->intTable = baseAddr + IRQtable; - -	return 0; -} - -static int moxa_load_code(struct moxa_board_conf *brd, const void *ptr, -		size_t len) -{ -	void __iomem *ofsAddr, *baseAddr = brd->basemem; -	struct moxa_port *port; -	int retval, i; - -	if (len % 2) { -		printk(KERN_ERR "MOXA: bios length is not even\n"); -		return -EINVAL; -	} - -	retval = moxa_real_load_code(brd, ptr, len); /* may change numPorts */ -	if (retval) -		return retval; - -	switch (brd->boardType) { -	case MOXA_BOARD_C218_ISA: -	case MOXA_BOARD_C218_PCI: -	case MOXA_BOARD_CP204J: -		port = brd->ports; -		for (i = 0; i < brd->numPorts; i++, port++) { -			port->board = brd; -			port->DCDState = 0; -			port->tableAddr = baseAddr + Extern_table + -					Extern_size * i; -			ofsAddr = port->tableAddr; -			writew(C218rx_mask, ofsAddr + RX_mask); -			writew(C218tx_mask, ofsAddr + TX_mask); -			writew(C218rx_spage + i * C218buf_pageno, ofsAddr + Page_rxb); -			writew(readw(ofsAddr + Page_rxb) + C218rx_pageno, ofsAddr + EndPage_rxb); - -			writew(C218tx_spage + i * C218buf_pageno, ofsAddr + Page_txb); -			writew(readw(ofsAddr + Page_txb) + C218tx_pageno, ofsAddr + EndPage_txb); - -		} -		break; -	default: -		port = brd->ports; -		for (i = 0; i < brd->numPorts; i++, port++) { -			port->board = brd; -			port->DCDState = 0; -			port->tableAddr = baseAddr + Extern_table + -					Extern_size * i; -			ofsAddr = port->tableAddr; -			switch (brd->numPorts) { -			case 8: -				writew(C320p8rx_mask, ofsAddr + RX_mask); -				writew(C320p8tx_mask, ofsAddr + TX_mask); -				writew(C320p8rx_spage + i * C320p8buf_pgno, ofsAddr + Page_rxb); -				writew(readw(ofsAddr + Page_rxb) + C320p8rx_pgno, ofsAddr + EndPage_rxb); -				writew(C320p8tx_spage + i * C320p8buf_pgno, ofsAddr + Page_txb); -				writew(readw(ofsAddr + Page_txb) + C320p8tx_pgno, ofsAddr + EndPage_txb); - -				break; -			case 16: -				writew(C320p16rx_mask, ofsAddr + RX_mask); -				writew(C320p16tx_mask, ofsAddr + TX_mask); -				writew(C320p16rx_spage + i * C320p16buf_pgno, ofsAddr + Page_rxb); -				writew(readw(ofsAddr + Page_rxb) + C320p16rx_pgno, ofsAddr + EndPage_rxb); -				writew(C320p16tx_spage + i * C320p16buf_pgno, ofsAddr + Page_txb); -				writew(readw(ofsAddr + Page_txb) + C320p16tx_pgno, ofsAddr + EndPage_txb); -				break; - -			case 24: -				writew(C320p24rx_mask, ofsAddr + RX_mask); -				writew(C320p24tx_mask, ofsAddr + TX_mask); -				writew(C320p24rx_spage + i * C320p24buf_pgno, ofsAddr + Page_rxb); -				writew(readw(ofsAddr + Page_rxb) + C320p24rx_pgno, ofsAddr + EndPage_rxb); -				writew(C320p24tx_spage + i * C320p24buf_pgno, ofsAddr + Page_txb); -				writew(readw(ofsAddr + Page_txb), ofsAddr + EndPage_txb); -				break; -			case 32: -				writew(C320p32rx_mask, ofsAddr + RX_mask); -				writew(C320p32tx_mask, ofsAddr + TX_mask); -				writew(C320p32tx_ofs, ofsAddr + Ofs_txb); -				writew(C320p32rx_spage + i * C320p32buf_pgno, ofsAddr + Page_rxb); -				writew(readb(ofsAddr + Page_rxb), ofsAddr + EndPage_rxb); -				writew(C320p32tx_spage + i * C320p32buf_pgno, ofsAddr + Page_txb); -				writew(readw(ofsAddr + Page_txb), ofsAddr + EndPage_txb); -				break; -			} -		} -		break; -	} -	return 0; -} - -static int moxa_load_fw(struct moxa_board_conf *brd, const struct firmware *fw) -{ -	const void *ptr = fw->data; -	char rsn[64]; -	u16 lens[5]; -	size_t len; -	unsigned int a, lenp, lencnt; -	int ret = -EINVAL; -	struct { -		__le32 magic;	/* 0x34303430 */ -		u8 reserved1[2]; -		u8 type;	/* UNIX = 3 */ -		u8 model;	/* C218T=1, C320T=2, CP204=3 */ -		u8 reserved2[8]; -		__le16 len[5]; -	} const *hdr = ptr; - -	BUILD_BUG_ON(ARRAY_SIZE(hdr->len) != ARRAY_SIZE(lens)); - -	if (fw->size < MOXA_FW_HDRLEN) { -		strcpy(rsn, "too short (even header won't fit)"); -		goto err; -	} -	if (hdr->magic != cpu_to_le32(0x30343034)) { -		sprintf(rsn, "bad magic: %.8x", le32_to_cpu(hdr->magic)); -		goto err; -	} -	if (hdr->type != 3) { -		sprintf(rsn, "not for linux, type is %u", hdr->type); -		goto err; -	} -	if (moxa_check_fw_model(brd, hdr->model)) { -		sprintf(rsn, "not for this card, model is %u", hdr->model); -		goto err; -	} - -	len = MOXA_FW_HDRLEN; -	lencnt = hdr->model == 2 ? 5 : 3; -	for (a = 0; a < ARRAY_SIZE(lens); a++) { -		lens[a] = le16_to_cpu(hdr->len[a]); -		if (lens[a] && len + lens[a] <= fw->size && -				moxa_check_fw(&fw->data[len])) -			printk(KERN_WARNING "MOXA firmware: unexpected input " -				"at offset %u, but going on\n", (u32)len); -		if (!lens[a] && a < lencnt) { -			sprintf(rsn, "too few entries in fw file"); -			goto err; -		} -		len += lens[a]; -	} - -	if (len != fw->size) { -		sprintf(rsn, "bad length: %u (should be %u)", (u32)fw->size, -				(u32)len); -		goto err; -	} - -	ptr += MOXA_FW_HDRLEN; -	lenp = 0; /* bios */ - -	strcpy(rsn, "read above"); - -	ret = moxa_load_bios(brd, ptr, lens[lenp]); -	if (ret) -		goto err; - -	/* we skip the tty section (lens[1]), since we don't need it */ -	ptr += lens[lenp] + lens[lenp + 1]; -	lenp += 2; /* comm */ - -	if (hdr->model == 2) { -		ret = moxa_load_320b(brd, ptr, lens[lenp]); -		if (ret) -			goto err; -		/* skip another tty */ -		ptr += lens[lenp] + lens[lenp + 1]; -		lenp += 2; -	} - -	ret = moxa_load_code(brd, ptr, lens[lenp]); -	if (ret) -		goto err; - -	return 0; -err: -	printk(KERN_ERR "firmware failed to load, reason: %s\n", rsn); -	return ret; -} - -static int moxa_init_board(struct moxa_board_conf *brd, struct device *dev) -{ -	const struct firmware *fw; -	const char *file; -	struct moxa_port *p; -	unsigned int i; -	int ret; - -	brd->ports = kcalloc(MAX_PORTS_PER_BOARD, sizeof(*brd->ports), -			GFP_KERNEL); -	if (brd->ports == NULL) { -		printk(KERN_ERR "cannot allocate memory for ports\n"); -		ret = -ENOMEM; -		goto err; -	} - -	for (i = 0, p = brd->ports; i < MAX_PORTS_PER_BOARD; i++, p++) { -		tty_port_init(&p->port); -		p->port.ops = &moxa_port_ops; -		p->type = PORT_16550A; -		p->cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL; -	} - -	switch (brd->boardType) { -	case MOXA_BOARD_C218_ISA: -	case MOXA_BOARD_C218_PCI: -		file = "c218tunx.cod"; -		break; -	case MOXA_BOARD_CP204J: -		file = "cp204unx.cod"; -		break; -	default: -		file = "c320tunx.cod"; -		break; -	} - -	ret = request_firmware(&fw, file, dev); -	if (ret) { -		printk(KERN_ERR "MOXA: request_firmware failed. Make sure " -				"you've placed '%s' file into your firmware " -				"loader directory (e.g. /lib/firmware)\n", -				file); -		goto err_free; -	} - -	ret = moxa_load_fw(brd, fw); - -	release_firmware(fw); - -	if (ret) -		goto err_free; - -	spin_lock_bh(&moxa_lock); -	brd->ready = 1; -	if (!timer_pending(&moxaTimer)) -		mod_timer(&moxaTimer, jiffies + HZ / 50); -	spin_unlock_bh(&moxa_lock); - -	return 0; -err_free: -	kfree(brd->ports); -err: -	return ret; -} - -static void moxa_board_deinit(struct moxa_board_conf *brd) -{ -	unsigned int a, opened; - -	mutex_lock(&moxa_openlock); -	spin_lock_bh(&moxa_lock); -	brd->ready = 0; -	spin_unlock_bh(&moxa_lock); - -	/* pci hot-un-plug support */ -	for (a = 0; a < brd->numPorts; a++) -		if (brd->ports[a].port.flags & ASYNC_INITIALIZED) { -			struct tty_struct *tty = tty_port_tty_get( -						&brd->ports[a].port); -			if (tty) { -				tty_hangup(tty); -				tty_kref_put(tty); -			} -		} -	while (1) { -		opened = 0; -		for (a = 0; a < brd->numPorts; a++) -			if (brd->ports[a].port.flags & ASYNC_INITIALIZED) -				opened++; -		mutex_unlock(&moxa_openlock); -		if (!opened) -			break; -		msleep(50); -		mutex_lock(&moxa_openlock); -	} - -	iounmap(brd->basemem); -	brd->basemem = NULL; -	kfree(brd->ports); -} - -#ifdef CONFIG_PCI -static int __devinit moxa_pci_probe(struct pci_dev *pdev, -		const struct pci_device_id *ent) -{ -	struct moxa_board_conf *board; -	unsigned int i; -	int board_type = ent->driver_data; -	int retval; - -	retval = pci_enable_device(pdev); -	if (retval) { -		dev_err(&pdev->dev, "can't enable pci device\n"); -		goto err; -	} - -	for (i = 0; i < MAX_BOARDS; i++) -		if (moxa_boards[i].basemem == NULL) -			break; - -	retval = -ENODEV; -	if (i >= MAX_BOARDS) { -		dev_warn(&pdev->dev, "more than %u MOXA Intellio family boards " -				"found. Board is ignored.\n", MAX_BOARDS); -		goto err; -	} - -	board = &moxa_boards[i]; - -	retval = pci_request_region(pdev, 2, "moxa-base"); -	if (retval) { -		dev_err(&pdev->dev, "can't request pci region 2\n"); -		goto err; -	} - -	board->basemem = ioremap_nocache(pci_resource_start(pdev, 2), 0x4000); -	if (board->basemem == NULL) { -		dev_err(&pdev->dev, "can't remap io space 2\n"); -		goto err_reg; -	} - -	board->boardType = board_type; -	switch (board_type) { -	case MOXA_BOARD_C218_ISA: -	case MOXA_BOARD_C218_PCI: -		board->numPorts = 8; -		break; - -	case MOXA_BOARD_CP204J: -		board->numPorts = 4; -		break; -	default: -		board->numPorts = 0; -		break; -	} -	board->busType = MOXA_BUS_TYPE_PCI; - -	retval = moxa_init_board(board, &pdev->dev); -	if (retval) -		goto err_base; - -	pci_set_drvdata(pdev, board); - -	dev_info(&pdev->dev, "board '%s' ready (%u ports, firmware loaded)\n", -			moxa_brdname[board_type - 1], board->numPorts); - -	return 0; -err_base: -	iounmap(board->basemem); -	board->basemem = NULL; -err_reg: -	pci_release_region(pdev, 2); -err: -	return retval; -} - -static void __devexit moxa_pci_remove(struct pci_dev *pdev) -{ -	struct moxa_board_conf *brd = pci_get_drvdata(pdev); - -	moxa_board_deinit(brd); - -	pci_release_region(pdev, 2); -} - -static struct pci_driver moxa_pci_driver = { -	.name = "moxa", -	.id_table = moxa_pcibrds, -	.probe = moxa_pci_probe, -	.remove = __devexit_p(moxa_pci_remove) -}; -#endif /* CONFIG_PCI */ - -static int __init moxa_init(void) -{ -	unsigned int isabrds = 0; -	int retval = 0; -	struct moxa_board_conf *brd = moxa_boards; -	unsigned int i; - -	printk(KERN_INFO "MOXA Intellio family driver version %s\n", -			MOXA_VERSION); -	moxaDriver = alloc_tty_driver(MAX_PORTS + 1); -	if (!moxaDriver) -		return -ENOMEM; - -	moxaDriver->owner = THIS_MODULE; -	moxaDriver->name = "ttyMX"; -	moxaDriver->major = ttymajor; -	moxaDriver->minor_start = 0; -	moxaDriver->type = TTY_DRIVER_TYPE_SERIAL; -	moxaDriver->subtype = SERIAL_TYPE_NORMAL; -	moxaDriver->init_termios = tty_std_termios; -	moxaDriver->init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL; -	moxaDriver->init_termios.c_ispeed = 9600; -	moxaDriver->init_termios.c_ospeed = 9600; -	moxaDriver->flags = TTY_DRIVER_REAL_RAW; -	tty_set_operations(moxaDriver, &moxa_ops); - -	if (tty_register_driver(moxaDriver)) { -		printk(KERN_ERR "can't register MOXA Smartio tty driver!\n"); -		put_tty_driver(moxaDriver); -		return -1; -	} - -	/* Find the boards defined from module args. */ - -	for (i = 0; i < MAX_BOARDS; i++) { -		if (!baseaddr[i]) -			break; -		if (type[i] == MOXA_BOARD_C218_ISA || -				type[i] == MOXA_BOARD_C320_ISA) { -			pr_debug("Moxa board %2d: %s board(baseAddr=%lx)\n", -					isabrds + 1, moxa_brdname[type[i] - 1], -					baseaddr[i]); -			brd->boardType = type[i]; -			brd->numPorts = type[i] == MOXA_BOARD_C218_ISA ? 8 : -					numports[i]; -			brd->busType = MOXA_BUS_TYPE_ISA; -			brd->basemem = ioremap_nocache(baseaddr[i], 0x4000); -			if (!brd->basemem) { -				printk(KERN_ERR "MOXA: can't remap %lx\n", -						baseaddr[i]); -				continue; -			} -			if (moxa_init_board(brd, NULL)) { -				iounmap(brd->basemem); -				brd->basemem = NULL; -				continue; -			} - -			printk(KERN_INFO "MOXA isa board found at 0x%.8lu and " -					"ready (%u ports, firmware loaded)\n", -					baseaddr[i], brd->numPorts); - -			brd++; -			isabrds++; -		} -	} - -#ifdef CONFIG_PCI -	retval = pci_register_driver(&moxa_pci_driver); -	if (retval) { -		printk(KERN_ERR "Can't register MOXA pci driver!\n"); -		if (isabrds) -			retval = 0; -	} -#endif - -	return retval; -} - -static void __exit moxa_exit(void) -{ -	unsigned int i; - -#ifdef CONFIG_PCI -	pci_unregister_driver(&moxa_pci_driver); -#endif - -	for (i = 0; i < MAX_BOARDS; i++) /* ISA boards */ -		if (moxa_boards[i].ready) -			moxa_board_deinit(&moxa_boards[i]); - -	del_timer_sync(&moxaTimer); - -	if (tty_unregister_driver(moxaDriver)) -		printk(KERN_ERR "Couldn't unregister MOXA Intellio family " -				"serial driver\n"); -	put_tty_driver(moxaDriver); -} - -module_init(moxa_init); -module_exit(moxa_exit); - -static void moxa_shutdown(struct tty_port *port) -{ -	struct moxa_port *ch = container_of(port, struct moxa_port, port); -        MoxaPortDisable(ch); -	MoxaPortFlushData(ch, 2); -	clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags); -} - -static int moxa_carrier_raised(struct tty_port *port) -{ -	struct moxa_port *ch = container_of(port, struct moxa_port, port); -	int dcd; - -	spin_lock_irq(&port->lock); -	dcd = ch->DCDState; -	spin_unlock_irq(&port->lock); -	return dcd; -} - -static void moxa_dtr_rts(struct tty_port *port, int onoff) -{ -	struct moxa_port *ch = container_of(port, struct moxa_port, port); -	MoxaPortLineCtrl(ch, onoff, onoff); -} - - -static int moxa_open(struct tty_struct *tty, struct file *filp) -{ -	struct moxa_board_conf *brd; -	struct moxa_port *ch; -	int port; -	int retval; - -	port = tty->index; -	if (port == MAX_PORTS) { -		return capable(CAP_SYS_ADMIN) ? 0 : -EPERM; -	} -	if (mutex_lock_interruptible(&moxa_openlock)) -		return -ERESTARTSYS; -	brd = &moxa_boards[port / MAX_PORTS_PER_BOARD]; -	if (!brd->ready) { -		mutex_unlock(&moxa_openlock); -		return -ENODEV; -	} - -	if (port % MAX_PORTS_PER_BOARD >= brd->numPorts) { -		mutex_unlock(&moxa_openlock); -		return -ENODEV; -	} - -	ch = &brd->ports[port % MAX_PORTS_PER_BOARD]; -	ch->port.count++; -	tty->driver_data = ch; -	tty_port_tty_set(&ch->port, tty); -	mutex_lock(&ch->port.mutex); -	if (!(ch->port.flags & ASYNC_INITIALIZED)) { -		ch->statusflags = 0; -		moxa_set_tty_param(tty, tty->termios); -		MoxaPortLineCtrl(ch, 1, 1); -		MoxaPortEnable(ch); -		MoxaSetFifo(ch, ch->type == PORT_16550A); -		ch->port.flags |= ASYNC_INITIALIZED; -	} -	mutex_unlock(&ch->port.mutex); -	mutex_unlock(&moxa_openlock); - -	retval = tty_port_block_til_ready(&ch->port, tty, filp); -	if (retval == 0) -	        set_bit(ASYNCB_NORMAL_ACTIVE, &ch->port.flags); -	return retval; -} - -static void moxa_close(struct tty_struct *tty, struct file *filp) -{ -	struct moxa_port *ch = tty->driver_data; -	ch->cflag = tty->termios->c_cflag; -	tty_port_close(&ch->port, tty, filp); -} - -static int moxa_write(struct tty_struct *tty, -		      const unsigned char *buf, int count) -{ -	struct moxa_port *ch = tty->driver_data; -	int len; - -	if (ch == NULL) -		return 0; - -	spin_lock_bh(&moxa_lock); -	len = MoxaPortWriteData(tty, buf, count); -	spin_unlock_bh(&moxa_lock); - -	set_bit(LOWWAIT, &ch->statusflags); -	return len; -} - -static int moxa_write_room(struct tty_struct *tty) -{ -	struct moxa_port *ch; - -	if (tty->stopped) -		return 0; -	ch = tty->driver_data; -	if (ch == NULL) -		return 0; -	return MoxaPortTxFree(ch); -} - -static void moxa_flush_buffer(struct tty_struct *tty) -{ -	struct moxa_port *ch = tty->driver_data; - -	if (ch == NULL) -		return; -	MoxaPortFlushData(ch, 1); -	tty_wakeup(tty); -} - -static int moxa_chars_in_buffer(struct tty_struct *tty) -{ -	struct moxa_port *ch = tty->driver_data; -	int chars; - -	chars = MoxaPortTxQueue(ch); -	if (chars) -		/* -		 * Make it possible to wakeup anything waiting for output -		 * in tty_ioctl.c, etc. -		 */ -        	set_bit(EMPTYWAIT, &ch->statusflags); -	return chars; -} - -static int moxa_tiocmget(struct tty_struct *tty, struct file *file) -{ -	struct moxa_port *ch = tty->driver_data; -	int flag = 0, dtr, rts; - -	MoxaPortGetLineOut(ch, &dtr, &rts); -	if (dtr) -		flag |= TIOCM_DTR; -	if (rts) -		flag |= TIOCM_RTS; -	dtr = MoxaPortLineStatus(ch); -	if (dtr & 1) -		flag |= TIOCM_CTS; -	if (dtr & 2) -		flag |= TIOCM_DSR; -	if (dtr & 4) -		flag |= TIOCM_CD; -	return flag; -} - -static int moxa_tiocmset(struct tty_struct *tty, struct file *file, -			 unsigned int set, unsigned int clear) -{ -	struct moxa_port *ch; -	int port; -	int dtr, rts; - -	port = tty->index; -	mutex_lock(&moxa_openlock); -	ch = tty->driver_data; -	if (!ch) { -		mutex_unlock(&moxa_openlock); -		return -EINVAL; -	} - -	MoxaPortGetLineOut(ch, &dtr, &rts); -	if (set & TIOCM_RTS) -		rts = 1; -	if (set & TIOCM_DTR) -		dtr = 1; -	if (clear & TIOCM_RTS) -		rts = 0; -	if (clear & TIOCM_DTR) -		dtr = 0; -	MoxaPortLineCtrl(ch, dtr, rts); -	mutex_unlock(&moxa_openlock); -	return 0; -} - -static void moxa_set_termios(struct tty_struct *tty, -		struct ktermios *old_termios) -{ -	struct moxa_port *ch = tty->driver_data; - -	if (ch == NULL) -		return; -	moxa_set_tty_param(tty, old_termios); -	if (!(old_termios->c_cflag & CLOCAL) && C_CLOCAL(tty)) -		wake_up_interruptible(&ch->port.open_wait); -} - -static void moxa_stop(struct tty_struct *tty) -{ -	struct moxa_port *ch = tty->driver_data; - -	if (ch == NULL) -		return; -	MoxaPortTxDisable(ch); -	set_bit(TXSTOPPED, &ch->statusflags); -} - - -static void moxa_start(struct tty_struct *tty) -{ -	struct moxa_port *ch = tty->driver_data; - -	if (ch == NULL) -		return; - -	if (!(ch->statusflags & TXSTOPPED)) -		return; - -	MoxaPortTxEnable(ch); -	clear_bit(TXSTOPPED, &ch->statusflags); -} - -static void moxa_hangup(struct tty_struct *tty) -{ -	struct moxa_port *ch = tty->driver_data; -	tty_port_hangup(&ch->port); -} - -static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd) -{ -	struct tty_struct *tty; -	unsigned long flags; -	dcd = !!dcd; - -	spin_lock_irqsave(&p->port.lock, flags); -	if (dcd != p->DCDState) { -        	p->DCDState = dcd; -        	spin_unlock_irqrestore(&p->port.lock, flags); -		tty = tty_port_tty_get(&p->port); -		if (tty && C_CLOCAL(tty) && !dcd) -			tty_hangup(tty); -		tty_kref_put(tty); -	} -	else -		spin_unlock_irqrestore(&p->port.lock, flags); -} - -static int moxa_poll_port(struct moxa_port *p, unsigned int handle, -		u16 __iomem *ip) -{ -	struct tty_struct *tty = tty_port_tty_get(&p->port); -	void __iomem *ofsAddr; -	unsigned int inited = p->port.flags & ASYNC_INITIALIZED; -	u16 intr; - -	if (tty) { -		if (test_bit(EMPTYWAIT, &p->statusflags) && -				MoxaPortTxQueue(p) == 0) { -			clear_bit(EMPTYWAIT, &p->statusflags); -			tty_wakeup(tty); -		} -		if (test_bit(LOWWAIT, &p->statusflags) && !tty->stopped && -				MoxaPortTxQueue(p) <= WAKEUP_CHARS) { -			clear_bit(LOWWAIT, &p->statusflags); -			tty_wakeup(tty); -		} - -		if (inited && !test_bit(TTY_THROTTLED, &tty->flags) && -				MoxaPortRxQueue(p) > 0) { /* RX */ -			MoxaPortReadData(p); -			tty_schedule_flip(tty); -		} -	} else { -		clear_bit(EMPTYWAIT, &p->statusflags); -		MoxaPortFlushData(p, 0); /* flush RX */ -	} - -	if (!handle) /* nothing else to do */ -		goto put; - -	intr = readw(ip); /* port irq status */ -	if (intr == 0) -		goto put; - -	writew(0, ip); /* ACK port */ -	ofsAddr = p->tableAddr; -	if (intr & IntrTx) /* disable tx intr */ -		writew(readw(ofsAddr + HostStat) & ~WakeupTx, -				ofsAddr + HostStat); - -	if (!inited) -		goto put; - -	if (tty && (intr & IntrBreak) && !I_IGNBRK(tty)) { /* BREAK */ -		tty_insert_flip_char(tty, 0, TTY_BREAK); -		tty_schedule_flip(tty); -	} - -	if (intr & IntrLine) -		moxa_new_dcdstate(p, readb(ofsAddr + FlagStat) & DCD_state); -put: -	tty_kref_put(tty); - -	return 0; -} - -static void moxa_poll(unsigned long ignored) -{ -	struct moxa_board_conf *brd; -	u16 __iomem *ip; -	unsigned int card, port, served = 0; - -	spin_lock(&moxa_lock); -	for (card = 0; card < MAX_BOARDS; card++) { -		brd = &moxa_boards[card]; -		if (!brd->ready) -			continue; - -		served++; - -		ip = NULL; -		if (readb(brd->intPend) == 0xff) -			ip = brd->intTable + readb(brd->intNdx); - -		for (port = 0; port < brd->numPorts; port++) -			moxa_poll_port(&brd->ports[port], !!ip, ip + port); - -		if (ip) -			writeb(0, brd->intPend); /* ACK */ - -		if (moxaLowWaterChk) { -			struct moxa_port *p = brd->ports; -			for (port = 0; port < brd->numPorts; port++, p++) -				if (p->lowChkFlag) { -					p->lowChkFlag = 0; -					moxa_low_water_check(p->tableAddr); -				} -		} -	} -	moxaLowWaterChk = 0; - -	if (served) -		mod_timer(&moxaTimer, jiffies + HZ / 50); -	spin_unlock(&moxa_lock); -} - -/******************************************************************************/ - -static void moxa_set_tty_param(struct tty_struct *tty, struct ktermios *old_termios) -{ -	register struct ktermios *ts = tty->termios; -	struct moxa_port *ch = tty->driver_data; -	int rts, cts, txflow, rxflow, xany, baud; - -	rts = cts = txflow = rxflow = xany = 0; -	if (ts->c_cflag & CRTSCTS) -		rts = cts = 1; -	if (ts->c_iflag & IXON) -		txflow = 1; -	if (ts->c_iflag & IXOFF) -		rxflow = 1; -	if (ts->c_iflag & IXANY) -		xany = 1; - -	/* Clear the features we don't support */ -	ts->c_cflag &= ~CMSPAR; -	MoxaPortFlowCtrl(ch, rts, cts, txflow, rxflow, xany); -	baud = MoxaPortSetTermio(ch, ts, tty_get_baud_rate(tty)); -	if (baud == -1) -		baud = tty_termios_baud_rate(old_termios); -	/* Not put the baud rate into the termios data */ -	tty_encode_baud_rate(tty, baud, baud); -} - -/***************************************************************************** - *	Driver level functions: 					     * - *****************************************************************************/ - -static void MoxaPortFlushData(struct moxa_port *port, int mode) -{ -	void __iomem *ofsAddr; -	if (mode < 0 || mode > 2) -		return; -	ofsAddr = port->tableAddr; -	moxafunc(ofsAddr, FC_FlushQueue, mode); -	if (mode != 1) { -		port->lowChkFlag = 0; -		moxa_low_water_check(ofsAddr); -	} -} - -/* - *    Moxa Port Number Description: - * - *      MOXA serial driver supports up to 4 MOXA-C218/C320 boards. And, - *      the port number using in MOXA driver functions will be 0 to 31 for - *      first MOXA board, 32 to 63 for second, 64 to 95 for third and 96 - *      to 127 for fourth. For example, if you setup three MOXA boards, - *      first board is C218, second board is C320-16 and third board is - *      C320-32. The port number of first board (C218 - 8 ports) is from - *      0 to 7. The port number of second board (C320 - 16 ports) is form - *      32 to 47. The port number of third board (C320 - 32 ports) is from - *      64 to 95. And those port numbers form 8 to 31, 48 to 63 and 96 to - *      127 will be invalid. - * - * - *      Moxa Functions Description: - * - *      Function 1:     Driver initialization routine, this routine must be - *                      called when initialized driver. - *      Syntax: - *      void MoxaDriverInit(); - * - * - *      Function 2:     Moxa driver private IOCTL command processing. - *      Syntax: - *      int  MoxaDriverIoctl(unsigned int cmd, unsigned long arg, int port); - * - *           unsigned int cmd   : IOCTL command - *           unsigned long arg  : IOCTL argument - *           int port           : port number (0 - 127) - * - *           return:    0  (OK) - *                      -EINVAL - *                      -ENOIOCTLCMD - * - * - *      Function 6:     Enable this port to start Tx/Rx data. - *      Syntax: - *      void MoxaPortEnable(int port); - *           int port           : port number (0 - 127) - * - * - *      Function 7:     Disable this port - *      Syntax: - *      void MoxaPortDisable(int port); - *           int port           : port number (0 - 127) - * - * - *      Function 10:    Setting baud rate of this port. - *      Syntax: - *      speed_t MoxaPortSetBaud(int port, speed_t baud); - *           int port           : port number (0 - 127) - *           long baud          : baud rate (50 - 115200) - * - *           return:    0       : this port is invalid or baud < 50 - *                      50 - 115200 : the real baud rate set to the port, if - *                                    the argument baud is large than maximun - *                                    available baud rate, the real setting - *                                    baud rate will be the maximun baud rate. - * - * - *      Function 12:    Configure the port. - *      Syntax: - *      int  MoxaPortSetTermio(int port, struct ktermios *termio, speed_t baud); - *           int port           : port number (0 - 127) - *           struct ktermios * termio : termio structure pointer - *	     speed_t baud	: baud rate - * - *           return:    -1      : this port is invalid or termio == NULL - *                      0       : setting O.K. - * - * - *      Function 13:    Get the DTR/RTS state of this port. - *      Syntax: - *      int  MoxaPortGetLineOut(int port, int *dtrState, int *rtsState); - *           int port           : port number (0 - 127) - *           int * dtrState     : pointer to INT to receive the current DTR - *                                state. (if NULL, this function will not - *                                write to this address) - *           int * rtsState     : pointer to INT to receive the current RTS - *                                state. (if NULL, this function will not - *                                write to this address) - * - *           return:    -1      : this port is invalid - *                      0       : O.K. - * - * - *      Function 14:    Setting the DTR/RTS output state of this port. - *      Syntax: - *      void MoxaPortLineCtrl(int port, int dtrState, int rtsState); - *           int port           : port number (0 - 127) - *           int dtrState       : DTR output state (0: off, 1: on) - *           int rtsState       : RTS output state (0: off, 1: on) - * - * - *      Function 15:    Setting the flow control of this port. - *      Syntax: - *      void MoxaPortFlowCtrl(int port, int rtsFlow, int ctsFlow, int rxFlow, - *                            int txFlow,int xany); - *           int port           : port number (0 - 127) - *           int rtsFlow        : H/W RTS flow control (0: no, 1: yes) - *           int ctsFlow        : H/W CTS flow control (0: no, 1: yes) - *           int rxFlow         : S/W Rx XON/XOFF flow control (0: no, 1: yes) - *           int txFlow         : S/W Tx XON/XOFF flow control (0: no, 1: yes) - *           int xany           : S/W XANY flow control (0: no, 1: yes) - * - * - *      Function 16:    Get ths line status of this port - *      Syntax: - *      int  MoxaPortLineStatus(int port); - *           int port           : port number (0 - 127) - * - *           return:    Bit 0 - CTS state (0: off, 1: on) - *                      Bit 1 - DSR state (0: off, 1: on) - *                      Bit 2 - DCD state (0: off, 1: on) - * - * - *      Function 19:    Flush the Rx/Tx buffer data of this port. - *      Syntax: - *      void MoxaPortFlushData(int port, int mode); - *           int port           : port number (0 - 127) - *           int mode     - *                      0       : flush the Rx buffer  - *                      1       : flush the Tx buffer  - *                      2       : flush the Rx and Tx buffer  - * - * - *      Function 20:    Write data. - *      Syntax: - *      int  MoxaPortWriteData(int port, unsigned char * buffer, int length); - *           int port           : port number (0 - 127) - *           unsigned char * buffer     : pointer to write data buffer. - *           int length         : write data length - * - *           return:    0 - length      : real write data length - * - * - *      Function 21:    Read data. - *      Syntax: - *      int  MoxaPortReadData(int port, struct tty_struct *tty); - *           int port           : port number (0 - 127) - *	     struct tty_struct *tty : tty for data - * - *           return:    0 - length      : real read data length - * - * - *      Function 24:    Get the Tx buffer current queued data bytes - *      Syntax: - *      int  MoxaPortTxQueue(int port); - *           int port           : port number (0 - 127) - * - *           return:    ..      : Tx buffer current queued data bytes - * - * - *      Function 25:    Get the Tx buffer current free space - *      Syntax: - *      int  MoxaPortTxFree(int port); - *           int port           : port number (0 - 127) - * - *           return:    ..      : Tx buffer current free space - * - * - *      Function 26:    Get the Rx buffer current queued data bytes - *      Syntax: - *      int  MoxaPortRxQueue(int port); - *           int port           : port number (0 - 127) - * - *           return:    ..      : Rx buffer current queued data bytes - * - * - *      Function 28:    Disable port data transmission. - *      Syntax: - *      void MoxaPortTxDisable(int port); - *           int port           : port number (0 - 127) - * - * - *      Function 29:    Enable port data transmission. - *      Syntax: - *      void MoxaPortTxEnable(int port); - *           int port           : port number (0 - 127) - * - * - *      Function 31:    Get the received BREAK signal count and reset it. - *      Syntax: - *      int  MoxaPortResetBrkCnt(int port); - *           int port           : port number (0 - 127) - * - *           return:    0 - ..  : BREAK signal count - * - * - */ - -static void MoxaPortEnable(struct moxa_port *port) -{ -	void __iomem *ofsAddr; -	u16 lowwater = 512; - -	ofsAddr = port->tableAddr; -	writew(lowwater, ofsAddr + Low_water); -	if (MOXA_IS_320(port->board)) -		moxafunc(ofsAddr, FC_SetBreakIrq, 0); -	else -		writew(readw(ofsAddr + HostStat) | WakeupBreak, -				ofsAddr + HostStat); - -	moxafunc(ofsAddr, FC_SetLineIrq, Magic_code); -	moxafunc(ofsAddr, FC_FlushQueue, 2); - -	moxafunc(ofsAddr, FC_EnableCH, Magic_code); -	MoxaPortLineStatus(port); -} - -static void MoxaPortDisable(struct moxa_port *port) -{ -	void __iomem *ofsAddr = port->tableAddr; - -	moxafunc(ofsAddr, FC_SetFlowCtl, 0);	/* disable flow control */ -	moxafunc(ofsAddr, FC_ClrLineIrq, Magic_code); -	writew(0, ofsAddr + HostStat); -	moxafunc(ofsAddr, FC_DisableCH, Magic_code); -} - -static speed_t MoxaPortSetBaud(struct moxa_port *port, speed_t baud) -{ -	void __iomem *ofsAddr = port->tableAddr; -	unsigned int clock, val; -	speed_t max; - -	max = MOXA_IS_320(port->board) ? 460800 : 921600; -	if (baud < 50) -		return 0; -	if (baud > max) -		baud = max; -	clock = 921600; -	val = clock / baud; -	moxafunc(ofsAddr, FC_SetBaud, val); -	baud = clock / val; -	return baud; -} - -static int MoxaPortSetTermio(struct moxa_port *port, struct ktermios *termio, -		speed_t baud) -{ -	void __iomem *ofsAddr; -	tcflag_t cflag; -	tcflag_t mode = 0; - -	ofsAddr = port->tableAddr; -	cflag = termio->c_cflag;	/* termio->c_cflag */ - -	mode = termio->c_cflag & CSIZE; -	if (mode == CS5) -		mode = MX_CS5; -	else if (mode == CS6) -		mode = MX_CS6; -	else if (mode == CS7) -		mode = MX_CS7; -	else if (mode == CS8) -		mode = MX_CS8; - -	if (termio->c_cflag & CSTOPB) { -		if (mode == MX_CS5) -			mode |= MX_STOP15; -		else -			mode |= MX_STOP2; -	} else -		mode |= MX_STOP1; - -	if (termio->c_cflag & PARENB) { -		if (termio->c_cflag & PARODD) -			mode |= MX_PARODD; -		else -			mode |= MX_PAREVEN; -	} else -		mode |= MX_PARNONE; - -	moxafunc(ofsAddr, FC_SetDataMode, (u16)mode); - -	if (MOXA_IS_320(port->board) && baud >= 921600) -		return -1; - -	baud = MoxaPortSetBaud(port, baud); - -	if (termio->c_iflag & (IXON | IXOFF | IXANY)) { -	        spin_lock_irq(&moxafunc_lock); -		writeb(termio->c_cc[VSTART], ofsAddr + FuncArg); -		writeb(termio->c_cc[VSTOP], ofsAddr + FuncArg1); -		writeb(FC_SetXonXoff, ofsAddr + FuncCode); -		moxa_wait_finish(ofsAddr); -		spin_unlock_irq(&moxafunc_lock); - -	} -	return baud; -} - -static int MoxaPortGetLineOut(struct moxa_port *port, int *dtrState, -		int *rtsState) -{ -	if (dtrState) -		*dtrState = !!(port->lineCtrl & DTR_ON); -	if (rtsState) -		*rtsState = !!(port->lineCtrl & RTS_ON); - -	return 0; -} - -static void MoxaPortLineCtrl(struct moxa_port *port, int dtr, int rts) -{ -	u8 mode = 0; - -	if (dtr) -		mode |= DTR_ON; -	if (rts) -		mode |= RTS_ON; -	port->lineCtrl = mode; -	moxafunc(port->tableAddr, FC_LineControl, mode); -} - -static void MoxaPortFlowCtrl(struct moxa_port *port, int rts, int cts, -		int txflow, int rxflow, int txany) -{ -	int mode = 0; - -	if (rts) -		mode |= RTS_FlowCtl; -	if (cts) -		mode |= CTS_FlowCtl; -	if (txflow) -		mode |= Tx_FlowCtl; -	if (rxflow) -		mode |= Rx_FlowCtl; -	if (txany) -		mode |= IXM_IXANY; -	moxafunc(port->tableAddr, FC_SetFlowCtl, mode); -} - -static int MoxaPortLineStatus(struct moxa_port *port) -{ -	void __iomem *ofsAddr; -	int val; - -	ofsAddr = port->tableAddr; -	if (MOXA_IS_320(port->board)) -		val = moxafuncret(ofsAddr, FC_LineStatus, 0); -	else -		val = readw(ofsAddr + FlagStat) >> 4; -	val &= 0x0B; -	if (val & 8) -		val |= 4; -	moxa_new_dcdstate(port, val & 8); -	val &= 7; -	return val; -} - -static int MoxaPortWriteData(struct tty_struct *tty, -		const unsigned char *buffer, int len) -{ -	struct moxa_port *port = tty->driver_data; -	void __iomem *baseAddr, *ofsAddr, *ofs; -	unsigned int c, total; -	u16 head, tail, tx_mask, spage, epage; -	u16 pageno, pageofs, bufhead; - -	ofsAddr = port->tableAddr; -	baseAddr = port->board->basemem; -	tx_mask = readw(ofsAddr + TX_mask); -	spage = readw(ofsAddr + Page_txb); -	epage = readw(ofsAddr + EndPage_txb); -	tail = readw(ofsAddr + TXwptr); -	head = readw(ofsAddr + TXrptr); -	c = (head > tail) ? (head - tail - 1) : (head - tail + tx_mask); -	if (c > len) -		c = len; -	moxaLog.txcnt[port->port.tty->index] += c; -	total = c; -	if (spage == epage) { -		bufhead = readw(ofsAddr + Ofs_txb); -		writew(spage, baseAddr + Control_reg); -		while (c > 0) { -			if (head > tail) -				len = head - tail - 1; -			else -				len = tx_mask + 1 - tail; -			len = (c > len) ? len : c; -			ofs = baseAddr + DynPage_addr + bufhead + tail; -			memcpy_toio(ofs, buffer, len); -			buffer += len; -			tail = (tail + len) & tx_mask; -			c -= len; -		} -	} else { -		pageno = spage + (tail >> 13); -		pageofs = tail & Page_mask; -		while (c > 0) { -			len = Page_size - pageofs; -			if (len > c) -				len = c; -			writeb(pageno, baseAddr + Control_reg); -			ofs = baseAddr + DynPage_addr + pageofs; -			memcpy_toio(ofs, buffer, len); -			buffer += len; -			if (++pageno == epage) -				pageno = spage; -			pageofs = 0; -			c -= len; -		} -		tail = (tail + total) & tx_mask; -	} -	writew(tail, ofsAddr + TXwptr); -	writeb(1, ofsAddr + CD180TXirq);	/* start to send */ -	return total; -} - -static int MoxaPortReadData(struct moxa_port *port) -{ -	struct tty_struct *tty = port->port.tty; -	unsigned char *dst; -	void __iomem *baseAddr, *ofsAddr, *ofs; -	unsigned int count, len, total; -	u16 tail, rx_mask, spage, epage; -	u16 pageno, pageofs, bufhead, head; - -	ofsAddr = port->tableAddr; -	baseAddr = port->board->basemem; -	head = readw(ofsAddr + RXrptr); -	tail = readw(ofsAddr + RXwptr); -	rx_mask = readw(ofsAddr + RX_mask); -	spage = readw(ofsAddr + Page_rxb); -	epage = readw(ofsAddr + EndPage_rxb); -	count = (tail >= head) ? (tail - head) : (tail - head + rx_mask + 1); -	if (count == 0) -		return 0; - -	total = count; -	moxaLog.rxcnt[tty->index] += total; -	if (spage == epage) { -		bufhead = readw(ofsAddr + Ofs_rxb); -		writew(spage, baseAddr + Control_reg); -		while (count > 0) { -			ofs = baseAddr + DynPage_addr + bufhead + head; -			len = (tail >= head) ? (tail - head) : -					(rx_mask + 1 - head); -			len = tty_prepare_flip_string(tty, &dst, -					min(len, count)); -			memcpy_fromio(dst, ofs, len); -			head = (head + len) & rx_mask; -			count -= len; -		} -	} else { -		pageno = spage + (head >> 13); -		pageofs = head & Page_mask; -		while (count > 0) { -			writew(pageno, baseAddr + Control_reg); -			ofs = baseAddr + DynPage_addr + pageofs; -			len = tty_prepare_flip_string(tty, &dst, -					min(Page_size - pageofs, count)); -			memcpy_fromio(dst, ofs, len); - -			count -= len; -			pageofs = (pageofs + len) & Page_mask; -			if (pageofs == 0 && ++pageno == epage) -				pageno = spage; -		} -		head = (head + total) & rx_mask; -	} -	writew(head, ofsAddr + RXrptr); -	if (readb(ofsAddr + FlagStat) & Xoff_state) { -		moxaLowWaterChk = 1; -		port->lowChkFlag = 1; -	} -	return total; -} - - -static int MoxaPortTxQueue(struct moxa_port *port) -{ -	void __iomem *ofsAddr = port->tableAddr; -	u16 rptr, wptr, mask; - -	rptr = readw(ofsAddr + TXrptr); -	wptr = readw(ofsAddr + TXwptr); -	mask = readw(ofsAddr + TX_mask); -	return (wptr - rptr) & mask; -} - -static int MoxaPortTxFree(struct moxa_port *port) -{ -	void __iomem *ofsAddr = port->tableAddr; -	u16 rptr, wptr, mask; - -	rptr = readw(ofsAddr + TXrptr); -	wptr = readw(ofsAddr + TXwptr); -	mask = readw(ofsAddr + TX_mask); -	return mask - ((wptr - rptr) & mask); -} - -static int MoxaPortRxQueue(struct moxa_port *port) -{ -	void __iomem *ofsAddr = port->tableAddr; -	u16 rptr, wptr, mask; - -	rptr = readw(ofsAddr + RXrptr); -	wptr = readw(ofsAddr + RXwptr); -	mask = readw(ofsAddr + RX_mask); -	return (wptr - rptr) & mask; -} - -static void MoxaPortTxDisable(struct moxa_port *port) -{ -	moxafunc(port->tableAddr, FC_SetXoffState, Magic_code); -} - -static void MoxaPortTxEnable(struct moxa_port *port) -{ -	moxafunc(port->tableAddr, FC_SetXonState, Magic_code); -} - -static int moxa_get_serial_info(struct moxa_port *info, -		struct serial_struct __user *retinfo) -{ -	struct serial_struct tmp = { -		.type = info->type, -		.line = info->port.tty->index, -		.flags = info->port.flags, -		.baud_base = 921600, -		.close_delay = info->port.close_delay -	}; -	return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0; -} - - -static int moxa_set_serial_info(struct moxa_port *info, -		struct serial_struct __user *new_info) -{ -	struct serial_struct new_serial; - -	if (copy_from_user(&new_serial, new_info, sizeof(new_serial))) -		return -EFAULT; - -	if (new_serial.irq != 0 || new_serial.port != 0 || -			new_serial.custom_divisor != 0 || -			new_serial.baud_base != 921600) -		return -EPERM; - -	if (!capable(CAP_SYS_ADMIN)) { -		if (((new_serial.flags & ~ASYNC_USR_MASK) != -		     (info->port.flags & ~ASYNC_USR_MASK))) -			return -EPERM; -	} else -		info->port.close_delay = new_serial.close_delay * HZ / 100; - -	new_serial.flags = (new_serial.flags & ~ASYNC_FLAGS); -	new_serial.flags |= (info->port.flags & ASYNC_FLAGS); - -	MoxaSetFifo(info, new_serial.type == PORT_16550A); - -	info->type = new_serial.type; -	return 0; -} - - - -/***************************************************************************** - *	Static local functions: 					     * - *****************************************************************************/ - -static void MoxaSetFifo(struct moxa_port *port, int enable) -{ -	void __iomem *ofsAddr = port->tableAddr; - -	if (!enable) { -		moxafunc(ofsAddr, FC_SetRxFIFOTrig, 0); -		moxafunc(ofsAddr, FC_SetTxFIFOCnt, 1); -	} else { -		moxafunc(ofsAddr, FC_SetRxFIFOTrig, 3); -		moxafunc(ofsAddr, FC_SetTxFIFOCnt, 16); -	} -}  | 
