moxa.c 54.4 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4
/*****************************************************************************/
/*
 *           moxa.c  -- MOXA Intellio family multiport serial driver.
 *
J
Jiri Slaby 已提交
5 6
 *      Copyright (C) 1999-2000  Moxa Technologies (support@moxa.com).
 *      Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com>
L
Linus Torvalds 已提交
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
 *
 *      This code is loosely based on the Linux serial driver, written by
 *      Linus Torvalds, Theodore T'so and others.
 *
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 2 of the License, or
 *      (at your option) any later version.
 */

/*
 *    MOXA Intellio Series Driver
 *      for             : LINUX
 *      date            : 1999/1/7
 *      version         : 5.1
 */

#include <linux/module.h>
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/ioport.h>
#include <linux/errno.h>
J
Jiri Slaby 已提交
29
#include <linux/firmware.h>
L
Linus Torvalds 已提交
30 31 32 33 34 35 36
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/major.h>
A
Alexey Dobriyan 已提交
37
#include <linux/smp_lock.h>
L
Linus Torvalds 已提交
38 39 40 41 42 43 44 45 46 47 48 49 50 51
#include <linux/string.h>
#include <linux/fcntl.h>
#include <linux/ptrace.h>
#include <linux/serial.h>
#include <linux/tty_driver.h>
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/bitops.h>

#include <asm/system.h>
#include <asm/io.h>
#include <asm/uaccess.h>

J
Jiri Slaby 已提交
52 53
#include "moxa.h"

J
Jiri Slaby 已提交
54
#define MOXA_VERSION		"6.0k"
L
Linus Torvalds 已提交
55

J
Jiri Slaby 已提交
56 57
#define MOXA_FW_HDRLEN		32

J
Jiri Slaby 已提交
58
#define MOXAMAJOR		172
L
Linus Torvalds 已提交
59

J
Jiri Slaby 已提交
60
#define MAX_BOARDS		4	/* Don't change this value */
L
Linus Torvalds 已提交
61
#define MAX_PORTS_PER_BOARD	32	/* Don't change this value */
J
Jiri Slaby 已提交
62
#define MAX_PORTS		(MAX_BOARDS * MAX_PORTS_PER_BOARD)
L
Linus Torvalds 已提交
63

64 65 66
#define MOXA_IS_320(brd) ((brd)->boardType == MOXA_BOARD_C320_ISA || \
		(brd)->boardType == MOXA_BOARD_C320_PCI)

L
Linus Torvalds 已提交
67 68 69
/*
 *    Define the Moxa PCI vendor and device IDs.
 */
J
Jiri Slaby 已提交
70 71
#define MOXA_BUS_TYPE_ISA	0
#define MOXA_BUS_TYPE_PCI	1
L
Linus Torvalds 已提交
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91

enum {
	MOXA_BOARD_C218_PCI = 1,
	MOXA_BOARD_C218_ISA,
	MOXA_BOARD_C320_PCI,
	MOXA_BOARD_C320_ISA,
	MOXA_BOARD_CP204J,
};

static char *moxa_brdname[] =
{
	"C218 Turbo PCI series",
	"C218 Turbo ISA series",
	"C320 Turbo PCI series",
	"C320 Turbo ISA series",
	"CP-204J series",
};

#ifdef CONFIG_PCI
static struct pci_device_id moxa_pcibrds[] = {
J
Jiri Slaby 已提交
92 93 94 95 96 97
	{ PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C218),
		.driver_data = MOXA_BOARD_C218_PCI },
	{ PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C320),
		.driver_data = MOXA_BOARD_C320_PCI },
	{ PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP204J),
		.driver_data = MOXA_BOARD_CP204J },
L
Linus Torvalds 已提交
98 99 100 101 102
	{ 0 }
};
MODULE_DEVICE_TABLE(pci, moxa_pcibrds);
#endif /* CONFIG_PCI */

J
Jiri Slaby 已提交
103 104
struct moxa_port;

105
static struct moxa_board_conf {
L
Linus Torvalds 已提交
106 107 108
	int boardType;
	int numPorts;
	int busType;
109

110
	unsigned int ready;
111

J
Jiri Slaby 已提交
112 113
	struct moxa_port *ports;

114 115 116 117 118 119 120 121 122 123 124 125
	void __iomem *basemem;
	void __iomem *intNdx;
	void __iomem *intPend;
	void __iomem *intTable;
} moxa_boards[MAX_BOARDS];

struct mxser_mstatus {
	tcflag_t cflag;
	int cts;
	int dsr;
	int ri;
	int dcd;
126
};
L
Linus Torvalds 已提交
127

128 129 130 131
struct moxaq_str {
	int inq;
	int outq;
};
L
Linus Torvalds 已提交
132

133
struct moxa_port {
A
Alan Cox 已提交
134
	struct tty_port port;
J
Jiri Slaby 已提交
135
	struct moxa_board_conf *board;
J
Jiri Slaby 已提交
136 137
	void __iomem *tableAddr;

L
Linus Torvalds 已提交
138 139
	int type;
	int cflag;
J
Jiri Slaby 已提交
140
	unsigned long statusflags;
L
Linus Torvalds 已提交
141

J
Jiri Slaby 已提交
142 143 144
	u8 DCDState;
	u8 lineCtrl;
	u8 lowChkFlag;
145
};
L
Linus Torvalds 已提交
146

J
Jiri Slaby 已提交
147 148 149 150 151 152
struct mon_str {
	int tick;
	int rxcnt[MAX_PORTS];
	int txcnt[MAX_PORTS];
};

L
Linus Torvalds 已提交
153 154 155 156 157 158 159 160 161 162 163
/* statusflags */
#define TXSTOPPED	0x1
#define LOWWAIT 	0x2
#define EMPTYWAIT	0x4
#define THROTTLE	0x8

#define SERIAL_DO_RESTART

#define WAKEUP_CHARS		256

static int ttymajor = MOXAMAJOR;
J
Jiri Slaby 已提交
164 165
static struct mon_str moxaLog;
static unsigned int moxaFuncTout = HZ / 2;
J
Jiri Slaby 已提交
166
static unsigned int moxaLowWaterChk;
J
Jiri Slaby 已提交
167
static DEFINE_MUTEX(moxa_openlock);
L
Linus Torvalds 已提交
168 169
/* Variables for insmod */
#ifdef MODULE
170 171 172
static unsigned long baseaddr[MAX_BOARDS];
static unsigned int type[MAX_BOARDS];
static unsigned int numports[MAX_BOARDS];
L
Linus Torvalds 已提交
173 174 175 176 177 178
#endif

MODULE_AUTHOR("William Chen");
MODULE_DESCRIPTION("MOXA Intellio Family Multiport Board Device Driver");
MODULE_LICENSE("GPL");
#ifdef MODULE
179 180 181 182 183 184
module_param_array(type, uint, NULL, 0);
MODULE_PARM_DESC(type, "card type: C218=2, C320=4");
module_param_array(baseaddr, ulong, NULL, 0);
MODULE_PARM_DESC(baseaddr, "base address");
module_param_array(numports, uint, NULL, 0);
MODULE_PARM_DESC(numports, "numports (ignored for C218)");
L
Linus Torvalds 已提交
185 186 187 188 189 190 191 192 193 194 195 196 197 198
#endif
module_param(ttymajor, int, 0);

/*
 * static functions:
 */
static int moxa_open(struct tty_struct *, struct file *);
static void moxa_close(struct tty_struct *, struct file *);
static int moxa_write(struct tty_struct *, const unsigned char *, int);
static int moxa_write_room(struct tty_struct *);
static void moxa_flush_buffer(struct tty_struct *);
static int moxa_chars_in_buffer(struct tty_struct *);
static void moxa_throttle(struct tty_struct *);
static void moxa_unthrottle(struct tty_struct *);
A
Alan Cox 已提交
199
static void moxa_set_termios(struct tty_struct *, struct ktermios *);
L
Linus Torvalds 已提交
200 201 202 203 204 205 206
static void moxa_stop(struct tty_struct *);
static void moxa_start(struct tty_struct *);
static void moxa_hangup(struct tty_struct *);
static int moxa_tiocmget(struct tty_struct *tty, struct file *file);
static int moxa_tiocmset(struct tty_struct *tty, struct file *file,
			 unsigned int set, unsigned int clear);
static void moxa_poll(unsigned long);
A
Alan Cox 已提交
207
static void moxa_set_tty_param(struct tty_struct *, struct ktermios *);
J
Jiri Slaby 已提交
208
static void moxa_setup_empty_event(struct tty_struct *);
A
Alan Cox 已提交
209
static void moxa_shut_down(struct tty_struct *);
210
static int moxa_carrier_raised(struct tty_port *);
L
Linus Torvalds 已提交
211 212 213
/*
 * moxa board interface functions:
 */
J
Jiri Slaby 已提交
214 215 216 217 218 219 220 221
static void MoxaPortEnable(struct moxa_port *);
static void MoxaPortDisable(struct moxa_port *);
static int MoxaPortSetTermio(struct moxa_port *, struct ktermios *, speed_t);
static int MoxaPortGetLineOut(struct moxa_port *, int *, int *);
static void MoxaPortLineCtrl(struct moxa_port *, int, int);
static void MoxaPortFlowCtrl(struct moxa_port *, int, int, int, int, int);
static int MoxaPortLineStatus(struct moxa_port *);
static void MoxaPortFlushData(struct moxa_port *, int);
A
Alan Cox 已提交
222
static int MoxaPortWriteData(struct tty_struct *, const unsigned char *, int);
J
Jiri Slaby 已提交
223
static int MoxaPortReadData(struct moxa_port *);
J
Jiri Slaby 已提交
224 225 226 227 228
static int MoxaPortTxQueue(struct moxa_port *);
static int MoxaPortRxQueue(struct moxa_port *);
static int MoxaPortTxFree(struct moxa_port *);
static void MoxaPortTxDisable(struct moxa_port *);
static void MoxaPortTxEnable(struct moxa_port *);
229 230
static int moxa_get_serial_info(struct moxa_port *, struct serial_struct __user *);
static int moxa_set_serial_info(struct moxa_port *, struct serial_struct __user *);
J
Jiri Slaby 已提交
231
static void MoxaSetFifo(struct moxa_port *port, int enable);
L
Linus Torvalds 已提交
232

J
Jiri Slaby 已提交
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
/*
 * I/O functions
 */

static void moxa_wait_finish(void __iomem *ofsAddr)
{
	unsigned long end = jiffies + moxaFuncTout;

	while (readw(ofsAddr + FuncCode) != 0)
		if (time_after(jiffies, end))
			return;
	if (readw(ofsAddr + FuncCode) != 0 && printk_ratelimit())
		printk(KERN_WARNING "moxa function expired\n");
}

J
Jiri Slaby 已提交
248
static void moxafunc(void __iomem *ofsAddr, u16 cmd, u16 arg)
J
Jiri Slaby 已提交
249 250 251 252 253 254
{
	writew(arg, ofsAddr + FuncArg);
	writew(cmd, ofsAddr + FuncCode);
	moxa_wait_finish(ofsAddr);
}

J
Jiri Slaby 已提交
255 256 257 258 259 260 261 262 263 264 265 266 267 268
static void moxa_low_water_check(void __iomem *ofsAddr)
{
	u16 rptr, wptr, mask, len;

	if (readb(ofsAddr + FlagStat) & Xoff_state) {
		rptr = readw(ofsAddr + RXrptr);
		wptr = readw(ofsAddr + RXwptr);
		mask = readw(ofsAddr + RX_mask);
		len = (wptr - rptr) & mask;
		if (len <= Low_water)
			moxafunc(ofsAddr, FC_SendXon, 0);
	}
}

J
Jiri Slaby 已提交
269 270 271 272 273 274 275 276 277
/*
 * TTY operations
 */

