moxa.c 52.5 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3 4
/*****************************************************************************/
/*
 *           moxa.c  -- MOXA Intellio family multiport serial driver.
 *
Jiri Slaby's avatar
Jiri Slaby committed
5 6
 *      Copyright (C) 1999-2000  Moxa Technologies (support@moxa.com).
 *      Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com>
Linus Torvalds's avatar
Linus Torvalds committed
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>
Jiri Slaby's avatar
Jiri Slaby committed
29
#include <linux/firmware.h>
Linus Torvalds's avatar
Linus Torvalds committed
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>
Alexey Dobriyan's avatar
Alexey Dobriyan committed
37
#include <linux/smp_lock.h>
Linus Torvalds's avatar
Linus Torvalds committed
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>

Jiri Slaby's avatar
Jiri Slaby committed
52 53
#include "moxa.h"

Jiri Slaby's avatar
Jiri Slaby committed
54
#define MOXA_VERSION		"6.0k"
Linus Torvalds's avatar
Linus Torvalds committed
55

Jiri Slaby's avatar
Jiri Slaby committed
56 57
#define MOXA_FW_HDRLEN		32

58
#define MOXAMAJOR		172
Linus Torvalds's avatar
Linus Torvalds committed
59

60
#define MAX_BOARDS		4	/* Don't change this value */
Linus Torvalds's avatar
Linus Torvalds committed
61
#define MAX_PORTS_PER_BOARD	32	/* Don't change this value */
62
#define MAX_PORTS		(MAX_BOARDS * MAX_PORTS_PER_BOARD)
Linus Torvalds's avatar
Linus Torvalds committed
63

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

Linus Torvalds's avatar
Linus Torvalds committed
67 68 69
/*
 *    Define the Moxa PCI vendor and device IDs.
 */
70 71
#define MOXA_BUS_TYPE_ISA	0
#define MOXA_BUS_TYPE_PCI	1
Linus Torvalds's avatar
Linus Torvalds committed
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[] = {
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 },
Linus Torvalds's avatar
Linus Torvalds committed
98 99 100 101 102
	{ 0 }
};
MODULE_DEVICE_TABLE(pci, moxa_pcibrds);
#endif /* CONFIG_PCI */

Jiri Slaby's avatar
Jiri Slaby committed
103 104
struct moxa_port;

105
static struct moxa_board_conf {
Linus Torvalds's avatar
Linus Torvalds committed
106 107 108
	int boardType;
	int numPorts;
	int busType;
109

110
	unsigned int ready;
111

Jiri Slaby's avatar
Jiri Slaby committed
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
};
Linus Torvalds's avatar
Linus Torvalds committed
127

128 129 130 131
struct moxaq_str {
	int inq;
	int outq;
};
Linus Torvalds's avatar
Linus Torvalds committed
132

133
struct moxa_port {
Alan Cox's avatar
Alan Cox committed
134
	struct tty_port port;
Jiri Slaby's avatar
Jiri Slaby committed
135
	struct moxa_board_conf *board;
136 137
	void __iomem *tableAddr;

Linus Torvalds's avatar
Linus Torvalds committed
138 139
	int type;
	int cflag;
140
	unsigned long statusflags;
Linus Torvalds's avatar
Linus Torvalds committed
141

142 143 144
	u8 DCDState;
	u8 lineCtrl;
	u8 lowChkFlag;
145
};
Linus Torvalds's avatar
Linus Torvalds committed
146

Jiri Slaby's avatar
Jiri Slaby committed
147 148 149 150 151 152
struct mon_str {
	int tick;
	int rxcnt[MAX_PORTS];
	int txcnt[MAX_PORTS];
};

Linus Torvalds's avatar
Linus Torvalds committed
153
/* statusflags */
Alan Cox's avatar
Alan Cox committed
154 155 156
#define TXSTOPPED	1
#define LOWWAIT 	2
#define EMPTYWAIT	3
Linus Torvalds's avatar
Linus Torvalds committed
157 158 159 160 161 162

#define SERIAL_DO_RESTART

#define WAKEUP_CHARS		256

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

