diff options
Diffstat (limited to 'drivers/char/moxa.c')
-rw-r--r-- | drivers/char/moxa.c | 3320 |
1 files changed, 3320 insertions, 0 deletions
diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c new file mode 100644 index 000000000..44f01bb77 --- /dev/null +++ b/drivers/char/moxa.c @@ -0,0 +1,3320 @@ +/*****************************************************************************/ +/* + * moxa.c -- MOXA Intellio family multiport serial driver. + * + * Copyright (C) 1999-2000 Moxa Technologies (support@moxa.com.tw). + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * MOXA Intellio Series Driver + * for : LINUX + * date : 1999/1/7 + * version : 5.1 + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/version.h> +#include <linux/mm.h> +#include <linux/ioport.h> +#include <linux/errno.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/config.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 <asm/system.h> +#include <asm/io.h> +#include <asm/segment.h> +#include <asm/bitops.h> +#include <asm/uaccess.h> + +#define MOXA_VERSION "5.1k" + +#define MOXAMAJOR 172 +#define MOXACUMAJOR 173 + +#define put_to_user(arg1, arg2) put_user(arg1, (unsigned long *)arg2) +#define get_from_user(arg1, arg2) get_user(arg1, (unsigned int *)arg2) + +#define MAX_BOARDS 4 /* Don't change this value */ +#define MAX_PORTS_PER_BOARD 32 /* Don't change this value */ +#define MAX_PORTS 128 /* Don't change this value */ + +/* + * Define the Moxa PCI vendor and device IDs. + */ +#define MOXA_BUS_TYPE_ISA 0 +#define MOXA_BUS_TYPE_PCI 1 + +#ifndef PCI_VENDOR_ID_MOXA +#define PCI_VENDOR_ID_MOXA 0x1393 +#endif +#ifndef PCI_DEVICE_ID_CP204J +#define PCI_DEVICE_ID_CP204J 0x2040 +#endif +#ifndef PCI_DEVICE_ID_C218 +#define PCI_DEVICE_ID_C218 0x2180 +#endif +#ifndef PCI_DEVICE_ID_C320 +#define PCI_DEVICE_ID_C320 0x3200 +#endif + +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", +}; + +typedef struct { + unsigned short vendor_id; + unsigned short device_id; + unsigned short board_type; +} moxa_pciinfo; + +static moxa_pciinfo moxa_pcibrds[] = +{ + {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_C218, MOXA_BOARD_C218_PCI}, + {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_C320, MOXA_BOARD_C320_PCI}, + {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_CP204J, MOXA_BOARD_CP204J}, +}; + +typedef struct _moxa_isa_board_conf { + int boardType; + int numPorts; + unsigned long baseAddr; +} moxa_isa_board_conf; + +static moxa_isa_board_conf moxa_isa_boards[] = +{ +/* {MOXA_BOARD_C218_ISA,8,0xDC000}, */ +}; + +typedef struct _moxa_pci_devinfo { + ushort busNum; + ushort devNum; +} moxa_pci_devinfo; + +typedef struct _moxa_board_conf { + int boardType; + int numPorts; + unsigned long baseAddr; + int busType; + moxa_pci_devinfo pciInfo; +} moxa_board_conf; + +static moxa_board_conf moxa_boards[MAX_BOARDS]; +static unsigned long moxaBaseAddr[MAX_BOARDS]; + +struct moxa_str { + int type; + int port; + int close_delay; + unsigned short closing_wait; + int count; + int blocked_open; + int event; + int asyncflags; + long session; + long pgrp; + unsigned long statusflags; + struct tty_struct *tty; + struct termios normal_termios; + struct termios callout_termios; + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; + struct tq_struct tqueue; +}; + +struct mxser_mstatus { + tcflag_t cflag; + int cts; + int dsr; + int ri; + int dcd; +}; + +static struct mxser_mstatus GMStatus[MAX_PORTS]; + +/* statusflags */ +#define TXSTOPPED 0x1 +#define LOWWAIT 0x2 +#define EMPTYWAIT 0x4 +#define THROTTLE 0x8 + +/* event */ +#define MOXA_EVENT_HANGUP 1 + +#define SERIAL_DO_RESTART + + +#define SERIAL_TYPE_NORMAL 1 +#define SERIAL_TYPE_CALLOUT 2 + +#define WAKEUP_CHARS 256 + +#define PORTNO(x) (MINOR((x)->device) - (x)->driver.minor_start) + +static int verbose = 0; +static int ttymajor = MOXAMAJOR; +static int calloutmajor = MOXACUMAJOR; +#ifdef MODULE +/* Variables for insmod */ +static int baseaddr[] = {0, 0, 0, 0}; +static int type[] = {0, 0, 0, 0}; +static int numports[] = {0, 0, 0, 0}; + +MODULE_AUTHOR("William Chen"); +MODULE_DESCRIPTION("MOXA Intellio Family Multiport Board Device Driver"); +MODULE_PARM(type, "1-4i"); +MODULE_PARM(baseaddr, "1-4i"); +MODULE_PARM(numports, "1-4i"); +MODULE_PARM(ttymajor, "i"); +MODULE_PARM(calloutmajor, "i"); +MODULE_PARM(verbose, "i"); + +#endif //MODULE + +static struct tty_driver moxaDriver; +static struct tty_driver moxaCallout; +static struct tty_struct *moxaTable[MAX_PORTS + 1]; +static struct termios *moxaTermios[MAX_PORTS + 1]; +static struct termios *moxaTermiosLocked[MAX_PORTS + 1]; +static struct moxa_str moxaChannels[MAX_PORTS]; +static int moxaRefcount; +static unsigned char *moxaXmitBuff; +static int moxaTimer_on; +static struct timer_list moxaTimer; +static int moxaEmptyTimer_on[MAX_PORTS]; +static struct timer_list moxaEmptyTimer[MAX_PORTS]; +static struct semaphore moxaBuffSem; + +int moxa_init(void); +#ifdef MODULE +int init_module(void); +void cleanup_module(void); +#endif +/* + * static functions: + */ +static int moxa_get_PCI_conf(struct pci_dev *, int, moxa_board_conf *); +static void do_moxa_softint(void *); +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 *, int, 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_flush_chars(struct tty_struct *); +static void moxa_put_char(struct tty_struct *, unsigned char); +static int moxa_ioctl(struct tty_struct *, struct file *, unsigned int, unsigned long); +static void moxa_throttle(struct tty_struct *); +static void moxa_unthrottle(struct tty_struct *); +static void moxa_set_termios(struct tty_struct *, struct termios *); +static void moxa_stop(struct tty_struct *); +static void moxa_start(struct tty_struct *); +static void moxa_hangup(struct tty_struct *); +static void moxa_poll(unsigned long); +static void set_tty_param(struct tty_struct *); +static int block_till_ready(struct tty_struct *, struct file *, + struct moxa_str *); +static void setup_empty_event(struct tty_struct *); +static void check_xmit_empty(unsigned long); +static void shut_down(struct moxa_str *); +static void receive_data(struct moxa_str *); +/* + * moxa board interface functions: + */ +static void MoxaDriverInit(void); +static int MoxaDriverIoctl(unsigned int, unsigned long, int); +static int MoxaDriverPoll(void); +static int MoxaPortsOfCard(int); +static int MoxaPortIsValid(int); +static void MoxaPortEnable(int); +static void MoxaPortDisable(int); +static long MoxaPortGetMaxBaud(int); +static long MoxaPortSetBaud(int, long); +static int MoxaPortSetTermio(int, struct termios *); +static int MoxaPortGetLineOut(int, int *, int *); +static void MoxaPortLineCtrl(int, int, int); +static void MoxaPortFlowCtrl(int, int, int, int, int, int); +static int MoxaPortLineStatus(int); +static int MoxaPortDCDChange(int); +static int MoxaPortDCDON(int); +static void MoxaPortFlushData(int, int); +static int MoxaPortWriteData(int, unsigned char *, int); +static int MoxaPortReadData(int, unsigned char *, int); +static int MoxaPortTxQueue(int); +static int MoxaPortRxQueue(int); +static int MoxaPortTxFree(int); +static void MoxaPortTxDisable(int); +static void MoxaPortTxEnable(int); +static int MoxaPortResetBrkCnt(int); +static void MoxaPortSendBreak(int, int); +static int moxa_get_serial_info(struct moxa_str *, struct serial_struct *); +static int moxa_set_serial_info(struct moxa_str *, struct serial_struct *); +static void MoxaSetFifo(int port, int enable); + +#ifdef MODULE +int init_module(void) +{ + int ret; + + if (verbose) + printk("Loading module moxa ...\n"); + ret = moxa_init(); + if (verbose) + printk("Done\n"); + return (ret); +} + +void cleanup_module(void) +{ + int i; + + if (verbose) + printk("Unloading module moxa ...\n"); + + if (moxaTimer_on) + del_timer(&moxaTimer); + + for (i = 0; i < MAX_PORTS; i++) + if (moxaEmptyTimer_on[i]) + del_timer(&moxaEmptyTimer[i]); + + if (tty_unregister_driver(&moxaCallout)) + printk("Couldn't unregister MOXA Intellio family callout driver\n"); + if (tty_unregister_driver(&moxaDriver)) + printk("Couldn't unregister MOXA Intellio family serial driver\n"); + if (verbose) + printk("Done\n"); + +} +#endif + +int moxa_init(void) +{ + int i, n, numBoards; + struct moxa_str *ch; + int ret1, ret2; + + printk(KERN_INFO "MOXA Intellio family driver version %s\n", MOXA_VERSION); + + init_MUTEX(&moxaBuffSem); + memset(&moxaDriver, 0, sizeof(struct tty_driver)); + memset(&moxaCallout, 0, sizeof(struct tty_driver)); + moxaDriver.magic = TTY_DRIVER_MAGIC; + moxaDriver.name = "ttya"; + moxaDriver.major = ttymajor; + moxaDriver.minor_start = 0; + moxaDriver.num = MAX_PORTS + 1; + moxaDriver.type = TTY_DRIVER_TYPE_SERIAL; + moxaDriver.subtype = SERIAL_TYPE_NORMAL; + moxaDriver.init_termios = tty_std_termios; + moxaDriver.init_termios.c_iflag = 0; + moxaDriver.init_termios.c_oflag = 0; + moxaDriver.init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL; + moxaDriver.init_termios.c_lflag = 0; + moxaDriver.flags = TTY_DRIVER_REAL_RAW; + moxaDriver.refcount = &moxaRefcount; + moxaDriver.table = moxaTable; + moxaDriver.termios = moxaTermios; + moxaDriver.termios_locked = moxaTermiosLocked; + + moxaDriver.open = moxa_open; + moxaDriver.close = moxa_close; + moxaDriver.write = moxa_write; + moxaDriver.write_room = moxa_write_room; + moxaDriver.flush_buffer = moxa_flush_buffer; + moxaDriver.chars_in_buffer = moxa_chars_in_buffer; + moxaDriver.flush_chars = moxa_flush_chars; + moxaDriver.put_char = moxa_put_char; + moxaDriver.ioctl = moxa_ioctl; + moxaDriver.throttle = moxa_throttle; + moxaDriver.unthrottle = moxa_unthrottle; + moxaDriver.set_termios = moxa_set_termios; + moxaDriver.stop = moxa_stop; + moxaDriver.start = moxa_start; + moxaDriver.hangup = moxa_hangup; + + moxaCallout = moxaDriver; + moxaCallout.name = "ttyA"; + moxaCallout.major = calloutmajor; + moxaCallout.subtype = SERIAL_TYPE_CALLOUT; + + moxaXmitBuff = 0; + + for (i = 0, ch = moxaChannels; i < MAX_PORTS; i++, ch++) { + ch->type = PORT_16550A; + ch->port = i; + ch->tqueue.routine = do_moxa_softint; + ch->tqueue.data = ch; + ch->tty = 0; + ch->close_delay = 5 * HZ / 10; + ch->closing_wait = 30 * HZ; + ch->count = 0; + ch->blocked_open = 0; + ch->callout_termios = moxaCallout.init_termios; + ch->normal_termios = moxaDriver.init_termios; + init_waitqueue_head(&ch->open_wait); + init_waitqueue_head(&ch->close_wait); + } + + for (i = 0; i < MAX_BOARDS; i++) { + moxa_boards[i].boardType = 0; + moxa_boards[i].numPorts = 0; + moxa_boards[i].baseAddr = 0; + moxa_boards[i].busType = 0; + moxa_boards[i].pciInfo.busNum = 0; + moxa_boards[i].pciInfo.devNum = 0; + } + MoxaDriverInit(); + printk("Tty devices major number = %d, callout devices major number = %d\n", ttymajor, calloutmajor); + + ret1 = 0; + ret2 = 0; + if ((ret1 = tty_register_driver(&moxaDriver))) { + printk(KERN_ERR "Couldn't install MOXA Smartio family driver !\n"); + } else if ((ret2 = tty_register_driver(&moxaCallout))) { + tty_unregister_driver(&moxaDriver); + printk(KERN_ERR "Couldn't install MOXA Smartio family callout driver !\n"); + } + if (ret1 || ret2) { + return -1; + } + for (i = 0; i < MAX_PORTS; i++) { + init_timer(&moxaEmptyTimer[i]); + moxaEmptyTimer[i].function = check_xmit_empty; + moxaEmptyTimer[i].data = (unsigned long) & moxaChannels[i]; + moxaEmptyTimer_on[i] = 0; + } + + init_timer(&moxaTimer); + moxaTimer.function = moxa_poll; + moxaTimer.expires = jiffies + (HZ / 50); + moxaTimer_on = 1; + add_timer(&moxaTimer); + + /* Find the boards defined in source code */ + numBoards = 0; + for (i = 0; i < MAX_BOARDS; i++) { + if ((moxa_isa_boards[i].boardType == MOXA_BOARD_C218_ISA) || + (moxa_isa_boards[i].boardType == MOXA_BOARD_C320_ISA)) { + moxa_boards[numBoards].boardType = moxa_isa_boards[i].boardType; + if (moxa_isa_boards[i].boardType == MOXA_BOARD_C218_ISA) + moxa_boards[numBoards].numPorts = 8; + else + moxa_boards[numBoards].numPorts = moxa_isa_boards[i].numPorts; + moxa_boards[numBoards].busType = MOXA_BUS_TYPE_ISA; + moxa_boards[numBoards].baseAddr = moxa_isa_boards[i].baseAddr; + if (verbose) + printk("Board %2d: %s board(baseAddr=%lx)\n", + numBoards + 1, + moxa_brdname[moxa_boards[numBoards].boardType - 1], + moxa_boards[numBoards].baseAddr); + numBoards++; + } + } + /* Find the boards defined form module args. */ +#ifdef MODULE + for (i = 0; i < MAX_BOARDS; i++) { + if ((type[i] == MOXA_BOARD_C218_ISA) || + (type[i] == MOXA_BOARD_C320_ISA)) { + if (verbose) + printk("Board %2d: %s board(baseAddr=%lx)\n", + numBoards + 1, + moxa_brdname[type[i] - 1], + (unsigned long) baseaddr[i]); + if (numBoards >= MAX_BOARDS) { + if (verbose) + printk("More than %d MOXA Intellio family boards found. Board is ignored.", MAX_BOARDS); + continue; + } + moxa_boards[numBoards].boardType = type[i]; + if (moxa_isa_boards[i].boardType == MOXA_BOARD_C218_ISA) + moxa_boards[numBoards].numPorts = 8; + else + moxa_boards[numBoards].numPorts = numports[i]; + moxa_boards[numBoards].busType = MOXA_BUS_TYPE_ISA; + moxa_boards[numBoards].baseAddr = baseaddr[i]; + numBoards++; + } + } +#endif + /* Find PCI boards here */ +#ifdef CONFIG_PCI + if (pci_present()) { + struct pci_dev *p = NULL; + n = sizeof(moxa_pcibrds) / sizeof(moxa_pciinfo); + i = 0; + while (i < n) { + while((p = pci_find_device(moxa_pcibrds[i].vendor_id, moxa_pcibrds[i].device_id, p))!=NULL) + { + if (numBoards >= MAX_BOARDS) { + if (verbose) + printk("More than %d MOXA Intellio family boards found. Board is ignored.", MAX_BOARDS); + } else { + moxa_get_PCI_conf(p, moxa_pcibrds[i].board_type, + &moxa_boards[numBoards]); + numBoards++; + } + } + i++; + } + } +#endif + for (i = 0; i < numBoards; i++) { + moxaBaseAddr[i] = (unsigned long) ioremap((unsigned long) moxa_boards[i].baseAddr, 0x4000); + } + + return (0); +} + +static int moxa_get_PCI_conf(struct pci_dev *p, int board_type, moxa_board_conf * board) +{ + unsigned int val; + + board->baseAddr = p->resource[2].start; + 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; + board->pciInfo.busNum = p->bus->number; + board->pciInfo.devNum = p->devfn >> 3; + + return (0); +} + +static void do_moxa_softint(void *private_) +{ + struct moxa_str *ch = (struct moxa_str *) private_; + struct tty_struct *tty; + + if (!ch || !(tty = ch->tty)) + return; + if (test_and_clear_bit(MOXA_EVENT_HANGUP, &ch->event)) { + tty_hangup(tty); + wake_up_interruptible(&ch->open_wait); + ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE); + } +} + +static int moxa_open(struct tty_struct *tty, struct file *filp) +{ + struct moxa_str *ch; + int port; + int retval; + unsigned long page; + + port = PORTNO(tty); + if (port == MAX_PORTS) { + MOD_INC_USE_COUNT; + return (0); + } + if (!MoxaPortIsValid(port)) { + tty->driver_data = NULL; + return (-ENODEV); + } + down(&moxaBuffSem); + if (!moxaXmitBuff) { + page = get_free_page(GFP_KERNEL); + if (!page) { + up(&moxaBuffSem); + return (-ENOMEM); + } + if (moxaXmitBuff) + free_page(page); + else + moxaXmitBuff = (unsigned char *) page; + } + up(&moxaBuffSem); + + MOD_INC_USE_COUNT; + ch = &moxaChannels[port]; + ch->count++; + tty->driver_data = ch; + ch->tty = tty; + if (ch->count == 1 && (ch->asyncflags & ASYNC_SPLIT_TERMIOS)) { + if (tty->driver.subtype == SERIAL_TYPE_NORMAL) + *tty->termios = ch->normal_termios; + else + *tty->termios = ch->callout_termios; + } + ch->session = current->session; + ch->pgrp = current->pgrp; + if (!(ch->asyncflags & ASYNC_INITIALIZED)) { + ch->statusflags = 0; + set_tty_param(tty); + MoxaPortLineCtrl(ch->port, 1, 1); + MoxaPortEnable(ch->port); + ch->asyncflags |= ASYNC_INITIALIZED; + } + retval = block_till_ready(tty, filp, ch); + + moxa_unthrottle(tty); + + if (ch->type == PORT_16550A) { + MoxaSetFifo(ch->port, 1); + } else { + MoxaSetFifo(ch->port, 0); + } + + return (retval); +} + +static void moxa_close(struct tty_struct *tty, struct file *filp) +{ + struct moxa_str *ch; + int port; + + port = PORTNO(tty); + if (port == MAX_PORTS) { + MOD_DEC_USE_COUNT; + return; + } + if (!MoxaPortIsValid(port)) { +#ifdef SERIAL_DEBUG_CLOSE + printk("Invalid portno in moxa_close\n"); +#endif + tty->driver_data = NULL; + return; + } + if (tty->driver_data == NULL) { + return; + } + if (tty_hung_up_p(filp)) { + MOD_DEC_USE_COUNT; + return; + } + ch = (struct moxa_str *) tty->driver_data; + + if ((tty->count == 1) && (ch->count != 1)) { + printk("moxa_close: bad serial port count; tty->count is 1, " + "ch->count is %d\n", ch->count); + ch->count = 1; + } + if (--ch->count < 0) { + printk("moxa_close: bad serial port count, minor=%d\n", + MINOR(tty->device)); + ch->count = 0; + } + if (ch->count) { + MOD_DEC_USE_COUNT; + return; + } + ch->asyncflags |= ASYNC_CLOSING; + + /* + * Save the termios structure, since this port may have + * separate termios for callout and dialin. + */ + if (ch->asyncflags & ASYNC_NORMAL_ACTIVE) + ch->normal_termios = *tty->termios; + if (ch->asyncflags & ASYNC_CALLOUT_ACTIVE) + ch->callout_termios = *tty->termios; + if (ch->asyncflags & ASYNC_INITIALIZED) { + setup_empty_event(tty); + tty_wait_until_sent(tty, 30 * HZ); /* 30 seconds timeout */ + moxaEmptyTimer_on[ch->port] = 0; + del_timer(&moxaEmptyTimer[ch->port]); + } + shut_down(ch); + MoxaPortFlushData(port, 2); + + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + tty->closing = 0; + ch->event = 0; + ch->tty = 0; + if (ch->blocked_open) { + if (ch->close_delay) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(ch->close_delay); + } + wake_up_interruptible(&ch->open_wait); + } + ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE | + ASYNC_CLOSING); + wake_up_interruptible(&ch->close_wait); + MOD_DEC_USE_COUNT; +} + +static int moxa_write(struct tty_struct *tty, int from_user, + const unsigned char *buf, int count) +{ + struct moxa_str *ch; + int len, port; + unsigned long flags; + unsigned char *temp; + + ch = (struct moxa_str *) tty->driver_data; + if (ch == NULL) + return (0); + port = ch->port; + save_flags(flags); + cli(); + if (from_user) { + copy_from_user(moxaXmitBuff, buf, count); + temp = moxaXmitBuff; + } else + temp = (unsigned char *) buf; + len = MoxaPortWriteData(port, temp, count); + restore_flags(flags); + /********************************************* + if ( !(ch->statusflags & LOWWAIT) && + ((len != count) || (MoxaPortTxFree(port) <= 100)) ) + ************************************************/ + ch->statusflags |= LOWWAIT; + return (len); +} + +static int moxa_write_room(struct tty_struct *tty) +{ + struct moxa_str *ch; + + if (tty->stopped) + return (0); + ch = (struct moxa_str *) tty->driver_data; + if (ch == NULL) + return (0); + return (MoxaPortTxFree(ch->port)); +} + +static void moxa_flush_buffer(struct tty_struct *tty) +{ + struct moxa_str *ch = (struct moxa_str *) tty->driver_data; + + if (ch == NULL) + return; + MoxaPortFlushData(ch->port, 1); + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup) (tty); + wake_up_interruptible(&tty->write_wait); +} + +static int moxa_chars_in_buffer(struct tty_struct *tty) +{ + int chars; + struct moxa_str *ch = (struct moxa_str *) tty->driver_data; + + /* + * Sigh...I have to check if driver_data is NULL here, because + * if an open() fails, the TTY subsystem eventually calls + * tty_wait_until_sent(), which calls the driver's chars_in_buffer() + * routine. And since the open() failed, we return 0 here. TDJ + */ + if (ch == NULL) + return (0); + chars = MoxaPortTxQueue(ch->port); + if (chars) { + /* + * Make it possible to wakeup anything waiting for output + * in tty_ioctl.c, etc. + */ + if (!(ch->statusflags & EMPTYWAIT)) + setup_empty_event(tty); + } + return (chars); +} + +static void moxa_flush_chars(struct tty_struct *tty) +{ + /* + * Don't think I need this, because this is called to empty the TX + * buffer for the 16450, 16550, etc. + */ +} + +static void moxa_put_char(struct tty_struct *tty, unsigned char c) +{ + struct moxa_str *ch; + int port; + unsigned long flags; + + ch = (struct moxa_str *) tty->driver_data; + if (ch == NULL) + return; + port = ch->port; + save_flags(flags); + cli(); + moxaXmitBuff[0] = c; + MoxaPortWriteData(port, moxaXmitBuff, 1); + restore_flags(flags); + /************************************************ + if ( !(ch->statusflags & LOWWAIT) && (MoxaPortTxFree(port) <= 100) ) + *************************************************/ + ch->statusflags |= LOWWAIT; +} + +static int moxa_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct moxa_str *ch = (struct moxa_str *) tty->driver_data; + register int port; + int retval, dtr, rts; + unsigned long flag; + + port = PORTNO(tty); + if ((port != MAX_PORTS) && (!ch)) + return (-EINVAL); + + switch (cmd) { + case TCSBRK: /* SVID version: non-zero arg --> no break */ + retval = tty_check_change(tty); + if (retval) + return (retval); + setup_empty_event(tty); + tty_wait_until_sent(tty, 0); + if (!arg) + MoxaPortSendBreak(ch->port, 0); + return (0); + case TCSBRKP: /* support for POSIX tcsendbreak() */ + retval = tty_check_change(tty); + if (retval) + return (retval); + setup_empty_event(tty); + tty_wait_until_sent(tty, 0); + MoxaPortSendBreak(ch->port, arg); + return (0); + case TIOCGSOFTCAR: + return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg); + case TIOCSSOFTCAR: + if(get_user(retval, (unsigned long *) arg)) + return -EFAULT; + arg = retval; + tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | + (arg ? CLOCAL : 0)); + if (C_CLOCAL(tty)) + ch->asyncflags &= ~ASYNC_CHECK_CD; + else + ch->asyncflags |= ASYNC_CHECK_CD; + return (0); + case TIOCMGET: + flag = 0; + MoxaPortGetLineOut(ch->port, &dtr, &rts); + if (dtr) + flag |= TIOCM_DTR; + if (rts) + flag |= TIOCM_RTS; + dtr = MoxaPortLineStatus(ch->port); + if (dtr & 1) + flag |= TIOCM_CTS; + if (dtr & 2) + flag |= TIOCM_DSR; + if (dtr & 4) + flag |= TIOCM_CD; + return put_user(flag, (unsigned int *) arg); + case TIOCMBIS: + if(get_user(retval, (unsigned int *) arg)) + return -EFAULT; + MoxaPortGetLineOut(ch->port, &dtr, &rts); + if (retval & TIOCM_RTS) + rts = 1; + if (retval & TIOCM_DTR) + dtr = 1; + MoxaPortLineCtrl(ch->port, dtr, rts); + return (0); + case TIOCMBIC: + if(get_user(retval, (unsigned int *) arg)) + return -EFAULT; + MoxaPortGetLineOut(ch->port, &dtr, &rts); + if (retval & TIOCM_RTS) + rts = 0; + if (retval & TIOCM_DTR) + dtr = 0; + MoxaPortLineCtrl(ch->port, dtr, rts); + return (0); + case TIOCMSET: + if(get_user(retval, (unsigned long *) arg)) + return -EFAULT; + dtr = rts = 0; + if (retval & TIOCM_RTS) + rts = 1; + if (retval & TIOCM_DTR) + dtr = 1; + MoxaPortLineCtrl(ch->port, dtr, rts); + return (0); + case TIOCGSERIAL: + return (moxa_get_serial_info(ch, (struct serial_struct *) arg)); + + case TIOCSSERIAL: + return (moxa_set_serial_info(ch, (struct serial_struct *) arg)); + default: + retval = MoxaDriverIoctl(cmd, arg, port); + } + return (retval); +} + +static void moxa_throttle(struct tty_struct *tty) +{ + struct moxa_str *ch = (struct moxa_str *) tty->driver_data; + + ch->statusflags |= THROTTLE; +} + +static void moxa_unthrottle(struct tty_struct *tty) +{ + struct moxa_str *ch = (struct moxa_str *) tty->driver_data; + + ch->statusflags &= ~THROTTLE; +} + +static void moxa_set_termios(struct tty_struct *tty, + struct termios *old_termios) +{ + struct moxa_str *ch = (struct moxa_str *) tty->driver_data; + + if (ch == NULL) + return; + set_tty_param(tty); + if (!(old_termios->c_cflag & CLOCAL) && + (tty->termios->c_cflag & CLOCAL)) + wake_up_interruptible(&ch->open_wait); +} + +static void moxa_stop(struct tty_struct *tty) +{ + struct moxa_str *ch = (struct moxa_str *) tty->driver_data; + + if (ch == NULL) + return; + MoxaPortTxDisable(ch->port); + ch->statusflags |= TXSTOPPED; +} + + +static void moxa_start(struct tty_struct *tty) +{ + struct moxa_str *ch = (struct moxa_str *) tty->driver_data; + + if (ch == NULL) + return; + + if (!(ch->statusflags & TXSTOPPED)) + return; + + MoxaPortTxEnable(ch->port); + ch->statusflags &= ~TXSTOPPED; +} + +static void moxa_hangup(struct tty_struct *tty) +{ + struct moxa_str *ch = (struct moxa_str *) tty->driver_data; + + moxa_flush_buffer(tty); + shut_down(ch); + ch->event = 0; + ch->count = 0; + ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE); + ch->tty = 0; + wake_up_interruptible(&ch->open_wait); +} + +static void moxa_poll(unsigned long ignored) +{ + register int card; + struct moxa_str *ch; + struct tty_struct *tp; + int i, ports; + + moxaTimer_on = 0; + del_timer(&moxaTimer); + + if (MoxaDriverPoll() < 0) { + moxaTimer.function = moxa_poll; + moxaTimer.expires = jiffies + (HZ / 50); + moxaTimer_on = 1; + add_timer(&moxaTimer); + return; + } + for (card = 0; card < MAX_BOARDS; card++) { + if ((ports = MoxaPortsOfCard(card)) <= 0) + continue; + ch = &moxaChannels[card * MAX_PORTS_PER_BOARD]; + for (i = 0; i < ports; i++, ch++) { + if ((ch->asyncflags & ASYNC_INITIALIZED) == 0) + continue; + if (!(ch->statusflags & THROTTLE) && + (MoxaPortRxQueue(ch->port) > 0)) + receive_data(ch); + if ((tp = ch->tty) == 0) + continue; + if (ch->statusflags & LOWWAIT) { + if (MoxaPortTxQueue(ch->port) <= WAKEUP_CHARS) { + if (!tp->stopped) { + ch->statusflags &= ~LOWWAIT; + if ((tp->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tp->ldisc.write_wakeup) + (tp->ldisc.write_wakeup) (tp); + wake_up_interruptible(&tp->write_wait); + } + } + } + if (!I_IGNBRK(tp) && (MoxaPortResetBrkCnt(ch->port) > 0)) { + tty_insert_flip_char(tp, 0, TTY_BREAK); + tty_schedule_flip(tp); + } + if (MoxaPortDCDChange(ch->port)) { + if (ch->asyncflags & ASYNC_CHECK_CD) { + if (MoxaPortDCDON(ch->port)) + wake_up_interruptible(&ch->open_wait); + else { + set_bit(MOXA_EVENT_HANGUP, &ch->event); + queue_task(&ch->tqueue, &tq_scheduler); + } + } + } + } + } + + moxaTimer.function = moxa_poll; + moxaTimer.expires = jiffies + (HZ / 50); + moxaTimer_on = 1; + add_timer(&moxaTimer); +} + +/******************************************************************************/ + +static void set_tty_param(struct tty_struct *tty) +{ + register struct termios *ts; + struct moxa_str *ch; + int rts, cts, txflow, rxflow, xany; + + ch = (struct moxa_str *) tty->driver_data; + ts = tty->termios; + if (ts->c_cflag & CLOCAL) + ch->asyncflags &= ~ASYNC_CHECK_CD; + else + ch->asyncflags |= ASYNC_CHECK_CD; + 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; + MoxaPortFlowCtrl(ch->port, rts, cts, txflow, rxflow, xany); + MoxaPortSetTermio(ch->port, ts); +} + +static int block_till_ready(struct tty_struct *tty, struct file *filp, + struct moxa_str *ch) +{ + DECLARE_WAITQUEUE(wait,current); + unsigned long flags; + int retval; + int do_clocal = C_CLOCAL(tty); + + /* + * If the device is in the middle of being closed, then block + * until it's done, and then try again. + */ + if (tty_hung_up_p(filp) || (ch->asyncflags & ASYNC_CLOSING)) { + if (ch->asyncflags & ASYNC_CLOSING) + interruptible_sleep_on(&ch->close_wait); +#ifdef SERIAL_DO_RESTART + if (ch->asyncflags & ASYNC_HUP_NOTIFY) + return (-EAGAIN); + else + return (-ERESTARTSYS); +#else + return (-EAGAIN); +#endif + } + /* + * If this is a callout device, then just make sure the normal + * device isn't being used. + */ + if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) { + if (ch->asyncflags & ASYNC_NORMAL_ACTIVE) + return (-EBUSY); + if ((ch->asyncflags & ASYNC_CALLOUT_ACTIVE) && + (ch->asyncflags & ASYNC_SESSION_LOCKOUT) && + (ch->session != current->session)) + return (-EBUSY); + if ((ch->asyncflags & ASYNC_CALLOUT_ACTIVE) && + (ch->asyncflags & ASYNC_PGRP_LOCKOUT) && + (ch->pgrp != current->pgrp)) + return (-EBUSY); + ch->asyncflags |= ASYNC_CALLOUT_ACTIVE; + return (0); + } + /* + * If non-blocking mode is set, then make the check up front + * and then exit. + */ + if (filp->f_flags & O_NONBLOCK) { + if (ch->asyncflags & ASYNC_CALLOUT_ACTIVE) + return (-EBUSY); + ch->asyncflags |= ASYNC_NORMAL_ACTIVE; + return (0); + } + /* + * Block waiting for the carrier detect and the line to become free + */ + retval = 0; + add_wait_queue(&ch->open_wait, &wait); +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready before block: ttys%d, count = %d\n", + ch->line, ch->count); +#endif + save_flags(flags); + cli(); + if (!tty_hung_up_p(filp)) + ch->count--; + restore_flags(flags); + ch->blocked_open++; + while (1) { + current->state = TASK_INTERRUPTIBLE; + if (tty_hung_up_p(filp) || + !(ch->asyncflags & ASYNC_INITIALIZED)) { +#ifdef SERIAL_DO_RESTART + if (ch->asyncflags & ASYNC_HUP_NOTIFY) + retval = -EAGAIN; + else + retval = -ERESTARTSYS; +#else + retval = -EAGAIN; +#endif + break; + } + if (!(ch->asyncflags & ASYNC_CALLOUT_ACTIVE) && + !(ch->asyncflags & ASYNC_CLOSING) && (do_clocal || + MoxaPortDCDON(ch->port))) + break; + + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&ch->open_wait, &wait); + if (!tty_hung_up_p(filp)) + ch->count++; + ch->blocked_open--; +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready after blocking: ttys%d, count = %d\n", + ch->line, ch->count); +#endif + if (retval) + return (retval); + ch->asyncflags |= ASYNC_NORMAL_ACTIVE; + return (0); +} + +static void setup_empty_event(struct tty_struct *tty) +{ + struct moxa_str *ch = tty->driver_data; + unsigned long flags; + + save_flags(flags); + cli(); + ch->statusflags |= EMPTYWAIT; + moxaEmptyTimer_on[ch->port] = 0; + del_timer(&moxaEmptyTimer[ch->port]); + moxaEmptyTimer[ch->port].expires = jiffies + HZ; + moxaEmptyTimer_on[ch->port] = 1; + add_timer(&moxaEmptyTimer[ch->port]); + restore_flags(flags); +} + +static void check_xmit_empty(unsigned long data) +{ + struct moxa_str *ch; + + ch = (struct moxa_str *) data; + moxaEmptyTimer_on[ch->port] = 0; + del_timer(&moxaEmptyTimer[ch->port]); + if (ch->tty && (ch->statusflags & EMPTYWAIT)) { + if (MoxaPortTxQueue(ch->port) == 0) { + ch->statusflags &= ~EMPTYWAIT; + if ((ch->tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + ch->tty->ldisc.write_wakeup) + (ch->tty->ldisc.write_wakeup) (ch->tty); + wake_up_interruptible(&ch->tty->write_wait); + return; + } + moxaEmptyTimer[ch->port].expires = jiffies + HZ; + moxaEmptyTimer_on[ch->port] = 1; + add_timer(&moxaEmptyTimer[ch->port]); + } else + ch->statusflags &= ~EMPTYWAIT; +} + +static void shut_down(struct moxa_str *ch) +{ + struct tty_struct *tp; + + if (!(ch->asyncflags & ASYNC_INITIALIZED)) + return; + + tp = ch->tty; + + MoxaPortDisable(ch->port); + + /* + * If we're a modem control device and HUPCL is on, drop RTS & DTR. + */ + if (tp->termios->c_cflag & HUPCL) + MoxaPortLineCtrl(ch->port, 0, 0); + + ch->asyncflags &= ~ASYNC_INITIALIZED; +} + +static void receive_data(struct moxa_str *ch) +{ + struct tty_struct *tp; + struct termios *ts; + int i, count, rc, space; + unsigned char *charptr, *flagptr; + unsigned long flags; + + ts = 0; + tp = ch->tty; + if (tp) + ts = tp->termios; + /************************************************** + if ( !tp || !ts || !(ts->c_cflag & CREAD) ) { + *****************************************************/ + if (!tp || !ts) { + MoxaPortFlushData(ch->port, 0); + return; + } + space = TTY_FLIPBUF_SIZE - tp->flip.count; + if (space <= 0) + return; + charptr = tp->flip.char_buf_ptr; + flagptr = tp->flip.flag_buf_ptr; + rc = tp->flip.count; + save_flags(flags); + cli(); + count = MoxaPortReadData(ch->port, charptr, space); + restore_flags(flags); + for (i = 0; i < count; i++) + *flagptr++ = 0; + charptr += count; + rc += count; + tp->flip.count = rc; + tp->flip.char_buf_ptr = charptr; + tp->flip.flag_buf_ptr = flagptr; + tty_schedule_flip(ch->tty); +} + +#define Magic_code 0x404 + +/* + * System Configuration + */ +/* + * for C218 BIOS initialization + */ +#define C218_ConfBase 0x800 +#define C218_status (C218_ConfBase + 0) /* BIOS running status */ +#define C218_diag (C218_ConfBase + 2) /* diagnostic status */ +#define C218_key (C218_ConfBase + 4) /* WORD (0x218 for C218) */ +#define C218DLoad_len (C218_ConfBase + 6) /* WORD */ +#define C218check_sum (C218_ConfBase + 8) /* BYTE */ +#define C218chksum_ok (C218_ConfBase + 0x0a) /* BYTE (1:ok) */ +#define C218_TestRx (C218_ConfBase + 0x10) /* 8 bytes for 8 ports */ +#define C218_TestTx (C218_ConfBase + 0x18) /* 8 bytes for 8 ports */ +#define C218_RXerr (C218_ConfBase + 0x20) /* 8 bytes for 8 ports */ +#define C218_ErrFlag (C218_ConfBase + 0x28) /* 8 bytes for 8 ports */ + +#define C218_LoadBuf 0x0F00 +#define C218_KeyCode 0x218 +#define CP204J_KeyCode 0x204 + +/* + * for C320 BIOS initialization + */ +#define C320_ConfBase 0x800 +#define C320_LoadBuf 0x0f00 +#define STS_init 0x05 /* for C320_status */ + +#define C320_status C320_ConfBase + 0 /* BIOS running status */ +#define C320_diag C320_ConfBase + 2 /* diagnostic status */ +#define C320_key C320_ConfBase + 4 /* WORD (0320H for C320) */ +#define C320DLoad_len C320_ConfBase + 6 /* WORD */ +#define C320check_sum C320_ConfBase + 8 /* WORD */ +#define C320chksum_ok C320_ConfBase + 0x0a /* WORD (1:ok) */ +#define C320bapi_len C320_ConfBase + 0x0c /* WORD */ +#define C320UART_no C320_ConfBase + 0x0e /* WORD */ + +#define C320_KeyCode 0x320 + +#define FixPage_addr 0x0000 /* starting addr of static page */ +#define DynPage_addr 0x2000 /* starting addr of dynamic page */ +#define C218_start 0x3000 /* starting addr of C218 BIOS prg */ +#define Control_reg 0x1ff0 /* select page and reset control */ +#define HW_reset 0x80 + +/* + * Function Codes + */ +#define FC_CardReset 0x80 +#define FC_ChannelReset 1 /* C320 firmware not supported */ +#define FC_EnableCH 2 +#define FC_DisableCH 3 +#define FC_SetParam 4 +#define FC_SetMode 5 +#define FC_SetRate 6 +#define FC_LineControl 7 +#define FC_LineStatus 8 +#define FC_XmitControl 9 +#define FC_FlushQueue 10 +#define FC_SendBreak 11 +#define FC_StopBreak 12 +#define FC_LoopbackON 13 +#define FC_LoopbackOFF 14 +#define FC_ClrIrqTable 15 +#define FC_SendXon 16 +#define FC_SetTermIrq 17 /* C320 firmware not supported */ +#define FC_SetCntIrq 18 /* C320 firmware not supported */ +#define FC_SetBreakIrq 19 +#define FC_SetLineIrq 20 +#define FC_SetFlowCtl 21 +#define FC_GenIrq 22 +#define FC_InCD180 23 +#define FC_OutCD180 24 +#define FC_InUARTreg 23 +#define FC_OutUARTreg 24 +#define FC_SetXonXoff 25 +#define FC_OutCD180CCR 26 +#define FC_ExtIQueue 27 +#define FC_ExtOQueue 28 +#define FC_ClrLineIrq 29 +#define FC_HWFlowCtl 30 +#define FC_GetClockRate 35 +#define FC_SetBaud 36 +#define FC_SetDataMode 41 +#define FC_GetCCSR 43 +#define FC_GetDataError 45 +#define FC_RxControl 50 +#define FC_ImmSend 51 +#define FC_SetXonState 52 +#define FC_SetXoffState 53 +#define FC_SetRxFIFOTrig 54 +#define FC_SetTxFIFOCnt 55 +#define FC_UnixRate 56 +#define FC_UnixResetTimer 57 + +#define RxFIFOTrig1 0 +#define RxFIFOTrig4 1 +#define RxFIFOTrig8 2 +#define RxFIFOTrig14 3 + +/* + * Dual-Ported RAM + */ +#define DRAM_global 0 +#define INT_data (DRAM_global + 0) +#define Config_base (DRAM_global + 0x108) + +#define IRQindex (INT_data + 0) +#define IRQpending (INT_data + 4) +#define IRQtable (INT_data + 8) + +/* + * Interrupt Status + */ +#define IntrRx 0x01 /* receiver data O.K. */ +#define IntrTx 0x02 /* transmit buffer empty */ +#define IntrFunc 0x04 /* function complete */ +#define IntrBreak 0x08 /* received break */ +#define IntrLine 0x10 /* line status change + for transmitter */ +#define IntrIntr 0x20 /* received INTR code */ +#define IntrQuit 0x40 /* received QUIT code */ +#define IntrEOF 0x80 /* received EOF code */ + +#define IntrRxTrigger 0x100 /* rx data count reach tigger value */ +#define IntrTxTrigger 0x200 /* tx data count below trigger value */ + +#define Magic_no (Config_base + 0) +#define Card_model_no (Config_base + 2) +#define Total_ports (Config_base + 4) +#define Module_cnt (Config_base + 8) +#define Module_no (Config_base + 10) +#define Timer_10ms (Config_base + 14) +#define Disable_IRQ (Config_base + 20) +#define TMS320_PORT1 (Config_base + 22) +#define TMS320_PORT2 (Config_base + 24) +#define TMS320_CLOCK (Config_base + 26) + +/* + * DATA BUFFER in DRAM + */ +#define Extern_table 0x400 /* Base address of the external table + (24 words * 64) total 3K bytes + (24 words * 128) total 6K bytes */ +#define Extern_size 0x60 /* 96 bytes */ +#define RXrptr 0x00 /* read pointer for RX buffer */ +#define RXwptr 0x02 /* write pointer for RX buffer */ +#define TXrptr 0x04 /* read pointer for TX buffer */ +#define TXwptr 0x06 /* write pointer for TX buffer */ +#define HostStat 0x08 /* IRQ flag and general flag */ +#define FlagStat 0x0A +#define FlowControl 0x0C /* B7 B6 B5 B4 B3 B2 B1 B0 */ + /* x x x x | | | | */ + /* | | | + CTS flow */ + /* | | +--- RTS flow */ + /* | +------ TX Xon/Xoff */ + /* +--------- RX Xon/Xoff */ +#define Break_cnt 0x0E /* received break count */ +#define CD180TXirq 0x10 /* if non-0: enable TX irq */ +#define RX_mask 0x12 +#define TX_mask 0x14 +#define Ofs_rxb 0x16 +#define Ofs_txb 0x18 +#define Page_rxb 0x1A +#define Page_txb 0x1C +#define EndPage_rxb 0x1E +#define EndPage_txb 0x20 +#define Data_error 0x22 +#define RxTrigger 0x28 +#define TxTrigger 0x2a + +#define rRXwptr 0x34 +#define Low_water 0x36 + +#define FuncCode 0x40 +#define FuncArg 0x42 +#define FuncArg1 0x44 + +#define C218rx_size 0x2000 /* 8K bytes */ +#define C218tx_size 0x8000 /* 32K bytes */ + +#define C218rx_mask (C218rx_size - 1) +#define C218tx_mask (C218tx_size - 1) + +#define C320p8rx_size 0x2000 +#define C320p8tx_size 0x8000 +#define C320p8rx_mask (C320p8rx_size - 1) +#define C320p8tx_mask (C320p8tx_size - 1) + +#define C320p16rx_size 0x2000 +#define C320p16tx_size 0x4000 +#define C320p16rx_mask (C320p16rx_size - 1) +#define C320p16tx_mask (C320p16tx_size - 1) + +#define C320p24rx_size 0x2000 +#define C320p24tx_size 0x2000 +#define C320p24rx_mask (C320p24rx_size - 1) +#define C320p24tx_mask (C320p24tx_size - 1) + +#define C320p32rx_size 0x1000 +#define C320p32tx_size 0x1000 +#define C320p32rx_mask (C320p32rx_size - 1) +#define C320p32tx_mask (C320p32tx_size - 1) + +#define Page_size 0x2000 +#define Page_mask (Page_size - 1) +#define C218rx_spage 3 +#define C218tx_spage 4 +#define C218rx_pageno 1 +#define C218tx_pageno 4 +#define C218buf_pageno 5 + +#define C320p8rx_spage 3 +#define C320p8tx_spage 4 +#define C320p8rx_pgno 1 +#define C320p8tx_pgno 4 +#define C320p8buf_pgno 5 + +#define C320p16rx_spage 3 +#define C320p16tx_spage 4 +#define C320p16rx_pgno 1 +#define C320p16tx_pgno 2 +#define C320p16buf_pgno 3 + +#define C320p24rx_spage 3 +#define C320p24tx_spage 4 +#define C320p24rx_pgno 1 +#define C320p24tx_pgno 1 +#define C320p24buf_pgno 2 + +#define C320p32rx_spage 3 +#define C320p32tx_ofs C320p32rx_size +#define C320p32tx_spage 3 +#define C320p32buf_pgno 1 + +/* + * Host Status + */ +#define WakeupRx 0x01 +#define WakeupTx 0x02 +#define WakeupBreak 0x08 +#define WakeupLine 0x10 +#define WakeupIntr 0x20 +#define WakeupQuit 0x40 +#define WakeupEOF 0x80 /* used in VTIME control */ +#define WakeupRxTrigger 0x100 +#define WakeupTxTrigger 0x200 +/* + * Flag status + */ +#define Rx_over 0x01 +#define Xoff_state 0x02 +#define Tx_flowOff 0x04 +#define Tx_enable 0x08 +#define CTS_state 0x10 +#define DSR_state 0x20 +#define DCD_state 0x80 +/* + * FlowControl + */ +#define CTS_FlowCtl 1 +#define RTS_FlowCtl 2 +#define Tx_FlowCtl 4 +#define Rx_FlowCtl 8 +#define IXM_IXANY 0x10 + +#define LowWater 128 + +#define DTR_ON 1 +#define RTS_ON 2 +#define CTS_ON 1 +#define DSR_ON 2 +#define DCD_ON 8 + +/* mode definition */ +#define MX_CS8 0x03 +#define MX_CS7 0x02 +#define MX_CS6 0x01 +#define MX_CS5 0x00 + +#define MX_STOP1 0x00 +#define MX_STOP15 0x04 +#define MX_STOP2 0x08 + +#define MX_PARNONE 0x00 +#define MX_PAREVEN 0x40 +#define MX_PARODD 0xC0 + +/* + * Query + */ +#define QueryPort MAX_PORTS + + + +struct mon_str { + int tick; + int rxcnt[MAX_PORTS]; + int txcnt[MAX_PORTS]; +}; +typedef struct mon_str mon_st; + +#define DCD_changed 0x01 +#define DCD_oldstate 0x80 + +static unsigned char moxaBuff[10240]; +static unsigned long moxaIntNdx[MAX_BOARDS]; +static unsigned long moxaIntPend[MAX_BOARDS]; +static unsigned long moxaIntTable[MAX_BOARDS]; +static char moxaChkPort[MAX_PORTS]; +static char moxaLineCtrl[MAX_PORTS]; +static unsigned long moxaTableAddr[MAX_PORTS]; +static long moxaCurBaud[MAX_PORTS]; +static char moxaDCDState[MAX_PORTS]; +static char moxaLowChkFlag[MAX_PORTS]; +static int moxaLowWaterChk; +static int moxaCard; +static mon_st moxaLog; +static int moxaFuncTout; +static ushort moxaBreakCnt[MAX_PORTS]; + +static void moxadelay(int); +static void moxafunc(unsigned long, int, ushort); +static void wait_finish(unsigned long); +static void low_water_check(unsigned long); +static int moxaloadbios(int, unsigned char *, int); +static int moxafindcard(int); +static int moxaload320b(int, unsigned char *, int); +static int moxaloadcode(int, unsigned char *, int); +static int moxaloadc218(int, unsigned long, int); +static int moxaloadc320(int, unsigned long, int, int *); + +/***************************************************************************** + * Driver level functions: * + * 1. MoxaDriverInit(void); * + * 2. MoxaDriverIoctl(unsigned int cmd, unsigned long arg, int port); * + * 3. MoxaDriverPoll(void); * + *****************************************************************************/ +void MoxaDriverInit(void) +{ + int i; + + moxaFuncTout = HZ / 2; /* 500 mini-seconds */ + moxaCard = 0; + moxaLog.tick = 0; + moxaLowWaterChk = 0; + for (i = 0; i < MAX_PORTS; i++) { + moxaChkPort[i] = 0; + moxaLowChkFlag[i] = 0; + moxaLineCtrl[i] = 0; + moxaLog.rxcnt[i] = 0; + moxaLog.txcnt[i] = 0; + } +} + +#define MOXA 0x400 +#define MOXA_GET_IQUEUE (MOXA + 1) /* get input buffered count */ +#define MOXA_GET_OQUEUE (MOXA + 2) /* get output buffered count */ +#define MOXA_INIT_DRIVER (MOXA + 6) /* moxaCard=0 */ +#define MOXA_LOAD_BIOS (MOXA + 9) /* download BIOS */ +#define MOXA_FIND_BOARD (MOXA + 10) /* Check if MOXA card exist? */ +#define MOXA_LOAD_C320B (MOXA + 11) /* download 320B firmware */ +#define MOXA_LOAD_CODE (MOXA + 12) /* download firmware */ +#define MOXA_GETDATACOUNT (MOXA + 23) +#define MOXA_GET_IOQUEUE (MOXA + 27) +#define MOXA_FLUSH_QUEUE (MOXA + 28) +#define MOXA_GET_CONF (MOXA + 35) /* configuration */ +#define MOXA_GET_MAJOR (MOXA + 63) +#define MOXA_GET_CUMAJOR (MOXA + 64) +#define MOXA_GETMSTATUS (MOXA + 65) + + +struct moxaq_str { + int inq; + int outq; +}; + +struct dl_str { + char *buf; + int len; + int cardno; +}; + +static struct moxaq_str temp_queue[MAX_PORTS]; +static struct dl_str dltmp; + +void MoxaPortFlushData(int port, int mode) +{ + unsigned long ofsAddr; + if ((mode < 0) || (mode > 2)) + return; + ofsAddr = moxaTableAddr[port]; + moxafunc(ofsAddr, FC_FlushQueue, mode); + if (mode != 1) { + moxaLowChkFlag[port] = 0; + low_water_check(ofsAddr); + } +} + +int MoxaDriverIoctl(unsigned int cmd, unsigned long arg, int port) +{ + int i; + int status; + int MoxaPortTxQueue(int), MoxaPortRxQueue(int); + + if (port == QueryPort) { + if ((cmd != MOXA_GET_CONF) && (cmd != MOXA_INIT_DRIVER) && + (cmd != MOXA_LOAD_BIOS) && (cmd != MOXA_FIND_BOARD) && (cmd != MOXA_LOAD_C320B) && + (cmd != MOXA_LOAD_CODE) && (cmd != MOXA_GETDATACOUNT) && + (cmd != MOXA_GET_IOQUEUE) && (cmd != MOXA_GET_MAJOR) && + (cmd != MOXA_GET_CUMAJOR) && (cmd != MOXA_GETMSTATUS)) + return (-EINVAL); + } + switch (cmd) { + case MOXA_GET_CONF: + if(copy_to_user((void *)arg, &moxa_boards, MAX_BOARDS * sizeof(moxa_board_conf))) + return -EFAULT; + return (0); + case MOXA_INIT_DRIVER: + if ((int) arg == 0x404) + MoxaDriverInit(); + return (0); + case MOXA_GETDATACOUNT: + moxaLog.tick = jiffies; + if(copy_to_user((void *)arg, &moxaLog, sizeof(mon_st))) + return -EFAULT; + return (0); + case MOXA_FLUSH_QUEUE: + MoxaPortFlushData(port, arg); + return (0); + case MOXA_GET_IOQUEUE: + for (i = 0; i < MAX_PORTS; i++) { + if (moxaChkPort[i]) { + temp_queue[i].inq = MoxaPortRxQueue(i); + temp_queue[i].outq = MoxaPortTxQueue(i); + } + } + if(copy_to_user((void *)arg, temp_queue, sizeof(struct moxaq_str) * MAX_PORTS)) + return -EFAULT; + return (0); + case MOXA_LOAD_BIOS: + if(copy_from_user(&dltmp, (void *)arg, sizeof(struct dl_str))) + return -EFAULT; + i = moxaloadbios(dltmp.cardno, dltmp.buf, dltmp.len); + return (i); + case MOXA_FIND_BOARD: + if(copy_from_user(&dltmp, (void *)arg, sizeof(struct dl_str))) + return -EFAULT; + return moxafindcard(dltmp.cardno); + case MOXA_LOAD_C320B: + if(copy_from_user(&dltmp, (void *)arg, sizeof(struct dl_str))) + return -EFAULT; + moxaload320b(dltmp.cardno, dltmp.buf, dltmp.len); + return (0); + case MOXA_LOAD_CODE: + if(copy_from_user(&dltmp, (void *)arg, sizeof(struct dl_str))) + return -EFAULT; + i = moxaloadcode(dltmp.cardno, dltmp.buf, dltmp.len); + if (i == -1) + return (-EFAULT); + return (i); + case MOXA_GET_OQUEUE: + i = MoxaPortTxQueue(port); + return put_user(i, (unsigned long *) arg); + case MOXA_GET_IQUEUE: + i = MoxaPortRxQueue(port); + return put_user(i, (unsigned long *) arg); + case MOXA_GET_MAJOR: + if(copy_to_user((void *)arg, &ttymajor, sizeof(int))) + return -EFAULT; + return 0; + case MOXA_GET_CUMAJOR: + if(copy_to_user((void *)arg, &calloutmajor, sizeof(int))) + return -EFAULT; + return 0; + case MOXA_GETMSTATUS: + for (i = 0; i < MAX_PORTS; i++) { + GMStatus[i].ri = 0; + GMStatus[i].dcd = 0; + GMStatus[i].dsr = 0; + GMStatus[i].cts = 0; + if (!moxaChkPort[i]) { + continue; + } else { + status = MoxaPortLineStatus(moxaChannels[i].port); + if (status & 1) + GMStatus[i].cts = 1; + if (status & 2) + GMStatus[i].dsr = 1; + if (status & 4) + GMStatus[i].dcd = 1; + } + + if (!moxaChannels[i].tty || !moxaChannels[i].tty->termios) + GMStatus[i].cflag = moxaChannels[i].normal_termios.c_cflag; + else + GMStatus[i].cflag = moxaChannels[i].tty->termios->c_cflag; + } + if(copy_to_user((void *)arg, GMStatus, sizeof(struct mxser_mstatus) * MAX_PORTS)) + return -EFAULT; + return 0; + + } + return (-ENOIOCTLCMD); +} + +int MoxaDriverPoll(void) +{ + register ushort temp; + register int card; + unsigned long ip, ofsAddr; + int port, p, ports; + + if (moxaCard == 0) + return (-1); + for (card = 0; card < MAX_BOARDS; card++) { + if ((ports = moxa_boards[card].numPorts) == 0) + continue; + if (readb(moxaIntPend[card]) == 0xff) { + ip = moxaIntTable[card] + readb(moxaIntNdx[card]); + p = card * MAX_PORTS_PER_BOARD; + ports <<= 1; + for (port = 0; port < ports; port += 2, p++) { + if ((temp = readw(ip + port)) != 0) { + writew(0, ip + port); + ofsAddr = moxaTableAddr[p]; + if (temp & IntrTx) + writew(readw(ofsAddr + HostStat) & ~WakeupTx, ofsAddr + HostStat); + if (temp & IntrBreak) { + moxaBreakCnt[p]++; + } + if (temp & IntrLine) { + if (readb(ofsAddr + FlagStat) & DCD_state) { + if ((moxaDCDState[p] & DCD_oldstate) == 0) + moxaDCDState[p] = (DCD_oldstate | + DCD_changed); + } else { + if (moxaDCDState[p] & DCD_oldstate) + moxaDCDState[p] = DCD_changed; + } + } + } + } + writeb(0, moxaIntPend[card]); + } + if (moxaLowWaterChk) { + p = card * MAX_PORTS_PER_BOARD; + for (port = 0; port < ports; port++, p++) { + if (moxaLowChkFlag[p]) { + moxaLowChkFlag[p] = 0; + ofsAddr = moxaTableAddr[p]; + low_water_check(ofsAddr); + } + } + } + } + moxaLowWaterChk = 0; + return (0); +} + +/***************************************************************************** + * Card level function: * + * 1. MoxaPortsOfCard(int cardno); * + *****************************************************************************/ +int MoxaPortsOfCard(int cardno) +{ + + if (moxa_boards[cardno].boardType == 0) + return (0); + return (moxa_boards[cardno].numPorts); +} + +/***************************************************************************** + * Port level functions: * + * 1. MoxaPortIsValid(int port); * + * 2. MoxaPortEnable(int port); * + * 3. MoxaPortDisable(int port); * + * 4. MoxaPortGetMaxBaud(int port); * + * 5. MoxaPortGetCurBaud(int port); * + * 6. MoxaPortSetBaud(int port, long baud); * + * 7. MoxaPortSetMode(int port, int databit, int stopbit, int parity); * + * 8. MoxaPortSetTermio(int port, unsigned char *termio); * + * 9. MoxaPortGetLineOut(int port, int *dtrState, int *rtsState); * + * 10. MoxaPortLineCtrl(int port, int dtrState, int rtsState); * + * 11. MoxaPortFlowCtrl(int port, int rts, int cts, int rx, int tx,int xany); * + * 12. MoxaPortLineStatus(int port); * + * 13. MoxaPortDCDChange(int port); * + * 14. MoxaPortDCDON(int port); * + * 15. MoxaPortFlushData(int port, int mode); * + * 16. MoxaPortWriteData(int port, unsigned char * buffer, int length); * + * 17. MoxaPortReadData(int port, unsigned char * buffer, int length); * + * 18. MoxaPortTxBufSize(int port); * + * 19. MoxaPortRxBufSize(int port); * + * 20. MoxaPortTxQueue(int port); * + * 21. MoxaPortTxFree(int port); * + * 22. MoxaPortRxQueue(int port); * + * 23. MoxaPortRxFree(int port); * + * 24. MoxaPortTxDisable(int port); * + * 25. MoxaPortTxEnable(int port); * + * 26. MoxaPortGetBrkCnt(int port); * + * 27. MoxaPortResetBrkCnt(int port); * + * 28. MoxaPortSetXonXoff(int port, int xonValue, int xoffValue); * + * 29. MoxaPortIsTxHold(int port); * + * 30. MoxaPortSendBreak(int port, int ticks); * + *****************************************************************************/ +/* + * 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 3: Moxa driver polling process routine. + * Syntax: + * int MoxaDriverPoll(void); + * + * return: 0 ; polling O.K. + * -1 : no any Moxa card. + * + * + * Function 4: Get the ports of this card. + * Syntax: + * int MoxaPortsOfCard(int cardno); + * + * int cardno : card number (0 - 3) + * + * return: 0 : this card is invalid + * 8/16/24/32 + * + * + * Function 5: Check this port is valid or invalid + * Syntax: + * int MoxaPortIsValid(int port); + * int port : port number (0 - 127, ref port description) + * + * return: 0 : this port is invalid + * 1 : this port is valid + * + * + * 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 8: Get the maximun available baud rate of this port. + * Syntax: + * long MoxaPortGetMaxBaud(int port); + * int port : port number (0 - 127) + * + * return: 0 : this port is invalid + * 38400/57600/115200 bps + * + * + * Function 9: Get the current baud rate of this port. + * Syntax: + * long MoxaPortGetCurBaud(int port); + * int port : port number (0 - 127) + * + * return: 0 : this port is invalid + * 50 - 115200 bps + * + * + * Function 10: Setting baud rate of this port. + * Syntax: + * long MoxaPortSetBaud(int port, long 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 11: Setting the data-bits/stop-bits/parity of this port + * Syntax: + * int MoxaPortSetMode(int port, int databits, int stopbits, int parity); + * int port : port number (0 - 127) + * int databits : data bits (8/7/6/5) + * int stopbits : stop bits (2/1/0, 0 show 1.5 stop bits) + int parity : parity (0:None,1:Odd,2:Even,3:Mark,4:Space) + * + * return: -1 : invalid parameter + * 0 : setting O.K. + * + * + * Function 12: Configure the port. + * Syntax: + * int MoxaPortSetTermio(int port, struct termios *termio); + * int port : port number (0 - 127) + * struct termios * termio : termio structure pointer + * + * 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 17: Check the DCD state has changed since the last read + * of this function. + * Syntax: + * int MoxaPortDCDChange(int port); + * int port : port number (0 - 127) + * + * return: 0 : no changed + * 1 : DCD has changed + * + * + * Function 18: Check ths current DCD state is ON or not. + * Syntax: + * int MoxaPortDCDON(int port); + * int port : port number (0 - 127) + * + * return: 0 : DCD off + * 1 : DCD 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, unsigned char * buffer, int length); + * int port : port number (0 - 127) + * unsigned char * buffer : pointer to read data buffer. + * int length : read data buffer length + * + * return: 0 - length : real read data length + * + * + * Function 22: Get the Tx buffer size of this port + * Syntax: + * int MoxaPortTxBufSize(int port); + * int port : port number (0 - 127) + * + * return: .. : Tx buffer size + * + * + * Function 23: Get the Rx buffer size of this port + * Syntax: + * int MoxaPortRxBufSize(int port); + * int port : port number (0 - 127) + * + * return: .. : Rx buffer size + * + * + * 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 27: Get the Rx buffer current free space + * Syntax: + * int MoxaPortRxFree(int port); + * int port : port number (0 - 127) + * + * return: .. : Rx buffer current free space + * + * + * 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 30: Get the received BREAK signal count. + * Syntax: + * int MoxaPortGetBrkCnt(int port); + * int port : port number (0 - 127) + * + * return: 0 - .. : BREAK signal count + * + * + * 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 + * + * + * Function 32: Set the S/W flow control new XON/XOFF value, default + * XON is 0x11 & XOFF is 0x13. + * Syntax: + * void MoxaPortSetXonXoff(int port, int xonValue, int xoffValue); + * int port : port number (0 - 127) + * int xonValue : new XON value (0 - 255) + * int xoffValue : new XOFF value (0 - 255) + * + * + * Function 33: Check this port's transmission is hold by remote site + * because the flow control. + * Syntax: + * int MoxaPortIsTxHold(int port); + * int port : port number (0 - 127) + * + * return: 0 : normal + * 1 : hold by remote site + * + * + * Function 34: Send out a BREAK signal. + * Syntax: + * void MoxaPortSendBreak(int port, int ms100); + * int port : port number (0 - 127) + * int ms100 : break signal time interval. + * unit: 100 mini-second. if ms100 == 0, it will + * send out a about 250 ms BREAK signal. + * + */ +int MoxaPortIsValid(int port) +{ + + if (moxaCard == 0) + return (0); + if (moxaChkPort[port] == 0) + return (0); + return (1); +} + +void MoxaPortEnable(int port) +{ + unsigned long ofsAddr; + int MoxaPortLineStatus(int); + short lowwater = 512; + + ofsAddr = moxaTableAddr[port]; + writew(lowwater, ofsAddr + Low_water); + moxaBreakCnt[port] = 0; + if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) || + (moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI)) { + 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); +} + +void MoxaPortDisable(int port) +{ + unsigned long ofsAddr; + + ofsAddr = moxaTableAddr[port]; + moxafunc(ofsAddr, FC_SetFlowCtl, 0); /* disable flow control */ + moxafunc(ofsAddr, FC_ClrLineIrq, Magic_code); + writew(0, ofsAddr + HostStat); + moxafunc(ofsAddr, FC_DisableCH, Magic_code); +} + +long MoxaPortGetMaxBaud(int port) +{ + if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) || + (moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI)) + return (460800L); + else + return (921600L); +} + + +long MoxaPortSetBaud(int port, long baud) +{ + unsigned long ofsAddr; + long max, clock; + unsigned int val; + + if ((baud < 50L) || ((max = MoxaPortGetMaxBaud(port)) == 0)) + return (0); + ofsAddr = moxaTableAddr[port]; + if (baud > max) + baud = max; + if (max == 38400L) + clock = 614400L; /* for 9.8304 Mhz : max. 38400 bps */ + else if (max == 57600L) + clock = 691200L; /* for 11.0592 Mhz : max. 57600 bps */ + else + clock = 921600L; /* for 14.7456 Mhz : max. 115200 bps */ + val = clock / baud; + moxafunc(ofsAddr, FC_SetBaud, val); + baud = clock / val; + moxaCurBaud[port] = baud; + return (baud); +} + +int MoxaPortSetTermio(int port, struct termios *termio) +{ + unsigned long ofsAddr; + tcflag_t cflag; + long baud; + tcflag_t mode = 0; + + if (moxaChkPort[port] == 0 || termio == 0) + return (-1); + ofsAddr = moxaTableAddr[port]; + 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, (ushort) mode); + + cflag &= (CBAUD | CBAUDEX); +#ifndef B921600 +#define B921600 (B460800+1) +#endif + switch (cflag) { + case B921600: + baud = 921600L; + break; + case B460800: + baud = 460800L; + break; + case B230400: + baud = 230400L; + break; + case B115200: + baud = 115200L; + break; + case B57600: + baud = 57600L; + break; + case B38400: + baud = 38400L; + break; + case B19200: + baud = 19200L; + break; + case B9600: + baud = 9600L; + break; + case B4800: + baud = 4800L; + break; + case B2400: + baud = 2400L; + break; + case B1800: + baud = 1800L; + break; + case B1200: + baud = 1200L; + break; + case B600: + baud = 600L; + break; + case B300: + baud = 300L; + break; + case B200: + baud = 200L; + break; + case B150: + baud = 150L; + break; + case B134: + baud = 134L; + break; + case B110: + baud = 110L; + break; + case B75: + baud = 75L; + break; + case B50: + baud = 50L; + break; + default: + baud = 0; + } + if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) || + (moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI)) { + if (baud == 921600L) + return (-1); + } + MoxaPortSetBaud(port, baud); + + if (termio->c_iflag & (IXON | IXOFF | IXANY)) { + writeb(termio->c_cc[VSTART], ofsAddr + FuncArg); + writeb(termio->c_cc[VSTOP], ofsAddr + FuncArg1); + writeb(FC_SetXonXoff, ofsAddr + FuncCode); + wait_finish(ofsAddr); + + } + return (0); +} + +int MoxaPortGetLineOut(int port, int *dtrState, int *rtsState) +{ + + if (!MoxaPortIsValid(port)) + return (-1); + if (dtrState) { + if (moxaLineCtrl[port] & DTR_ON) + *dtrState = 1; + else + *dtrState = 0; + } + if (rtsState) { + if (moxaLineCtrl[port] & RTS_ON) + *rtsState = 1; + else + *rtsState = 0; + } + return (0); +} + +void MoxaPortLineCtrl(int port, int dtr, int rts) +{ + unsigned long ofsAddr; + int mode; + + ofsAddr = moxaTableAddr[port]; + mode = 0; + if (dtr) + mode |= DTR_ON; + if (rts) + mode |= RTS_ON; + moxaLineCtrl[port] = mode; + moxafunc(ofsAddr, FC_LineControl, mode); +} + +void MoxaPortFlowCtrl(int port, int rts, int cts, int txflow, int rxflow, int txany) +{ + unsigned long ofsAddr; + int mode; + + ofsAddr = moxaTableAddr[port]; + 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(ofsAddr, FC_SetFlowCtl, mode); +} + +int MoxaPortLineStatus(int port) +{ + unsigned long ofsAddr; + int val; + + ofsAddr = moxaTableAddr[port]; + if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) || + (moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI)) { + moxafunc(ofsAddr, FC_LineStatus, 0); + val = readw(ofsAddr + FuncArg); + } else { + val = readw(ofsAddr + FlagStat) >> 4; + } + val &= 0x0B; + if (val & 8) { + val |= 4; + if ((moxaDCDState[port] & DCD_oldstate) == 0) + moxaDCDState[port] = (DCD_oldstate | DCD_changed); + } else { + if (moxaDCDState[port] & DCD_oldstate) + moxaDCDState[port] = DCD_changed; + } + val &= 7; + return (val); +} + +int MoxaPortDCDChange(int port) +{ + int n; + + if (moxaChkPort[port] == 0) + return (0); + n = moxaDCDState[port]; + moxaDCDState[port] &= ~DCD_changed; + n &= DCD_changed; + return (n); +} + +int MoxaPortDCDON(int port) +{ + int n; + + if (moxaChkPort[port] == 0) + return (0); + if (moxaDCDState[port] & DCD_oldstate) + n = 1; + else + n = 0; + return (n); +} + + +/* + int MoxaDumpMem(int port, unsigned char * buffer, int len) + { + int i; + unsigned long baseAddr,ofsAddr,ofs; + + baseAddr = moxaBaseAddr[port / MAX_PORTS_PER_BOARD]; + ofs = baseAddr + DynPage_addr + pageofs; + if (len > 0x2000L) + len = 0x2000L; + for (i = 0; i < len; i++) + buffer[i] = readb(ofs+i); + } + */ + + +int MoxaPortWriteData(int port, unsigned char * buffer, int len) +{ + int c, total, i; + ushort tail; + int cnt; + ushort head, tx_mask, spage, epage; + ushort pageno, pageofs, bufhead; + unsigned long baseAddr, ofsAddr, ofs; + + ofsAddr = moxaTableAddr[port]; + baseAddr = moxaBaseAddr[port / MAX_PORTS_PER_BOARD]; + 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] += 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; + for (i = 0; i < len; i++) + writeb(*buffer++, ofs + i); + tail = (tail + len) & tx_mask; + c -= len; + } + writew(tail, ofsAddr + TXwptr); + } else { + len = c; + pageno = spage + (tail >> 13); + pageofs = tail & Page_mask; + do { + cnt = Page_size - pageofs; + if (cnt > c) + cnt = c; + c -= cnt; + writeb(pageno, baseAddr + Control_reg); + ofs = baseAddr + DynPage_addr + pageofs; + for (i = 0; i < cnt; i++) + writeb(*buffer++, ofs + i); + if (c == 0) { + writew((tail + len) & tx_mask, ofsAddr + TXwptr); + break; + } + if (++pageno == epage) + pageno = spage; + pageofs = 0; + } while (1); + } + writeb(1, ofsAddr + CD180TXirq); /* start to send */ + return (total); +} + +int MoxaPortReadData(int port, unsigned char * buffer, int space) +{ + register ushort head, pageofs; + int i, count, cnt, len, total, remain; + ushort tail, rx_mask, spage, epage; + ushort pageno, bufhead; + unsigned long baseAddr, ofsAddr, ofs; + + ofsAddr = moxaTableAddr[port]; + baseAddr = moxaBaseAddr[port / MAX_PORTS_PER_BOARD]; + 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 = (space > count) ? count : space; + remain = count - total; + moxaLog.rxcnt[port] += total; + count = total; + if (spage == epage) { + bufhead = readw(ofsAddr + Ofs_rxb); + writew(spage, baseAddr + Control_reg); + while (count > 0) { + if (tail >= head) + len = tail - head; + else + len = rx_mask + 1 - head; + len = (count > len) ? len : count; + ofs = baseAddr + DynPage_addr + bufhead + head; + for (i = 0; i < len; i++) + *buffer++ = readb(ofs + i); + head = (head + len) & rx_mask; + count -= len; + } + writew(head, ofsAddr + RXrptr); + } else { + len = count; + pageno = spage + (head >> 13); + pageofs = head & Page_mask; + do { + cnt = Page_size - pageofs; + if (cnt > count) + cnt = count; + count -= cnt; + writew(pageno, baseAddr + Control_reg); + ofs = baseAddr + DynPage_addr + pageofs; + for (i = 0; i < cnt; i++) + *buffer++ = readb(ofs + i); + if (count == 0) { + writew((head + len) & rx_mask, ofsAddr + RXrptr); + break; + } + if (++pageno == epage) + pageno = spage; + pageofs = 0; + } while (1); + } + if ((readb(ofsAddr + FlagStat) & Xoff_state) && (remain < LowWater)) { + moxaLowWaterChk = 1; + moxaLowChkFlag[port] = 1; + } + return (total); +} + + +int MoxaPortTxQueue(int port) +{ + unsigned long ofsAddr; + ushort rptr, wptr, mask; + int len; + + ofsAddr = moxaTableAddr[port]; + rptr = readw(ofsAddr + TXrptr); + wptr = readw(ofsAddr + TXwptr); + mask = readw(ofsAddr + TX_mask); + len = (wptr - rptr) & mask; + return (len); +} + +int MoxaPortTxFree(int port) +{ + unsigned long ofsAddr; + ushort rptr, wptr, mask; + int len; + + ofsAddr = moxaTableAddr[port]; + rptr = readw(ofsAddr + TXrptr); + wptr = readw(ofsAddr + TXwptr); + mask = readw(ofsAddr + TX_mask); + len = mask - ((wptr - rptr) & mask); + return (len); +} + +int MoxaPortRxQueue(int port) +{ + unsigned long ofsAddr; + ushort rptr, wptr, mask; + int len; + + ofsAddr = moxaTableAddr[port]; + rptr = readw(ofsAddr + RXrptr); + wptr = readw(ofsAddr + RXwptr); + mask = readw(ofsAddr + RX_mask); + len = (wptr - rptr) & mask; + return (len); +} + + +void MoxaPortTxDisable(int port) +{ + unsigned long ofsAddr; + + ofsAddr = moxaTableAddr[port]; + moxafunc(ofsAddr, FC_SetXoffState, Magic_code); +} + +void MoxaPortTxEnable(int port) +{ + unsigned long ofsAddr; + + ofsAddr = moxaTableAddr[port]; + moxafunc(ofsAddr, FC_SetXonState, Magic_code); +} + + +int MoxaPortResetBrkCnt(int port) +{ + ushort cnt; + cnt = moxaBreakCnt[port]; + moxaBreakCnt[port] = 0; + return (cnt); +} + + +void MoxaPortSendBreak(int port, int ms100) +{ + unsigned long ofsAddr; + + ofsAddr = moxaTableAddr[port]; + if (ms100) { + moxafunc(ofsAddr, FC_SendBreak, Magic_code); + moxadelay(ms100 * (HZ / 10)); + } else { + moxafunc(ofsAddr, FC_SendBreak, Magic_code); + moxadelay(HZ / 4); /* 250 ms */ + } + moxafunc(ofsAddr, FC_StopBreak, Magic_code); +} + +static int moxa_get_serial_info(struct moxa_str *info, + struct serial_struct *retinfo) +{ + struct serial_struct tmp; + + if (!retinfo) + return (-EFAULT); + memset(&tmp, 0, sizeof(tmp)); + tmp.type = info->type; + tmp.line = info->port; + tmp.port = 0; + tmp.irq = 0; + tmp.flags = info->asyncflags; + tmp.baud_base = 921600; + tmp.close_delay = info->close_delay; + tmp.closing_wait = info->closing_wait; + tmp.custom_divisor = 0; + tmp.hub6 = 0; + if(copy_to_user(retinfo, &tmp, sizeof(*retinfo))) + return -EFAULT; + return (0); +} + + +static int moxa_set_serial_info(struct moxa_str *info, + struct serial_struct *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.type != info->type) || + (new_serial.custom_divisor != 0) || + (new_serial.baud_base != 921600)) + return (-EPERM); + + if (!suser()) { + if (((new_serial.flags & ~ASYNC_USR_MASK) != + (info->asyncflags & ~ASYNC_USR_MASK))) + return (-EPERM); + } else { + info->close_delay = new_serial.close_delay * HZ / 100; + info->closing_wait = new_serial.closing_wait * HZ / 100; + } + + new_serial.flags = (new_serial.flags & ~ASYNC_FLAGS); + new_serial.flags |= (info->asyncflags & ASYNC_FLAGS); + + if (new_serial.type == PORT_16550A) { + MoxaSetFifo(info->port, 1); + } else { + MoxaSetFifo(info->port, 0); + } + + info->type = new_serial.type; + return (0); +} + + + +/***************************************************************************** + * Static local functions: * + *****************************************************************************/ +/* + * moxadelay - delays a specified number ticks + */ +static void moxadelay(int tick) +{ + unsigned long st, et; + + st = jiffies; + et = st + tick; + while (jiffies < et); +} + +static void moxafunc(unsigned long ofsAddr, int cmd, ushort arg) +{ + + writew(arg, ofsAddr + FuncArg); + writew(cmd, ofsAddr + FuncCode); + wait_finish(ofsAddr); +} + +static void wait_finish(unsigned long ofsAddr) +{ + unsigned long i, j; + + i = jiffies; + while (readw(ofsAddr + FuncCode) != 0) { + j = jiffies; + if ((j - i) > moxaFuncTout) { + return; + } + } +} + +static void low_water_check(unsigned long ofsAddr) +{ + int len; + ushort rptr, wptr, mask; + + 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); + } +} + +static int moxaloadbios(int cardno, unsigned char *tmp, int len) +{ + unsigned long baseAddr; + int i; + + if(copy_from_user(moxaBuff, tmp, len)) + return -EFAULT; + baseAddr = moxaBaseAddr[cardno]; + writeb(HW_reset, baseAddr + Control_reg); /* reset */ + moxadelay(1); /* delay 10 ms */ + for (i = 0; i < 4096; i++) + writeb(0, baseAddr + i); /* clear fix page */ + for (i = 0; i < len; i++) + writeb(moxaBuff[i], baseAddr + i); /* download BIOS */ + writeb(0, baseAddr + Control_reg); /* restart */ + return (0); +} + +static int moxafindcard(int cardno) +{ + unsigned long baseAddr; + ushort tmp; + + baseAddr = moxaBaseAddr[cardno]; + switch (moxa_boards[cardno].boardType) { + case MOXA_BOARD_C218_ISA: + case MOXA_BOARD_C218_PCI: + if ((tmp = readw(baseAddr + C218_key)) != C218_KeyCode) { + return (-1); + } + break; + case MOXA_BOARD_CP204J: + if ((tmp = readw(baseAddr + C218_key)) != CP204J_KeyCode) { + return (-1); + } + break; + default: + if ((tmp = readw(baseAddr + C320_key)) != C320_KeyCode) { + return (-1); + } + if ((tmp = readw(baseAddr + C320_status)) != STS_init) { + return (-2); + } + } + return (0); +} + +static int moxaload320b(int cardno, unsigned char * tmp, int len) +{ + unsigned long baseAddr; + int i; + + if(copy_from_user(moxaBuff, tmp, len)) + return -EFAULT; + baseAddr = moxaBaseAddr[cardno]; + writew(len - 7168 - 2, baseAddr + C320bapi_len); + writeb(1, baseAddr + Control_reg); /* Select Page 1 */ + for (i = 0; i < 7168; i++) + writeb(moxaBuff[i], baseAddr + DynPage_addr + i); + writeb(2, baseAddr + Control_reg); /* Select Page 2 */ + for (i = 0; i < (len - 7168); i++) + writeb(moxaBuff[i + 7168], baseAddr + DynPage_addr + i); + return (0); +} + +static int moxaloadcode(int cardno, unsigned char * tmp, int len) +{ + unsigned long baseAddr, ofsAddr; + int retval, port, i; + + if(copy_from_user(moxaBuff, tmp, len)) + return -EFAULT; + baseAddr = moxaBaseAddr[cardno]; + switch (moxa_boards[cardno].boardType) { + case MOXA_BOARD_C218_ISA: + case MOXA_BOARD_C218_PCI: + case MOXA_BOARD_CP204J: + retval = moxaloadc218(cardno, baseAddr, len); + if (retval) + return (retval); + port = cardno * MAX_PORTS_PER_BOARD; + for (i = 0; i < moxa_boards[cardno].numPorts; i++, port++) { + moxaChkPort[port] = 1; + moxaCurBaud[port] = 9600L; + moxaDCDState[port] = 0; + moxaTableAddr[port] = baseAddr + Extern_table + Extern_size * i; + ofsAddr = moxaTableAddr[port]; + 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: + retval = moxaloadc320(cardno, baseAddr, len, + &moxa_boards[cardno].numPorts); + if (retval) + return (retval); + port = cardno * MAX_PORTS_PER_BOARD; + for (i = 0; i < moxa_boards[cardno].numPorts; i++, port++) { + moxaChkPort[port] = 1; + moxaCurBaud[port] = 9600L; + moxaDCDState[port] = 0; + moxaTableAddr[port] = baseAddr + Extern_table + Extern_size * i; + ofsAddr = moxaTableAddr[port]; + if (moxa_boards[cardno].numPorts == 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); + + } else if (moxa_boards[cardno].numPorts == 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); + + } else if (moxa_boards[cardno].numPorts == 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); + } else if (moxa_boards[cardno].numPorts == 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; + } + return (0); +} + +static int moxaloadc218(int cardno, unsigned long baseAddr, int len) +{ + char retry; + int i, j, len1, len2; + ushort usum, *ptr, keycode; + + if (moxa_boards[cardno].boardType == MOXA_BOARD_CP204J) + keycode = CP204J_KeyCode; + else + keycode = C218_KeyCode; + usum = 0; + len1 = len >> 1; + ptr = (ushort *) moxaBuff; + for (i = 0; i < len1; i++) + usum += *(ptr + i); + retry = 0; + do { + len1 = len >> 1; + j = 0; + while (len1) { + len2 = (len1 > 2048) ? 2048 : len1; + len1 -= len2; + for (i = 0; i < len2 << 1; i++) + writeb(moxaBuff[i + j], baseAddr + C218_LoadBuf + i); + j += i; + + writew(len2, baseAddr + C218DLoad_len); + writew(0, baseAddr + C218_key); + for (i = 0; i < 100; i++) { + if (readw(baseAddr + C218_key) == keycode) + break; + moxadelay(1); /* delay 10 ms */ + } + if (readw(baseAddr + C218_key) != keycode) { + return (-1); + } + } + writew(0, baseAddr + C218DLoad_len); + writew(usum, baseAddr + C218check_sum); + writew(0, baseAddr + C218_key); + for (i = 0; i < 100; i++) { + if (readw(baseAddr + C218_key) == keycode) + break; + moxadelay(1); /* delay 10 ms */ + } + retry++; + } while ((readb(baseAddr + C218chksum_ok) != 1) && (retry < 3)); + if (readb(baseAddr + C218chksum_ok) != 1) { + return (-1); + } + writew(0, baseAddr + C218_key); + for (i = 0; i < 100; i++) { + if (readw(baseAddr + Magic_no) == Magic_code) + break; + moxadelay(1); /* delay 10 ms */ + } + if (readw(baseAddr + Magic_no) != Magic_code) { + return (-1); + } + writew(1, baseAddr + Disable_IRQ); + writew(0, baseAddr + Magic_no); + for (i = 0; i < 100; i++) { + if (readw(baseAddr + Magic_no) == Magic_code) + break; + moxadelay(1); /* delay 10 ms */ + } + if (readw(baseAddr + Magic_no) != Magic_code) { + return (-1); + } + moxaCard = 1; + moxaIntNdx[cardno] = baseAddr + IRQindex; + moxaIntPend[cardno] = baseAddr + IRQpending; + moxaIntTable[cardno] = baseAddr + IRQtable; + return (0); +} + +static int moxaloadc320(int cardno, unsigned long baseAddr, int len, int *numPorts) +{ + ushort usum; + int i, j, wlen, len2, retry; + ushort *uptr; + + usum = 0; + wlen = len >> 1; + uptr = (ushort *) moxaBuff; + for (i = 0; i < wlen; i++) + usum += uptr[i]; + retry = 0; + j = 0; + do { + while (wlen) { + if (wlen > 2048) + len2 = 2048; + else + len2 = wlen; + wlen -= len2; + len2 <<= 1; + for (i = 0; i < len2; i++) + writeb(moxaBuff[j + i], baseAddr + C320_LoadBuf + i); + len2 >>= 1; + j += i; + writew(len2, baseAddr + C320DLoad_len); + writew(0, baseAddr + C320_key); + for (i = 0; i < 10; i++) { + if (readw(baseAddr + C320_key) == C320_KeyCode) + break; + moxadelay(1); + } + if (readw(baseAddr + C320_key) != C320_KeyCode) + return (-1); + } + writew(0, baseAddr + C320DLoad_len); + writew(usum, baseAddr + C320check_sum); + writew(0, baseAddr + C320_key); + for (i = 0; i < 10; i++) { + if (readw(baseAddr + C320_key) == C320_KeyCode) + break; + moxadelay(1); + } + retry++; + } while ((readb(baseAddr + C320chksum_ok) != 1) && (retry < 3)); + if (readb(baseAddr + C320chksum_ok) != 1) + return (-1); + writew(0, baseAddr + C320_key); + for (i = 0; i < 600; i++) { + if (readw(baseAddr + Magic_no) == Magic_code) + break; + moxadelay(1); + } + if (readw(baseAddr + Magic_no) != Magic_code) + return (-100); + + if (moxa_boards[cardno].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; + moxadelay(1); + } + if (readw(baseAddr + Magic_no) != Magic_code) + return (-102); + + j = readw(baseAddr + Module_cnt); + if (j <= 0) + return (-101); + *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; + moxadelay(1); + } + if (readw(baseAddr + Magic_no) != Magic_code) + return (-102); + moxaCard = 1; + moxaIntNdx[cardno] = baseAddr + IRQindex; + moxaIntPend[cardno] = baseAddr + IRQpending; + moxaIntTable[cardno] = baseAddr + IRQtable; + return (0); +} + +long MoxaPortGetCurBaud(int port) +{ + + if (moxaChkPort[port] == 0) + return (0); + return (moxaCurBaud[port]); +} + +static void MoxaSetFifo(int port, int enable) +{ + unsigned long ofsAddr = moxaTableAddr[port]; + + if (!enable) { + moxafunc(ofsAddr, FC_SetRxFIFOTrig, 0); + moxafunc(ofsAddr, FC_SetTxFIFOCnt, 1); + } else { + moxafunc(ofsAddr, FC_SetRxFIFOTrig, 3); + moxafunc(ofsAddr, FC_SetTxFIFOCnt, 16); + } +} + +#if 0 +int MoxaPortSetMode(int port, int databits, int stopbits, int parity) +{ + unsigned long ofsAddr; + int val; + + val = 0; + switch (databits) { + case 5: + val |= 0; + break; + case 6: + val |= 1; + break; + case 7: + val |= 2; + break; + case 8: + val |= 3; + break; + default: + return (-1); + } + switch (stopbits) { + case 0: + val |= 0; + break; /* stop bits 1.5 */ + case 1: + val |= 0; + break; + case 2: + val |= 4; + break; + default: + return (-1); + } + switch (parity) { + case 0: + val |= 0x00; + break; /* None */ + case 1: + val |= 0x08; + break; /* Odd */ + case 2: + val |= 0x18; + break; /* Even */ + case 3: + val |= 0x28; + break; /* Mark */ + case 4: + val |= 0x38; + break; /* Space */ + default: + return (-1); + } + ofsAddr = moxaTableAddr[port]; + moxafunc(ofsAddr, FC_SetMode, val); + return (0); +} + +int MoxaPortTxBufSize(int port) +{ + unsigned long ofsAddr; + int size; + + ofsAddr = moxaTableAddr[port]; + size = readw(ofsAddr + TX_mask); + return (size); +} + +int MoxaPortRxBufSize(int port) +{ + unsigned long ofsAddr; + int size; + + ofsAddr = moxaTableAddr[port]; + size = readw(ofsAddr + RX_mask); + return (size); +} + +int MoxaPortRxFree(int port) +{ + unsigned long ofsAddr; + ushort rptr, wptr, mask; + int len; + + ofsAddr = moxaTableAddr[port]; + rptr = readw(ofsAddr + RXrptr); + wptr = readw(ofsAddr + RXwptr); + mask = readw(ofsAddr + RX_mask); + len = mask - ((wptr - rptr) & mask); + return (len); +} +int MoxaPortGetBrkCnt(int port) +{ + return (moxaBreakCnt[port]); +} + +void MoxaPortSetXonXoff(int port, int xonValue, int xoffValue) +{ + unsigned long ofsAddr; + + ofsAddr = moxaTableAddr[port]; + writew(xonValue, ofsAddr + FuncArg); + writew(xoffValue, ofsAddr + FuncArg1); + writew(FC_SetXonXoff, ofsAddr + FuncCode); + wait_finish(ofsAddr); +} + +int MoxaPortIsTxHold(int port) +{ + unsigned long ofsAddr; + int val; + + ofsAddr = moxaTableAddr[port]; + if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) || + (moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI)) { + moxafunc(ofsAddr, FC_GetCCSR, 0); + val = readw(ofsAddr + FuncArg); + if (val & 0x04) + return (1); + } else { + if (readw(ofsAddr + FlagStat) & Tx_flowOff) + return (1); + } + return (0); +} +#endif |