static int moxa_ioctl(struct tty_struct *tty, struct file *file,
		      unsigned int cmd, unsigned long arg)
{
	struct moxa_port *ch = tty->driver_data;
	void __user *argp = (void __user *)arg;
J
Jiri Slaby 已提交
278
	int status, ret = 0;
J
Jiri Slaby 已提交
279 280 281 282 283 284 285 286 287 288 289

	if (tty->index == MAX_PORTS) {
		if (cmd != MOXA_GETDATACOUNT && cmd != MOXA_GET_IOQUEUE &&
				cmd != MOXA_GETMSTATUS)
			return -EINVAL;
	} else if (!ch)
		return -ENODEV;

	switch (cmd) {
	case MOXA_GETDATACOUNT:
		moxaLog.tick = jiffies;
J
Jiri Slaby 已提交
290 291 292
		if (copy_to_user(argp, &moxaLog, sizeof(moxaLog)))
			ret = -EFAULT;
		break;
J
Jiri Slaby 已提交
293 294
	case MOXA_FLUSH_QUEUE:
		MoxaPortFlushData(ch, arg);
J
Jiri Slaby 已提交
295
		break;
J
Jiri Slaby 已提交
296 297 298 299 300 301
	case MOXA_GET_IOQUEUE: {
		struct moxaq_str __user *argm = argp;
		struct moxaq_str tmp;
		struct moxa_port *p;
		unsigned int i, j;

J
Jiri Slaby 已提交
302
		mutex_lock(&moxa_openlock);
J
Jiri Slaby 已提交
303 304 305 306 307 308 309 310
		for (i = 0; i < MAX_BOARDS; i++) {
			p = moxa_boards[i].ports;
			for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
				memset(&tmp, 0, sizeof(tmp));
				if (moxa_boards[i].ready) {
					tmp.inq = MoxaPortRxQueue(p);
					tmp.outq = MoxaPortTxQueue(p);
				}
J
Jiri Slaby 已提交
311 312
				if (copy_to_user(argm, &tmp, sizeof(tmp))) {
					mutex_unlock(&moxa_openlock);
J
Jiri Slaby 已提交
313
					return -EFAULT;
J
Jiri Slaby 已提交
314
				}
J
Jiri Slaby 已提交
315 316
			}
		}
J
Jiri Slaby 已提交
317 318
		mutex_unlock(&moxa_openlock);
		break;
J
Jiri Slaby 已提交
319 320
	} case MOXA_GET_OQUEUE:
		status = MoxaPortTxQueue(ch);
J
Jiri Slaby 已提交
321 322
		ret = put_user(status, (unsigned long __user *)argp);
		break;
J
Jiri Slaby 已提交
323 324
	case MOXA_GET_IQUEUE:
		status = MoxaPortRxQueue(ch);
J
Jiri Slaby 已提交
325 326
		ret = put_user(status, (unsigned long __user *)argp);
		break;
J
Jiri Slaby 已提交
327 328 329 330 331 332
	case MOXA_GETMSTATUS: {
		struct mxser_mstatus __user *argm = argp;
		struct mxser_mstatus tmp;
		struct moxa_port *p;
		unsigned int i, j;

J
Jiri Slaby 已提交
333
		mutex_lock(&moxa_openlock);
J
Jiri Slaby 已提交
334 335 336
		for (i = 0; i < MAX_BOARDS; i++) {
			p = moxa_boards[i].ports;
			for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
A
Alan Cox 已提交
337
				struct tty_struct *ttyp;
J
Jiri Slaby 已提交
338 339 340 341 342 343 344 345 346 347 348 349
				memset(&tmp, 0, sizeof(tmp));
				if (!moxa_boards[i].ready)
					goto copy;

				status = MoxaPortLineStatus(p);
				if (status & 1)
					tmp.cts = 1;
				if (status & 2)
					tmp.dsr = 1;
				if (status & 4)
					tmp.dcd = 1;

A
Alan Cox 已提交
350 351
				ttyp = tty_port_tty_get(&p->port);
				if (!ttyp || !ttyp->termios)
J
Jiri Slaby 已提交
352 353
					tmp.cflag = p->cflag;
				else
A
Alan Cox 已提交
354 355
					tmp.cflag = ttyp->termios->c_cflag;
				tty_kref_put(tty);
J
Jiri Slaby 已提交
356
copy:
J
Jiri Slaby 已提交
357 358
				if (copy_to_user(argm, &tmp, sizeof(tmp))) {
					mutex_unlock(&moxa_openlock);
J
Jiri Slaby 已提交
359
					return -EFAULT;
J
Jiri Slaby 已提交
360
				}
J
Jiri Slaby 已提交
361 362
			}
		}
J
Jiri Slaby 已提交
363 364
		mutex_unlock(&moxa_openlock);
		break;
J
Jiri Slaby 已提交
365 366
	}
	case TIOCGSERIAL:
J
Jiri Slaby 已提交
367 368 369 370
		mutex_lock(&moxa_openlock);
		ret = moxa_get_serial_info(ch, argp);
		mutex_unlock(&moxa_openlock);
		break;
J
Jiri Slaby 已提交
371
	case TIOCSSERIAL:
J
Jiri Slaby 已提交
372 373 374 375 376 377
		mutex_lock(&moxa_openlock);
		ret = moxa_set_serial_info(ch, argp);
		mutex_unlock(&moxa_openlock);
		break;
	default:
		ret = -ENOIOCTLCMD;
J
Jiri Slaby 已提交
378
	}
J
Jiri Slaby 已提交
379
	return ret;
J
Jiri Slaby 已提交
380 381
}

A
Alan Cox 已提交
382
static int moxa_break_ctl(struct tty_struct *tty, int state)
J
Jiri Slaby 已提交
383 384 385 386 387
{
	struct moxa_port *port = tty->driver_data;

	moxafunc(port->tableAddr, state ? FC_SendBreak : FC_StopBreak,
			Magic_code);
A
Alan Cox 已提交
388
	return 0;
J
Jiri Slaby 已提交
389 390
}

J
Jeff Dike 已提交
391
static const struct tty_operations moxa_ops = {
L
Linus Torvalds 已提交
392 393 394 395 396 397 398 399 400 401 402 403 404
	.open = moxa_open,
	.close = moxa_close,
	.write = moxa_write,
	.write_room = moxa_write_room,
	.flush_buffer = moxa_flush_buffer,
	.chars_in_buffer = moxa_chars_in_buffer,
	.ioctl = moxa_ioctl,
	.throttle = moxa_throttle,
	.unthrottle = moxa_unthrottle,
	.set_termios = moxa_set_termios,
	.stop = moxa_stop,
	.start = moxa_start,
	.hangup = moxa_hangup,
J
Jiri Slaby 已提交
405
	.break_ctl = moxa_break_ctl,
L
Linus Torvalds 已提交
406 407 408 409
	.tiocmget = moxa_tiocmget,
	.tiocmset = moxa_tiocmset,
};

410 411 412 413
static const struct tty_port_operations moxa_port_ops = {
	.carrier_raised = moxa_carrier_raised,
};

J
Jiri Slaby 已提交
414 415
static struct tty_driver *moxaDriver;
static DEFINE_TIMER(moxaTimer, moxa_poll, 0, 0);
I
Ingo Molnar 已提交
416
static DEFINE_SPINLOCK(moxa_lock);
A
Alan Cox 已提交
417

J
Jiri Slaby 已提交
418 419 420 421
/*
 * HW init
 */

J
Jiri Slaby 已提交
422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485
static int moxa_check_fw_model(struct moxa_board_conf *brd, u8 model)
{
	switch (brd->boardType) {
	case MOXA_BOARD_C218_ISA:
	case MOXA_BOARD_C218_PCI:
		if (model != 1)
			goto err;
		break;
	case MOXA_BOARD_CP204J:
		if (model != 3)
			goto err;
		break;
	default:
		if (model != 2)
			goto err;
		break;
	}
	return 0;
err:
	return -EINVAL;
}

static int moxa_check_fw(const void *ptr)
{
	const __le16 *lptr = ptr;

	if (*lptr != cpu_to_le16(0x7980))
		return -EINVAL;

	return 0;
}

static int moxa_load_bios(struct moxa_board_conf *brd, const u8 *buf,
		size_t len)
{
	void __iomem *baseAddr = brd->basemem;
	u16 tmp;

	writeb(HW_reset, baseAddr + Control_reg);	/* reset */
	msleep(10);
	memset_io(baseAddr, 0, 4096);
	memcpy_toio(baseAddr, buf, len);	/* download BIOS */
	writeb(0, baseAddr + Control_reg);	/* restart */

	msleep(2000);

	switch (brd->boardType) {
	case MOXA_BOARD_C218_ISA:
	case MOXA_BOARD_C218_PCI:
		tmp = readw(baseAddr + C218_key);
		if (tmp != C218_KeyCode)
			goto err;
		break;
	case MOXA_BOARD_CP204J:
		tmp = readw(baseAddr + C218_key);
		if (tmp != CP204J_KeyCode)
			goto err;
		break;
	default:
		tmp = readw(baseAddr + C320_key);
		if (tmp != C320_KeyCode)
			goto err;
		tmp = readw(baseAddr + C320_status);
		if (tmp != STS_init) {
J
Jiri Slaby 已提交
486
			printk(KERN_ERR "MOXA: bios upload failed -- CPU/Basic "
J
Jiri Slaby 已提交
487 488 489 490 491 492 493 494
					"module not found\n");
			return -EIO;
		}
		break;
	}

	return 0;
err:
J
Jiri Slaby 已提交
495
	printk(KERN_ERR "MOXA: bios upload failed -- board not found\n");
J
Jiri Slaby 已提交
496 497 498 499 500 501 502 503 504
	return -EIO;
}

static int moxa_load_320b(struct moxa_board_conf *brd, const u8 *ptr,
		size_t len)
{
	void __iomem *baseAddr = brd->basemem;

	if (len < 7168) {
J
Jiri Slaby 已提交
505
		printk(KERN_ERR "MOXA: invalid 320 bios -- too short\n");
J
Jiri Slaby 已提交
506 507 508 509 510 511 512 513 514 515 516 517
		return -EINVAL;
	}

	writew(len - 7168 - 2, baseAddr + C320bapi_len);
	writeb(1, baseAddr + Control_reg);	/* Select Page 1 */
	memcpy_toio(baseAddr + DynPage_addr, ptr, 7168);
	writeb(2, baseAddr + Control_reg);	/* Select Page 2 */
	memcpy_toio(baseAddr + DynPage_addr, ptr + 7168, len - 7168);

	return 0;
}

518
static int moxa_real_load_code(struct moxa_board_conf *brd, const void *ptr,
J
Jiri Slaby 已提交
519 520 521
		size_t len)
{
	void __iomem *baseAddr = brd->basemem;
H
Harvey Harrison 已提交
522
	const __le16 *uptr = ptr;
J
Jiri Slaby 已提交
523
	size_t wlen, len2, j;
524
	unsigned long key, loadbuf, loadlen, checksum, checksum_ok;
525
	unsigned int i, retry;
J
Jiri Slaby 已提交
526 527
	u16 usum, keycode;

528 529
	keycode = (brd->boardType == MOXA_BOARD_CP204J) ? CP204J_KeyCode :
				C218_KeyCode;
J
Jiri Slaby 已提交
530

531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548
	switch (brd->boardType) {
	case MOXA_BOARD_CP204J:
	case MOXA_BOARD_C218_ISA:
	case MOXA_BOARD_C218_PCI:
		key = C218_key;
		loadbuf = C218_LoadBuf;
		loadlen = C218DLoad_len;
		checksum = C218check_sum;
		checksum_ok = C218chksum_ok;
		break;
	default:
		key = C320_key;
		keycode = C320_KeyCode;
		loadbuf = C320_LoadBuf;
		loadlen = C320DLoad_len;
		checksum = C320check_sum;
		checksum_ok = C320chksum_ok;
		break;
J
Jiri Slaby 已提交
549 550 551 552 553 554 555 556 557 558 559 560 561
	}

	usum = 0;
	wlen = len >> 1;
	for (i = 0; i < wlen; i++)
		usum += le16_to_cpu(uptr[i]);
	retry = 0;
	do {
		wlen = len >> 1;
		j = 0;
		while (wlen) {
			len2 = (wlen > 2048) ? 2048 : wlen;
			wlen -= len2;
562
			memcpy_toio(baseAddr + loadbuf, ptr + j, len2 << 1);
J
Jiri Slaby 已提交
563
			j += len2 << 1;
564 565 566 567 568

			writew(len2, baseAddr + loadlen);
			writew(0, baseAddr + key);
			for (i = 0; i < 100; i++) {
				if (readw(baseAddr + key) == keycode)
J
Jiri Slaby 已提交
569 570 571
					break;
				msleep(10);
			}
572
			if (readw(baseAddr + key) != keycode)
J
Jiri Slaby 已提交
573 574
				return -EIO;
		}
575 576 577 578 579
		writew(0, baseAddr + loadlen);
		writew(usum, baseAddr + checksum);
		writew(0, baseAddr + key);
		for (i = 0; i < 100; i++) {
			if (readw(baseAddr + key) == keycode)
J
Jiri Slaby 已提交
580 581 582 583
				break;
			msleep(10);
		}
		retry++;
584 585
	} while ((readb(baseAddr + checksum_ok) != 1) && (retry < 3));
	if (readb(baseAddr + checksum_ok) != 1)
J
Jiri Slaby 已提交
586 587
		return -EIO;

588
	writew(0, baseAddr + key);
J
Jiri Slaby 已提交
589 590 591 592 593 594 595 596
	for (i = 0; i < 600; i++) {
		if (readw(baseAddr + Magic_no) == Magic_code)
			break;
		msleep(10);
	}
	if (readw(baseAddr + Magic_no) != Magic_code)
		return -EIO;

597
	if (MOXA_IS_320(brd)) {
598 599 600 601 602 603 604 605 606
		if (brd->busType == MOXA_BUS_TYPE_PCI) {	/* ASIC board */
			writew(0x3800, baseAddr + TMS320_PORT1);
			writew(0x3900, baseAddr + TMS320_PORT2);
			writew(28499, baseAddr + TMS320_CLOCK);
		} else {
			writew(0x3200, baseAddr + TMS320_PORT1);
			writew(0x3400, baseAddr + TMS320_PORT2);
			writew(19999, baseAddr + TMS320_CLOCK);
		}
J
Jiri Slaby 已提交
607 608 609 610 611 612 613 614 615 616 617
	}
	writew(1, baseAddr + Disable_IRQ);
	writew(0, baseAddr + Magic_no);
	for (i = 0; i < 500; i++) {
		if (readw(baseAddr + Magic_no) == Magic_code)
			break;
		msleep(10);
	}
	if (readw(baseAddr + Magic_no) != Magic_code)
		return -EIO;

618
	if (MOXA_IS_320(brd)) {
619 620 621 622 623 624 625 626 627 628 629 630 631
		j = readw(baseAddr + Module_cnt);
		if (j <= 0)
			return -EIO;
		brd->numPorts = j * 8;
		writew(j, baseAddr + Module_no);
		writew(0, baseAddr + Magic_no);
		for (i = 0; i < 600; i++) {
			if (readw(baseAddr + Magic_no) == Magic_code)
				break;
			msleep(10);
		}
		if (readw(baseAddr + Magic_no) != Magic_code)
			return -EIO;
J
Jiri Slaby 已提交
632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647
	}
	brd->intNdx = baseAddr + IRQindex;
	brd->intPend = baseAddr + IRQpending;
	brd->intTable = baseAddr + IRQtable;

	return 0;
}