MODULE_AUTHOR("William Chen");
MODULE_DESCRIPTION("MOXA Intellio Family Multiport Board Device Driver");
MODULE_LICENSE("GPL");
#ifdef MODULE
178 179 180 181 182 183
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)");
Linus Torvalds's avatar
Linus Torvalds committed
184 185 186 187 188 189 190 191 192 193 194 195
#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 *);
Alan Cox's avatar
Alan Cox committed
196
static void moxa_set_termios(struct tty_struct *, struct ktermios *);
Linus Torvalds's avatar
Linus Torvalds committed
197 198 199 200 201 202 203
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);
204
static void moxa_set_tty_param(struct tty_struct *, struct ktermios *);
205
static void moxa_setup_empty_event(struct tty_struct *);
Alan Cox's avatar
Alan Cox committed
206
static void moxa_shutdown(struct tty_port *);
207
static int moxa_carrier_raised(struct tty_port *);
Alan Cox's avatar
Alan Cox committed
208
static void moxa_dtr_rts(struct tty_port *, int);
Linus Torvalds's avatar
Linus Torvalds committed
209 210 211
/*
 * moxa board interface functions:
 */
Jiri Slaby's avatar
Jiri Slaby committed
212 213 214 215 216 217 218 219
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);
Alan Cox's avatar
Alan Cox committed
220
static int MoxaPortWriteData(struct tty_struct *, const unsigned char *, int);
221
static int MoxaPortReadData(struct moxa_port *);
Jiri Slaby's avatar
Jiri Slaby committed
222 223 224 225 226
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 *);
227 228
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 *);
Jiri Slaby's avatar
Jiri Slaby committed
229
static void MoxaSetFifo(struct moxa_port *port, int enable);
Linus Torvalds's avatar
Linus Torvalds committed
230

Jiri Slaby's avatar
Jiri Slaby committed
231 232 233 234
/*
 * I/O functions
 */

Alan Cox's avatar
Alan Cox committed
235 236
static DEFINE_SPINLOCK(moxafunc_lock);

Jiri Slaby's avatar
Jiri Slaby committed
237 238 239 240 241 242 243 244 245 246 247
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");
}

Jiri Slaby's avatar
Jiri Slaby committed
248
static void moxafunc(void __iomem *ofsAddr, u16 cmd, u16 arg)
Jiri Slaby's avatar
Jiri Slaby committed
249
{
Alan Cox's avatar
Alan Cox committed
250 251
        unsigned long flags;
        spin_lock_irqsave(&moxafunc_lock, flags);
Jiri Slaby's avatar
Jiri Slaby committed
252 253 254
	writew(arg, ofsAddr + FuncArg);
	writew(cmd, ofsAddr + FuncCode);
	moxa_wait_finish(ofsAddr);
Alan Cox's avatar
Alan Cox committed
255 256 257 258 259 260 261 262 263 264 265 266 267 268
	spin_unlock_irqrestore(&moxafunc_lock, flags);
}

static int moxafuncret(void __iomem *ofsAddr, u16 cmd, u16 arg)
{
        unsigned long flags;
        u16 ret;
        spin_lock_irqsave(&moxafunc_lock, flags);
	writew(arg, ofsAddr + FuncArg);
	writew(cmd, ofsAddr + FuncCode);
	moxa_wait_finish(ofsAddr);
	ret = readw(ofsAddr + FuncArg);
	spin_unlock_irqrestore(&moxafunc_lock, flags);
	return ret;
Jiri Slaby's avatar
Jiri Slaby committed
269 270
}

271 272 273 274 275 276 277 278 279 280 281 282 283 284
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);
	}
}

