Commit 037ad48b authored by Jiri Slaby's avatar Jiri Slaby Committed by Linus Torvalds
Browse files

[PATCH] mxser: make an experimental clone



Clone a new driver for moxa smartio devices by copying mxser.c to mxser_new.c
and mxser.h to mxser_new.h.  No other changes are made.

This is for purposes of updating the driver to the latest vendor version.
Signed-off-by: default avatarJiri Slaby <jirislaby@gmail.com>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 1187ece3
......@@ -201,6 +201,21 @@ config MOXA_SMARTIO
The module will be called mxser. If you want to do that, say M
here.
config MOXA_SMARTIO_NEW
tristate "Moxa SmartIO support v. 2.0 (EXPERIMENTAL)"
depends on SERIAL_NONSTANDARD
help
Say Y here if you have a Moxa SmartIO multiport serial card and/or
want to help develop a new version of this driver.
This is upgraded (1.9.1) driver from original Moxa drivers with
changes finally resulting in PCI probing.
Use at your own risk.
This driver can also be built as a module. The module will be called
mxser_new. If you want to do that, say M here.
config ISI
tristate "Multi-Tech multiport card support (EXPERIMENTAL)"
depends on SERIAL_NONSTANDARD
......
......@@ -31,6 +31,7 @@ obj-$(CONFIG_MOXA_INTELLIO) += moxa.o
obj-$(CONFIG_A2232) += ser_a2232.o generic_serial.o
obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o
obj-$(CONFIG_MOXA_SMARTIO) += mxser.o
obj-$(CONFIG_MOXA_SMARTIO_NEW) += mxser_new.o
obj-$(CONFIG_COMPUTONE) += ip2/
obj-$(CONFIG_RISCOM8) += riscom8.o
obj-$(CONFIG_ISI) += isicom.o
......
/*
* mxser.c -- MOXA Smartio/Industio family multiport serial driver.
*
* Copyright (C) 1999-2001 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.
*
* Original release 10/26/00
*
* 02/06/01 Support MOXA Industio family boards.
* 02/06/01 Support TIOCGICOUNT.
* 02/06/01 Fix the problem for connecting to serial mouse.
* 02/06/01 Fix the problem for H/W flow control.
* 02/06/01 Fix the compling warning when CONFIG_PCI
* don't be defined.
*
* Fed through a cleanup, indent and remove of non 2.6 code by Alan Cox
* <alan@redhat.com>. The original 1.8 code is available on www.moxa.com.
* - Fixed x86_64 cleanness
* - Fixed sleep with spinlock held in mxser_send_break
*/
#include <linux/module.h>
#include <linux/autoconf.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/serial.h>
#include <linux/serial_reg.h>
#include <linux/major.h>
#include <linux/string.h>
#include <linux/fcntl.h>
#include <linux/ptrace.h>
#include <linux/gfp.h>
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/smp_lock.h>
#include <linux/delay.h>
#include <linux/pci.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/bitops.h>
#include <asm/uaccess.h>
#include "mxser.h"
#define MXSER_VERSION "1.8"
#define MXSERMAJOR 174
#define MXSERCUMAJOR 175
#define MXSER_EVENT_TXLOW 1
#define MXSER_EVENT_HANGUP 2
#define MXSER_BOARDS 4 /* Max. boards */
#define MXSER_PORTS 32 /* Max. ports */
#define MXSER_PORTS_PER_BOARD 8 /* Max. ports per board */
#define MXSER_ISR_PASS_LIMIT 256
#define MXSER_ERR_IOADDR -1
#define MXSER_ERR_IRQ -2
#define MXSER_ERR_IRQ_CONFLIT -3
#define MXSER_ERR_VECTOR -4
#define SERIAL_TYPE_NORMAL 1
#define SERIAL_TYPE_CALLOUT 2
#define WAKEUP_CHARS 256
#define UART_MCR_AFE 0x20
#define UART_LSR_SPECIAL 0x1E
#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK|\
IXON|IXOFF))
#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? IRQF_SHARED : IRQF_DISABLED)
#define C168_ASIC_ID 1
#define C104_ASIC_ID 2
#define C102_ASIC_ID 0xB
#define CI132_ASIC_ID 4
#define CI134_ASIC_ID 3
#define CI104J_ASIC_ID 5
enum {
MXSER_BOARD_C168_ISA = 1,
MXSER_BOARD_C104_ISA,
MXSER_BOARD_CI104J,
MXSER_BOARD_C168_PCI,
MXSER_BOARD_C104_PCI,
MXSER_BOARD_C102_ISA,
MXSER_BOARD_CI132,
MXSER_BOARD_CI134,
MXSER_BOARD_CP132,
MXSER_BOARD_CP114,
MXSER_BOARD_CT114,
MXSER_BOARD_CP102,
MXSER_BOARD_CP104U,
MXSER_BOARD_CP168U,
MXSER_BOARD_CP132U,
MXSER_BOARD_CP134U,
MXSER_BOARD_CP104JU,
MXSER_BOARD_RC7000,
MXSER_BOARD_CP118U,
MXSER_BOARD_CP102UL,
MXSER_BOARD_CP102U,
};
static char *mxser_brdname[] = {
"C168 series",
"C104 series",
"CI-104J series",
"C168H/PCI series",
"C104H/PCI series",
"C102 series",
"CI-132 series",
"CI-134 series",
"CP-132 series",
"CP-114 series",
"CT-114 series",
"CP-102 series",
"CP-104U series",
"CP-168U series",
"CP-132U series",
"CP-134U series",
"CP-104JU series",
"Moxa UC7000 Serial",
"CP-118U series",
"CP-102UL series",
"CP-102U series",
};
static int mxser_numports[] = {
8, /* C168-ISA */
4, /* C104-ISA */
4, /* CI104J */
8, /* C168-PCI */
4, /* C104-PCI */
2, /* C102-ISA */
2, /* CI132 */
4, /* CI134 */
2, /* CP132 */
4, /* CP114 */
4, /* CT114 */
2, /* CP102 */
4, /* CP104U */
8, /* CP168U */
2, /* CP132U */
4, /* CP134U */
4, /* CP104JU */
8, /* RC7000 */
8, /* CP118U */
2, /* CP102UL */
2, /* CP102U */
};
#define UART_TYPE_NUM 2
static const unsigned int Gmoxa_uart_id[UART_TYPE_NUM] = {
MOXA_MUST_MU150_HWID,
MOXA_MUST_MU860_HWID
};
/* This is only for PCI */
#define UART_INFO_NUM 3
struct mxpciuart_info {
int type;
int tx_fifo;
int rx_fifo;
int xmit_fifo_size;
int rx_high_water;
int rx_trigger;
int rx_low_water;
long max_baud;
};
static const struct mxpciuart_info Gpci_uart_info[UART_INFO_NUM] = {
{MOXA_OTHER_UART, 16, 16, 16, 14, 14, 1, 921600L},
{MOXA_MUST_MU150_HWID, 64, 64, 64, 48, 48, 16, 230400L},
{MOXA_MUST_MU860_HWID, 128, 128, 128, 96, 96, 32, 921600L}
};
#ifdef CONFIG_PCI
static struct pci_device_id mxser_pcibrds[] = {
{PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C168, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_C168_PCI},
{PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C104, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_C104_PCI},
{PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP132},
{PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP114, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP114},
{PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CT114, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CT114},
{PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP102},
{PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP104U, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP104U},
{PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP168U, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP168U},
{PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP132U, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP132U},
{PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP134U, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP134U},
{PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP104JU, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP104JU},
{PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_RC7000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_RC7000},
{PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP118U, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP118U},
{PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102UL, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP102UL},
{PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102U, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP102U},
{0}
};
MODULE_DEVICE_TABLE(pci, mxser_pcibrds);
#endif
typedef struct _moxa_pci_info {
unsigned short busNum;
unsigned short devNum;
struct pci_dev *pdev; /* add by Victor Yu. 06-23-2003 */
} moxa_pci_info;
static int ioaddr[MXSER_BOARDS] = { 0, 0, 0, 0 };
static int ttymajor = MXSERMAJOR;
static int calloutmajor = MXSERCUMAJOR;
static int verbose = 0;
/* Variables for insmod */
MODULE_AUTHOR("Casper Yang");
MODULE_DESCRIPTION("MOXA Smartio/Industio Family Multiport Board Device Driver");
module_param_array(ioaddr, int, NULL, 0);
module_param(ttymajor, int, 0);
module_param(calloutmajor, int, 0);
module_param(verbose, bool, 0);
MODULE_LICENSE("GPL");
struct mxser_log {
int tick;
unsigned long rxcnt[MXSER_PORTS];
unsigned long txcnt[MXSER_PORTS];
};
struct mxser_mon {
unsigned long rxcnt;
unsigned long txcnt;
unsigned long up_rxcnt;
unsigned long up_txcnt;
int modem_status;
unsigned char hold_reason;
};
struct mxser_mon_ext {
unsigned long rx_cnt[32];
unsigned long tx_cnt[32];
unsigned long up_rxcnt[32];
unsigned long up_txcnt[32];
int modem_status[32];
long baudrate[32];
int databits[32];
int stopbits[32];
int parity[32];
int flowctrl[32];
int fifo[32];
int iftype[32];
};
struct mxser_hwconf {
int board_type;
int ports;
int irq;
int vector;
int vector_mask;
int uart_type;
int ioaddr[MXSER_PORTS_PER_BOARD];
int baud_base[MXSER_PORTS_PER_BOARD];
moxa_pci_info pciInfo;
int IsMoxaMustChipFlag; /* add by Victor Yu. 08-30-2002 */
int MaxCanSetBaudRate[MXSER_PORTS_PER_BOARD]; /* add by Victor Yu. 09-04-2002 */
int opmode_ioaddr[MXSER_PORTS_PER_BOARD]; /* add by Victor Yu. 01-05-2004 */
};
struct mxser_struct {
int port;
int base; /* port base address */
int irq; /* port using irq no. */
int vector; /* port irq vector */
int vectormask; /* port vector mask */
int rx_high_water;
int rx_trigger; /* Rx fifo trigger level */
int rx_low_water;
int baud_base; /* max. speed */
int flags; /* defined in tty.h */
int type; /* UART type */
struct tty_struct *tty;
int read_status_mask;
int ignore_status_mask;
int xmit_fifo_size;
int custom_divisor;
int x_char; /* xon/xoff character */
int close_delay;
unsigned short closing_wait;
int IER; /* Interrupt Enable Register */
int MCR; /* Modem control register */
unsigned long event;
int count; /* # of fd on device */
int blocked_open; /* # of blocked opens */
long session; /* Session of opening process */
long pgrp; /* pgrp of opening process */
unsigned char *xmit_buf;
int xmit_head;
int xmit_tail;
int xmit_cnt;
struct work_struct tqueue;
struct termios normal_termios;
struct termios callout_termios;
wait_queue_head_t open_wait;
wait_queue_head_t close_wait;
wait_queue_head_t delta_msr_wait;
struct async_icount icount; /* kernel counters for the 4 input interrupts */
int timeout;
int IsMoxaMustChipFlag; /* add by Victor Yu. 08-30-2002 */
int MaxCanSetBaudRate; /* add by Victor Yu. 09-04-2002 */
int opmode_ioaddr; /* add by Victor Yu. 01-05-2004 */
unsigned char stop_rx;
unsigned char ldisc_stop_rx;
long realbaud;
struct mxser_mon mon_data;
unsigned char err_shadow;
spinlock_t slock;
};
struct mxser_mstatus {
tcflag_t cflag;
int cts;
int dsr;
int ri;
int dcd;
};
static struct mxser_mstatus GMStatus[MXSER_PORTS];
static int mxserBoardCAP[MXSER_BOARDS] = {
0, 0, 0, 0
/* 0x180, 0x280, 0x200, 0x320 */
};
static struct tty_driver *mxvar_sdriver;
static struct mxser_struct mxvar_table[MXSER_PORTS];
static struct tty_struct *mxvar_tty[MXSER_PORTS + 1];
static struct termios *mxvar_termios[MXSER_PORTS + 1];
static struct termios *mxvar_termios_locked[MXSER_PORTS + 1];
static struct mxser_log mxvar_log;
static int mxvar_diagflag;
static unsigned char mxser_msr[MXSER_PORTS + 1];
static struct mxser_mon_ext mon_data_ext;
static int mxser_set_baud_method[MXSER_PORTS + 1];
static spinlock_t gm_lock;
/*
* This is used to figure out the divisor speeds and the timeouts
*/
static struct mxser_hwconf mxsercfg[MXSER_BOARDS];
/*
* static functions:
*/
static void mxser_getcfg(int board, struct mxser_hwconf *hwconf);
static int mxser_init(void);
/* static void mxser_poll(unsigned long); */
static int mxser_get_ISA_conf(int, struct mxser_hwconf *);
static int mxser_get_PCI_conf(int, int, int, struct mxser_hwconf *);
static void mxser_do_softint(void *);
static int mxser_open(struct tty_struct *, struct file *);
static void mxser_close(struct tty_struct *, struct file *);
static int mxser_write(struct tty_struct *, const unsigned char *, int);
static int mxser_write_room(struct tty_struct *);
static void mxser_flush_buffer(struct tty_struct *);
static int mxser_chars_in_buffer(struct tty_struct *);
static void mxser_flush_chars(struct tty_struct *);
static void mxser_put_char(struct tty_struct *, unsigned char);
static int mxser_ioctl(struct tty_struct *, struct file *, uint, ulong);
static int mxser_ioctl_special(unsigned int, void __user *);
static void mxser_throttle(struct tty_struct *);
static void mxser_unthrottle(struct tty_struct *);
static void mxser_set_termios(struct tty_struct *, struct termios *);
static void mxser_stop(struct tty_struct *);
static void mxser_start(struct tty_struct *);
static void mxser_hangup(struct tty_struct *);
static void mxser_rs_break(struct tty_struct *, int);
static irqreturn_t mxser_interrupt(int, void *, struct pt_regs *);
static void mxser_receive_chars(struct mxser_struct *, int *);
static void mxser_transmit_chars(struct mxser_struct *);
static void mxser_check_modem_status(struct mxser_struct *, int);
static int mxser_block_til_ready(struct tty_struct *, struct file *, struct mxser_struct *);
static int mxser_startup(struct mxser_struct *);
static void mxser_shutdown(struct mxser_struct *);
static int mxser_change_speed(struct mxser_struct *, struct termios *old_termios);
static int mxser_get_serial_info(struct mxser_struct *, struct serial_struct __user *);
static int mxser_set_serial_info(struct mxser_struct *, struct serial_struct __user *);
static int mxser_get_lsr_info(struct mxser_struct *, unsigned int __user *);
static void mxser_send_break(struct mxser_struct *, int);
static int mxser_tiocmget(struct tty_struct *, struct file *);
static int mxser_tiocmset(struct tty_struct *, struct file *, unsigned int, unsigned int);
static int mxser_set_baud(struct mxser_struct *info, long newspd);
static void mxser_wait_until_sent(struct tty_struct *tty, int timeout);
static void mxser_startrx(struct tty_struct *tty);
static void mxser_stoprx(struct tty_struct *tty);
static int CheckIsMoxaMust(int io)
{
u8 oldmcr, hwid;
int i;
outb(0, io + UART_LCR);
DISABLE_MOXA_MUST_ENCHANCE_MODE(io);
oldmcr = inb(io + UART_MCR);
outb(0, io + UART_MCR);
SET_MOXA_MUST_XON1_VALUE(io, 0x11);
if ((hwid = inb(io + UART_MCR)) != 0) {
outb(oldmcr, io + UART_MCR);
return MOXA_OTHER_UART;
}
GET_MOXA_MUST_HARDWARE_ID(io, &hwid);
for (i = 0; i < UART_TYPE_NUM; i++) {
if (hwid == Gmoxa_uart_id[i])
return (int)hwid;
}
return MOXA_OTHER_UART;
}
/* above is modified by Victor Yu. 08-15-2002 */
static const struct tty_operations mxser_ops = {
.open = mxser_open,
.close = mxser_close,
.write = mxser_write,
.put_char = mxser_put_char,
.flush_chars = mxser_flush_chars,
.write_room = mxser_write_room,
.chars_in_buffer = mxser_chars_in_buffer,
.flush_buffer = mxser_flush_buffer,
.ioctl = mxser_ioctl,
.throttle = mxser_throttle,
.unthrottle = mxser_unthrottle,
.set_termios = mxser_set_termios,
.stop = mxser_stop,
.start = mxser_start,
.hangup = mxser_hangup,
.break_ctl = mxser_rs_break,
.wait_until_sent = mxser_wait_until_sent,
.tiocmget = mxser_tiocmget,
.tiocmset = mxser_tiocmset,
};
/*
* The MOXA Smartio/Industio serial driver boot-time initialization code!
*/
static int __init mxser_module_init(void)
{
int ret;
if (verbose)
printk(KERN_DEBUG "Loading module mxser ...\n");
ret = mxser_init();
if (verbose)
printk(KERN_DEBUG "Done.\n");
return ret;
}
static void __exit mxser_module_exit(void)
{
int i, err;
if (verbose)
printk(KERN_DEBUG "Unloading module mxser ...\n");
err = tty_unregister_driver(mxvar_sdriver);
if (!err)
put_tty_driver(mxvar_sdriver);
else
printk(KERN_ERR "Couldn't unregister MOXA Smartio/Industio family serial driver\n");
for (i = 0; i < MXSER_BOARDS; i++) {
struct pci_dev *pdev;
if (mxsercfg[i].board_type == -1)
continue;
else {
pdev = mxsercfg[i].pciInfo.pdev;
free_irq(mxsercfg[i].irq, &mxvar_table[i * MXSER_PORTS_PER_BOARD]);
if (pdev != NULL) { /* PCI */
release_region(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2));
release_region(pci_resource_start(pdev, 3), pci_resource_len(pdev, 3));
pci_dev_put(pdev);
} else {
release_region(mxsercfg[i].ioaddr[0], 8 * mxsercfg[i].ports);
release_region(mxsercfg[i].vector, 1);
}
}
}
if (verbose)
printk(KERN_DEBUG "Done.\n");
}
static void process_txrx_fifo(struct mxser_struct *info)
{
int i;
if ((info->type == PORT_16450) || (info->type == PORT_8250)) {
info->rx_trigger = 1;
info->rx_high_water = 1;
info->rx_low_water = 1;
info->xmit_fifo_size = 1;
} else {
for (i = 0; i < UART_INFO_NUM; i++) {
if (info->IsMoxaMustChipFlag == Gpci_uart_info[i].type) {
info->rx_trigger = Gpci_uart_info[i].rx_trigger;
info->rx_low_water = Gpci_uart_info[i].rx_low_water;
info->rx_high_water = Gpci_uart_info[i].rx_high_water;
info->xmit_fifo_size = Gpci_uart_info[i].xmit_fifo_size;
break;
}
}
}
}
static int mxser_initbrd(int board, struct mxser_hwconf *hwconf)
{
struct mxser_struct *info;
int retval;
int i, n;
n = board * MXSER_PORTS_PER_BOARD;
info = &mxvar_table[n];
/*if (verbose) */ {
printk(KERN_DEBUG " ttyM%d - ttyM%d ",
n, n + hwconf->ports - 1);
printk(" max. baud rate = %d bps.\n",
hwconf->MaxCanSetBaudRate[0]);
}
for (i = 0; i < hwconf->ports; i++, n++, info++) {
info->port = n;
info->base = hwconf->ioaddr[i];
info->irq = hwconf->irq;
info->vector = hwconf->vector;
info->vectormask = hwconf->vector_mask;
info->opmode_ioaddr = hwconf->opmode_ioaddr[i]; /* add by Victor Yu. 01-05-2004 */
info->stop_rx = 0;
info->ldisc_stop_rx = 0;
info->IsMoxaMustChipFlag = hwconf->IsMoxaMustChipFlag;
/* Enhance mode enabled here */
if (info->IsMoxaMustChipFlag != MOXA_OTHER_UART) {
ENABLE_MOXA_MUST_ENCHANCE_MODE(info->base);
}
info->flags = ASYNC_SHARE_IRQ;
info->type = hwconf->uart_type;
info->baud_base = hwconf->baud_base[i];
info->MaxCanSetBaudRate = hwconf->MaxCanSetBaudRate[i];
process_txrx_fifo(info);