static int moxa_load_code(struct moxa_board_conf *brd, const void *ptr,
		size_t len)
{
	void __iomem *ofsAddr, *baseAddr = brd->basemem;
	struct moxa_port *port;
	int retval, i;

	if (len % 2) {
J
Jiri Slaby 已提交
648
		printk(KERN_ERR "MOXA: bios length is not even\n");
J
Jiri Slaby 已提交
649 650 651
		return -EINVAL;
	}

652 653 654 655
	retval = moxa_real_load_code(brd, ptr, len); /* may change numPorts */
	if (retval)
		return retval;

J
Jiri Slaby 已提交
656 657 658 659 660 661
	switch (brd->boardType) {
	case MOXA_BOARD_C218_ISA:
	case MOXA_BOARD_C218_PCI:
	case MOXA_BOARD_CP204J:
		port = brd->ports;
		for (i = 0; i < brd->numPorts; i++, port++) {
J
Jiri Slaby 已提交
662
			port->board = brd;
J
Jiri Slaby 已提交
663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679
			port->DCDState = 0;
			port->tableAddr = baseAddr + Extern_table +
					Extern_size * i;
			ofsAddr = port->tableAddr;
			writew(C218rx_mask, ofsAddr + RX_mask);
			writew(C218tx_mask, ofsAddr + TX_mask);
			writew(C218rx_spage + i * C218buf_pageno, ofsAddr + Page_rxb);
			writew(readw(ofsAddr + Page_rxb) + C218rx_pageno, ofsAddr + EndPage_rxb);

			writew(C218tx_spage + i * C218buf_pageno, ofsAddr + Page_txb);
			writew(readw(ofsAddr + Page_txb) + C218tx_pageno, ofsAddr + EndPage_txb);

		}
		break;
	default:
		port = brd->ports;
		for (i = 0; i < brd->numPorts; i++, port++) {
J
Jiri Slaby 已提交
680
			port->board = brd;
J
Jiri Slaby 已提交
681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729
			port->DCDState = 0;
			port->tableAddr = baseAddr + Extern_table +
					Extern_size * i;
			ofsAddr = port->tableAddr;
			switch (brd->numPorts) {
			case 8:
				writew(C320p8rx_mask, ofsAddr + RX_mask);
				writew(C320p8tx_mask, ofsAddr + TX_mask);
				writew(C320p8rx_spage + i * C320p8buf_pgno, ofsAddr + Page_rxb);
				writew(readw(ofsAddr + Page_rxb) + C320p8rx_pgno, ofsAddr + EndPage_rxb);
				writew(C320p8tx_spage + i * C320p8buf_pgno, ofsAddr + Page_txb);
				writew(readw(ofsAddr + Page_txb) + C320p8tx_pgno, ofsAddr + EndPage_txb);

				break;
			case 16:
				writew(C320p16rx_mask, ofsAddr + RX_mask);
				writew(C320p16tx_mask, ofsAddr + TX_mask);
				writew(C320p16rx_spage + i * C320p16buf_pgno, ofsAddr + Page_rxb);
				writew(readw(ofsAddr + Page_rxb) + C320p16rx_pgno, ofsAddr + EndPage_rxb);
				writew(C320p16tx_spage + i * C320p16buf_pgno, ofsAddr + Page_txb);
				writew(readw(ofsAddr + Page_txb) + C320p16tx_pgno, ofsAddr + EndPage_txb);
				break;

			case 24:
				writew(C320p24rx_mask, ofsAddr + RX_mask);
				writew(C320p24tx_mask, ofsAddr + TX_mask);
				writew(C320p24rx_spage + i * C320p24buf_pgno, ofsAddr + Page_rxb);
				writew(readw(ofsAddr + Page_rxb) + C320p24rx_pgno, ofsAddr + EndPage_rxb);
				writew(C320p24tx_spage + i * C320p24buf_pgno, ofsAddr + Page_txb);
				writew(readw(ofsAddr + Page_txb), ofsAddr + EndPage_txb);
				break;
			case 32:
				writew(C320p32rx_mask, ofsAddr + RX_mask);
				writew(C320p32tx_mask, ofsAddr + TX_mask);
				writew(C320p32tx_ofs, ofsAddr + Ofs_txb);
				writew(C320p32rx_spage + i * C320p32buf_pgno, ofsAddr + Page_rxb);
				writew(readb(ofsAddr + Page_rxb), ofsAddr + EndPage_rxb);
				writew(C320p32tx_spage + i * C320p32buf_pgno, ofsAddr + Page_txb);
				writew(readw(ofsAddr + Page_txb), ofsAddr + EndPage_txb);
				break;
			}
		}
		break;
	}
	return 0;
}

static int moxa_load_fw(struct moxa_board_conf *brd, const struct firmware *fw)
{
730
	const void *ptr = fw->data;
J
Jiri Slaby 已提交
731 732 733 734 735 736 737 738 739 740 741 742
	char rsn[64];
	u16 lens[5];
	size_t len;
	unsigned int a, lenp, lencnt;
	int ret = -EINVAL;
	struct {
		__le32 magic;	/* 0x34303430 */
		u8 reserved1[2];
		u8 type;	/* UNIX = 3 */
		u8 model;	/* C218T=1, C320T=2, CP204=3 */
		u8 reserved2[8];
		__le16 len[5];
743
	} const *hdr = ptr;
J
Jiri Slaby 已提交
744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769

	BUILD_BUG_ON(ARRAY_SIZE(hdr->len) != ARRAY_SIZE(lens));

	if (fw->size < MOXA_FW_HDRLEN) {
		strcpy(rsn, "too short (even header won't fit)");
		goto err;
	}
	if (hdr->magic != cpu_to_le32(0x30343034)) {
		sprintf(rsn, "bad magic: %.8x", le32_to_cpu(hdr->magic));
		goto err;
	}
	if (hdr->type != 3) {
		sprintf(rsn, "not for linux, type is %u", hdr->type);
		goto err;
	}
	if (moxa_check_fw_model(brd, hdr->model)) {
		sprintf(rsn, "not for this card, model is %u", hdr->model);
		goto err;
	}

	len = MOXA_FW_HDRLEN;
	lencnt = hdr->model == 2 ? 5 : 3;
	for (a = 0; a < ARRAY_SIZE(lens); a++) {
		lens[a] = le16_to_cpu(hdr->len[a]);
		if (lens[a] && len + lens[a] <= fw->size &&
				moxa_check_fw(&fw->data[len]))
J
Jiri Slaby 已提交
770
			printk(KERN_WARNING "MOXA firmware: unexpected input "
J
Jiri Slaby 已提交
771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820
				"at offset %u, but going on\n", (u32)len);
		if (!lens[a] && a < lencnt) {
			sprintf(rsn, "too few entries in fw file");
			goto err;
		}
		len += lens[a];
	}

	if (len != fw->size) {
		sprintf(rsn, "bad length: %u (should be %u)", (u32)fw->size,
				(u32)len);
		goto err;
	}

	ptr += MOXA_FW_HDRLEN;
	lenp = 0; /* bios */

	strcpy(rsn, "read above");

	ret = moxa_load_bios(brd, ptr, lens[lenp]);
	if (ret)
		goto err;

	/* we skip the tty section (lens[1]), since we don't need it */
	ptr += lens[lenp] + lens[lenp + 1];
	lenp += 2; /* comm */

	if (hdr->model == 2) {
		ret = moxa_load_320b(brd, ptr, lens[lenp]);
		if (ret)
			goto err;
		/* skip another tty */
		ptr += lens[lenp] + lens[lenp + 1];
		lenp += 2;
	}

	ret = moxa_load_code(brd, ptr, lens[lenp]);
	if (ret)
		goto err;

	return 0;
err:
	printk(KERN_ERR "firmware failed to load, reason: %s\n", rsn);
	return ret;
}

static int moxa_init_board(struct moxa_board_conf *brd, struct device *dev)
{
	const struct firmware *fw;
	const char *file;
821 822
	struct moxa_port *p;
	unsigned int i;
J
Jiri Slaby 已提交
823 824
	int ret;

825 826 827 828 829 830 831 832 833
	brd->ports = kcalloc(MAX_PORTS_PER_BOARD, sizeof(*brd->ports),
			GFP_KERNEL);
	if (brd->ports == NULL) {
		printk(KERN_ERR "cannot allocate memory for ports\n");
		ret = -ENOMEM;
		goto err;
	}

	for (i = 0, p = brd->ports; i < MAX_PORTS_PER_BOARD; i++, p++) {
A
Alan Cox 已提交
834
		tty_port_init(&p->port);
835
		p->port.ops = &moxa_port_ops;
836 837 838 839
		p->type = PORT_16550A;
		p->cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
	}

J
Jiri Slaby 已提交
840 841 842 843 844 845 846 847 848 849 850 851 852 853 854
	switch (brd->boardType) {
	case MOXA_BOARD_C218_ISA:
	case MOXA_BOARD_C218_PCI:
		file = "c218tunx.cod";
		break;
	case MOXA_BOARD_CP204J:
		file = "cp204unx.cod";
		break;
	default:
		file = "c320tunx.cod";
		break;
	}

	ret = request_firmware(&fw, file, dev);
	if (ret) {
855 856 857 858
		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);
859
		goto err_free;
J
Jiri Slaby 已提交
860 861 862 863 864
	}

	ret = moxa_load_fw(brd, fw);

	release_firmware(fw);
865 866 867 868

	if (ret)
		goto err_free;

J
Jiri Slaby 已提交
869
	spin_lock_bh(&moxa_lock);
870
	brd->ready = 1;
J
Jiri Slaby 已提交
871 872
	if (!timer_pending(&moxaTimer))
		mod_timer(&moxaTimer, jiffies + HZ / 50);
J
Jiri Slaby 已提交
873
	spin_unlock_bh(&moxa_lock);
J
Jiri Slaby 已提交
874

875 876 877 878
	return 0;
err_free:
	kfree(brd->ports);
err:
J
Jiri Slaby 已提交
879 880 881
	return ret;
}