Jiri Slaby's avatar
Jiri Slaby committed
285 286 287 288 289 290 291 292 293
/*
 * 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;
Jiri Slaby's avatar
Jiri Slaby committed
294
	int status, ret = 0;
Jiri Slaby's avatar
Jiri Slaby committed
295 296 297 298 299 300 301 302 303 304 305

	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;
Jiri Slaby's avatar
Jiri Slaby committed
306 307 308
		if (copy_to_user(argp, &moxaLog, sizeof(moxaLog)))
			ret = -EFAULT;
		break;
Jiri Slaby's avatar
Jiri Slaby committed
309 310
	case MOXA_FLUSH_QUEUE:
		MoxaPortFlushData(ch, arg);
Jiri Slaby's avatar
Jiri Slaby committed
311
		break;
Jiri Slaby's avatar
Jiri Slaby committed
312 313 314 315 316 317
	case MOXA_GET_IOQUEUE: {
		struct moxaq_str __user *argm = argp;
		struct moxaq_str tmp;
		struct moxa_port *p;
		unsigned int i, j;

Jiri Slaby's avatar
Jiri Slaby committed
318
		mutex_lock(&moxa_openlock);
Jiri Slaby's avatar
Jiri Slaby committed
319 320 321 322 323 324 325 326
		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);
				}
Jiri Slaby's avatar
Jiri Slaby committed
327 328
				if (copy_to_user(argm, &tmp, sizeof(tmp))) {
					mutex_unlock(&moxa_openlock);
Jiri Slaby's avatar
Jiri Slaby committed
329
					return -EFAULT;
Jiri Slaby's avatar
Jiri Slaby committed
330
				}
Jiri Slaby's avatar
Jiri Slaby committed
331 332
			}
		}
Jiri Slaby's avatar
Jiri Slaby committed
333 334
		mutex_unlock(&moxa_openlock);
		break;
Jiri Slaby's avatar
Jiri Slaby committed
335 336
	} case MOXA_GET_OQUEUE:
		status = MoxaPortTxQueue(ch);
Jiri Slaby's avatar
Jiri Slaby committed
337 338
		ret = put_user(status, (unsigned long __user *)argp);
		break;
Jiri Slaby's avatar
Jiri Slaby committed
339 340
	case MOXA_GET_IQUEUE:
		status = MoxaPortRxQueue(ch);
Jiri Slaby's avatar
Jiri Slaby committed
341 342
		ret = put_user(status, (unsigned long __user *)argp);
		break;
Jiri Slaby's avatar
Jiri Slaby committed
343 344 345 346 347 348
	case MOXA_GETMSTATUS: {
		struct mxser_mstatus __user *argm = argp;
		struct mxser_mstatus tmp;
		struct moxa_port *p;
		unsigned int i, j;

Jiri Slaby's avatar
Jiri Slaby committed
349
		mutex_lock(&moxa_openlock);
Jiri Slaby's avatar
Jiri Slaby committed
350 351 352
		for (i = 0; i < MAX_BOARDS; i++) {
			p = moxa_boards[i].ports;
			for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
Alan Cox's avatar
Alan Cox committed
353
				struct tty_struct *ttyp;
Jiri Slaby's avatar
Jiri Slaby committed
354 355 356 357 358 359 360 361 362 363 364 365
				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;

Alan Cox's avatar
Alan Cox committed
366 367
				ttyp = tty_port_tty_get(&p->port);
				if (!ttyp || !ttyp->termios)
Jiri Slaby's avatar
Jiri Slaby committed
368 369
					tmp.cflag = p->cflag;
				else
Alan Cox's avatar
Alan Cox committed
370 371
					tmp.cflag = ttyp->termios->c_cflag;
				tty_kref_put(tty);
Jiri Slaby's avatar
Jiri Slaby committed
372
copy:
Jiri Slaby's avatar
Jiri Slaby committed
373 374
				if (copy_to_user(argm, &tmp, sizeof(tmp))) {
					mutex_unlock(&moxa_openlock);
Jiri Slaby's avatar
Jiri Slaby committed
375
					return -EFAULT;
Jiri Slaby's avatar
Jiri Slaby committed
376
				}
Jiri Slaby's avatar
Jiri Slaby committed
377 378
			}
		}
Jiri Slaby's avatar
Jiri Slaby committed
379 380
		mutex_unlock(&moxa_openlock);
		break;
Jiri Slaby's avatar
Jiri Slaby committed
381 382
	}
	case TIOCGSERIAL:
Alan Cox's avatar
Alan Cox committed
383
	        mutex_lock(&ch->port.mutex);
Jiri Slaby's avatar
Jiri Slaby committed
384
		ret = moxa_get_serial_info(ch, argp);
Alan Cox's avatar
Alan Cox committed
385
		mutex_unlock(&ch->port.mutex);
Jiri Slaby's avatar
Jiri Slaby committed
386
		break;
Jiri Slaby's avatar
Jiri Slaby committed
387
	case TIOCSSERIAL:
Alan Cox's avatar
Alan Cox committed
388
	        mutex_lock(&ch->port.mutex);
Jiri Slaby's avatar
Jiri Slaby committed
389
		ret = moxa_set_serial_info(ch, argp);
Alan Cox's avatar
Alan Cox committed
390
		mutex_unlock(&ch->port.mutex);
Jiri Slaby's avatar
Jiri Slaby committed
391 392 393
		break;
	default:
		ret = -ENOIOCTLCMD;
Jiri Slaby's avatar
Jiri Slaby committed
394
	}
Jiri Slaby's avatar
Jiri Slaby committed
395
	return ret;
Jiri Slaby's avatar
Jiri Slaby committed
396 397
}

Alan Cox's avatar
Alan Cox committed
398
static int moxa_break_ctl(struct tty_struct *tty, int state)
Jiri Slaby's avatar
Jiri Slaby committed
399 400 401 402 403
{
	struct moxa_port *port = tty->driver_data;

	moxafunc(port->tableAddr, state ? FC_SendBreak : FC_StopBreak,
			Magic_code);
Alan Cox's avatar
Alan Cox committed
404
	return 0;
Jiri Slaby's avatar
Jiri Slaby committed
405 406
}

407
static const struct tty_operations moxa_ops = {
Linus Torvalds's avatar
Linus Torvalds committed
408 409 410 411 412 413 414 415 416 417 418
	.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,
	.set_termios = moxa_set_termios,
	.stop = moxa_stop,
	.start = moxa_start,
	.hangup = moxa_hangup,
Jiri Slaby's avatar
Jiri Slaby committed
419
	.break_ctl = moxa_break_ctl,
Linus Torvalds's avatar
Linus Torvalds committed
420 421 422 423
	.tiocmget = moxa_tiocmget,
	.tiocmset = moxa_tiocmset,
};

424 425
static const struct tty_port_operations moxa_port_ops = {
	.carrier_raised = moxa_carrier_raised,
Alan Cox's avatar
Alan Cox committed
426 427
	.dtr_rts = moxa_dtr_rts,
	.shutdown = moxa_shutdown,
428 429
};

430 431
static struct tty_driver *moxaDriver;
static DEFINE_TIMER(moxaTimer, moxa_poll, 0, 0);
432
static DEFINE_SPINLOCK(moxa_lock);
Alan Cox's avatar
Alan Cox committed
433

Jiri Slaby's avatar
Jiri Slaby committed
434 435 436 437
/*
 * HW init
 */

