/*
* moxa.c -- MOXA Intellio family multiport serial driver.
*
- * Copyright (C) 1999-2000 Moxa Technologies (support@moxa.com.tw).
+ * Copyright (C) 1999-2000 Moxa Technologies (support@moxa.com).
+ * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com>
*
* This code is loosely based on the Linux serial driver, written by
* Linus Torvalds, Theodore T'so and others.
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/bitops.h>
-#include <linux/completion.h>
#include <asm/system.h>
#include <asm/io.h>
#include "moxa.h"
-#define MOXA_VERSION "5.1k"
+#define MOXA_VERSION "6.0k"
#define MOXA_FW_HDRLEN 32
#define MOXAMAJOR 172
-#define MOXACUMAJOR 173
#define MAX_BOARDS 4 /* Don't change this value */
#define MAX_PORTS_PER_BOARD 32 /* Don't change this value */
#define MAX_PORTS (MAX_BOARDS * MAX_PORTS_PER_BOARD)
+#define MOXA_IS_320(brd) ((brd)->boardType == MOXA_BOARD_C320_ISA || \
+ (brd)->boardType == MOXA_BOARD_C320_PCI)
+
/*
* Define the Moxa PCI vendor and device IDs.
*/
};
struct moxa_port {
+ struct tty_port port;
struct moxa_board_conf *board;
- struct tty_struct *tty;
void __iomem *tableAddr;
int type;
- int close_delay;
- int count;
- int blocked_open;
- int asyncflags;
int cflag;
unsigned long statusflags;
- wait_queue_head_t open_wait;
- struct completion close_wait;
u8 DCDState;
u8 lineCtrl;
static struct mon_str moxaLog;
static unsigned int moxaFuncTout = HZ / 2;
static unsigned int moxaLowWaterChk;
+static DEFINE_MUTEX(moxa_openlock);
/* Variables for insmod */
#ifdef MODULE
static unsigned long baseaddr[MAX_BOARDS];
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 void moxa_throttle(struct tty_struct *);
static void moxa_unthrottle(struct tty_struct *);
static void moxa_set_termios(struct tty_struct *, struct ktermios *);
unsigned int set, unsigned int clear);
static void moxa_poll(unsigned long);
static void moxa_set_tty_param(struct tty_struct *, struct ktermios *);
-static int moxa_block_till_ready(struct tty_struct *, struct file *,
- struct moxa_port *);
static void moxa_setup_empty_event(struct tty_struct *);
static void moxa_shut_down(struct moxa_port *);
/*
printk(KERN_WARNING "moxa function expired\n");
}
-static void moxafunc(void __iomem *ofsAddr, int cmd, ushort arg)
+static void moxafunc(void __iomem *ofsAddr, u16 cmd, u16 arg)
{
writew(arg, ofsAddr + FuncArg);
writew(cmd, ofsAddr + FuncCode);
{
struct moxa_port *ch = tty->driver_data;
void __user *argp = (void __user *)arg;
- int status;
+ int status, ret = 0;
if (tty->index == MAX_PORTS) {
if (cmd != MOXA_GETDATACOUNT && cmd != MOXA_GET_IOQUEUE &&
switch (cmd) {
case MOXA_GETDATACOUNT:
moxaLog.tick = jiffies;
- return copy_to_user(argp, &moxaLog, sizeof(moxaLog)) ?
- -EFAULT : 0;
+ if (copy_to_user(argp, &moxaLog, sizeof(moxaLog)))
+ ret = -EFAULT;
+ break;
case MOXA_FLUSH_QUEUE:
MoxaPortFlushData(ch, arg);
- return 0;
+ break;
case MOXA_GET_IOQUEUE: {
struct moxaq_str __user *argm = argp;
struct moxaq_str tmp;
struct moxa_port *p;
unsigned int i, j;
+ mutex_lock(&moxa_openlock);
for (i = 0; i < MAX_BOARDS; i++) {
p = moxa_boards[i].ports;
for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
tmp.inq = MoxaPortRxQueue(p);
tmp.outq = MoxaPortTxQueue(p);
}
- if (copy_to_user(argm, &tmp, sizeof(tmp)))
+ if (copy_to_user(argm, &tmp, sizeof(tmp))) {
+ mutex_unlock(&moxa_openlock);
return -EFAULT;
+ }
}
}
- return 0;
+ mutex_unlock(&moxa_openlock);
+ break;
} case MOXA_GET_OQUEUE:
status = MoxaPortTxQueue(ch);
- return put_user(status, (unsigned long __user *)argp);
+ ret = put_user(status, (unsigned long __user *)argp);
+ break;
case MOXA_GET_IQUEUE:
status = MoxaPortRxQueue(ch);
- return put_user(status, (unsigned long __user *)argp);
+ ret = put_user(status, (unsigned long __user *)argp);
+ break;
case MOXA_GETMSTATUS: {
struct mxser_mstatus __user *argm = argp;
struct mxser_mstatus tmp;
struct moxa_port *p;
unsigned int i, j;
+ mutex_lock(&moxa_openlock);
for (i = 0; i < MAX_BOARDS; i++) {
p = moxa_boards[i].ports;
for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
if (status & 4)
tmp.dcd = 1;
- if (!p->tty || !p->tty->termios)
+ if (!p->port.tty || !p->port.tty->termios)
tmp.cflag = p->cflag;
else
- tmp.cflag = p->tty->termios->c_cflag;
+ tmp.cflag = p->port.tty->termios->c_cflag;
copy:
- if (copy_to_user(argm, &tmp, sizeof(tmp)))
+ if (copy_to_user(argm, &tmp, sizeof(tmp))) {
+ mutex_unlock(&moxa_openlock);
return -EFAULT;
+ }
}
}
- return 0;
+ mutex_unlock(&moxa_openlock);
+ break;
}
case TIOCGSERIAL:
- return moxa_get_serial_info(ch, argp);
+ mutex_lock(&moxa_openlock);
+ ret = moxa_get_serial_info(ch, argp);
+ mutex_unlock(&moxa_openlock);
+ break;
case TIOCSSERIAL:
- return moxa_set_serial_info(ch, argp);
+ mutex_lock(&moxa_openlock);
+ ret = moxa_set_serial_info(ch, argp);
+ mutex_unlock(&moxa_openlock);
+ break;
+ default:
+ ret = -ENOIOCTLCMD;
}
- return -ENOIOCTLCMD;
+ return ret;
}
-static void moxa_break_ctl(struct tty_struct *tty, int state)
+static int moxa_break_ctl(struct tty_struct *tty, int state)
{
struct moxa_port *port = tty->driver_data;
moxafunc(port->tableAddr, state ? FC_SendBreak : FC_StopBreak,
Magic_code);
+ return 0;
}
static const struct tty_operations moxa_ops = {
.write_room = moxa_write_room,
.flush_buffer = moxa_flush_buffer,
.chars_in_buffer = moxa_chars_in_buffer,
- .flush_chars = moxa_flush_chars,
- .put_char = moxa_put_char,
.ioctl = moxa_ioctl,
.throttle = moxa_throttle,
.unthrottle = moxa_unthrottle,
goto err;
tmp = readw(baseAddr + C320_status);
if (tmp != STS_init) {
- printk(KERN_ERR "moxa: bios upload failed -- CPU/Basic "
+ printk(KERN_ERR "MOXA: bios upload failed -- CPU/Basic "
"module not found\n");
return -EIO;
}
return 0;
err:
- printk(KERN_ERR "moxa: bios upload failed -- board not found\n");
+ printk(KERN_ERR "MOXA: bios upload failed -- board not found\n");
return -EIO;
}
void __iomem *baseAddr = brd->basemem;
if (len < 7168) {
- printk(KERN_ERR "moxa: invalid 320 bios -- too short\n");
+ printk(KERN_ERR "MOXA: invalid 320 bios -- too short\n");
return -EINVAL;
}
const u16 *uptr = ptr;
size_t wlen, len2, j;
unsigned long key, loadbuf, loadlen, checksum, checksum_ok;
- unsigned int i, retry, c320;
+ unsigned int i, retry;
u16 usum, keycode;
- c320 = brd->boardType == MOXA_BOARD_C320_PCI ||
- brd->boardType == MOXA_BOARD_C320_ISA;
keycode = (brd->boardType == MOXA_BOARD_CP204J) ? CP204J_KeyCode :
C218_KeyCode;
if (readw(baseAddr + Magic_no) != Magic_code)
return -EIO;
- if (c320) {
+ if (MOXA_IS_320(brd)) {
if (brd->busType == MOXA_BUS_TYPE_PCI) { /* ASIC board */
writew(0x3800, baseAddr + TMS320_PORT1);
writew(0x3900, baseAddr + TMS320_PORT2);
if (readw(baseAddr + Magic_no) != Magic_code)
return -EIO;
- if (c320) {
+ if (MOXA_IS_320(brd)) {
j = readw(baseAddr + Module_cnt);
if (j <= 0)
return -EIO;
int retval, i;
if (len % 2) {
- printk(KERN_ERR "moxa: bios length is not even\n");
+ printk(KERN_ERR "MOXA: bios length is not even\n");
return -EINVAL;
}
static int moxa_load_fw(struct moxa_board_conf *brd, const struct firmware *fw)
{
- void *ptr = fw->data;
+ const void *ptr = fw->data;
char rsn[64];
u16 lens[5];
size_t len;
u8 model; /* C218T=1, C320T=2, CP204=3 */
u8 reserved2[8];
__le16 len[5];
- } *hdr = ptr;
+ } const *hdr = ptr;
BUILD_BUG_ON(ARRAY_SIZE(hdr->len) != ARRAY_SIZE(lens));
lens[a] = le16_to_cpu(hdr->len[a]);
if (lens[a] && len + lens[a] <= fw->size &&
moxa_check_fw(&fw->data[len]))
- printk(KERN_WARNING "moxa firmware: unexpected input "
+ printk(KERN_WARNING "MOXA firmware: unexpected input "
"at offset %u, but going on\n", (u32)len);
if (!lens[a] && a < lencnt) {
sprintf(rsn, "too few entries in fw file");
}
for (i = 0, p = brd->ports; i < MAX_PORTS_PER_BOARD; i++, p++) {
+ tty_port_init(&p->port);
p->type = PORT_16550A;
- p->close_delay = 5 * HZ / 10;
p->cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
- init_waitqueue_head(&p->open_wait);
- init_completion(&p->close_wait);
}
switch (brd->boardType) {
ret = request_firmware(&fw, file, dev);
if (ret) {
- printk(KERN_ERR "request_firmware failed\n");
+ printk(KERN_ERR "MOXA: request_firmware failed. Make sure "
+ "you've placed '%s' file into your firmware "
+ "loader directory (e.g. /lib/firmware)\n",
+ file);
goto err_free;
}
if (ret)
goto err_free;
+ spin_lock_bh(&moxa_lock);
brd->ready = 1;
-
if (!timer_pending(&moxaTimer))
mod_timer(&moxaTimer, jiffies + HZ / 50);
+ spin_unlock_bh(&moxa_lock);
return 0;
err_free:
static void moxa_board_deinit(struct moxa_board_conf *brd)
{
+ unsigned int a, opened;
+
+ mutex_lock(&moxa_openlock);
spin_lock_bh(&moxa_lock);
brd->ready = 0;
spin_unlock_bh(&moxa_lock);
+
+ /* pci hot-un-plug support */
+ for (a = 0; a < brd->numPorts; a++)
+ if (brd->ports[a].port.flags & ASYNC_INITIALIZED)
+ tty_hangup(brd->ports[a].port.tty);
+ while (1) {
+ opened = 0;
+ for (a = 0; a < brd->numPorts; a++)
+ if (brd->ports[a].port.flags & ASYNC_INITIALIZED)
+ opened++;
+ mutex_unlock(&moxa_openlock);
+ if (!opened)
+ break;
+ msleep(50);
+ mutex_lock(&moxa_openlock);
+ }
+
iounmap(brd->basemem);
brd->basemem = NULL;
kfree(brd->ports);
goto err;
}
- board->basemem = ioremap(pci_resource_start(pdev, 2), 0x4000);
+ board->basemem = ioremap_nocache(pci_resource_start(pdev, 2), 0x4000);
if (board->basemem == NULL) {
dev_err(&pdev->dev, "can't remap io space 2\n");
goto err_reg;
pci_set_drvdata(pdev, board);
- return (0);
+ dev_info(&pdev->dev, "board '%s' ready (%u ports, firmware loaded)\n",
+ moxa_brdname[board_type - 1], board->numPorts);
+
+ return 0;
err_base:
iounmap(board->basemem);
board->basemem = NULL;
moxaDriver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(moxaDriver, &moxa_ops);
- pr_debug("Moxa tty devices major number = %d\n", ttymajor);
-
if (tty_register_driver(moxaDriver)) {
- printk(KERN_ERR "Couldn't install MOXA Smartio family driver !\n");
+ printk(KERN_ERR "can't register MOXA Smartio tty driver!\n");
put_tty_driver(moxaDriver);
return -1;
}
brd->numPorts = type[i] == MOXA_BOARD_C218_ISA ? 8 :
numports[i];
brd->busType = MOXA_BUS_TYPE_ISA;
- brd->basemem = ioremap(baseaddr[i], 0x4000);
+ brd->basemem = ioremap_nocache(baseaddr[i], 0x4000);
if (!brd->basemem) {
- printk(KERN_ERR "moxa: can't remap %lx\n",
+ printk(KERN_ERR "MOXA: can't remap %lx\n",
baseaddr[i]);
continue;
}
continue;
}
+ printk(KERN_INFO "MOXA isa board found at 0x%.8lu and "
+ "ready (%u ports, firmware loaded)\n",
+ baseaddr[i], brd->numPorts);
+
brd++;
isabrds++;
}
#ifdef CONFIG_PCI
retval = pci_register_driver(&moxa_pci_driver);
if (retval) {
- printk(KERN_ERR "Can't register moxa pci driver!\n");
+ printk(KERN_ERR "Can't register MOXA pci driver!\n");
if (isabrds)
retval = 0;
}
static void __exit moxa_exit(void)
{
- int i;
-
- del_timer_sync(&moxaTimer);
-
- if (tty_unregister_driver(moxaDriver))
- printk(KERN_ERR "Couldn't unregister MOXA Intellio family "
- "serial driver\n");
- put_tty_driver(moxaDriver);
+ unsigned int i;
#ifdef CONFIG_PCI
pci_unregister_driver(&moxa_pci_driver);
for (i = 0; i < MAX_BOARDS; i++) /* ISA boards */
if (moxa_boards[i].ready)
moxa_board_deinit(&moxa_boards[i]);
+
+ del_timer_sync(&moxaTimer);
+
+ if (tty_unregister_driver(moxaDriver))
+ printk(KERN_ERR "Couldn't unregister MOXA Intellio family "
+ "serial driver\n");
+ put_tty_driver(moxaDriver);
}
module_init(moxa_init);
module_exit(moxa_exit);
+static void moxa_close_port(struct moxa_port *ch)
+{
+ moxa_shut_down(ch);
+ MoxaPortFlushData(ch, 2);
+ ch->port.flags &= ~ASYNC_NORMAL_ACTIVE;
+ ch->port.tty->driver_data = NULL;
+ ch->port.tty = NULL;
+}
+
+static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp,
+ struct moxa_port *ch)
+{
+ DEFINE_WAIT(wait);
+ int retval = 0;
+ u8 dcd;
+
+ while (1) {
+ prepare_to_wait(&ch->port.open_wait, &wait, TASK_INTERRUPTIBLE);
+ if (tty_hung_up_p(filp)) {
+#ifdef SERIAL_DO_RESTART
+ retval = -ERESTARTSYS;
+#else
+ retval = -EAGAIN;
+#endif
+ break;
+ }
+ spin_lock_bh(&moxa_lock);
+ dcd = ch->DCDState;
+ spin_unlock_bh(&moxa_lock);
+ if (dcd)
+ break;
+
+ if (signal_pending(current)) {
+ retval = -ERESTARTSYS;
+ break;
+ }
+ schedule();
+ }
+ finish_wait(&ch->port.open_wait, &wait);
+
+ return retval;
+}
+
static int moxa_open(struct tty_struct *tty, struct file *filp)
{
struct moxa_board_conf *brd;
if (port == MAX_PORTS) {
return capable(CAP_SYS_ADMIN) ? 0 : -EPERM;
}
+ if (mutex_lock_interruptible(&moxa_openlock))
+ return -ERESTARTSYS;
brd = &moxa_boards[port / MAX_PORTS_PER_BOARD];
- if (!brd->ready)
+ if (!brd->ready) {
+ mutex_unlock(&moxa_openlock);
return -ENODEV;
+ }
ch = &brd->ports[port % MAX_PORTS_PER_BOARD];
- ch->count++;
+ ch->port.count++;
tty->driver_data = ch;
- ch->tty = tty;
- if (!(ch->asyncflags & ASYNC_INITIALIZED)) {
+ ch->port.tty = tty;
+ if (!(ch->port.flags & ASYNC_INITIALIZED)) {
ch->statusflags = 0;
moxa_set_tty_param(tty, tty->termios);
MoxaPortLineCtrl(ch, 1, 1);
MoxaPortEnable(ch);
- ch->asyncflags |= ASYNC_INITIALIZED;
+ MoxaSetFifo(ch, ch->type == PORT_16550A);
+ ch->port.flags |= ASYNC_INITIALIZED;
}
- retval = moxa_block_till_ready(tty, filp, ch);
-
- moxa_unthrottle(tty);
+ mutex_unlock(&moxa_openlock);
- if (ch->type == PORT_16550A) {
- MoxaSetFifo(ch, 1);
- } else {
- MoxaSetFifo(ch, 0);
- }
+ retval = 0;
+ if (!(filp->f_flags & O_NONBLOCK) && !C_CLOCAL(tty))
+ retval = moxa_block_till_ready(tty, filp, ch);
+ mutex_lock(&moxa_openlock);
+ if (retval) {
+ if (ch->port.count) /* 0 means already hung up... */
+ if (--ch->port.count == 0)
+ moxa_close_port(ch);
+ } else
+ ch->port.flags |= ASYNC_NORMAL_ACTIVE;
+ mutex_unlock(&moxa_openlock);
- return (retval);
+ return retval;
}
static void moxa_close(struct tty_struct *tty, struct file *filp)
int port;
port = tty->index;
- if (port == MAX_PORTS) {
+ if (port == MAX_PORTS || tty_hung_up_p(filp))
return;
- }
- if (tty->driver_data == NULL) {
- return;
- }
- if (tty_hung_up_p(filp)) {
- return;
- }
- ch = (struct moxa_port *) tty->driver_data;
- if ((tty->count == 1) && (ch->count != 1)) {
+ mutex_lock(&moxa_openlock);
+ ch = tty->driver_data;
+ if (ch == NULL)
+ goto unlock;
+ if (tty->count == 1 && ch->port.count != 1) {
printk(KERN_WARNING "moxa_close: bad serial port count; "
- "tty->count is 1, ch->count is %d\n", ch->count);
- ch->count = 1;
+ "tty->count is 1, ch->port.count is %d\n", ch->port.count);
+ ch->port.count = 1;
}
- if (--ch->count < 0) {
+ if (--ch->port.count < 0) {
printk(KERN_WARNING "moxa_close: bad serial port count, "
"device=%s\n", tty->name);
- ch->count = 0;
+ ch->port.count = 0;
}
- if (ch->count) {
- return;
- }
- ch->asyncflags |= ASYNC_CLOSING;
+ if (ch->port.count)
+ goto unlock;
ch->cflag = tty->termios->c_cflag;
- if (ch->asyncflags & ASYNC_INITIALIZED) {
+ if (ch->port.flags & ASYNC_INITIALIZED) {
moxa_setup_empty_event(tty);
tty_wait_until_sent(tty, 30 * HZ); /* 30 seconds timeout */
}
- moxa_shut_down(ch);
- MoxaPortFlushData(ch, 2);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
- tty_ldisc_flush(tty);
-
- tty->closing = 0;
- ch->tty = NULL;
- if (ch->blocked_open) {
- if (ch->close_delay) {
- msleep_interruptible(jiffies_to_msecs(ch->close_delay));
- }
- wake_up_interruptible(&ch->open_wait);
- }
- ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
- complete_all(&ch->close_wait);
+ moxa_close_port(ch);
+unlock:
+ mutex_unlock(&moxa_openlock);
}
static int moxa_write(struct tty_struct *tty,
len = MoxaPortWriteData(ch, buf, count);
spin_unlock_bh(&moxa_lock);
- /*********************************************
- if ( !(ch->statusflags & LOWWAIT) &&
- ((len != count) || (MoxaPortTxFree(port) <= 100)) )
- ************************************************/
ch->statusflags |= LOWWAIT;
- return (len);
+ return len;
}
static int moxa_write_room(struct tty_struct *tty)
struct moxa_port *ch;
if (tty->stopped)
- return (0);
+ return 0;
ch = tty->driver_data;
if (ch == NULL)
- return (0);
+ return 0;
return MoxaPortTxFree(ch);
}
* routine. And since the open() failed, we return 0 here. TDJ
*/
if (ch == NULL)
- return (0);
+ return 0;
+ lock_kernel();
chars = MoxaPortTxQueue(ch);
if (chars) {
/*
if (!(ch->statusflags & EMPTYWAIT))
moxa_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_port *ch = tty->driver_data;
-
- if (ch == NULL)
- return;
- spin_lock_bh(&moxa_lock);
- MoxaPortWriteData(ch, &c, 1);
- spin_unlock_bh(&moxa_lock);
- /************************************************
- if ( !(ch->statusflags & LOWWAIT) && (MoxaPortTxFree(port) <= 100) )
- *************************************************/
- ch->statusflags |= LOWWAIT;
+ unlock_kernel();
+ return chars;
}
static int moxa_tiocmget(struct tty_struct *tty, struct file *file)
{
- struct moxa_port *ch = tty->driver_data;
+ struct moxa_port *ch;
int flag = 0, dtr, rts;
- if (!ch)
+ mutex_lock(&moxa_openlock);
+ ch = tty->driver_data;
+ if (!ch) {
+ mutex_unlock(&moxa_openlock);
return -EINVAL;
+ }
MoxaPortGetLineOut(ch, &dtr, &rts);
if (dtr)
flag |= TIOCM_DSR;
if (dtr & 4)
flag |= TIOCM_CD;
+ mutex_unlock(&moxa_openlock);
return flag;
}
static int moxa_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear)
{
- struct moxa_port *ch = tty->driver_data;
+ struct moxa_port *ch;
int port;
int dtr, rts;
port = tty->index;
- if (!ch)
+ mutex_lock(&moxa_openlock);
+ ch = tty->driver_data;
+ if (!ch) {
+ mutex_unlock(&moxa_openlock);
return -EINVAL;
+ }
MoxaPortGetLineOut(ch, &dtr, &rts);
if (set & TIOCM_RTS)
if (clear & TIOCM_DTR)
dtr = 0;
MoxaPortLineCtrl(ch, dtr, rts);
+ mutex_unlock(&moxa_openlock);
return 0;
}
static void moxa_throttle(struct tty_struct *tty)
{
- struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
+ struct moxa_port *ch = tty->driver_data;
ch->statusflags |= THROTTLE;
}
static void moxa_unthrottle(struct tty_struct *tty)
{
- struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
+ struct moxa_port *ch = tty->driver_data;
ch->statusflags &= ~THROTTLE;
}
static void moxa_set_termios(struct tty_struct *tty,
- struct ktermios *old_termios)
+ struct ktermios *old_termios)
{
- struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
+ struct moxa_port *ch = tty->driver_data;
if (ch == NULL)
return;
moxa_set_tty_param(tty, old_termios);
- if (!(old_termios->c_cflag & CLOCAL) &&
- (tty->termios->c_cflag & CLOCAL))
- wake_up_interruptible(&ch->open_wait);
+ if (!(old_termios->c_cflag & CLOCAL) && C_CLOCAL(tty))
+ wake_up_interruptible(&ch->port.open_wait);
}
static void moxa_stop(struct tty_struct *tty)
{
- struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
+ struct moxa_port *ch = tty->driver_data;
if (ch == NULL)
return;
static void moxa_start(struct tty_struct *tty)
{
- struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
+ struct moxa_port *ch = tty->driver_data;
if (ch == NULL)
return;
static void moxa_hangup(struct tty_struct *tty)
{
- struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
+ struct moxa_port *ch;
- moxa_flush_buffer(tty);
- moxa_shut_down(ch);
- ch->count = 0;
- ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
- ch->tty = NULL;
- wake_up_interruptible(&ch->open_wait);
+ mutex_lock(&moxa_openlock);
+ ch = tty->driver_data;
+ if (ch == NULL) {
+ mutex_unlock(&moxa_openlock);
+ return;
+ }
+ ch->port.count = 0;
+ moxa_close_port(ch);
+ mutex_unlock(&moxa_openlock);
+
+ wake_up_interruptible(&ch->port.open_wait);
}
static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd)
{
dcd = !!dcd;
- if ((dcd != p->DCDState) && p->tty && C_CLOCAL(p->tty)) {
- if (!dcd) {
- tty_hangup(p->tty);
- p->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
- }
- wake_up_interruptible(&p->open_wait);
+ if (dcd != p->DCDState && p->port.tty && C_CLOCAL(p->port.tty)) {
+ if (!dcd)
+ tty_hangup(p->port.tty);
}
p->DCDState = dcd;
}
static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
u16 __iomem *ip)
{
- struct tty_struct *tty = p->tty;
+ struct tty_struct *tty = p->port.tty;
void __iomem *ofsAddr;
- unsigned int inited = p->asyncflags & ASYNC_INITIALIZED;
+ unsigned int inited = p->port.flags & ASYNC_INITIALIZED;
u16 intr;
if (tty) {
{
struct moxa_board_conf *brd;
u16 __iomem *ip;
- unsigned int card, port;
+ unsigned int card, port, served = 0;
spin_lock(&moxa_lock);
for (card = 0; card < MAX_BOARDS; card++) {
if (!brd->ready)
continue;
+ served++;
+
ip = NULL;
if (readb(brd->intPend) == 0xff)
ip = brd->intTable + readb(brd->intNdx);
}
}
moxaLowWaterChk = 0;
- spin_unlock(&moxa_lock);
- mod_timer(&moxaTimer, jiffies + HZ / 50);
+ if (served)
+ mod_timer(&moxaTimer, jiffies + HZ / 50);
+ spin_unlock(&moxa_lock);
}
/******************************************************************************/
static void moxa_set_tty_param(struct tty_struct *tty, struct ktermios *old_termios)
{
- register struct ktermios *ts;
- struct moxa_port *ch;
+ register struct ktermios *ts = tty->termios;
+ struct moxa_port *ch = tty->driver_data;
int rts, cts, txflow, rxflow, xany, baud;
- ch = (struct moxa_port *) tty->driver_data;
- ts = tty->termios;
rts = cts = txflow = rxflow = xany = 0;
if (ts->c_cflag & CRTSCTS)
rts = cts = 1;
tty_encode_baud_rate(tty, baud, baud);
}
-static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp,
- struct moxa_port *ch)
-{
- DECLARE_WAITQUEUE(wait,current);
- 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)
- wait_for_completion_interruptible(&ch->close_wait);
-#ifdef SERIAL_DO_RESTART
- if (ch->asyncflags & ASYNC_HUP_NOTIFY)
- return (-EAGAIN);
- else
- return (-ERESTARTSYS);
-#else
- return (-EAGAIN);
-#endif
- }
- /*
- * If non-blocking mode is set, then make the check up front
- * and then exit.
- */
- if (filp->f_flags & O_NONBLOCK) {
- 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);
- pr_debug("block_til_ready before block: ttys%d, count = %d\n",
- tty->index, ch->count);
- spin_lock_bh(&moxa_lock);
- if (!tty_hung_up_p(filp))
- ch->count--;
- ch->blocked_open++;
- spin_unlock_bh(&moxa_lock);
-
- while (1) {
- set_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_CLOSING) && (do_clocal ||
- ch->DCDState))
- break;
-
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
- schedule();
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&ch->open_wait, &wait);
-
- spin_lock_bh(&moxa_lock);
- if (!tty_hung_up_p(filp))
- ch->count++;
- ch->blocked_open--;
- spin_unlock_bh(&moxa_lock);
- pr_debug("block_til_ready after blocking: ttys%d, count = %d\n",
- tty->index, ch->count);
- if (retval)
- return (retval);
- /* FIXME: review to see if we need to use set_bit on these */
- ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
- return 0;
-}
-
static void moxa_setup_empty_event(struct tty_struct *tty)
{
struct moxa_port *ch = tty->driver_data;
static void moxa_shut_down(struct moxa_port *ch)
{
- struct tty_struct *tp;
+ struct tty_struct *tp = ch->port.tty;
- if (!(ch->asyncflags & ASYNC_INITIALIZED))
+ if (!(ch->port.flags & ASYNC_INITIALIZED))
return;
- tp = ch->tty;
-
MoxaPortDisable(ch);
/*
* If we're a modem control device and HUPCL is on, drop RTS & DTR.
*/
- if (tp->termios->c_cflag & HUPCL)
+ if (C_HUPCL(tp))
MoxaPortLineCtrl(ch, 0, 0);
- ch->asyncflags &= ~ASYNC_INITIALIZED;
+ spin_lock_bh(&moxa_lock);
+ ch->port.flags &= ~ASYNC_INITIALIZED;
+ spin_unlock_bh(&moxa_lock);
}
/*****************************************************************************
static void MoxaPortFlushData(struct moxa_port *port, int mode)
{
void __iomem *ofsAddr;
- if ((mode < 0) || (mode > 2))
+ if (mode < 0 || mode > 2)
return;
ofsAddr = port->tableAddr;
moxafunc(ofsAddr, FC_FlushQueue, mode);
}
}
-/*****************************************************************************
- * Port level functions: *
- * 2. MoxaPortEnable(int port); *
- * 3. MoxaPortDisable(int port); *
- * 4. MoxaPortGetMaxBaud(int port); *
- * 6. MoxaPortSetBaud(int port, long baud); *
- * 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); *
- * 15. MoxaPortFlushData(int port, int mode); *
- * 16. MoxaPortWriteData(int port, unsigned char * buffer, int length); *
- * 17. MoxaPortReadData(int port, struct tty_struct *tty); *
- * 20. MoxaPortTxQueue(int port); *
- * 21. MoxaPortTxFree(int port); *
- * 22. MoxaPortRxQueue(int port); *
- * 24. MoxaPortTxDisable(int port); *
- * 25. MoxaPortTxEnable(int port); *
- * 27. MoxaPortResetBrkCnt(int port); *
- *****************************************************************************/
/*
* Moxa Port Number Description:
*
* 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 10: Setting baud rate of this port.
* Syntax:
- * long MoxaPortSetBaud(int port, long baud);
+ * speed_t MoxaPortSetBaud(int port, speed_t baud);
* int port : port number (0 - 127)
* long baud : baud rate (50 - 115200)
*
static void MoxaPortEnable(struct moxa_port *port)
{
void __iomem *ofsAddr;
- short lowwater = 512;
+ u16 lowwater = 512;
ofsAddr = port->tableAddr;
writew(lowwater, ofsAddr + Low_water);
- if (port->board->boardType == MOXA_BOARD_C320_ISA ||
- port->board->boardType == MOXA_BOARD_C320_PCI) {
+ if (MOXA_IS_320(port->board))
moxafunc(ofsAddr, FC_SetBreakIrq, 0);
- } else {
- writew(readw(ofsAddr + HostStat) | WakeupBreak, ofsAddr + HostStat);
- }
+ else
+ writew(readw(ofsAddr + HostStat) | WakeupBreak,
+ ofsAddr + HostStat);
moxafunc(ofsAddr, FC_SetLineIrq, Magic_code);
moxafunc(ofsAddr, FC_FlushQueue, 2);
moxafunc(ofsAddr, FC_DisableCH, Magic_code);
}
-static long MoxaPortGetMaxBaud(struct moxa_port *port)
-{
- if (port->board->boardType == MOXA_BOARD_C320_ISA ||
- port->board->boardType == MOXA_BOARD_C320_PCI)
- return (460800L);
- else
- return (921600L);
-}
-
-
-static long MoxaPortSetBaud(struct moxa_port *port, long baud)
+static speed_t MoxaPortSetBaud(struct moxa_port *port, speed_t baud)
{
- void __iomem *ofsAddr;
- long max, clock;
- unsigned int val;
+ void __iomem *ofsAddr = port->tableAddr;
+ unsigned int clock, val;
+ speed_t max;
- if ((baud < 50L) || ((max = MoxaPortGetMaxBaud(port)) == 0))
- return (0);
- ofsAddr = port->tableAddr;
+ max = MOXA_IS_320(port->board) ? 460800 : 921600;
+ if (baud < 50)
+ return 0;
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 */
+ clock = 921600;
val = clock / baud;
moxafunc(ofsAddr, FC_SetBaud, val);
baud = clock / val;
- return (baud);
+ return baud;
}
static int MoxaPortSetTermio(struct moxa_port *port, struct ktermios *termio,
} else
mode |= MX_PARNONE;
- moxafunc(ofsAddr, FC_SetDataMode, (ushort) mode);
+ moxafunc(ofsAddr, FC_SetDataMode, (u16)mode);
+
+ if (MOXA_IS_320(port->board) && baud >= 921600)
+ return -1;
- if (port->board->boardType == MOXA_BOARD_C320_ISA ||
- port->board->boardType == MOXA_BOARD_C320_PCI) {
- if (baud >= 921600L)
- return (-1);
- }
baud = MoxaPortSetBaud(port, baud);
if (termio->c_iflag & (IXON | IXOFF | IXANY)) {
moxa_wait_finish(ofsAddr);
}
- return (baud);
+ return baud;
}
static int MoxaPortGetLineOut(struct moxa_port *port, int *dtrState,
int *rtsState)
{
-
if (dtrState)
*dtrState = !!(port->lineCtrl & DTR_ON);
if (rtsState)
*rtsState = !!(port->lineCtrl & RTS_ON);
- return (0);
+ return 0;
}
static void MoxaPortLineCtrl(struct moxa_port *port, int dtr, int rts)
{
- int mode = 0;
+ u8 mode = 0;
if (dtr)
mode |= DTR_ON;
int val;
ofsAddr = port->tableAddr;
- if (port->board->boardType == MOXA_BOARD_C320_ISA ||
- port->board->boardType == MOXA_BOARD_C320_PCI) {
+ if (MOXA_IS_320(port->board)) {
moxafunc(ofsAddr, FC_LineStatus, 0);
val = readw(ofsAddr + FuncArg);
} else {
val &= 0x0B;
if (val & 8)
val |= 4;
+ spin_lock_bh(&moxa_lock);
moxa_new_dcdstate(port, val & 8);
+ spin_unlock_bh(&moxa_lock);
val &= 7;
return val;
}
c = (head > tail) ? (head - tail - 1) : (head - tail + tx_mask);
if (c > len)
c = len;
- moxaLog.txcnt[port->tty->index] += c;
+ moxaLog.txcnt[port->port.tty->index] += c;
total = c;
if (spage == epage) {
bufhead = readw(ofsAddr + Ofs_txb);
static int MoxaPortReadData(struct moxa_port *port)
{
- struct tty_struct *tty = port->tty;
+ struct tty_struct *tty = port->port.tty;
unsigned char *dst;
void __iomem *baseAddr, *ofsAddr, *ofs;
unsigned int count, len, total;
}
static int moxa_get_serial_info(struct moxa_port *info,
- struct serial_struct __user *retinfo)
+ struct serial_struct __user *retinfo)
{
- struct serial_struct tmp;
-
- memset(&tmp, 0, sizeof(tmp));
- tmp.type = info->type;
- tmp.line = info->tty->index;
- tmp.port = 0;
- tmp.irq = 0;
- tmp.flags = info->asyncflags;
- tmp.baud_base = 921600;
- tmp.close_delay = info->close_delay;
- tmp.custom_divisor = 0;
- tmp.hub6 = 0;
- if(copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
- return -EFAULT;
- return (0);
+ struct serial_struct tmp = {
+ .type = info->type,
+ .line = info->port.tty->index,
+ .flags = info->port.flags,
+ .baud_base = 921600,
+ .close_delay = info->port.close_delay
+ };
+ return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
}
static int moxa_set_serial_info(struct moxa_port *info,
- struct serial_struct __user *new_info)
+ struct serial_struct __user *new_info)
{
struct serial_struct new_serial;
- if(copy_from_user(&new_serial, new_info, sizeof(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 (new_serial.irq != 0 || new_serial.port != 0 ||
+ new_serial.custom_divisor != 0 ||
+ new_serial.baud_base != 921600)
+ return -EPERM;
if (!capable(CAP_SYS_ADMIN)) {
if (((new_serial.flags & ~ASYNC_USR_MASK) !=
- (info->asyncflags & ~ASYNC_USR_MASK)))
- return (-EPERM);
- } else {
- info->close_delay = new_serial.close_delay * HZ / 100;
- }
+ (info->port.flags & ~ASYNC_USR_MASK)))
+ return -EPERM;
+ } else
+ info->port.close_delay = new_serial.close_delay * HZ / 100;
new_serial.flags = (new_serial.flags & ~ASYNC_FLAGS);
- new_serial.flags |= (info->asyncflags & ASYNC_FLAGS);
+ new_serial.flags |= (info->port.flags & ASYNC_FLAGS);
- if (new_serial.type == PORT_16550A) {
- MoxaSetFifo(info, 1);
- } else {
- MoxaSetFifo(info, 0);
- }
+ MoxaSetFifo(info, new_serial.type == PORT_16550A);
info->type = new_serial.type;
- return (0);
+ return 0;
}