882 883
static void moxa_board_deinit(struct moxa_board_conf *brd)
{
J
Jiri Slaby 已提交
884 885 886
	unsigned int a, opened;

	mutex_lock(&moxa_openlock);
J
Jiri Slaby 已提交
887
	spin_lock_bh(&moxa_lock);
888
	brd->ready = 0;
J
Jiri Slaby 已提交
889
	spin_unlock_bh(&moxa_lock);
J
Jiri Slaby 已提交
890 891 892

	/* pci hot-un-plug support */
	for (a = 0; a < brd->numPorts; a++)
A
Alan Cox 已提交
893 894 895 896 897 898 899 900
		if (brd->ports[a].port.flags & ASYNC_INITIALIZED) {
			struct tty_struct *tty = tty_port_tty_get(
						&brd->ports[a].port);
			if (tty) {
				tty_hangup(tty);
				tty_kref_put(tty);
			}
		}
J
Jiri Slaby 已提交
901 902 903
	while (1) {
		opened = 0;
		for (a = 0; a < brd->numPorts; a++)
A
Alan Cox 已提交
904
			if (brd->ports[a].port.flags & ASYNC_INITIALIZED)
J
Jiri Slaby 已提交
905 906 907 908 909 910 911 912
				opened++;
		mutex_unlock(&moxa_openlock);
		if (!opened)
			break;
		msleep(50);
		mutex_lock(&moxa_openlock);
	}

913 914 915 916 917
	iounmap(brd->basemem);
	brd->basemem = NULL;
	kfree(brd->ports);
}

L
Linus Torvalds 已提交
918
#ifdef CONFIG_PCI
919 920
static int __devinit moxa_pci_probe(struct pci_dev *pdev,
		const struct pci_device_id *ent)
L
Linus Torvalds 已提交
921
{
922 923 924 925 926 927
	struct moxa_board_conf *board;
	unsigned int i;
	int board_type = ent->driver_data;
	int retval;

	retval = pci_enable_device(pdev);
J
Jiri Slaby 已提交
928 929
	if (retval) {
		dev_err(&pdev->dev, "can't enable pci device\n");
930
		goto err;
J
Jiri Slaby 已提交
931
	}
932 933 934 935 936 937 938

	for (i = 0; i < MAX_BOARDS; i++)
		if (moxa_boards[i].basemem == NULL)
			break;

	retval = -ENODEV;
	if (i >= MAX_BOARDS) {
J
Jiri Slaby 已提交
939
		dev_warn(&pdev->dev, "more than %u MOXA Intellio family boards "
940 941 942 943 944
				"found. Board is ignored.\n", MAX_BOARDS);
		goto err;
	}

	board = &moxa_boards[i];
J
Jiri Slaby 已提交
945 946 947 948 949 950 951

	retval = pci_request_region(pdev, 2, "moxa-base");
	if (retval) {
		dev_err(&pdev->dev, "can't request pci region 2\n");
		goto err;
	}

952
	board->basemem = ioremap_nocache(pci_resource_start(pdev, 2), 0x4000);
J
Jiri Slaby 已提交
953 954
	if (board->basemem == NULL) {
		dev_err(&pdev->dev, "can't remap io space 2\n");
J
Jiri Slaby 已提交
955
		goto err_reg;
J
Jiri Slaby 已提交
956
	}
957

L
Linus Torvalds 已提交
958 959 960 961 962 963 964 965 966 967 968 969 970 971 972
	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;
J
Jiri Slaby 已提交
973

J
Jiri Slaby 已提交
974 975 976 977
	retval = moxa_init_board(board, &pdev->dev);
	if (retval)
		goto err_base;

978
	pci_set_drvdata(pdev, board);
L
Linus Torvalds 已提交
979

980 981 982
	dev_info(&pdev->dev, "board '%s' ready (%u ports, firmware loaded)\n",
			moxa_brdname[board_type - 1], board->numPorts);

J
Jiri Slaby 已提交
983
	return 0;
J
Jiri Slaby 已提交
984 985 986
err_base:
	iounmap(board->basemem);
	board->basemem = NULL;
J
Jiri Slaby 已提交
987 988
err_reg:
	pci_release_region(pdev, 2);
989 990 991 992 993 994 995 996
err:
	return retval;
}

static void __devexit moxa_pci_remove(struct pci_dev *pdev)
{
	struct moxa_board_conf *brd = pci_get_drvdata(pdev);

997 998
	moxa_board_deinit(brd);

J
Jiri Slaby 已提交
999
	pci_release_region(pdev, 2);
L
Linus Torvalds 已提交
1000
}
J
Jiri Slaby 已提交
1001 1002 1003 1004 1005 1006 1007

static struct pci_driver moxa_pci_driver = {
	.name = "moxa",
	.id_table = moxa_pcibrds,
	.probe = moxa_pci_probe,
	.remove = __devexit_p(moxa_pci_remove)
};
L
Linus Torvalds 已提交
1008 1009 1010 1011
#endif /* CONFIG_PCI */

static int __init moxa_init(void)
{
1012
	unsigned int isabrds = 0;
1013
	int retval = 0;
L
Linus Torvalds 已提交
1014

J
Jiri Slaby 已提交
1015 1016
	printk(KERN_INFO "MOXA Intellio family driver version %s\n",
			MOXA_VERSION);
L
Linus Torvalds 已提交
1017 1018 1019 1020 1021
	moxaDriver = alloc_tty_driver(MAX_PORTS + 1);
	if (!moxaDriver)
		return -ENOMEM;

	moxaDriver->owner = THIS_MODULE;
1022
	moxaDriver->name = "ttyMX";
L
Linus Torvalds 已提交
1023 1024 1025 1026 1027 1028
	moxaDriver->major = ttymajor;
	moxaDriver->minor_start = 0;
	moxaDriver->type = TTY_DRIVER_TYPE_SERIAL;
	moxaDriver->subtype = SERIAL_TYPE_NORMAL;
	moxaDriver->init_termios = tty_std_termios;
	moxaDriver->init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
A
Alan Cox 已提交
1029 1030
	moxaDriver->init_termios.c_ispeed = 9600;
	moxaDriver->init_termios.c_ospeed = 9600;
L
Linus Torvalds 已提交
1031 1032 1033 1034
	moxaDriver->flags = TTY_DRIVER_REAL_RAW;
	tty_set_operations(moxaDriver, &moxa_ops);

	if (tty_register_driver(moxaDriver)) {
J
Jiri Slaby 已提交
1035
		printk(KERN_ERR "can't register MOXA Smartio tty driver!\n");
L
Linus Torvalds 已提交
1036 1037 1038 1039
		put_tty_driver(moxaDriver);
		return -1;
	}

1040
	/* Find the boards defined from module args. */
L
Linus Torvalds 已提交
1041
#ifdef MODULE
1042 1043
	{
	struct moxa_board_conf *brd = moxa_boards;
1044
	unsigned int i;
L
Linus Torvalds 已提交
1045
	for (i = 0; i < MAX_BOARDS; i++) {
1046 1047 1048 1049
		if (!baseaddr[i])
			break;
		if (type[i] == MOXA_BOARD_C218_ISA ||
				type[i] == MOXA_BOARD_C320_ISA) {
J
Jiri Slaby 已提交
1050
			pr_debug("Moxa board %2d: %s board(baseAddr=%lx)\n",
1051 1052 1053 1054 1055 1056
					isabrds + 1, moxa_brdname[type[i] - 1],
					baseaddr[i]);
			brd->boardType = type[i];
			brd->numPorts = type[i] == MOXA_BOARD_C218_ISA ? 8 :
					numports[i];
			brd->busType = MOXA_BUS_TYPE_ISA;
1057
			brd->basemem = ioremap_nocache(baseaddr[i], 0x4000);
1058
			if (!brd->basemem) {
J
Jiri Slaby 已提交
1059
				printk(KERN_ERR "MOXA: can't remap %lx\n",
1060
						baseaddr[i]);
L
Linus Torvalds 已提交
1061 1062
				continue;
			}
J
Jiri Slaby 已提交
1063 1064 1065 1066 1067
			if (moxa_init_board(brd, NULL)) {
				iounmap(brd->basemem);
				brd->basemem = NULL;
				continue;
			}
1068

1069 1070 1071 1072
			printk(KERN_INFO "MOXA isa board found at 0x%.8lu and "
					"ready (%u ports, firmware loaded)\n",
					baseaddr[i], brd->numPorts);

1073 1074
			brd++;
			isabrds++;
L
Linus Torvalds 已提交
1075 1076
		}
	}
1077
	}
L
Linus Torvalds 已提交
1078
#endif
J
Jiri Slaby 已提交
1079

L
Linus Torvalds 已提交
1080
#ifdef CONFIG_PCI
J
Jiri Slaby 已提交
1081 1082
	retval = pci_register_driver(&moxa_pci_driver);
	if (retval) {
J
Jiri Slaby 已提交
1083
		printk(KERN_ERR "Can't register MOXA pci driver!\n");
1084
		if (isabrds)
J
Jiri Slaby 已提交
1085
			retval = 0;
L
Linus Torvalds 已提交
1086 1087
	}
#endif
J
Jiri Slaby 已提交
1088 1089

	return retval;
L
Linus Torvalds 已提交
1090 1091 1092 1093
}

static void __exit moxa_exit(void)
{
J
Jiri Slaby 已提交
1094
	unsigned int i;
L
Linus Torvalds 已提交
1095

1096
#ifdef CONFIG_PCI
J
Jiri Slaby 已提交
1097
	pci_unregister_driver(&moxa_pci_driver);
1098
#endif
J
Jiri Slaby 已提交
1099

1100 1101 1102
	for (i = 0; i < MAX_BOARDS; i++) /* ISA boards */
		if (moxa_boards[i].ready)
			moxa_board_deinit(&moxa_boards[i]);
J
Jiri Slaby 已提交
1103 1104 1105 1106 1107 1108 1109

	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);
L
Linus Torvalds 已提交
1110 1111 1112 1113 1114
}

module_init(moxa_init);
module_exit(moxa_exit);

A
Alan Cox 已提交
1115
static void moxa_close_port(struct tty_struct *tty)
J
Jiri Slaby 已提交
1116
{
A
Alan Cox 已提交
1117 1118
	struct moxa_port *ch = tty->driver_data;
	moxa_shut_down(tty);
J
Jiri Slaby 已提交
1119
	MoxaPortFlushData(ch, 2);
A
Alan Cox 已提交
1120
	ch->port.flags &= ~ASYNC_NORMAL_ACTIVE;
A
Alan Cox 已提交
1121 1122
	tty->driver_data = NULL;
	tty_port_tty_set(&ch->port, NULL);
J
Jiri Slaby 已提交
1123 1124
}

1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135
static int moxa_carrier_raised(struct tty_port *port)
{
	struct moxa_port *ch = container_of(port, struct moxa_port, port);
	int dcd;

	spin_lock_bh(&moxa_lock);
	dcd = ch->DCDState;
	spin_unlock_bh(&moxa_lock);
	return dcd;
}

J
Jiri Slaby 已提交
1136 1137 1138
static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp,
			    struct moxa_port *ch)
{
1139
	struct tty_port *port = &ch->port;
J
Jiri Slaby 已提交
1140 1141 1142 1143 1144
	DEFINE_WAIT(wait);
	int retval = 0;
	u8 dcd;

	while (1) {
1145
		prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
J
Jiri Slaby 已提交
1146 1147 1148 1149 1150 1151 1152 1153
		if (tty_hung_up_p(filp)) {
#ifdef SERIAL_DO_RESTART
			retval = -ERESTARTSYS;
#else
			retval = -EAGAIN;
#endif
			break;
		}
1154
		dcd = tty_port_carrier_raised(port);
J
Jiri Slaby 已提交
1155 1156 1157 1158 1159 1160 1161 1162 1163
		if (dcd)
			break;

		if (signal_pending(current)) {
			retval = -ERESTARTSYS;
			break;
		}
		schedule();
	}
1164
	finish_wait(&port->open_wait, &wait);
J
Jiri Slaby 已提交
1165 1166 1167 1168

	return retval;
}