Jiri Slaby's avatar
Jiri Slaby committed
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 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501
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) {
Jiri Slaby's avatar
Jiri Slaby committed
502
			printk(KERN_ERR "MOXA: bios upload failed -- CPU/Basic "
Jiri Slaby's avatar
Jiri Slaby committed
503 504 505 506 507 508 509 510
					"module not found\n");
			return -EIO;
		}
		break;
	}

	return 0;
err:
Jiri Slaby's avatar
Jiri Slaby committed
511
	printk(KERN_ERR "MOXA: bios upload failed -- board not found\n");
Jiri Slaby's avatar
Jiri Slaby committed
512 513 514 515 516 517 518 519 520
	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) {
Jiri Slaby's avatar
Jiri Slaby committed
521
		printk(KERN_ERR "MOXA: invalid 320 bios -- too short\n");
Jiri Slaby's avatar
Jiri Slaby committed
522 523 524 525 526 527 528 529 530 531 532 533
		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;
}

534
static int moxa_real_load_code(struct moxa_board_conf *brd, const void *ptr,
Jiri Slaby's avatar
Jiri Slaby committed
535 536 537
		size_t len)
{
	void __iomem *baseAddr = brd->basemem;
538
	const __le16 *uptr = ptr;
Jiri Slaby's avatar
Jiri Slaby committed
539
	size_t wlen, len2, j;
540
	unsigned long key, loadbuf, loadlen, checksum, checksum_ok;
541
	unsigned int i, retry;
Jiri Slaby's avatar
Jiri Slaby committed
542 543
	u16 usum, keycode;

544 545
	keycode = (brd->boardType == MOXA_BOARD_CP204J) ? CP204J_KeyCode :
				C218_KeyCode;
Jiri Slaby's avatar
Jiri Slaby committed
546

547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564
	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;
Jiri Slaby's avatar
Jiri Slaby committed
565 566 567 568 569 570 571 572 573 574 575 576 577
	}

	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;
