/*
* 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 "moxa.h"
-#define MOXA_VERSION "5.1k"
+#define MOXA_VERSION "6.0k"
#define MOXA_FW_HDRLEN 32
#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;
- unsigned int count;
- int asyncflags;
int cflag;
unsigned long statusflags;
- wait_queue_head_t open_wait;
u8 DCDState;
u8 lineCtrl;
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))) {
mutex_unlock(&moxa_openlock);
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 = {
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;
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));
}
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);
}
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;
}
/* pci hot-un-plug support */
for (a = 0; a < brd->numPorts; a++)
- if (brd->ports[a].asyncflags & ASYNC_INITIALIZED)
- tty_hangup(brd->ports[a].tty);
+ 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].asyncflags & ASYNC_INITIALIZED)
+ if (brd->ports[a].port.flags & ASYNC_INITIALIZED)
opened++;
mutex_unlock(&moxa_openlock);
if (!opened)
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);
+ 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);
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",
baseaddr[i]);
continue;
}
+ printk(KERN_INFO "MOXA isa board found at 0x%.8lu and "
+ "ready (%u ports, firmware loaded)\n",
+ baseaddr[i], brd->numPorts);
+
brd++;
isabrds++;
}
{
moxa_shut_down(ch);
MoxaPortFlushData(ch, 2);
- ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
- ch->tty->driver_data = NULL;
- ch->tty = NULL;
+ 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,
u8 dcd;
while (1) {
- prepare_to_wait(&ch->open_wait, &wait, TASK_INTERRUPTIBLE);
+ prepare_to_wait(&ch->port.open_wait, &wait, TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp)) {
#ifdef SERIAL_DO_RESTART
retval = -ERESTARTSYS;
}
schedule();
}
- finish_wait(&ch->open_wait, &wait);
+ finish_wait(&ch->port.open_wait, &wait);
return retval;
}
}
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);
MoxaSetFifo(ch, ch->type == PORT_16550A);
- ch->asyncflags |= ASYNC_INITIALIZED;
+ ch->port.flags |= ASYNC_INITIALIZED;
}
mutex_unlock(&moxa_openlock);
retval = moxa_block_till_ready(tty, filp, ch);
mutex_lock(&moxa_openlock);
if (retval) {
- if (ch->count) /* 0 means already hung up... */
- if (--ch->count == 0)
+ if (ch->port.count) /* 0 means already hung up... */
+ if (--ch->port.count == 0)
moxa_close_port(ch);
} else
- ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
+ ch->port.flags |= ASYNC_NORMAL_ACTIVE;
mutex_unlock(&moxa_openlock);
return retval;
ch = tty->driver_data;
if (ch == NULL)
goto unlock;
- if (tty->count == 1 && ch->count != 1) {
+ 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)
+ 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 */
}
*/
if (ch == NULL)
return 0;
+ lock_kernel();
chars = MoxaPortTxQueue(ch);
if (chars) {
/*
if (!(ch->statusflags & EMPTYWAIT))
moxa_setup_empty_event(tty);
}
+ unlock_kernel();
return chars;
}
return;
moxa_set_tty_param(tty, old_termios);
if (!(old_termios->c_cflag & CLOCAL) && C_CLOCAL(tty))
- wake_up_interruptible(&ch->open_wait);
+ wake_up_interruptible(&ch->port.open_wait);
}
static void moxa_stop(struct tty_struct *tty)
mutex_unlock(&moxa_openlock);
return;
}
- ch->count = 0;
+ ch->port.count = 0;
moxa_close_port(ch);
mutex_unlock(&moxa_openlock);
- wake_up_interruptible(&ch->open_wait);
+ 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 != p->DCDState && p->port.tty && C_CLOCAL(p->port.tty)) {
if (!dcd)
- tty_hangup(p->tty);
+ 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) {
static void moxa_shut_down(struct moxa_port *ch)
{
- struct tty_struct *tp = ch->tty;
+ struct tty_struct *tp = ch->port.tty;
- if (!(ch->asyncflags & ASYNC_INITIALIZED))
+ if (!(ch->port.flags & ASYNC_INITIALIZED))
return;
MoxaPortDisable(ch);
MoxaPortLineCtrl(ch, 0, 0);
spin_lock_bh(&moxa_lock);
- ch->asyncflags &= ~ASYNC_INITIALIZED;
+ ch->port.flags &= ~ASYNC_INITIALIZED;
spin_unlock_bh(&moxa_lock);
}
* 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)
*
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,
moxafunc(ofsAddr, FC_DisableCH, Magic_code);
}
-static long MoxaPortGetMaxBaud(struct moxa_port *port)
+static speed_t MoxaPortSetBaud(struct moxa_port *port, speed_t baud)
{
- 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)
-{
- 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)
+ max = MOXA_IS_320(port->board) ? 460800 : 921600;
+ if (baud < 50)
return 0;
- ofsAddr = port->tableAddr;
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;
moxafunc(ofsAddr, FC_SetDataMode, (u16)mode);
- if (port->board->boardType == MOXA_BOARD_C320_ISA ||
- port->board->boardType == MOXA_BOARD_C320_PCI) {
- if (baud >= 921600L)
- return -1;
- }
+ if (MOXA_IS_320(port->board) && baud >= 921600)
+ return -1;
+
baud = MoxaPortSetBaud(port, baud);
if (termio->c_iflag & (IXON | IXOFF | IXANY)) {
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 {
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;
{
struct serial_struct tmp = {
.type = info->type,
- .line = info->tty->index,
- .flags = info->asyncflags,
+ .line = info->port.tty->index,
+ .flags = info->port.flags,
.baud_base = 921600,
- .close_delay = info->close_delay
+ .close_delay = info->port.close_delay
};
return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
}
if (!capable(CAP_SYS_ADMIN)) {
if (((new_serial.flags & ~ASYNC_USR_MASK) !=
- (info->asyncflags & ~ASYNC_USR_MASK)))
+ (info->port.flags & ~ASYNC_USR_MASK)))
return -EPERM;
} else
- info->close_delay = new_serial.close_delay * HZ / 100;
+ 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);
MoxaSetFifo(info, new_serial.type == PORT_16550A);