L
Linus Torvalds 已提交
1169 1170
static int moxa_open(struct tty_struct *tty, struct file *filp)
{
1171
	struct moxa_board_conf *brd;
1172
	struct moxa_port *ch;
L
Linus Torvalds 已提交
1173 1174 1175
	int port;
	int retval;

J
Jiri Slaby 已提交
1176
	port = tty->index;
L
Linus Torvalds 已提交
1177
	if (port == MAX_PORTS) {
J
Jiri Slaby 已提交
1178
		return capable(CAP_SYS_ADMIN) ? 0 : -EPERM;
L
Linus Torvalds 已提交
1179
	}
J
Jiri Slaby 已提交
1180 1181
	if (mutex_lock_interruptible(&moxa_openlock))
		return -ERESTARTSYS;
1182
	brd = &moxa_boards[port / MAX_PORTS_PER_BOARD];
J
Jiri Slaby 已提交
1183 1184
	if (!brd->ready) {
		mutex_unlock(&moxa_openlock);
1185
		return -ENODEV;
J
Jiri Slaby 已提交
1186
	}
L
Linus Torvalds 已提交
1187

1188 1189 1190 1191 1192
	if (port % MAX_PORTS_PER_BOARD >= brd->numPorts) {
		mutex_unlock(&moxa_openlock);
		return -ENODEV;
	}

1193
	ch = &brd->ports[port % MAX_PORTS_PER_BOARD];
A
Alan Cox 已提交
1194
	ch->port.count++;
L
Linus Torvalds 已提交
1195
	tty->driver_data = ch;
A
Alan Cox 已提交
1196
	tty_port_tty_set(&ch->port, tty);
A
Alan Cox 已提交
1197
	if (!(ch->port.flags & ASYNC_INITIALIZED)) {
L
Linus Torvalds 已提交
1198
		ch->statusflags = 0;
A
Alan Cox 已提交
1199
		moxa_set_tty_param(tty, tty->termios);
J
Jiri Slaby 已提交
1200 1201
		MoxaPortLineCtrl(ch, 1, 1);
		MoxaPortEnable(ch);
J
Jiri Slaby 已提交
1202
		MoxaSetFifo(ch, ch->type == PORT_16550A);
A
Alan Cox 已提交
1203
		ch->port.flags |= ASYNC_INITIALIZED;
L
Linus Torvalds 已提交
1204
	}
J
Jiri Slaby 已提交
1205
	mutex_unlock(&moxa_openlock);
L
Linus Torvalds 已提交
1206

J
Jiri Slaby 已提交
1207 1208 1209 1210 1211
	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) {
A
Alan Cox 已提交
1212 1213
		if (ch->port.count) /* 0 means already hung up... */
			if (--ch->port.count == 0)
A
Alan Cox 已提交
1214
				moxa_close_port(tty);
J
Jiri Slaby 已提交
1215
	} else
A
Alan Cox 已提交
1216
		ch->port.flags |= ASYNC_NORMAL_ACTIVE;
J
Jiri Slaby 已提交
1217
	mutex_unlock(&moxa_openlock);
1218

J
Jiri Slaby 已提交
1219
	return retval;
L
Linus Torvalds 已提交
1220 1221 1222 1223
}

static void moxa_close(struct tty_struct *tty, struct file *filp)
{
1224
	struct moxa_port *ch;
L
Linus Torvalds 已提交
1225 1226
	int port;

J
Jiri Slaby 已提交
1227
	port = tty->index;
J
Jiri Slaby 已提交
1228
	if (port == MAX_PORTS || tty_hung_up_p(filp))
L
Linus Torvalds 已提交
1229 1230
		return;

J
Jiri Slaby 已提交
1231 1232 1233 1234
	mutex_lock(&moxa_openlock);
	ch = tty->driver_data;
	if (ch == NULL)
		goto unlock;
A
Alan Cox 已提交
1235
	if (tty->count == 1 && ch->port.count != 1) {
J
Jiri Slaby 已提交
1236
		printk(KERN_WARNING "moxa_close: bad serial port count; "
A
Alan Cox 已提交
1237 1238
			"tty->count is 1, ch->port.count is %d\n", ch->port.count);
		ch->port.count = 1;
L
Linus Torvalds 已提交
1239
	}
A
Alan Cox 已提交
1240
	if (--ch->port.count < 0) {
J
Jiri Slaby 已提交
1241 1242
		printk(KERN_WARNING "moxa_close: bad serial port count, "
			"device=%s\n", tty->name);
A
Alan Cox 已提交
1243
		ch->port.count = 0;
L
Linus Torvalds 已提交
1244
	}
A
Alan Cox 已提交
1245
	if (ch->port.count)
J
Jiri Slaby 已提交
1246
		goto unlock;
L
Linus Torvalds 已提交
1247 1248

	ch->cflag = tty->termios->c_cflag;
A
Alan Cox 已提交
1249
	if (ch->port.flags & ASYNC_INITIALIZED) {
J
Jiri Slaby 已提交
1250
		moxa_setup_empty_event(tty);
L
Linus Torvalds 已提交
1251 1252 1253
		tty_wait_until_sent(tty, 30 * HZ);	/* 30 seconds timeout */
	}

A
Alan Cox 已提交
1254
	moxa_close_port(tty);
J
Jiri Slaby 已提交
1255 1256
unlock:
	mutex_unlock(&moxa_openlock);
L
Linus Torvalds 已提交
1257 1258 1259 1260 1261
}

static int moxa_write(struct tty_struct *tty,
		      const unsigned char *buf, int count)
{
J
Jiri Slaby 已提交
1262 1263
	struct moxa_port *ch = tty->driver_data;
	int len;
L
Linus Torvalds 已提交
1264 1265

	if (ch == NULL)
J
Jiri Slaby 已提交
1266
		return 0;
A
Alan Cox 已提交
1267

J
Jiri Slaby 已提交
1268
	spin_lock_bh(&moxa_lock);
A
Alan Cox 已提交
1269
	len = MoxaPortWriteData(tty, buf, count);
J
Jiri Slaby 已提交
1270
	spin_unlock_bh(&moxa_lock);
L
Linus Torvalds 已提交
1271 1272

	ch->statusflags |= LOWWAIT;
J
Jiri Slaby 已提交
1273
	return len;
L
Linus Torvalds 已提交
1274 1275 1276 1277
}

static int moxa_write_room(struct tty_struct *tty)
{
1278
	struct moxa_port *ch;
L
Linus Torvalds 已提交
1279 1280

	if (tty->stopped)
J
Jiri Slaby 已提交
1281
		return 0;
J
Jiri Slaby 已提交
1282
	ch = tty->driver_data;
L
Linus Torvalds 已提交
1283
	if (ch == NULL)
J
Jiri Slaby 已提交
1284
		return 0;
J
Jiri Slaby 已提交
1285
	return MoxaPortTxFree(ch);
L
Linus Torvalds 已提交
1286 1287 1288 1289
}

static void moxa_flush_buffer(struct tty_struct *tty)
{
J
Jiri Slaby 已提交
1290
	struct moxa_port *ch = tty->driver_data;
L
Linus Torvalds 已提交
1291 1292 1293

	if (ch == NULL)
		return;
J
Jiri Slaby 已提交
1294
	MoxaPortFlushData(ch, 1);
L
Linus Torvalds 已提交
1295 1296 1297 1298 1299
	tty_wakeup(tty);
}

static int moxa_chars_in_buffer(struct tty_struct *tty)
{
J
Jiri Slaby 已提交
1300
	struct moxa_port *ch = tty->driver_data;
L
Linus Torvalds 已提交
1301 1302 1303 1304 1305 1306 1307 1308 1309
	int chars;

	/*
	 * 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)
J
Jiri Slaby 已提交
1310
		return 0;
1311
	lock_kernel();
J
Jiri Slaby 已提交
1312
	chars = MoxaPortTxQueue(ch);
L
Linus Torvalds 已提交
1313 1314 1315 1316 1317 1318
	if (chars) {
		/*
		 * Make it possible to wakeup anything waiting for output
		 * in tty_ioctl.c, etc.
		 */
		if (!(ch->statusflags & EMPTYWAIT))
J
Jiri Slaby 已提交
1319
			moxa_setup_empty_event(tty);
L
Linus Torvalds 已提交
1320
	}
1321
	unlock_kernel();
J
Jiri Slaby 已提交
1322
	return chars;
L
Linus Torvalds 已提交
1323 1324 1325 1326
}

static int moxa_tiocmget(struct tty_struct *tty, struct file *file)
{
J
Jiri Slaby 已提交
1327
	struct moxa_port *ch;
L
Linus Torvalds 已提交
1328 1329
	int flag = 0, dtr, rts;

J
Jiri Slaby 已提交
1330 1331 1332 1333
	mutex_lock(&moxa_openlock);
	ch = tty->driver_data;
	if (!ch) {
		mutex_unlock(&moxa_openlock);
J
Jiri Slaby 已提交
1334
		return -EINVAL;
J
Jiri Slaby 已提交
1335
	}
L
Linus Torvalds 已提交
1336

J
Jiri Slaby 已提交
1337
	MoxaPortGetLineOut(ch, &dtr, &rts);
L
Linus Torvalds 已提交
1338 1339 1340 1341
	if (dtr)
		flag |= TIOCM_DTR;
	if (rts)
		flag |= TIOCM_RTS;
J
Jiri Slaby 已提交
1342
	dtr = MoxaPortLineStatus(ch);
L
Linus Torvalds 已提交
1343 1344 1345 1346 1347 1348
	if (dtr & 1)
		flag |= TIOCM_CTS;
	if (dtr & 2)
		flag |= TIOCM_DSR;
	if (dtr & 4)
		flag |= TIOCM_CD;
J
Jiri Slaby 已提交
1349
	mutex_unlock(&moxa_openlock);
L
Linus Torvalds 已提交
1350 1351 1352 1353 1354 1355
	return flag;
}

static int moxa_tiocmset(struct tty_struct *tty, struct file *file,
			 unsigned int set, unsigned int clear)
{
J
Jiri Slaby 已提交
1356
	struct moxa_port *ch;
L
Linus Torvalds 已提交
1357 1358 1359
	int port;
	int dtr, rts;

J
Jiri Slaby 已提交
1360
	port = tty->index;
J
Jiri Slaby 已提交
1361 1362 1363 1364
	mutex_lock(&moxa_openlock);
	ch = tty->driver_data;
	if (!ch) {
		mutex_unlock(&moxa_openlock);
J
Jiri Slaby 已提交
1365
		return -EINVAL;
J
Jiri Slaby 已提交
1366
	}
L
Linus Torvalds 已提交
1367

J
Jiri Slaby 已提交
1368
	MoxaPortGetLineOut(ch, &dtr, &rts);
L
Linus Torvalds 已提交
1369 1370 1371 1372 1373 1374 1375 1376
	if (set & TIOCM_RTS)
		rts = 1;
	if (set & TIOCM_DTR)
		dtr = 1;
	if (clear & TIOCM_RTS)
		rts = 0;
	if (clear & TIOCM_DTR)
		dtr = 0;
J
Jiri Slaby 已提交
1377
	MoxaPortLineCtrl(ch, dtr, rts);
J
Jiri Slaby 已提交
1378
	mutex_unlock(&moxa_openlock);
L
Linus Torvalds 已提交
1379 1380 1381 1382 1383
	return 0;
}

static void moxa_throttle(struct tty_struct *tty)
{
J
Jiri Slaby 已提交
1384
	struct moxa_port *ch = tty->driver_data;
L
Linus Torvalds 已提交
1385 1386 1387 1388 1389 1390

	ch->statusflags |= THROTTLE;
}

static void moxa_unthrottle(struct tty_struct *tty)
{
J
Jiri Slaby 已提交
1391
	struct moxa_port *ch = tty->driver_data;
L
Linus Torvalds 已提交
1392 1393 1394 1395 1396

	ch->statusflags &= ~THROTTLE;
}

static void moxa_set_termios(struct tty_struct *tty,
J
Jiri Slaby 已提交
1397
		struct ktermios *old_termios)
L
Linus Torvalds 已提交
1398
{
J
Jiri Slaby 已提交
1399
	struct moxa_port *ch = tty->driver_data;
L
Linus Torvalds 已提交
1400 1401 1402

	if (ch == NULL)
		return;
A
Alan Cox 已提交
1403
	moxa_set_tty_param(tty, old_termios);
J
Jiri Slaby 已提交
1404
	if (!(old_termios->c_cflag & CLOCAL) && C_CLOCAL(tty))
A
Alan Cox 已提交
1405
		wake_up_interruptible(&ch->port.open_wait);
L
Linus Torvalds 已提交
1406 1407 1408 1409
}

static void moxa_stop(struct tty_struct *tty)
{
J
Jiri Slaby 已提交
1410
	struct moxa_port *ch = tty->driver_data;
L
Linus Torvalds 已提交
1411 1412 1413

	if (ch == NULL)
		return;
J
Jiri Slaby 已提交
1414
	MoxaPortTxDisable(ch);
L
Linus Torvalds 已提交
1415 1416 1417 1418 1419 1420
	ch->statusflags |= TXSTOPPED;
}