578
			memcpy_toio(baseAddr + loadbuf, ptr + j, len2 << 1);
Jiri Slaby's avatar
Jiri Slaby committed
579
			j += len2 << 1;
580 581 582 583 584

			writew(len2, baseAddr + loadlen);
			writew(0, baseAddr + key);
			for (i = 0; i < 100; i++) {
				if (readw(baseAddr + key) == keycode)
Jiri Slaby's avatar
Jiri Slaby committed
585 586 587
					break;
				msleep(10);
			}
588
			if (readw(baseAddr + key) != keycode)
Jiri Slaby's avatar
Jiri Slaby committed
589 590
				return -EIO;
		}
591 592 593 594 595
		writew(0, baseAddr + loadlen);
		writew(usum, baseAddr + checksum);
		writew(0, baseAddr + key);
		for (i = 0; i < 100; i++) {
			if (readw(baseAddr + key) == keycode)
Jiri Slaby's avatar
Jiri Slaby committed
596 597 598 599
				break;
			msleep(10);
		}
		retry++;
600 601
	} while ((readb(baseAddr + checksum_ok) != 1) && (retry < 3));
	if (readb(baseAddr + checksum_ok) != 1)
Jiri Slaby's avatar
Jiri Slaby committed
602 603
		return -EIO;

604
	writew(0, baseAddr + key);
Jiri Slaby's avatar
Jiri Slaby committed
605 606 607 608 609 610 611 612
	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;

613
	if (MOXA_IS_320(brd)) {
614 615 616 617 618 619 620 621 622
		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);
		}
Jiri Slaby's avatar
Jiri Slaby committed
623 624 625 626 627 628 629 630 631 632 633
	}
	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;

634
	if (MOXA_IS_320(brd)) {
635 636 637 638 639 640 641 642 643 644 645 646 647
		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;
Jiri Slaby's avatar
Jiri Slaby committed
648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663
	}
	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) {
Jiri Slaby's avatar
Jiri Slaby committed
664
		printk(KERN_ERR "MOXA: bios length is not even\n");
Jiri Slaby's avatar
Jiri Slaby committed
665 666 667
		return -EINVAL;
	}

668 669 670 671
	retval = moxa_real_load_code(brd, ptr, len); /* may change numPorts */
	if (retval)
		return retval;

Jiri Slaby's avatar
Jiri Slaby committed
672 673 674 675 676 677
	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++) {
Jiri Slaby's avatar
Jiri Slaby committed
678
			port->board = brd;
Jiri Slaby's avatar
Jiri Slaby committed
679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695
			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++) {
Jiri Slaby's avatar
Jiri Slaby committed
696
			port->board = brd;
Jiri Slaby's avatar
Jiri Slaby committed
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 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745
			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)
{
746
	const void *ptr = fw->data;
Jiri Slaby's avatar
Jiri Slaby committed
747 748 749 750 751 752 753 754 755 756 757 758
	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];
759
	} const *hdr = ptr;
Jiri Slaby's avatar
Jiri Slaby committed
760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785

	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]))
Jiri Slaby's avatar
Jiri Slaby committed
786
			printk(KERN_WARNING "MOXA firmware: unexpected input "
Jiri Slaby's avatar
Jiri Slaby committed
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 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836
				"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;
837 838
	struct moxa_port *p;
	unsigned int i;
Jiri Slaby's avatar
Jiri Slaby committed
839 840
	int ret;

841 842 843 844 845 846 847 848 849
	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++) {
Alan Cox's avatar
Alan Cox committed
850
		tty_port_init(&p->port);
851
		p->port.ops = &moxa_port_ops;
852 853 854 855
		p->type = PORT_16550A;
		p->cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
	}

Jiri Slaby's avatar
Jiri Slaby committed
856 857 858 859 860 861 862 863 864 865 866 867 868 869 870
	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) {
871 872 873 874
		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);
875
		goto err_free;
Jiri Slaby's avatar
Jiri Slaby committed
876 877 878 879 880
	}

	ret = moxa_load_fw(brd, fw);

	release_firmware(fw);
881 882 883 884

	if (ret)
		goto err_free;

Jiri Slaby's avatar
Jiri Slaby committed
885
	spin_lock_bh(&moxa_lock);
886
	brd->ready = 1;
Jiri Slaby's avatar
Jiri Slaby committed
887 888
	if (!timer_pending(&moxaTimer))
		mod_timer(&moxaTimer, jiffies + HZ / 50);
Jiri Slaby's avatar
Jiri Slaby committed
889
	spin_unlock_bh(&moxa_lock);
Jiri Slaby's avatar
Jiri Slaby committed
890

891 892 893 894
	return 0;
err_free:
	kfree(brd->ports);
err:
Jiri Slaby's avatar
Jiri Slaby committed
895 896 897
	return ret;
}

898 899
static void moxa_board_deinit(struct moxa_board_conf *brd)
{
Jiri Slaby's avatar
Jiri Slaby committed
900 901 902
	unsigned int a, opened;

	mutex_lock(&moxa_openlock);
903
	spin_lock_bh(&moxa_lock);
904
	brd->ready = 0;
905
	spin_unlock_bh(&moxa_lock);
Jiri Slaby's avatar
Jiri Slaby committed
906 907 908

	/* pci hot-un-plug support */
	for (a = 0; a < brd->numPorts; a++)
Alan Cox's avatar
Alan Cox committed
909 910 911 912 913 914 915 916
		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);
			}
		}
Jiri Slaby's avatar
Jiri Slaby committed
917 918 919
	while (1) {
		opened = 0;
		for (a = 0; a < brd->numPorts; a++)
Alan Cox's avatar
Alan Cox committed
920
			if (brd->ports[a].port.flags & ASYNC_INITIALIZED)
Jiri Slaby's avatar
Jiri Slaby committed
921 922 923 924 925 926 927 928
				opened++;
		mutex_unlock(&moxa_openlock);
		if (!opened)
			break;
		msleep(50);
		mutex_lock(&moxa_openlock);
	}

929 930 931 932 933
	iounmap(brd->basemem);
	brd->basemem = NULL;
	kfree(brd->ports);
}

Linus Torvalds's avatar
Linus Torvalds committed
934
#ifdef CONFIG_PCI
935 936
static int __devinit moxa_pci_probe(struct pci_dev *pdev,
		const struct pci_device_id *ent)
Linus Torvalds's avatar
Linus Torvalds committed
937
{
938 939 940 941 942 943
	struct moxa_board_conf *board;
	unsigned int i;
	int board_type = ent->driver_data;
	int retval;

	retval = pci_enable_device(pdev);
Jiri Slaby's avatar
Jiri Slaby committed
944 945
	if (retval) {
		dev_err(&pdev->dev, "can't enable pci device\n");
946
		goto err;
Jiri Slaby's avatar
Jiri Slaby committed
947
	}
948 949 950 951 952 953 954

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

	retval = -ENODEV;
	if (i >= MAX_BOARDS) {
Jiri Slaby's avatar
Jiri Slaby committed
955
		dev_warn(&pdev->dev, "more than %u MOXA Intellio family boards "
956 957 958 959 960
				"found. Board is ignored.\n", MAX_BOARDS);
		goto err;
	}

	board = &moxa_boards[i];
Jiri Slaby's avatar
Jiri Slaby committed
961 962 963 964 965 966 967

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

968
	board->basemem = ioremap_nocache(pci_resource_start(pdev, 2), 0x4000);
Jiri Slaby's avatar
Jiri Slaby committed
969 970
	if (board->basemem == NULL) {
		dev_err(&pdev->dev, "can't remap io space 2\n");
Jiri Slaby's avatar
Jiri Slaby committed
971
		goto err_reg;
Jiri Slaby's avatar
Jiri Slaby committed
972
	}
973

Linus Torvalds's avatar
Linus Torvalds committed
974 975 976 977 978 979 980 981 982 983 984 985 986 987 988
	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;
Jiri Slaby's avatar
Jiri Slaby committed
989

Jiri Slaby's avatar
Jiri Slaby committed
990 991 992 993
	retval = moxa_init_board(board, &pdev->dev);
	if (retval)
		goto err_base;

994
	pci_set_drvdata(pdev, board);
Linus Torvalds's avatar
Linus Torvalds committed
995

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

Jiri Slaby's avatar
Jiri Slaby committed
999
	return 0;
Jiri Slaby's avatar
Jiri Slaby committed
1000 1001 1002
err_base:
	iounmap(board->basemem);
	board->basemem = NULL;
Jiri Slaby's avatar
Jiri Slaby committed
1003 1004
err_reg:
	pci_release_region(pdev, 2);
1005 1006 1007 1008 1009 1010 1011 1012
err:
	return retval;
}

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