static void moxa_start(struct tty_struct *tty)
{
J
Jiri Slaby 已提交
1421
	struct moxa_port *ch = tty->driver_data;
L
Linus Torvalds 已提交
1422 1423 1424 1425 1426 1427 1428

	if (ch == NULL)
		return;

	if (!(ch->statusflags & TXSTOPPED))
		return;

J
Jiri Slaby 已提交
1429
	MoxaPortTxEnable(ch);
L
Linus Torvalds 已提交
1430 1431 1432 1433 1434
	ch->statusflags &= ~TXSTOPPED;
}

static void moxa_hangup(struct tty_struct *tty)
{
J
Jiri Slaby 已提交
1435
	struct moxa_port *ch;
L
Linus Torvalds 已提交
1436

J
Jiri Slaby 已提交
1437 1438 1439 1440 1441 1442
	mutex_lock(&moxa_openlock);
	ch = tty->driver_data;
	if (ch == NULL) {
		mutex_unlock(&moxa_openlock);
		return;
	}
A
Alan Cox 已提交
1443
	ch->port.count = 0;
A
Alan Cox 已提交
1444
	moxa_close_port(tty);
J
Jiri Slaby 已提交
1445 1446
	mutex_unlock(&moxa_openlock);

A
Alan Cox 已提交
1447
	wake_up_interruptible(&ch->port.open_wait);
L
Linus Torvalds 已提交
1448 1449
}

J
Jiri Slaby 已提交
1450
static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd)
L
Linus Torvalds 已提交
1451
{
A
Alan Cox 已提交
1452
	struct tty_struct *tty;
J
Jiri Slaby 已提交
1453
	dcd = !!dcd;
L
Linus Torvalds 已提交
1454

A
Alan Cox 已提交
1455 1456 1457 1458 1459
	if (dcd != p->DCDState) {
		tty = tty_port_tty_get(&p->port);
		if (tty && C_CLOCAL(tty) && !dcd)
			tty_hangup(tty);
		tty_kref_put(tty);
J
Jiri Slaby 已提交
1460 1461 1462
	}
	p->DCDState = dcd;
}
L
Linus Torvalds 已提交
1463

J
Jiri Slaby 已提交
1464 1465 1466
static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
		u16 __iomem *ip)
{
A
Alan Cox 已提交
1467
	struct tty_struct *tty = tty_port_tty_get(&p->port);
J
Jiri Slaby 已提交
1468
	void __iomem *ofsAddr;
A
Alan Cox 已提交
1469
	unsigned int inited = p->port.flags & ASYNC_INITIALIZED;
J
Jiri Slaby 已提交
1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491
	u16 intr;

	if (tty) {
		if ((p->statusflags & EMPTYWAIT) &&
				MoxaPortTxQueue(p) == 0) {
			p->statusflags &= ~EMPTYWAIT;
			tty_wakeup(tty);
		}
		if ((p->statusflags & LOWWAIT) && !tty->stopped &&
				MoxaPortTxQueue(p) <= WAKEUP_CHARS) {
			p->statusflags &= ~LOWWAIT;
			tty_wakeup(tty);
		}

		if (inited && !(p->statusflags & THROTTLE) &&
				MoxaPortRxQueue(p) > 0) { /* RX */
			MoxaPortReadData(p);
			tty_schedule_flip(tty);
		}
	} else {
		p->statusflags &= ~EMPTYWAIT;
		MoxaPortFlushData(p, 0); /* flush RX */
L
Linus Torvalds 已提交
1492
	}
J
Jiri Slaby 已提交
1493

J
Jiri Slaby 已提交
1494
	if (!handle) /* nothing else to do */
1495
		goto put;
J
Jiri Slaby 已提交
1496 1497 1498

	intr = readw(ip); /* port irq status */
	if (intr == 0)
1499
		goto put;
J
Jiri Slaby 已提交
1500 1501 1502 1503 1504 1505 1506 1507

	writew(0, ip); /* ACK port */
	ofsAddr = p->tableAddr;
	if (intr & IntrTx) /* disable tx intr */
		writew(readw(ofsAddr + HostStat) & ~WakeupTx,
				ofsAddr + HostStat);

	if (!inited)
1508
		goto put;
J
Jiri Slaby 已提交
1509 1510 1511 1512 1513 1514 1515 1516

	if (tty && (intr & IntrBreak) && !I_IGNBRK(tty)) { /* BREAK */
		tty_insert_flip_char(tty, 0, TTY_BREAK);
		tty_schedule_flip(tty);
	}

	if (intr & IntrLine)
		moxa_new_dcdstate(p, readb(ofsAddr + FlagStat) & DCD_state);
1517 1518
put:
	tty_kref_put(tty);
J
Jiri Slaby 已提交
1519 1520 1521 1522 1523 1524 1525 1526

	return 0;
}

static void moxa_poll(unsigned long ignored)
{
	struct moxa_board_conf *brd;
	u16 __iomem *ip;
J
Jiri Slaby 已提交
1527
	unsigned int card, port, served = 0;
J
Jiri Slaby 已提交
1528 1529

	spin_lock(&moxa_lock);
L
Linus Torvalds 已提交
1530
	for (card = 0; card < MAX_BOARDS; card++) {
J
Jiri Slaby 已提交
1531 1532
		brd = &moxa_boards[card];
		if (!brd->ready)
L
Linus Torvalds 已提交
1533
			continue;
J
Jiri Slaby 已提交
1534

J
Jiri Slaby 已提交
1535 1536
		served++;

J
Jiri Slaby 已提交
1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552
		ip = NULL;
		if (readb(brd->intPend) == 0xff)
			ip = brd->intTable + readb(brd->intNdx);

		for (port = 0; port < brd->numPorts; port++)
			moxa_poll_port(&brd->ports[port], !!ip, ip + port);

		if (ip)
			writeb(0, brd->intPend); /* ACK */

		if (moxaLowWaterChk) {
			struct moxa_port *p = brd->ports;
			for (port = 0; port < brd->numPorts; port++, p++)
				if (p->lowChkFlag) {
					p->lowChkFlag = 0;
					moxa_low_water_check(p->tableAddr);
L
Linus Torvalds 已提交
1553 1554 1555
				}
		}
	}
J
Jiri Slaby 已提交
1556
	moxaLowWaterChk = 0;
L
Linus Torvalds 已提交
1557

J
Jiri Slaby 已提交
1558 1559 1560
	if (served)
		mod_timer(&moxaTimer, jiffies + HZ / 50);
	spin_unlock(&moxa_lock);
L
Linus Torvalds 已提交
1561 1562 1563 1564
}

/******************************************************************************/

A
Alan Cox 已提交
1565
static void moxa_set_tty_param(struct tty_struct *tty, struct ktermios *old_termios)
L
Linus Torvalds 已提交
1566
{
J
Jiri Slaby 已提交
1567 1568
	register struct ktermios *ts = tty->termios;
	struct moxa_port *ch = tty->driver_data;
A
Alan Cox 已提交
1569
	int rts, cts, txflow, rxflow, xany, baud;
L
Linus Torvalds 已提交
1570 1571 1572 1573 1574 1575 1576 1577 1578 1579

	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;
A
Alan Cox 已提交
1580 1581 1582

	/* Clear the features we don't support */
	ts->c_cflag &= ~CMSPAR;
J
Jiri Slaby 已提交
1583 1584
	MoxaPortFlowCtrl(ch, rts, cts, txflow, rxflow, xany);
	baud = MoxaPortSetTermio(ch, ts, tty_get_baud_rate(tty));
A
Alan Cox 已提交
1585 1586 1587 1588
	if (baud == -1)
		baud = tty_termios_baud_rate(old_termios);
	/* Not put the baud rate into the termios data */
	tty_encode_baud_rate(tty, baud, baud);
L
Linus Torvalds 已提交
1589 1590
}

J
Jiri Slaby 已提交
1591
static void moxa_setup_empty_event(struct tty_struct *tty)
L
Linus Torvalds 已提交
1592
{
1593
	struct moxa_port *ch = tty->driver_data;
L
Linus Torvalds 已提交
1594

J
Jiri Slaby 已提交
1595
	spin_lock_bh(&moxa_lock);
L
Linus Torvalds 已提交
1596
	ch->statusflags |= EMPTYWAIT;
J
Jiri Slaby 已提交
1597
	spin_unlock_bh(&moxa_lock);
L
Linus Torvalds 已提交
1598 1599
}

A
Alan Cox 已提交
1600
static void moxa_shut_down(struct tty_struct *tty)
L
Linus Torvalds 已提交
1601
{
A
Alan Cox 已提交
1602
	struct moxa_port *ch = tty->driver_data;
L
Linus Torvalds 已提交
1603

A
Alan Cox 已提交
1604
	if (!(ch->port.flags & ASYNC_INITIALIZED))
L
Linus Torvalds 已提交
1605 1606
		return;

J
Jiri Slaby 已提交
1607
	MoxaPortDisable(ch);
L
Linus Torvalds 已提交
1608 1609 1610 1611

	/*
	 * If we're a modem control device and HUPCL is on, drop RTS & DTR.
	 */
A
Alan Cox 已提交
1612
	if (C_HUPCL(tty))
J
Jiri Slaby 已提交
1613
		MoxaPortLineCtrl(ch, 0, 0);
L
Linus Torvalds 已提交
1614

J
Jiri Slaby 已提交
1615
	spin_lock_bh(&moxa_lock);
A
Alan Cox 已提交
1616
	ch->port.flags &= ~ASYNC_INITIALIZED;
J
Jiri Slaby 已提交
1617
	spin_unlock_bh(&moxa_lock);
L
Linus Torvalds 已提交
1618 1619 1620 1621 1622 1623
}

/*****************************************************************************
 *	Driver level functions: 					     *
 *****************************************************************************/

J
Jiri Slaby 已提交
1624
static void MoxaPortFlushData(struct moxa_port *port, int mode)
L
Linus Torvalds 已提交
1625 1626
{
	void __iomem *ofsAddr;
J
Jiri Slaby 已提交
1627
	if (mode < 0 || mode > 2)
L
Linus Torvalds 已提交
1628
		return;
J
Jiri Slaby 已提交
1629
	ofsAddr = port->tableAddr;
L
Linus Torvalds 已提交
1630 1631
	moxafunc(ofsAddr, FC_FlushQueue, mode);
	if (mode != 1) {
J
Jiri Slaby 已提交
1632
		port->lowChkFlag = 0;
J
Jiri Slaby 已提交
1633
		moxa_low_water_check(ofsAddr);
L
Linus Torvalds 已提交
1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686
	}
}