1013 1014
	moxa_board_deinit(brd);

Jiri Slaby's avatar
Jiri Slaby committed
1015
	pci_release_region(pdev, 2);
Linus Torvalds's avatar
Linus Torvalds committed
1016
}
Jiri Slaby's avatar
Jiri Slaby committed
1017 1018 1019 1020 1021 1022 1023

static struct pci_driver moxa_pci_driver = {
	.name = "moxa",
	.id_table = moxa_pcibrds,
	.probe = moxa_pci_probe,
	.remove = __devexit_p(moxa_pci_remove)
};
Linus Torvalds's avatar
Linus Torvalds committed
1024 1025 1026 1027
#endif /* CONFIG_PCI */

static int __init moxa_init(void)
{
1028
	unsigned int isabrds = 0;
1029
	int retval = 0;
Linus Torvalds's avatar
Linus Torvalds committed
1030

Jiri Slaby's avatar
Jiri Slaby committed
1031 1032
	printk(KERN_INFO "MOXA Intellio family driver version %s\n",
			MOXA_VERSION);
Linus Torvalds's avatar
Linus Torvalds committed
1033 1034 1035 1036 1037
	moxaDriver = alloc_tty_driver(MAX_PORTS + 1);
	if (!moxaDriver)
		return -ENOMEM;

	moxaDriver->owner = THIS_MODULE;
1038
	moxaDriver->name = "ttyMX";
Linus Torvalds's avatar
Linus Torvalds committed
1039 1040 1041 1042 1043 1044
	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;
Alan Cox's avatar
Alan Cox committed
1045 1046
	moxaDriver->init_termios.c_ispeed = 9600;
	moxaDriver->init_termios.c_ospeed = 9600;
Linus Torvalds's avatar
Linus Torvalds committed
1047 1048 1049 1050
	moxaDriver->flags = TTY_DRIVER_REAL_RAW;
	tty_set_operations(moxaDriver, &moxa_ops);

	if (tty_register_driver(moxaDriver)) {
Jiri Slaby's avatar
Jiri Slaby committed
1051
		printk(KERN_ERR "can't register MOXA Smartio tty driver!\n");
Linus Torvalds's avatar
Linus Torvalds committed
1052 1053 1054 1055
		put_tty_driver(moxaDriver);
		return -1;
	}

1056
	/* Find the boards defined from module args. */
Linus Torvalds's avatar
Linus Torvalds committed
1057
#ifdef MODULE
1058 1059
	{
	struct moxa_board_conf *brd = moxa_boards;
1060
	unsigned int i;
Linus Torvalds's avatar
Linus Torvalds committed
1061
	for (i = 0; i < MAX_BOARDS; i++) {
1062 1063 1064 1065
		if (!baseaddr[i])
			break;
		if (type[i] == MOXA_BOARD_C218_ISA ||
				type[i] == MOXA_BOARD_C320_ISA) {
Jiri Slaby's avatar
Jiri Slaby committed
1066
			pr_debug("Moxa board %2d: %s board(baseAddr=%lx)\n",
1067 1068 1069 1070 1071 1072
					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;
1073
			brd->basemem = ioremap_nocache(baseaddr[i], 0x4000);
1074
			if (!brd->basemem) {
Jiri Slaby's avatar
Jiri Slaby committed
1075
				printk(KERN_ERR "MOXA: can't remap %lx\n",
1076
						baseaddr[i]);
Linus Torvalds's avatar
Linus Torvalds committed
1077 1078
				continue;
			}
Jiri Slaby's avatar
Jiri Slaby committed
1079 1080 1081 1082 1083
			if (moxa_init_board(brd, NULL)) {
				iounmap(brd->basemem);
				brd->basemem = NULL;
				continue;
			}
1084

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

1089 1090
			brd++;
			isabrds++;
Linus Torvalds's avatar
Linus Torvalds committed
1091 1092
		}
	}
1093
	}
Linus Torvalds's avatar
Linus Torvalds committed
1094
#endif
Jiri Slaby's avatar
Jiri Slaby committed
1095

Linus Torvalds's avatar
Linus Torvalds committed
1096
#ifdef CONFIG_PCI
Jiri Slaby's avatar
Jiri Slaby committed
1097 1098
	retval = pci_register_driver(&moxa_pci_driver);
	if (retval) {
Jiri Slaby's avatar
Jiri Slaby committed
1099
		printk(KERN_ERR "Can't register MOXA pci driver!\n");
1100
		if (isabrds)
Jiri Slaby's avatar
Jiri Slaby committed
1101
			retval = 0;
Linus Torvalds's avatar
Linus Torvalds committed
1102 1103
	}
#endif
Jiri Slaby's avatar
Jiri Slaby committed
1104 1105

	return retval;
Linus Torvalds's avatar
Linus Torvalds committed
1106 1107 1108 1109
}

static void __exit moxa_exit(void)
{
Jiri Slaby's avatar
Jiri Slaby committed
1110
	unsigned int i;
Linus Torvalds's avatar
Linus Torvalds committed
1111

1112
#ifdef CONFIG_PCI
Jiri Slaby's avatar
Jiri Slaby committed
1113
	pci_unregister_driver(&moxa_pci_driver);
1114
#endif
Jiri Slaby's avatar
Jiri Slaby committed
1115

1116 1117 1118
	for (i = 0; i < MAX_BOARDS; i++) /* ISA boards */
		if (moxa_boards[i].ready)
			moxa_board_deinit(&moxa_boards[i]);
Jiri Slaby's avatar
Jiri Slaby committed
1119 1120 1121 1122 1123 1124 1125

	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);
Linus Torvalds's avatar
Linus Torvalds committed
1126 1127 1128 1129 1130
}