/*
 *    Moxa Port Number Description:
 *
 *      MOXA serial driver supports up to 4 MOXA-C218/C320 boards. And,
 *      the port number using in MOXA driver functions will be 0 to 31 for
 *      first MOXA board, 32 to 63 for second, 64 to 95 for third and 96
 *      to 127 for fourth. For example, if you setup three MOXA boards,
 *      first board is C218, second board is C320-16 and third board is
 *      C320-32. The port number of first board (C218 - 8 ports) is from
 *      0 to 7. The port number of second board (C320 - 16 ports) is form
 *      32 to 47. The port number of third board (C320 - 32 ports) is from
 *      64 to 95. And those port numbers form 8 to 31, 48 to 63 and 96 to
 *      127 will be invalid.
 *
 *
 *      Moxa Functions Description:
 *
 *      Function 1:     Driver initialization routine, this routine must be
 *                      called when initialized driver.
 *      Syntax:
 *      void MoxaDriverInit();
 *
 *
 *      Function 2:     Moxa driver private IOCTL command processing.
 *      Syntax:
 *      int  MoxaDriverIoctl(unsigned int cmd, unsigned long arg, int port);
 *
 *           unsigned int cmd   : IOCTL command
 *           unsigned long arg  : IOCTL argument
 *           int port           : port number (0 - 127)
 *
 *           return:    0  (OK)
 *                      -EINVAL
 *                      -ENOIOCTLCMD
 *
 *
 *      Function 6:     Enable this port to start Tx/Rx data.
 *      Syntax:
 *      void MoxaPortEnable(int port);
 *           int port           : port number (0 - 127)
 *
 *
 *      Function 7:     Disable this port
 *      Syntax:
 *      void MoxaPortDisable(int port);
 *           int port           : port number (0 - 127)
 *
 *
 *      Function 10:    Setting baud rate of this port.
 *      Syntax:
1687
 *      speed_t MoxaPortSetBaud(int port, speed_t baud);
L
Linus Torvalds 已提交
1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699
 *           int port           : port number (0 - 127)
 *           long baud          : baud rate (50 - 115200)
 *
 *           return:    0       : this port is invalid or baud < 50
 *                      50 - 115200 : the real baud rate set to the port, if
 *                                    the argument baud is large than maximun
 *                                    available baud rate, the real setting
 *                                    baud rate will be the maximun baud rate.
 *
 *
 *      Function 12:    Configure the port.
 *      Syntax:
A
Alan Cox 已提交
1700
 *      int  MoxaPortSetTermio(int port, struct ktermios *termio, speed_t baud);
L
Linus Torvalds 已提交
1701
 *           int port           : port number (0 - 127)
A
Alan Cox 已提交
1702
 *           struct ktermios * termio : termio structure pointer
1703
 *	     speed_t baud	: baud rate
L
Linus Torvalds 已提交
1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775
 *
 *           return:    -1      : this port is invalid or termio == NULL
 *                      0       : setting O.K.
 *
 *
 *      Function 13:    Get the DTR/RTS state of this port.
 *      Syntax:
 *      int  MoxaPortGetLineOut(int port, int *dtrState, int *rtsState);
 *           int port           : port number (0 - 127)
 *           int * dtrState     : pointer to INT to receive the current DTR
 *                                state. (if NULL, this function will not
 *                                write to this address)
 *           int * rtsState     : pointer to INT to receive the current RTS
 *                                state. (if NULL, this function will not
 *                                write to this address)
 *
 *           return:    -1      : this port is invalid
 *                      0       : O.K.
 *
 *
 *      Function 14:    Setting the DTR/RTS output state of this port.
 *      Syntax:
 *      void MoxaPortLineCtrl(int port, int dtrState, int rtsState);
 *           int port           : port number (0 - 127)
 *           int dtrState       : DTR output state (0: off, 1: on)
 *           int rtsState       : RTS output state (0: off, 1: on)
 *
 *
 *      Function 15:    Setting the flow control of this port.
 *      Syntax:
 *      void MoxaPortFlowCtrl(int port, int rtsFlow, int ctsFlow, int rxFlow,
 *                            int txFlow,int xany);
 *           int port           : port number (0 - 127)
 *           int rtsFlow        : H/W RTS flow control (0: no, 1: yes)
 *           int ctsFlow        : H/W CTS flow control (0: no, 1: yes)
 *           int rxFlow         : S/W Rx XON/XOFF flow control (0: no, 1: yes)
 *           int txFlow         : S/W Tx XON/XOFF flow control (0: no, 1: yes)
 *           int xany           : S/W XANY flow control (0: no, 1: yes)
 *
 *
 *      Function 16:    Get ths line status of this port
 *      Syntax:
 *      int  MoxaPortLineStatus(int port);
 *           int port           : port number (0 - 127)
 *
 *           return:    Bit 0 - CTS state (0: off, 1: on)
 *                      Bit 1 - DSR state (0: off, 1: on)
 *                      Bit 2 - DCD state (0: off, 1: on)
 *
 *
 *      Function 19:    Flush the Rx/Tx buffer data of this port.
 *      Syntax:
 *      void MoxaPortFlushData(int port, int mode);
 *           int port           : port number (0 - 127)
 *           int mode    
 *                      0       : flush the Rx buffer 
 *                      1       : flush the Tx buffer 
 *                      2       : flush the Rx and Tx buffer 
 *
 *
 *      Function 20:    Write data.
 *      Syntax:
 *      int  MoxaPortWriteData(int port, unsigned char * buffer, int length);
 *           int port           : port number (0 - 127)
 *           unsigned char * buffer     : pointer to write data buffer.
 *           int length         : write data length
 *
 *           return:    0 - length      : real write data length
 *
 *
 *      Function 21:    Read data.
 *      Syntax:
A
Alan Cox 已提交
1776
 *      int  MoxaPortReadData(int port, struct tty_struct *tty);
L
Linus Torvalds 已提交
1777
 *           int port           : port number (0 - 127)
A
Alan Cox 已提交
1778
 *	     struct tty_struct *tty : tty for data
L
Linus Torvalds 已提交
1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828
 *
 *           return:    0 - length      : real read data length
 *
 *
 *      Function 24:    Get the Tx buffer current queued data bytes
 *      Syntax:
 *      int  MoxaPortTxQueue(int port);
 *           int port           : port number (0 - 127)
 *
 *           return:    ..      : Tx buffer current queued data bytes
 *
 *
 *      Function 25:    Get the Tx buffer current free space
 *      Syntax:
 *      int  MoxaPortTxFree(int port);
 *           int port           : port number (0 - 127)
 *
 *           return:    ..      : Tx buffer current free space
 *
 *
 *      Function 26:    Get the Rx buffer current queued data bytes
 *      Syntax:
 *      int  MoxaPortRxQueue(int port);
 *           int port           : port number (0 - 127)
 *
 *           return:    ..      : Rx buffer current queued data bytes
 *
 *
 *      Function 28:    Disable port data transmission.
 *      Syntax:
 *      void MoxaPortTxDisable(int port);
 *           int port           : port number (0 - 127)
 *
 *
 *      Function 29:    Enable port data transmission.
 *      Syntax:
 *      void MoxaPortTxEnable(int port);
 *           int port           : port number (0 - 127)
 *
 *
 *      Function 31:    Get the received BREAK signal count and reset it.
 *      Syntax:
 *      int  MoxaPortResetBrkCnt(int port);
 *           int port           : port number (0 - 127)
 *
 *           return:    0 - ..  : BREAK signal count
 *
 *
 */

J
Jiri Slaby 已提交
1829
static void MoxaPortEnable(struct moxa_port *port)
L
Linus Torvalds 已提交
1830 1831
{
	void __iomem *ofsAddr;
J
Jiri Slaby 已提交
1832
	u16 lowwater = 512;
L
Linus Torvalds 已提交
1833

J
Jiri Slaby 已提交
1834
	ofsAddr = port->tableAddr;
L
Linus Torvalds 已提交
1835
	writew(lowwater, ofsAddr + Low_water);
1836
	if (MOXA_IS_320(port->board))
L
Linus Torvalds 已提交
1837
		moxafunc(ofsAddr, FC_SetBreakIrq, 0);
J
Jiri Slaby 已提交
1838 1839 1840
	else
		writew(readw(ofsAddr + HostStat) | WakeupBreak,
				ofsAddr + HostStat);
L
Linus Torvalds 已提交
1841 1842 1843 1844 1845 1846 1847 1848

	moxafunc(ofsAddr, FC_SetLineIrq, Magic_code);
	moxafunc(ofsAddr, FC_FlushQueue, 2);

	moxafunc(ofsAddr, FC_EnableCH, Magic_code);
	MoxaPortLineStatus(port);
}

J
Jiri Slaby 已提交
1849
static void MoxaPortDisable(struct moxa_port *port)
L
Linus Torvalds 已提交
1850
{
J
Jiri Slaby 已提交
1851
	void __iomem *ofsAddr = port->tableAddr;
L
Linus Torvalds 已提交
1852 1853 1854 1855 1856 1857 1858

	moxafunc(ofsAddr, FC_SetFlowCtl, 0);	/* disable flow control */
	moxafunc(ofsAddr, FC_ClrLineIrq, Magic_code);
	writew(0, ofsAddr + HostStat);
	moxafunc(ofsAddr, FC_DisableCH, Magic_code);
}

1859
static speed_t MoxaPortSetBaud(struct moxa_port *port, speed_t baud)
L
Linus Torvalds 已提交
1860
{
1861 1862 1863
	void __iomem *ofsAddr = port->tableAddr;
	unsigned int clock, val;
	speed_t max;
L
Linus Torvalds 已提交
1864

1865 1866
	max = MOXA_IS_320(port->board) ? 460800 : 921600;
	if (baud < 50)
J
Jiri Slaby 已提交
1867
		return 0;
L
Linus Torvalds 已提交
1868 1869
	if (baud > max)
		baud = max;
1870
	clock = 921600;
L
Linus Torvalds 已提交
1871 1872 1873
	val = clock / baud;
	moxafunc(ofsAddr, FC_SetBaud, val);
	baud = clock / val;
J
Jiri Slaby 已提交
1874
	return baud;
L
Linus Torvalds 已提交
1875 1876
}

J
Jiri Slaby 已提交
1877 1878
static int MoxaPortSetTermio(struct moxa_port *port, struct ktermios *termio,
		speed_t baud)
L
Linus Torvalds 已提交
1879 1880 1881 1882 1883
{
	void __iomem *ofsAddr;
	tcflag_t cflag;
	tcflag_t mode = 0;

J
Jiri Slaby 已提交
1884
	ofsAddr = port->tableAddr;
L
Linus Torvalds 已提交
1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912
	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;

J
Jiri Slaby 已提交
1913
	moxafunc(ofsAddr, FC_SetDataMode, (u16)mode);
L
Linus Torvalds 已提交
1914

1915 1916 1917
	if (MOXA_IS_320(port->board) && baud >= 921600)
		return -1;

A
Alan Cox 已提交
1918
	baud = MoxaPortSetBaud(port, baud);
L
Linus Torvalds 已提交
1919 1920 1921 1922 1923

	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);
J
Jiri Slaby 已提交
1924
		moxa_wait_finish(ofsAddr);
L
Linus Torvalds 已提交
1925 1926

	}
J
Jiri Slaby 已提交
1927
	return baud;
L
Linus Torvalds 已提交
1928 1929
}

J
Jiri Slaby 已提交
1930 1931
static int MoxaPortGetLineOut(struct moxa_port *port, int *dtrState,
		int *rtsState)
L
Linus Torvalds 已提交
1932
{
J
Jiri Slaby 已提交
1933 1934 1935 1936 1937
	if (dtrState)
		*dtrState = !!(port->lineCtrl & DTR_ON);
	if (rtsState)
		*rtsState = !!(port->lineCtrl & RTS_ON);

J
Jiri Slaby 已提交
1938
	return 0;
L
Linus Torvalds 已提交
1939 1940
}

J
Jiri Slaby 已提交
1941
static void MoxaPortLineCtrl(struct moxa_port *port, int dtr, int rts)
L
Linus Torvalds 已提交
1942
{
J
Jiri Slaby 已提交
1943
	u8 mode = 0;
L
Linus Torvalds 已提交
1944 1945 1946 1947 1948

	if (dtr)
		mode |= DTR_ON;
	if (rts)
		mode |= RTS_ON;
J
Jiri Slaby 已提交
1949 1950
	port->lineCtrl = mode;
	moxafunc(port->tableAddr, FC_LineControl, mode);
L
Linus Torvalds 已提交
1951 1952
}

J
Jiri Slaby 已提交
1953 1954
static void MoxaPortFlowCtrl(struct moxa_port *port, int rts, int cts,
		int txflow, int rxflow, int txany)
L
Linus Torvalds 已提交
1955
{
J
Jiri Slaby 已提交
1956
	int mode = 0;
L
Linus Torvalds 已提交
1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967

	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;
J
Jiri Slaby 已提交
1968
	moxafunc(port->tableAddr, FC_SetFlowCtl, mode);
L
Linus Torvalds 已提交
1969 1970
}

J
Jiri Slaby 已提交
1971
static int MoxaPortLineStatus(struct moxa_port *port)
L
Linus Torvalds 已提交
1972 1973 1974 1975
{
	void __iomem *ofsAddr;
	int val;

J
Jiri Slaby 已提交
1976
	ofsAddr = port->tableAddr;
1977
	if (MOXA_IS_320(port->board)) {
L
Linus Torvalds 已提交
1978 1979 1980 1981 1982 1983
		moxafunc(ofsAddr, FC_LineStatus, 0);
		val = readw(ofsAddr + FuncArg);
	} else {
		val = readw(ofsAddr + FlagStat) >> 4;
	}
	val &= 0x0B;
J
Jiri Slaby 已提交
1984
	if (val & 8)
L
Linus Torvalds 已提交
1985
		val |= 4;
J
Jiri Slaby 已提交
1986
	spin_lock_bh(&moxa_lock);
J
Jiri Slaby 已提交
1987
	moxa_new_dcdstate(port, val & 8);
J
Jiri Slaby 已提交
1988
	spin_unlock_bh(&moxa_lock);
L
Linus Torvalds 已提交
1989
	val &= 7;
J
Jiri Slaby 已提交
1990
	return val;
L
Linus Torvalds 已提交
1991 1992
}

A
Alan Cox 已提交
1993
static int MoxaPortWriteData(struct tty_struct *tty,
J
Jiri Slaby 已提交
1994
		const unsigned char *buffer, int len)