module_init(moxa_init);
module_exit(moxa_exit);

Alan Cox's avatar
Alan Cox committed
1131
static void moxa_shutdown(struct tty_port *port)
Jiri Slaby's avatar
Jiri Slaby committed
1132
{
Alan Cox's avatar
Alan Cox committed
1133 1134
	struct moxa_port *ch = container_of(port, struct moxa_port, port);
        MoxaPortDisable(ch);
Jiri Slaby's avatar
Jiri Slaby committed
1135
	MoxaPortFlushData(ch, 2);
Alan Cox's avatar
Alan Cox committed
1136
	clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags);
Jiri Slaby's avatar
Jiri Slaby committed
1137 1138
}

1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149
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;
}

Alan Cox's avatar
Alan Cox committed
1150
static void moxa_dtr_rts(struct tty_port *port, int onoff)
Jiri Slaby's avatar
Jiri Slaby committed
1151
{
Alan Cox's avatar
Alan Cox committed
1152 1153
	struct moxa_port *ch = container_of(port, struct moxa_port, port);
	MoxaPortLineCtrl(ch, onoff, onoff);
Jiri Slaby's avatar
Jiri Slaby committed
1154 1155
}

Alan Cox's avatar
Alan Cox committed
1156

Linus Torvalds's avatar
Linus Torvalds committed
1157 1158
static int moxa_open(struct tty_struct *tty, struct file *filp)
{
1159
	struct moxa_board_conf *brd;