L
Linus Torvalds 已提交
1995
{
A
Alan Cox 已提交
1996
	struct moxa_port *port = tty->driver_data;
L
Linus Torvalds 已提交
1997
	void __iomem *baseAddr, *ofsAddr, *ofs;
J
Jiri Slaby 已提交
1998 1999 2000
	unsigned int c, total;
	u16 head, tail, tx_mask, spage, epage;
	u16 pageno, pageofs, bufhead;
L
Linus Torvalds 已提交
2001

J
Jiri Slaby 已提交
2002 2003
	ofsAddr = port->tableAddr;
	baseAddr = port->board->basemem;
L
Linus Torvalds 已提交
2004 2005 2006 2007 2008
	tx_mask = readw(ofsAddr + TX_mask);
	spage = readw(ofsAddr + Page_txb);
	epage = readw(ofsAddr + EndPage_txb);
	tail = readw(ofsAddr + TXwptr);
	head = readw(ofsAddr + TXrptr);
J
Jiri Slaby 已提交
2009
	c = (head > tail) ? (head - tail - 1) : (head - tail + tx_mask);
L
Linus Torvalds 已提交
2010 2011
	if (c > len)
		c = len;
A
Alan Cox 已提交
2012
	moxaLog.txcnt[port->port.tty->index] += c;
L
Linus Torvalds 已提交
2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023
	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;
J
Jiri Slaby 已提交
2024 2025
			memcpy_toio(ofs, buffer, len);
			buffer += len;
L
Linus Torvalds 已提交
2026 2027 2028 2029 2030 2031
			tail = (tail + len) & tx_mask;
			c -= len;
		}
	} else {
		pageno = spage + (tail >> 13);
		pageofs = tail & Page_mask;
J
Jiri Slaby 已提交
2032 2033 2034 2035
		while (c > 0) {
			len = Page_size - pageofs;
			if (len > c)
				len = c;
L
Linus Torvalds 已提交
2036 2037
			writeb(pageno, baseAddr + Control_reg);
			ofs = baseAddr + DynPage_addr + pageofs;
J
Jiri Slaby 已提交
2038 2039
			memcpy_toio(ofs, buffer, len);
			buffer += len;
L
Linus Torvalds 已提交
2040 2041 2042
			if (++pageno == epage)
				pageno = spage;
			pageofs = 0;
J
Jiri Slaby 已提交
2043 2044 2045
			c -= len;
		}
		tail = (tail + total) & tx_mask;
L
Linus Torvalds 已提交
2046
	}
J
Jiri Slaby 已提交
2047
	writew(tail, ofsAddr + TXwptr);
L
Linus Torvalds 已提交
2048
	writeb(1, ofsAddr + CD180TXirq);	/* start to send */
J
Jiri Slaby 已提交
2049
	return total;
L
Linus Torvalds 已提交
2050 2051
}

J
Jiri Slaby 已提交
2052
static int MoxaPortReadData(struct moxa_port *port)
L
Linus Torvalds 已提交
2053
{
A
Alan Cox 已提交
2054
	struct tty_struct *tty = port->port.tty;
J
Jiri Slaby 已提交
2055
	unsigned char *dst;
L
Linus Torvalds 已提交
2056
	void __iomem *baseAddr, *ofsAddr, *ofs;
J
Jiri Slaby 已提交
2057 2058 2059
	unsigned int count, len, total;
	u16 tail, rx_mask, spage, epage;
	u16 pageno, pageofs, bufhead, head;
L
Linus Torvalds 已提交
2060

J
Jiri Slaby 已提交
2061 2062
	ofsAddr = port->tableAddr;
	baseAddr = port->board->basemem;
L
Linus Torvalds 已提交
2063 2064 2065 2066 2067
	head = readw(ofsAddr + RXrptr);
	tail = readw(ofsAddr + RXwptr);
	rx_mask = readw(ofsAddr + RX_mask);
	spage = readw(ofsAddr + Page_rxb);
	epage = readw(ofsAddr + EndPage_rxb);
J
Jiri Slaby 已提交
2068
	count = (tail >= head) ? (tail - head) : (tail - head + rx_mask + 1);
L
Linus Torvalds 已提交
2069
	if (count == 0)
A
Alan Cox 已提交
2070
		return 0;
L
Linus Torvalds 已提交
2071

A
Alan Cox 已提交
2072
	total = count;
J
Jiri Slaby 已提交
2073
	moxaLog.rxcnt[tty->index] += total;
L
Linus Torvalds 已提交
2074 2075 2076 2077 2078
	if (spage == epage) {
		bufhead = readw(ofsAddr + Ofs_rxb);
		writew(spage, baseAddr + Control_reg);
		while (count > 0) {
			ofs = baseAddr + DynPage_addr + bufhead + head;
J
Jiri Slaby 已提交
2079 2080 2081 2082 2083
			len = (tail >= head) ? (tail - head) :
					(rx_mask + 1 - head);
			len = tty_prepare_flip_string(tty, &dst,
					min(len, count));
			memcpy_fromio(dst, ofs, len);
L
Linus Torvalds 已提交
2084 2085 2086 2087 2088 2089
			head = (head + len) & rx_mask;
			count -= len;
		}
	} else {
		pageno = spage + (head >> 13);
		pageofs = head & Page_mask;
J
Jiri Slaby 已提交
2090
		while (count > 0) {
L
Linus Torvalds 已提交
2091 2092
			writew(pageno, baseAddr + Control_reg);
			ofs = baseAddr + DynPage_addr + pageofs;
J
Jiri Slaby 已提交
2093 2094 2095 2096 2097 2098 2099
			len = tty_prepare_flip_string(tty, &dst,
					min(Page_size - pageofs, count));
			memcpy_fromio(dst, ofs, len);

			count -= len;
			pageofs = (pageofs + len) & Page_mask;
			if (pageofs == 0 && ++pageno == epage)
L
Linus Torvalds 已提交
2100
				pageno = spage;
J
Jiri Slaby 已提交
2101 2102
		}
		head = (head + total) & rx_mask;
L
Linus Torvalds 已提交
2103
	}
J
Jiri Slaby 已提交
2104 2105
	writew(head, ofsAddr + RXrptr);
	if (readb(ofsAddr + FlagStat) & Xoff_state) {
L
Linus Torvalds 已提交
2106
		moxaLowWaterChk = 1;
J
Jiri Slaby 已提交
2107
		port->lowChkFlag = 1;
L
Linus Torvalds 已提交
2108
	}
J
Jiri Slaby 已提交
2109
	return total;
L
Linus Torvalds 已提交
2110 2111 2112
}


J
Jiri Slaby 已提交
2113
static int MoxaPortTxQueue(struct moxa_port *port)
L
Linus Torvalds 已提交
2114
{
J
Jiri Slaby 已提交
2115
	void __iomem *ofsAddr = port->tableAddr;
J
Jiri Slaby 已提交
2116
	u16 rptr, wptr, mask;
L
Linus Torvalds 已提交
2117 2118 2119 2120

	rptr = readw(ofsAddr + TXrptr);
	wptr = readw(ofsAddr + TXwptr);
	mask = readw(ofsAddr + TX_mask);
J
Jiri Slaby 已提交
2121
	return (wptr - rptr) & mask;
L
Linus Torvalds 已提交
2122 2123
}

J
Jiri Slaby 已提交
2124
static int MoxaPortTxFree(struct moxa_port *port)
L
Linus Torvalds 已提交
2125
{
J
Jiri Slaby 已提交
2126
	void __iomem *ofsAddr = port->tableAddr;
J
Jiri Slaby 已提交
2127
	u16 rptr, wptr, mask;
L
Linus Torvalds 已提交
2128 2129 2130 2131

	rptr = readw(ofsAddr + TXrptr);
	wptr = readw(ofsAddr + TXwptr);
	mask = readw(ofsAddr + TX_mask);
J
Jiri Slaby 已提交
2132
	return mask - ((wptr - rptr) & mask);
L
Linus Torvalds 已提交
2133 2134
}

J
Jiri Slaby 已提交
2135
static int MoxaPortRxQueue(struct moxa_port *port)
L
Linus Torvalds 已提交
2136
{
J
Jiri Slaby 已提交
2137
	void __iomem *ofsAddr = port->tableAddr;
J
Jiri Slaby 已提交
2138
	u16 rptr, wptr, mask;
L
Linus Torvalds 已提交
2139 2140 2141 2142

	rptr = readw(ofsAddr + RXrptr);
	wptr = readw(ofsAddr + RXwptr);
	mask = readw(ofsAddr + RX_mask);
J
Jiri Slaby 已提交
2143
	return (wptr - rptr) & mask;
L
Linus Torvalds 已提交
2144 2145
}

J
Jiri Slaby 已提交
2146
static void MoxaPortTxDisable(struct moxa_port *port)
L
Linus Torvalds 已提交
2147
{
J
Jiri Slaby 已提交
2148
	moxafunc(port->tableAddr, FC_SetXoffState, Magic_code);
L
Linus Torvalds 已提交
2149 2150
}

J
Jiri Slaby 已提交
2151
static void MoxaPortTxEnable(struct moxa_port *port)
L
Linus Torvalds 已提交
2152
{
J
Jiri Slaby 已提交
2153
	moxafunc(port->tableAddr, FC_SetXonState, Magic_code);
L
Linus Torvalds 已提交
2154 2155
}

2156
static int moxa_get_serial_info(struct moxa_port *info,
J
Jiri Slaby 已提交
2157
		struct serial_struct __user *retinfo)
L
Linus Torvalds 已提交
2158
{
J
Jiri Slaby 已提交
2159 2160
	struct serial_struct tmp = {
		.type = info->type,
A
Alan Cox 已提交
2161 2162
		.line = info->port.tty->index,
		.flags = info->port.flags,
J
Jiri Slaby 已提交
2163
		.baud_base = 921600,
A
Alan Cox 已提交
2164
		.close_delay = info->port.close_delay
J
Jiri Slaby 已提交
2165 2166
	};
	return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
L
Linus Torvalds 已提交
2167 2168 2169
}


2170
static int moxa_set_serial_info(struct moxa_port *info,
J
Jiri Slaby 已提交
2171
		struct serial_struct __user *new_info)
L
Linus Torvalds 已提交
2172 2173 2174
{
	struct serial_struct new_serial;

J
Jiri Slaby 已提交
2175
	if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
L
Linus Torvalds 已提交
2176 2177
		return -EFAULT;

J
Jiri Slaby 已提交
2178 2179 2180 2181
	if (new_serial.irq != 0 || new_serial.port != 0 ||
			new_serial.custom_divisor != 0 ||
			new_serial.baud_base != 921600)
		return -EPERM;
L
Linus Torvalds 已提交
2182 2183 2184

	if (!capable(CAP_SYS_ADMIN)) {
		if (((new_serial.flags & ~ASYNC_USR_MASK) !=
A
Alan Cox 已提交
2185
		     (info->port.flags & ~ASYNC_USR_MASK)))
J
Jiri Slaby 已提交
2186 2187
			return -EPERM;
	} else
A
Alan Cox 已提交
2188
		info->port.close_delay = new_serial.close_delay * HZ / 100;
L
Linus Torvalds 已提交
2189 2190

	new_serial.flags = (new_serial.flags & ~ASYNC_FLAGS);
A
Alan Cox 已提交
2191
	new_serial.flags |= (info->port.flags & ASYNC_FLAGS);
L
Linus Torvalds 已提交
2192

J
Jiri Slaby 已提交
2193
	MoxaSetFifo(info, new_serial.type == PORT_16550A);
L
Linus Torvalds 已提交
2194 2195

	info->type = new_serial.type;
J
Jiri Slaby 已提交
2196
	return 0;
L
Linus Torvalds 已提交
2197 2198 2199 2200 2201 2202 2203 2204
}



/*****************************************************************************
 *	Static local functions: 					     *
 *****************************************************************************/

J
Jiri Slaby 已提交
2205
static void MoxaSetFifo(struct moxa_port *port, int enable)
L
Linus Torvalds 已提交
2206
{
J
Jiri Slaby 已提交
2207
	void __iomem *ofsAddr = port->tableAddr;
L
Linus Torvalds 已提交
2208 2209 2210 2211 2212 2213 2214 2215 2216

	if (!enable) {
		moxafunc(ofsAddr, FC_SetRxFIFOTrig, 0);
		moxafunc(ofsAddr, FC_SetTxFIFOCnt, 1);
	} else {
		moxafunc(ofsAddr, FC_SetRxFIFOTrig, 3);
		moxafunc(ofsAddr, FC_SetTxFIFOCnt, 16);
	}
}