isicom.c 41.4 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9
/*
 *	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.
 *
 *	Original driver code supplied by Multi-Tech
 *
 *	Changes
10 11
 *	1/9/98	alan@lxorguk.ukuu.org.uk
 *					Merge to 2.0.x kernel tree
L
Linus Torvalds 已提交
12 13 14 15
 *					Obtain and use official major/minors
 *					Loader switched to a misc device
 *					(fixed range check bug as a side effect)
 *					Printk clean up
16 17
 *	9/12/98	alan@lxorguk.ukuu.org.uk
 *					Rough port to 2.1.x
L
Linus Torvalds 已提交
18 19 20 21 22 23 24
 *
 *	10/6/99 sameer			Merged the ISA and PCI drivers to
 *					a new unified driver.
 *
 *	3/9/99	sameer			Added support for ISI4616 cards.
 *
 *	16/9/99	sameer			We do not force RTS low anymore.
25
 *					This is to prevent the firmware
L
Linus Torvalds 已提交
26 27 28 29 30 31 32 33 34 35
 *					from getting confused.
 *
 *	26/10/99 sameer			Cosmetic changes:The driver now
 *					dumps the Port Count information
 *					along with I/O address and IRQ.
 *
 *	13/12/99 sameer			Fixed the problem with IRQ sharing.
 *
 *	10/5/00  sameer			Fixed isicom_shutdown_board()
 *					to not lower DTR on all the ports
36
 *					when the last port on the card is
L
Linus Torvalds 已提交
37 38 39
 *					closed.
 *
 *	10/5/00  sameer			Signal mask setup command added
40
 *					to  isicom_setup_port and
L
Linus Torvalds 已提交
41 42 43
 *					isicom_shutdown_port.
 *
 *	24/5/00  sameer			The driver is now SMP aware.
44 45
 *
 *
L
Linus Torvalds 已提交
46
 *	27/11/00 Vinayak P Risbud	Fixed the Driver Crash Problem
47 48
 *
 *
L
Linus Torvalds 已提交
49 50 51 52 53 54
 *	03/01/01  anil .s		Added support for resetting the
 *					internal modems on ISI cards.
 *
 *	08/02/01  anil .s		Upgraded the driver for kernel
 *					2.4.x
 *
55
 *	11/04/01  Kevin			Fixed firmware load problem with
L
Linus Torvalds 已提交
56
 *					ISIHP-4X card
57
 *
L
Linus Torvalds 已提交
58 59 60 61 62 63 64 65 66
 *	30/04/01  anil .s		Fixed the remote login through
 *					ISI port problem. Now the link
 *					does not go down before password
 *					prompt.
 *
 *	03/05/01  anil .s		Fixed the problem with IRQ sharing
 *					among ISI-PCI cards.
 *
 *	03/05/01  anil .s		Added support to display the version
67
 *					info during insmod as well as module
L
Linus Torvalds 已提交
68
 *					listing by lsmod.
69
 *
L
Linus Torvalds 已提交
70 71 72 73 74 75 76 77
 *	10/05/01  anil .s		Done the modifications to the source
 *					file and Install script so that the
 *					same installation can be used for
 *					2.2.x and 2.4.x kernel.
 *
 *	06/06/01  anil .s		Now we drop both dtr and rts during
 *					shutdown_port as well as raise them
 *					during isicom_config_port.
78
 *
L
Linus Torvalds 已提交
79 80 81 82 83
 *	09/06/01 acme@conectiva.com.br	use capable, not suser, do
 *					restore_flags on failure in
 *					isicom_send_break, verify put_user
 *					result
 *
84 85 86 87 88 89 90
 *	11/02/03  ranjeeth		Added support for 230 Kbps and 460 Kbps
 *					Baud index extended to 21
 *
 *	20/03/03  ranjeeth		Made to work for Linux Advanced server.
 *					Taken care of license warning.
 *
 *	10/12/03  Ravindra		Made to work for Fedora Core 1 of
L
Linus Torvalds 已提交
91 92 93 94 95 96 97
 *					Red Hat Distribution
 *
 *	06/01/05  Alan Cox 		Merged the ISI and base kernel strands
 *					into a single 2.6 driver
 *
 *	***********************************************************
 *
98
 *	To use this driver you also need the support package. You
L
Linus Torvalds 已提交
99 100
 *	can find this in RPM format on
 *		ftp://ftp.linux.org.uk/pub/linux/alan
101
 *
L
Linus Torvalds 已提交
102 103 104 105 106 107 108 109 110 111 112 113 114 115
 *	You can find the original tools for this direct from Multitech
 *		ftp://ftp.multitech.com/ISI-Cards/
 *
 *	Having installed the cards the module options (/etc/modprobe.conf)
 *
 *	options isicom   io=card1,card2,card3,card4 irq=card1,card2,card3,card4
 *
 *	Omit those entries for boards you don't have installed.
 *
 *	TODO
 *		Merge testing
 *		64-bit verification
 */

116 117
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

L
Linus Torvalds 已提交
118
#include <linux/module.h>
119
#include <linux/firmware.h>
L
Linus Torvalds 已提交
120 121
#include <linux/kernel.h>
#include <linux/tty.h>
A
Alan Cox 已提交
122
#include <linux/tty_flip.h>
L
Linus Torvalds 已提交
123 124 125 126 127 128 129 130 131
#include <linux/termios.h>
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/serial.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/timer.h>
#include <linux/delay.h>
#include <linux/ioport.h>
132
#include <linux/slab.h>
L
Linus Torvalds 已提交
133

A
Alan Cox 已提交
134 135
#include <linux/uaccess.h>
#include <linux/io.h>
L
Linus Torvalds 已提交
136 137 138 139 140 141
#include <asm/system.h>

#include <linux/pci.h>

#include <linux/isicom.h>

142 143 144 145 146 147 148 149 150
#define InterruptTheCard(base) outw(0, (base) + 0xc)
#define ClearInterrupt(base) inw((base) + 0x0a)

#ifdef DEBUG
#define isicom_paranoia_check(a, b, c) __isicom_paranoia_check((a), (b), (c))
#else
#define isicom_paranoia_check(a, b, c) 0
#endif

151 152 153
static int isicom_probe(struct pci_dev *, const struct pci_device_id *);
static void __devexit isicom_remove(struct pci_dev *);

L
Linus Torvalds 已提交
154
static struct pci_device_id isicom_pci_tbl[] = {
155 156 157 158 159 160 161 162 163
	{ PCI_DEVICE(VENDOR_ID, 0x2028) },
	{ PCI_DEVICE(VENDOR_ID, 0x2051) },
	{ PCI_DEVICE(VENDOR_ID, 0x2052) },
	{ PCI_DEVICE(VENDOR_ID, 0x2053) },
	{ PCI_DEVICE(VENDOR_ID, 0x2054) },
	{ PCI_DEVICE(VENDOR_ID, 0x2055) },
	{ PCI_DEVICE(VENDOR_ID, 0x2056) },
	{ PCI_DEVICE(VENDOR_ID, 0x2057) },
	{ PCI_DEVICE(VENDOR_ID, 0x2058) },
L
Linus Torvalds 已提交
164 165 166 167
	{ 0 }
};
MODULE_DEVICE_TABLE(pci, isicom_pci_tbl);

168 169 170 171 172 173 174
static struct pci_driver isicom_driver = {
	.name		= "isicom",
	.id_table	= isicom_pci_tbl,
	.probe		= isicom_probe,
	.remove		= __devexit_p(isicom_remove)
};

L
Linus Torvalds 已提交
175 176 177 178
static int prev_card = 3;	/*	start servicing isi_card[0]	*/
static struct tty_driver *isicom_normal;

static void isicom_tx(unsigned long _data);
179
static void isicom_start(struct tty_struct *tty);
L
Linus Torvalds 已提交
180

J
Jiri Slaby 已提交
181 182
static DEFINE_TIMER(tx, isicom_tx, 0, 0);

L
Linus Torvalds 已提交
183 184 185
/*   baud index mappings from linux defns to isi */

static signed char linuxb_to_isib[] = {
186
	-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13, 15, 16, 17, 18, 19, 20, 21
L
Linus Torvalds 已提交
187 188 189
};

struct	isi_board {
190
	unsigned long		base;
191
	int			irq;
L
Linus Torvalds 已提交
192 193
	unsigned char		port_count;
	unsigned short		status;
194
	unsigned short		port_status; /* each bit for each port */
L
Linus Torvalds 已提交
195
	unsigned short		shift_count;
A
Alan Cox 已提交
196
	struct isi_port		*ports;
L
Linus Torvalds 已提交
197 198 199
	signed char		count;
	spinlock_t		card_lock; /* Card wide lock 11/5/00 -sameer */
	unsigned long		flags;
200
	unsigned int		index;
L
Linus Torvalds 已提交
201 202 203 204
};

struct	isi_port {
	unsigned short		magic;
A
Alan Cox 已提交
205
	struct tty_port		port;
206 207
	u16			channel;
	u16			status;
A
Alan Cox 已提交
208 209
	struct isi_board	*card;
	unsigned char		*xmit_buf;
L
Linus Torvalds 已提交
210 211 212 213 214 215 216 217 218 219 220 221 222
	int			xmit_head;
	int			xmit_tail;
	int			xmit_cnt;
};

static struct isi_board isi_card[BOARD_COUNT];
static struct isi_port  isi_ports[PORT_COUNT];

/*
 *	Locking functions for card level locking. We need to own both
 *	the kernel lock for the card and have the card in a position that
 *	it wants to talk.
 */
223

224
static inline int WaitTillCardIsFree(unsigned long base)
225 226 227 228 229 230 231 232 233 234 235 236 237
{
	unsigned int count = 0;
	unsigned int a = in_atomic(); /* do we run under spinlock? */

	while (!(inw(base + 0xe) & 0x1) && count++ < 100)
		if (a)
			mdelay(1);
		else
			msleep(1);

	return !(inw(base + 0xe) & 0x1);
}

L
Linus Torvalds 已提交
238 239
static int lock_card(struct isi_board *card)
{
240
	unsigned long base = card->base;
J
Jiri Slaby 已提交
241
	unsigned int retries, a;
L
Linus Torvalds 已提交
242

J
Jiri Slaby 已提交
243
	for (retries = 0; retries < 10; retries++) {
L
Linus Torvalds 已提交
244
		spin_lock_irqsave(&card->card_lock, card->flags);
J
Jiri Slaby 已提交
245 246 247 248
		for (a = 0; a < 10; a++) {
			if (inw(base + 0xe) & 0x1)
				return 1;
			udelay(10);
L
Linus Torvalds 已提交
249
		}
J
Jiri Slaby 已提交
250 251
		spin_unlock_irqrestore(&card->card_lock, card->flags);
		msleep(10);
L
Linus Torvalds 已提交
252
	}
253
	pr_warning("Failed to lock Card (0x%lx)\n", card->base);
254

A
Adrian Bunk 已提交
255
	return 0;	/* Failed to acquire the card! */
L
Linus Torvalds 已提交
256 257 258 259 260 261 262 263 264 265
}

static void unlock_card(struct isi_board *card)
{
	spin_unlock_irqrestore(&card->card_lock, card->flags);
}

/*
 *  ISI Card specific ops ...
 */
266

267
/* card->lock HAS to be held */
268
static void raise_dtr(struct isi_port *port)
L
Linus Torvalds 已提交
269
{
270
	struct isi_board *card = port->card;
271 272
	unsigned long base = card->base;
	u16 channel = port->channel;
L
Linus Torvalds 已提交
273

274
	if (WaitTillCardIsFree(base))
L
Linus Torvalds 已提交
275 276
		return;

277
	outw(0x8000 | (channel << card->shift_count) | 0x02, base);
L
Linus Torvalds 已提交
278 279 280 281 282
	outw(0x0504, base);
	InterruptTheCard(base);
	port->status |= ISI_DTR;
}

283
/* card->lock HAS to be held */
284 285 286
static inline void drop_dtr(struct isi_port *port)
{
	struct isi_board *card = port->card;
287 288
	unsigned long base = card->base;
	u16 channel = port->channel;
L
Linus Torvalds 已提交
289

290
	if (WaitTillCardIsFree(base))
L
Linus Torvalds 已提交
291 292
		return;

293
	outw(0x8000 | (channel << card->shift_count) | 0x02, base);
L
Linus Torvalds 已提交
294
	outw(0x0404, base);
295
	InterruptTheCard(base);
L
Linus Torvalds 已提交
296 297 298
	port->status &= ~ISI_DTR;
}

299
/* card->lock HAS to be held */
300
static inline void raise_rts(struct isi_port *port)
L
Linus Torvalds 已提交
301
{
302
	struct isi_board *card = port->card;
303 304
	unsigned long base = card->base;
	u16 channel = port->channel;
L
Linus Torvalds 已提交
305

306
	if (WaitTillCardIsFree(base))
L
Linus Torvalds 已提交
307 308
		return;

309
	outw(0x8000 | (channel << card->shift_count) | 0x02, base);
L
Linus Torvalds 已提交
310
	outw(0x0a04, base);
311
	InterruptTheCard(base);
L
Linus Torvalds 已提交
312 313
	port->status |= ISI_RTS;
}
314 315

/* card->lock HAS to be held */
316
static inline void drop_rts(struct isi_port *port)
L
Linus Torvalds 已提交
317
{
318
	struct isi_board *card = port->card;
319 320
	unsigned long base = card->base;
	u16 channel = port->channel;
L
Linus Torvalds 已提交
321

322
	if (WaitTillCardIsFree(base))
L
Linus Torvalds 已提交
323 324
		return;

325
	outw(0x8000 | (channel << card->shift_count) | 0x02, base);
L
Linus Torvalds 已提交
326
	outw(0x0804, base);
327
	InterruptTheCard(base);
L
Linus Torvalds 已提交
328 329 330
	port->status &= ~ISI_RTS;
}

331
/* card->lock MUST NOT be held */
A
Alan Cox 已提交
332

333
static void isicom_dtr_rts(struct tty_port *port, int on)
L
Linus Torvalds 已提交
334
{
A
Alan Cox 已提交
335 336
	struct isi_port *ip = container_of(port, struct isi_port, port);
	struct isi_board *card = ip->card;
337
	unsigned long base = card->base;
A
Alan Cox 已提交
338
	u16 channel = ip->channel;
L
Linus Torvalds 已提交
339 340 341 342

	if (!lock_card(card))
		return;

343 344 345 346 347 348 349 350 351 352 353
	if (on) {
		outw(0x8000 | (channel << card->shift_count) | 0x02, base);
		outw(0x0f04, base);
		InterruptTheCard(base);
		ip->status |= (ISI_DTR | ISI_RTS);
	} else {
		outw(0x8000 | (channel << card->shift_count) | 0x02, base);
		outw(0x0C04, base);
		InterruptTheCard(base);
		ip->status &= ~(ISI_DTR | ISI_RTS);
	}
L
Linus Torvalds 已提交
354 355 356
	unlock_card(card);
}

357
/* card->lock HAS to be held */
358
static void drop_dtr_rts(struct isi_port *port)
L
Linus Torvalds 已提交
359
{
360
	struct isi_board *card = port->card;
361 362
	unsigned long base = card->base;
	u16 channel = port->channel;
L
Linus Torvalds 已提交
363

364
	if (WaitTillCardIsFree(base))
L
Linus Torvalds 已提交
365 366
		return;

367
	outw(0x8000 | (channel << card->shift_count) | 0x02, base);
L
Linus Torvalds 已提交
368
	outw(0x0c04, base);
369
	InterruptTheCard(base);
L
Linus Torvalds 已提交
370 371 372 373 374 375 376
	port->status &= ~(ISI_RTS | ISI_DTR);
}

/*
 *	ISICOM Driver specific routines ...
 *
 */
377

378 379
static inline int __isicom_paranoia_check(struct isi_port const *port,
	char *name, const char *routine)
L
Linus Torvalds 已提交
380 381
{
	if (!port) {
382 383
		pr_warning("Warning: bad isicom magic for dev %s in %s.\n",
			   name, routine);
L
Linus Torvalds 已提交
384 385 386
		return 1;
	}
	if (port->magic != ISICOM_MAGIC) {
387 388
		pr_warning("Warning: NULL isicom port for dev %s in %s.\n",
			   name, routine);
L
Linus Torvalds 已提交
389
		return 1;
390
	}
391

L
Linus Torvalds 已提交
392 393
	return 0;
}
394

L
Linus Torvalds 已提交
395
/*
396
 *	Transmitter.
L
Linus Torvalds 已提交
397 398 399 400 401 402 403
 *
 *	We shovel data into the card buffers on a regular basis. The card
 *	will do the rest of the work for us.
 */

static void isicom_tx(unsigned long _data)
{
404
	unsigned long flags, base;
J
Jiri Slaby 已提交
405
	unsigned int retries;
406
	short count = (BOARD_COUNT-1), card;
L
Linus Torvalds 已提交
407
	short txcount, wrd, residue, word_count, cnt;
408 409 410
	struct isi_port *port;
	struct tty_struct *tty;

L
Linus Torvalds 已提交
411 412
	/*	find next active board	*/
	card = (prev_card + 1) & 0x0003;
A
Alan Cox 已提交
413
	while (count-- > 0) {
414
		if (isi_card[card].status & BOARD_ACTIVE)
L
Linus Torvalds 已提交
415
			break;
416
		card = (card + 1) & 0x0003;
L
Linus Torvalds 已提交
417 418 419
	}
	if (!(isi_card[card].status & BOARD_ACTIVE))
		goto sched_again;
420

L
Linus Torvalds 已提交
421
	prev_card = card;
422

L
Linus Torvalds 已提交
423 424 425
	count = isi_card[card].port_count;
	port = isi_card[card].ports;
	base = isi_card[card].base;
J
Jiri Slaby 已提交
426 427 428 429 430 431 432 433 434 435

	spin_lock_irqsave(&isi_card[card].card_lock, flags);
	for (retries = 0; retries < 100; retries++) {
		if (inw(base + 0xe) & 0x1)
			break;
		udelay(2);
	}
	if (retries >= 100)
		goto unlock;

A
Alan Cox 已提交
436 437 438 439
	tty = tty_port_tty_get(&port->port);
	if (tty == NULL)
		goto put_unlock;

A
Alan Cox 已提交
440
	for (; count > 0; count--, port++) {
L
Linus Torvalds 已提交
441
		/* port not active or tx disabled to force flow control */
A
Alan Cox 已提交
442
		if (!(port->port.flags & ASYNC_INITIALIZED) ||
443
				!(port->status & ISI_TXOK))
L
Linus Torvalds 已提交
444
			continue;
445

L
Linus Torvalds 已提交
446
		txcount = min_t(short, TX_SIZE, port->xmit_cnt);
J
Jiri Slaby 已提交
447
		if (txcount <= 0 || tty->stopped || tty->hw_stopped)
L
Linus Torvalds 已提交
448
			continue;
J
Jiri Slaby 已提交
449 450

		if (!(inw(base + 0x02) & (1 << port->channel)))
451
			continue;
J
Jiri Slaby 已提交
452

453 454
		pr_debug("txing %d bytes, port%d.\n",
			 txcount, port->channel + 1);
455 456
		outw((port->channel << isi_card[card].shift_count) | txcount,
			base);
L
Linus Torvalds 已提交
457
		residue = NO;
458
		wrd = 0;
L
Linus Torvalds 已提交
459
		while (1) {
460 461
			cnt = min_t(int, txcount, (SERIAL_XMIT_SIZE
					- port->xmit_tail));
L
Linus Torvalds 已提交
462 463 464
			if (residue == YES) {
				residue = NO;
				if (cnt > 0) {
A
Alan Cox 已提交
465
					wrd |= (port->port.xmit_buf[port->xmit_tail]
466 467 468
									<< 8);
					port->xmit_tail = (port->xmit_tail + 1)
						& (SERIAL_XMIT_SIZE - 1);
L
Linus Torvalds 已提交
469 470 471
					port->xmit_cnt--;
					txcount--;
					cnt--;
472
					outw(wrd, base);
473
				} else {
L
Linus Torvalds 已提交
474 475 476
					outw(wrd, base);
					break;
				}
477
			}
A
Alan Cox 已提交
478 479
			if (cnt <= 0)
				break;
L
Linus Torvalds 已提交
480
			word_count = cnt >> 1;
A
Alan Cox 已提交
481
			outsw(base, port->port.xmit_buf+port->xmit_tail, word_count);
482 483
			port->xmit_tail = (port->xmit_tail
				+ (word_count << 1)) & (SERIAL_XMIT_SIZE - 1);
L
Linus Torvalds 已提交
484 485 486 487
			txcount -= (word_count << 1);
			port->xmit_cnt -= (word_count << 1);
			if (cnt & 0x0001) {
				residue = YES;
A
Alan Cox 已提交
488
				wrd = port->port.xmit_buf[port->xmit_tail];
489 490
				port->xmit_tail = (port->xmit_tail + 1)
					& (SERIAL_XMIT_SIZE - 1);
L
Linus Torvalds 已提交
491 492 493 494 495 496 497 498 499
				port->xmit_cnt--;
				txcount--;
			}
		}

		InterruptTheCard(base);
		if (port->xmit_cnt <= 0)
			port->status &= ~ISI_TXOK;
		if (port->xmit_cnt <= WAKEUP_CHARS)
500
			tty_wakeup(tty);
501
	}
L
Linus Torvalds 已提交
502

A
Alan Cox 已提交
503 504
put_unlock:
	tty_kref_put(tty);
J
Jiri Slaby 已提交
505 506
unlock:
	spin_unlock_irqrestore(&isi_card[card].card_lock, flags);
507 508
	/*	schedule another tx for hopefully in about 10ms	*/
sched_again:
J
Jiri Slaby 已提交
509
	mod_timer(&tx, jiffies + msecs_to_jiffies(10));
510 511
}

L
Linus Torvalds 已提交
512
/*
513
 *	Main interrupt handler routine
L
Linus Torvalds 已提交
514
 */
515

516
static irqreturn_t isicom_interrupt(int irq, void *dev_id)
L
Linus Torvalds 已提交
517
{
518
	struct isi_board *card = dev_id;
519 520
	struct isi_port *port;
	struct tty_struct *tty;
521 522
	unsigned long base;
	u16 header, word_count, count, channel;
L
Linus Torvalds 已提交
523
	short byte_count;
A
Alan Cox 已提交
524
	unsigned char *rp;
525

L
Linus Torvalds 已提交
526 527
	if (!card || !(card->status & FIRMWARE_LOADED))
		return IRQ_NONE;
528

L
Linus Torvalds 已提交
529
	base = card->base;
530 531 532 533 534

	/* did the card interrupt us? */
	if (!(inw(base + 0x0e) & 0x02))
		return IRQ_NONE;

L
Linus Torvalds 已提交
535
	spin_lock(&card->card_lock);
536

J
Jiri Slaby 已提交
537 538 539 540 541 542
	/*
	 * disable any interrupts from the PCI card and lower the
	 * interrupt line
	 */
	outw(0x8000, base+0x04);
	ClearInterrupt(base);
543

L
Linus Torvalds 已提交
544 545 546 547 548 549
	inw(base);		/* get the dummy word out */
	header = inw(base);
	channel = (header & 0x7800) >> card->shift_count;
	byte_count = header & 0xff;

	if (channel + 1 > card->port_count) {
550 551
		pr_warning("%s(0x%lx): %d(channel) > port_count.\n",
			   __func__, base, channel+1);
J
Jiri Slaby 已提交
552
		outw(0x0000, base+0x04); /* enable interrupts */
L
Linus Torvalds 已提交
553
		spin_unlock(&card->card_lock);
554
		return IRQ_HANDLED;
L
Linus Torvalds 已提交
555 556
	}
	port = card->ports + channel;
A
Alan Cox 已提交
557
	if (!(port->port.flags & ASYNC_INITIALIZED)) {
J
Jiri Slaby 已提交
558
		outw(0x0000, base+0x04); /* enable interrupts */
559
		spin_unlock(&card->card_lock);
L
Linus Torvalds 已提交
560
		return IRQ_HANDLED;
561 562
	}

A
Alan Cox 已提交
563
	tty = tty_port_tty_get(&port->port);
L
Linus Torvalds 已提交
564 565
	if (tty == NULL) {
		word_count = byte_count >> 1;
A
Alan Cox 已提交
566
		while (byte_count > 1) {
L
Linus Torvalds 已提交
567 568 569 570 571
			inw(base);
			byte_count -= 2;
		}
		if (byte_count & 0x01)
			inw(base);
J
Jiri Slaby 已提交
572
		outw(0x0000, base+0x04); /* enable interrupts */
L
Linus Torvalds 已提交
573 574 575
		spin_unlock(&card->card_lock);
		return IRQ_HANDLED;
	}
576

L
Linus Torvalds 已提交
577 578
	if (header & 0x8000) {		/* Status Packet */
		header = inw(base);
A
Alan Cox 已提交
579
		switch (header & 0xff) {
580
		case 0:	/* Change in EIA signals */
A
Alan Cox 已提交
581
			if (port->port.flags & ASYNC_CHECK_CD) {
582 583 584
				if (port->status & ISI_DCD) {
					if (!(header & ISI_DCD)) {
					/* Carrier has been lost  */
585 586
						pr_debug("%s: DCD->low.\n",
							 __func__);
587
						port->status &= ~ISI_DCD;
588
						tty_hangup(tty);
L
Linus Torvalds 已提交
589
					}
590 591
				} else if (header & ISI_DCD) {
				/* Carrier has been detected */
592 593
					pr_debug("%s: DCD->high.\n",
						__func__);
594
					port->status |= ISI_DCD;
A
Alan Cox 已提交
595
					wake_up_interruptible(&port->port.open_wait);
L
Linus Torvalds 已提交
596
				}
597
			} else {
598 599 600 601 602 603
				if (header & ISI_DCD)
					port->status |= ISI_DCD;
				else
					port->status &= ~ISI_DCD;
			}

A
Alan Cox 已提交
604
			if (port->port.flags & ASYNC_CTS_FLOW) {
A
Alan Cox 已提交
605
				if (tty->hw_stopped) {
606
					if (header & ISI_CTS) {
A
Alan Cox 已提交
607
						port->port.tty->hw_stopped = 0;
608
						/* start tx ing */
609 610
						port->status |= (ISI_TXOK
							| ISI_CTS);
611
						tty_wakeup(tty);
L
Linus Torvalds 已提交
612
					}
613
				} else if (!(header & ISI_CTS)) {
A
Alan Cox 已提交
614
					tty->hw_stopped = 1;
615 616
					/* stop tx ing */
					port->status &= ~(ISI_TXOK | ISI_CTS);
L
Linus Torvalds 已提交
617
				}
618
			} else {
619 620
				if (header & ISI_CTS)
					port->status |= ISI_CTS;
L
Linus Torvalds 已提交
621
				else
622 623 624 625 626 627 628 629 630 631 632 633 634 635 636
					port->status &= ~ISI_CTS;
			}

			if (header & ISI_DSR)
				port->status |= ISI_DSR;
			else
				port->status &= ~ISI_DSR;

			if (header & ISI_RI)
				port->status |= ISI_RI;
			else
				port->status &= ~ISI_RI;

			break;

637
		case 1:	/* Received Break !!! */
638
			tty_insert_flip_char(tty, 0, TTY_BREAK);
A
Alan Cox 已提交
639
			if (port->port.flags & ASYNC_SAK)
640 641 642 643 644
				do_SAK(tty);
			tty_flip_buffer_push(tty);
			break;

		case 2:	/* Statistics		 */
645
			pr_debug("%s: stats!!!\n", __func__);
646 647 648
			break;

		default:
649 650
			pr_debug("%s: Unknown code in status packet.\n",
				 __func__);
651 652
			break;
		}
653
	} else {				/* Data   Packet */
A
Alan Cox 已提交
654 655

		count = tty_prepare_flip_string(tty, &rp, byte_count & ~1);
656 657
		pr_debug("%s: Can rx %d of %d bytes.\n",
			 __func__, count, byte_count);
L
Linus Torvalds 已提交
658
		word_count = count >> 1;
A
Alan Cox 已提交
659
		insw(base, rp, word_count);
L
Linus Torvalds 已提交
660 661
		byte_count -= (word_count << 1);
		if (count & 0x0001) {
662 663
			tty_insert_flip_char(tty,  inw(base) & 0xff,
				TTY_NORMAL);
L
Linus Torvalds 已提交
664
			byte_count -= 2;
665
		}
L
Linus Torvalds 已提交
666
		if (byte_count > 0) {
667 668
			pr_debug("%s(0x%lx:%d): Flip buffer overflow! dropping bytes...\n",
				 __func__, base, channel + 1);
A
Alan Cox 已提交
669 670
		/* drain out unread xtra data */
		while (byte_count > 0) {
L
Linus Torvalds 已提交
671 672 673 674
				inw(base);
				byte_count -= 2;
			}
		}
A
Alan Cox 已提交
675
		tty_flip_buffer_push(tty);
L
Linus Torvalds 已提交
676
	}
J
Jiri Slaby 已提交
677
	outw(0x0000, base+0x04); /* enable interrupts */
678
	spin_unlock(&card->card_lock);
A
Alan Cox 已提交
679
	tty_kref_put(tty);
680

L
Linus Torvalds 已提交
681
	return IRQ_HANDLED;
682
}
L
Linus Torvalds 已提交
683

A
Alan Cox 已提交
684
static void isicom_config_port(struct tty_struct *tty)
L
Linus Torvalds 已提交
685
{
A
Alan Cox 已提交
686
	struct isi_port *port = tty->driver_data;
687
	struct isi_board *card = port->card;
L
Linus Torvalds 已提交
688
	unsigned long baud;
689 690 691
	unsigned long base = card->base;
	u16 channel_setup, channel = port->channel,
		shift_count = card->shift_count;
L
Linus Torvalds 已提交
692
	unsigned char flow_ctrl;
693

A
Alan Cox 已提交
694
	/* FIXME: Switch to new tty baud API */
L
Linus Torvalds 已提交
695 696 697
	baud = C_BAUD(tty);
	if (baud & CBAUDEX) {
		baud &= ~CBAUDEX;
698

L
Linus Torvalds 已提交
699 700 701
		/*  if CBAUDEX bit is on and the baud is set to either 50 or 75
		 *  then the card is programmed for 57.6Kbps or 115Kbps
		 *  respectively.
702 703
		 */

704 705
		/* 1,2,3,4 => 57.6, 115.2, 230, 460 kbps resp. */
		if (baud < 1 || baud > 4)
A
Alan Cox 已提交
706
			tty->termios->c_cflag &= ~CBAUDEX;
L
Linus Torvalds 已提交
707 708
		else
			baud += 15;
709
	}
L
Linus Torvalds 已提交
710
	if (baud == 15) {
711 712

		/*  the ASYNC_SPD_HI and ASYNC_SPD_VHI options are set
L
Linus Torvalds 已提交
713 714
		 *  by the set_serial_info ioctl ... this is done by
		 *  the 'setserial' utility.
715 716
		 */

A
Alan Cox 已提交
717
		if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
718
			baud++; /*  57.6 Kbps */
A
Alan Cox 已提交
719
		if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
A
Alan Cox 已提交
720
			baud += 2; /*  115  Kbps */
A
Alan Cox 已提交
721
		if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
722
			baud += 3; /* 230 kbps*/
A
Alan Cox 已提交
723
		if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
724
			baud += 4; /* 460 kbps*/
L
Linus Torvalds 已提交
725 726 727
	}
	if (linuxb_to_isib[baud] == -1) {
		/* hang up */
728 729
		drop_dtr(port);
		return;
A
Alan Cox 已提交
730
	} else
L
Linus Torvalds 已提交
731
		raise_dtr(port);
732

733
	if (WaitTillCardIsFree(base) == 0) {
A
Alan Cox 已提交
734
		outw(0x8000 | (channel << shift_count) | 0x03, base);
L
Linus Torvalds 已提交
735 736
		outw(linuxb_to_isib[baud] << 8 | 0x03, base);
		channel_setup = 0;
A
Alan Cox 已提交
737
		switch (C_CSIZE(tty)) {
738 739 740 741 742 743 744 745 746 747 748 749
		case CS5:
			channel_setup |= ISICOM_CS5;
			break;
		case CS6:
			channel_setup |= ISICOM_CS6;
			break;
		case CS7:
			channel_setup |= ISICOM_CS7;
			break;
		case CS8:
			channel_setup |= ISICOM_CS8;
			break;
L
Linus Torvalds 已提交
750
		}
751

L
Linus Torvalds 已提交
752 753 754 755 756
		if (C_CSTOPB(tty))
			channel_setup |= ISICOM_2SB;
		if (C_PARENB(tty)) {
			channel_setup |= ISICOM_EVPAR;
			if (C_PARODD(tty))
757
				channel_setup |= ISICOM_ODPAR;
L
Linus Torvalds 已提交
758
		}
759
		outw(channel_setup, base);
L
Linus Torvalds 已提交
760
		InterruptTheCard(base);
761
	}
L
Linus Torvalds 已提交
762
	if (C_CLOCAL(tty))
A
Alan Cox 已提交
763
		port->port.flags &= ~ASYNC_CHECK_CD;
L
Linus Torvalds 已提交
764
	else
A
Alan Cox 已提交
765
		port->port.flags |= ASYNC_CHECK_CD;
766

L
Linus Torvalds 已提交
767 768
	/* flow control settings ...*/
	flow_ctrl = 0;
A
Alan Cox 已提交
769
	port->port.flags &= ~ASYNC_CTS_FLOW;
L
Linus Torvalds 已提交
770
	if (C_CRTSCTS(tty)) {
A
Alan Cox 已提交
771
		port->port.flags |= ASYNC_CTS_FLOW;
L
Linus Torvalds 已提交
772
		flow_ctrl |= ISICOM_CTSRTS;
773 774
	}
	if (I_IXON(tty))
L
Linus Torvalds 已提交
775 776
		flow_ctrl |= ISICOM_RESPOND_XONXOFF;
	if (I_IXOFF(tty))
777 778
		flow_ctrl |= ISICOM_INITIATE_XONXOFF;

779
	if (WaitTillCardIsFree(base) == 0) {
A
Alan Cox 已提交
780
		outw(0x8000 | (channel << shift_count) | 0x04, base);
L
Linus Torvalds 已提交
781 782 783 784
		outw(flow_ctrl << 8 | 0x05, base);
		outw((STOP_CHAR(tty)) << 8 | (START_CHAR(tty)), base);
		InterruptTheCard(base);
	}
785

L
Linus Torvalds 已提交
786 787 788 789 790 791 792
	/*	rx enabled -> enable port for rx on the card	*/
	if (C_CREAD(tty)) {
		card->port_status |= (1 << channel);
		outw(card->port_status, base + 0x02);
	}
}

793 794 795
/* open et all */

static inline void isicom_setup_board(struct isi_board *bp)
L
Linus Torvalds 已提交
796 797
{
	int channel;
798 799
	struct isi_port *port;

800
	bp->count++;
801 802 803 804 805 806
	if (!(bp->status & BOARD_INIT)) {
		port = bp->ports;
		for (channel = 0; channel < bp->port_count; channel++, port++)
			drop_dtr_rts(port);
	}
	bp->status |= BOARD_ACTIVE | BOARD_INIT;
L
Linus Torvalds 已提交
807
}
808

809 810 811
/* Activate and thus setup board are protected from races against shutdown
   by the tty_port mutex */

812
static int isicom_activate(struct tty_port *tport, struct tty_struct *tty)
L
Linus Torvalds 已提交
813
{
814
	struct isi_port *port = container_of(tport, struct isi_port, port);
815
	struct isi_board *card = port->card;
L
Linus Torvalds 已提交
816
	unsigned long flags;
817

818
	if (tty_port_alloc_xmit_buf(tport) < 0)
A
Alan Cox 已提交
819
		return -ENOMEM;
L
Linus Torvalds 已提交
820 821

	spin_lock_irqsave(&card->card_lock, flags);
822
	isicom_setup_board(card);
823

L
Linus Torvalds 已提交
824
	port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
825

L
Linus Torvalds 已提交
826
	/*	discard any residual data	*/
827 828 829 830 831 832
	if (WaitTillCardIsFree(card->base) == 0) {
		outw(0x8000 | (port->channel << card->shift_count) | 0x02,
				card->base);
		outw(((ISICOM_KILLTX | ISICOM_KILLRX) << 8) | 0x06, card->base);
		InterruptTheCard(card->base);
	}
A
Alan Cox 已提交
833
	isicom_config_port(tty);
L
Linus Torvalds 已提交
834
	spin_unlock_irqrestore(&card->card_lock, flags);
835 836 837 838

	return 0;
}

839 840 841 842 843 844
static int isicom_carrier_raised(struct tty_port *port)
{
	struct isi_port *ip = container_of(port, struct isi_port, port);
	return (ip->status & ISI_DCD)?1 : 0;
}

845
static struct tty_port *isicom_find_port(struct tty_struct *tty)
L
Linus Torvalds 已提交
846
{
847 848
	struct isi_port *port;
	struct isi_board *card;
849
	unsigned int board;
850
	int line = tty->index;
L
Linus Torvalds 已提交
851 852 853

	board = BOARD(line);
	card = &isi_card[board];
854

L
Linus Torvalds 已提交
855
	if (!(card->status & FIRMWARE_LOADED))
856
		return NULL;
857

L
Linus Torvalds 已提交
858 859
	/*  open on a port greater than the port count for the card !!! */
	if (line > ((board * 16) + card->port_count - 1))
860
		return NULL;
L
Linus Torvalds 已提交
861

862
	port = &isi_ports[line];
L
Linus Torvalds 已提交
863
	if (isicom_paranoia_check(port, tty->name, "isicom_open"))
864 865 866 867
		return NULL;

	return &port->port;
}
868

869 870 871 872
static int isicom_open(struct tty_struct *tty, struct file *filp)
{
	struct isi_port *port;
	struct tty_port *tport;
873

874 875 876 877
	tport = isicom_find_port(tty);
	if (tport == NULL)
		return -ENODEV;
	port = container_of(tport, struct isi_port, port);
878

879
	tty->driver_data = port;
880
	return tty_port_open(tport, tty, filp);
L
Linus Torvalds 已提交
881
}
882

L
Linus Torvalds 已提交
883 884
/* close et all */

885
/* card->lock HAS to be held */
886
static void isicom_shutdown_port(struct isi_port *port)
L
Linus Torvalds 已提交
887
{
888
	struct isi_board *card = port->card;
L
Linus Torvalds 已提交
889 890

	if (--card->count < 0) {
891 892
		pr_debug("%s: bad board(0x%lx) count %d.\n",
			 __func__, card->base, card->count);
893
		card->count = 0;
L
Linus Torvalds 已提交
894
	}
895
	/* last port was closed, shutdown that board too */
896 897
	if (!card->count)
		card->status &= BOARD_ACTIVE;
L
Linus Torvalds 已提交
898 899
}

900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915
static void isicom_flush_buffer(struct tty_struct *tty)
{
	struct isi_port *port = tty->driver_data;
	struct isi_board *card = port->card;
	unsigned long flags;

	if (isicom_paranoia_check(port, tty->name, "isicom_flush_buffer"))
		return;

	spin_lock_irqsave(&card->card_lock, flags);
	port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
	spin_unlock_irqrestore(&card->card_lock, flags);

	tty_wakeup(tty);
}

916
static void isicom_shutdown(struct tty_port *port)
L
Linus Torvalds 已提交
917
{
918 919
	struct isi_port *ip = container_of(port, struct isi_port, port);
	struct isi_board *card = ip->card;
L
Linus Torvalds 已提交
920
	unsigned long flags;
921 922

	/* indicate to the card that no more data can be received
L
Linus Torvalds 已提交
923 924
	   on this port */
	spin_lock_irqsave(&card->card_lock, flags);
925 926
	card->port_status &= ~(1 << ip->channel);
	outw(card->port_status, card->base + 0x02);
927
	isicom_shutdown_port(ip);
L
Linus Torvalds 已提交
928
	spin_unlock_irqrestore(&card->card_lock, flags);
A
Alan Cox 已提交
929
	tty_port_free_xmit_buf(port);
930
}
931

932 933 934
static void isicom_close(struct tty_struct *tty, struct file *filp)
{
	struct isi_port *ip = tty->driver_data;
935 936 937 938 939 940
	struct tty_port *port;

	if (ip == NULL)
		return;

	port = &ip->port;
941 942
	if (isicom_paranoia_check(ip, tty->name, "isicom_close"))
		return;
943
	tty_port_close(port, tty, filp);
L
Linus Torvalds 已提交
944 945 946
}

/* write et all */
947 948
static int isicom_write(struct tty_struct *tty,	const unsigned char *buf,
	int count)
L
Linus Torvalds 已提交
949
{
950
	struct isi_port *port = tty->driver_data;
951
	struct isi_board *card = port->card;
L
Linus Torvalds 已提交
952 953 954 955 956
	unsigned long flags;
	int cnt, total = 0;

	if (isicom_paranoia_check(port, tty->name, "isicom_write"))
		return 0;
957

L
Linus Torvalds 已提交
958
	spin_lock_irqsave(&card->card_lock, flags);
959

A
Alan Cox 已提交
960
	while (1) {
961 962
		cnt = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt
				- 1, SERIAL_XMIT_SIZE - port->xmit_head));
963
		if (cnt <= 0)
L
Linus Torvalds 已提交
964
			break;
965

A
Alan Cox 已提交
966
		memcpy(port->port.xmit_buf + port->xmit_head, buf, cnt);
967 968
		port->xmit_head = (port->xmit_head + cnt) & (SERIAL_XMIT_SIZE
			- 1);
L
Linus Torvalds 已提交
969 970 971 972
		port->xmit_cnt += cnt;
		buf += cnt;
		count -= cnt;
		total += cnt;
973
	}
L
Linus Torvalds 已提交
974 975 976
	if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped)
		port->status |= ISI_TXOK;
	spin_unlock_irqrestore(&card->card_lock, flags);
977
	return total;
L
Linus Torvalds 已提交
978 979 980
}

/* put_char et all */
A
Alan Cox 已提交
981
static int isicom_put_char(struct tty_struct *tty, unsigned char ch)
L
Linus Torvalds 已提交
982
{
983
	struct isi_port *port = tty->driver_data;
984
	struct isi_board *card = port->card;
L
Linus Torvalds 已提交
985
	unsigned long flags;
986

L
Linus Torvalds 已提交
987
	if (isicom_paranoia_check(port, tty->name, "isicom_put_char"))
A
Alan Cox 已提交
988
		return 0;
989

L
Linus Torvalds 已提交
990
	spin_lock_irqsave(&card->card_lock, flags);
A
Alan Cox 已提交
991 992 993 994
	if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
		spin_unlock_irqrestore(&card->card_lock, flags);
		return 0;
	}
995

A
Alan Cox 已提交
996
	port->port.xmit_buf[port->xmit_head++] = ch;
L
Linus Torvalds 已提交
997 998 999
	port->xmit_head &= (SERIAL_XMIT_SIZE - 1);
	port->xmit_cnt++;
	spin_unlock_irqrestore(&card->card_lock, flags);
A
Alan Cox 已提交
1000
	return 1;
L
Linus Torvalds 已提交
1001 1002 1003
}

/* flush_chars et all */
1004
static void isicom_flush_chars(struct tty_struct *tty)
L
Linus Torvalds 已提交
1005
{
1006
	struct isi_port *port = tty->driver_data;
1007

L
Linus Torvalds 已提交
1008 1009
	if (isicom_paranoia_check(port, tty->name, "isicom_flush_chars"))
		return;
1010

1011
	if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
A
Alan Cox 已提交
1012
			!port->port.xmit_buf)
L
Linus Torvalds 已提交
1013
		return;
1014

L
Linus Torvalds 已提交
1015 1016
	/* this tells the transmitter to consider this port for
	   data output to the card ... that's the best we can do. */
1017
	port->status |= ISI_TXOK;
L
Linus Torvalds 已提交
1018 1019 1020
}

/* write_room et all */
1021
static int isicom_write_room(struct tty_struct *tty)
L
Linus Torvalds 已提交
1022
{
1023
	struct isi_port *port = tty->driver_data;
L
Linus Torvalds 已提交
1024 1025 1026 1027
	int free;

	if (isicom_paranoia_check(port, tty->name, "isicom_write_room"))
		return 0;
1028

L
Linus Torvalds 已提交
1029 1030 1031 1032 1033 1034 1035
	free = SERIAL_XMIT_SIZE - port->xmit_cnt - 1;
	if (free < 0)
		free = 0;
	return free;
}

/* chars_in_buffer et all */
1036
static int isicom_chars_in_buffer(struct tty_struct *tty)
L
Linus Torvalds 已提交
1037
{
1038
	struct isi_port *port = tty->driver_data;
L
Linus Torvalds 已提交
1039 1040 1041 1042 1043 1044
	if (isicom_paranoia_check(port, tty->name, "isicom_chars_in_buffer"))
		return 0;
	return port->xmit_cnt;
}

/* ioctl et all */
1045
static int isicom_send_break(struct tty_struct *tty, int length)
L
Linus Torvalds 已提交
1046
{
1047
	struct isi_port *port = tty->driver_data;
1048
	struct isi_board *card = port->card;
1049
	unsigned long base = card->base;
1050

1051 1052 1053
	if (length == -1)
		return -EOPNOTSUPP;

1054
	if (!lock_card(card))
1055
		return -EINVAL;
1056

L
Linus Torvalds 已提交
1057 1058 1059 1060 1061 1062
	outw(0x8000 | ((port->channel) << (card->shift_count)) | 0x3, base);
	outw((length & 0xff) << 8 | 0x00, base);
	outw((length & 0xff00), base);
	InterruptTheCard(base);

	unlock_card(card);
1063
	return 0;
L
Linus Torvalds 已提交
1064 1065
}

1066
static int isicom_tiocmget(struct tty_struct *tty)
L
Linus Torvalds 已提交
1067
{
1068
	struct isi_port *port = tty->driver_data;
L
Linus Torvalds 已提交
1069
	/* just send the port status */
1070
	u16 status = port->status;
L
Linus Torvalds 已提交
1071 1072 1073

	if (isicom_paranoia_check(port, tty->name, "isicom_ioctl"))
		return -ENODEV;
1074

L
Linus Torvalds 已提交
1075 1076 1077 1078 1079 1080 1081 1082
	return  ((status & ISI_RTS) ? TIOCM_RTS : 0) |
		((status & ISI_DTR) ? TIOCM_DTR : 0) |
		((status & ISI_DCD) ? TIOCM_CAR : 0) |
		((status & ISI_DSR) ? TIOCM_DSR : 0) |
		((status & ISI_CTS) ? TIOCM_CTS : 0) |
		((status & ISI_RI ) ? TIOCM_RI  : 0);
}

1083 1084
static int isicom_tiocmset(struct tty_struct *tty,
					unsigned int set, unsigned int clear)
L
Linus Torvalds 已提交
1085
{
1086
	struct isi_port *port = tty->driver_data;
1087
	unsigned long flags;
1088

L
Linus Torvalds 已提交
1089 1090
	if (isicom_paranoia_check(port, tty->name, "isicom_ioctl"))
		return -ENODEV;
1091

1092
	spin_lock_irqsave(&port->card->card_lock, flags);
L
Linus Torvalds 已提交
1093 1094 1095 1096 1097 1098 1099 1100 1101
	if (set & TIOCM_RTS)
		raise_rts(port);
	if (set & TIOCM_DTR)
		raise_dtr(port);

	if (clear & TIOCM_RTS)
		drop_rts(port);
	if (clear & TIOCM_DTR)
		drop_dtr(port);
1102
	spin_unlock_irqrestore(&port->card->card_lock, flags);
L
Linus Torvalds 已提交
1103 1104

	return 0;
1105
}
L
Linus Torvalds 已提交
1106

A
Alan Cox 已提交
1107 1108
static int isicom_set_serial_info(struct tty_struct *tty,
					struct serial_struct __user *info)
L
Linus Torvalds 已提交
1109
{
A
Alan Cox 已提交
1110
	struct isi_port *port = tty->driver_data;
L
Linus Torvalds 已提交
1111 1112 1113
	struct serial_struct newinfo;
	int reconfig_port;

1114
	if (copy_from_user(&newinfo, info, sizeof(newinfo)))
L
Linus Torvalds 已提交
1115
		return -EFAULT;
1116

A
Alan Cox 已提交
1117
	mutex_lock(&port->port.mutex);
A
Alan Cox 已提交
1118
	reconfig_port = ((port->port.flags & ASYNC_SPD_MASK) !=
1119 1120
		(newinfo.flags & ASYNC_SPD_MASK));

L
Linus Torvalds 已提交
1121
	if (!capable(CAP_SYS_ADMIN)) {
A
Alan Cox 已提交
1122 1123
		if ((newinfo.close_delay != port->port.close_delay) ||
				(newinfo.closing_wait != port->port.closing_wait) ||
1124
				((newinfo.flags & ~ASYNC_USR_MASK) !=
A
Alan Cox 已提交
1125
				(port->port.flags & ~ASYNC_USR_MASK))) {
A
Alan Cox 已提交
1126
			mutex_unlock(&port->port.mutex);
L
Linus Torvalds 已提交
1127
			return -EPERM;
1128
		}
A
Alan Cox 已提交
1129
		port->port.flags = ((port->port.flags & ~ASYNC_USR_MASK) |
L
Linus Torvalds 已提交
1130
				(newinfo.flags & ASYNC_USR_MASK));
A
Alan Cox 已提交
1131
	} else {
A
Alan Cox 已提交
1132 1133
		port->port.close_delay = newinfo.close_delay;
		port->port.closing_wait = newinfo.closing_wait;
A
Alan Cox 已提交
1134
		port->port.flags = ((port->port.flags & ~ASYNC_FLAGS) |
L
Linus Torvalds 已提交
1135 1136 1137
				(newinfo.flags & ASYNC_FLAGS));
	}
	if (reconfig_port) {
1138 1139
		unsigned long flags;
		spin_lock_irqsave(&port->card->card_lock, flags);
A
Alan Cox 已提交
1140
		isicom_config_port(tty);
1141
		spin_unlock_irqrestore(&port->card->card_lock, flags);
L
Linus Torvalds 已提交
1142
	}
A
Alan Cox 已提交
1143
	mutex_unlock(&port->port.mutex);
1144 1145
	return 0;
}
L
Linus Torvalds 已提交
1146

1147 1148
static int isicom_get_serial_info(struct isi_port *port,
	struct serial_struct __user *info)
L
Linus Torvalds 已提交
1149 1150
{
	struct serial_struct out_info;
1151

A
Alan Cox 已提交
1152
	mutex_lock(&port->port.mutex);
L
Linus Torvalds 已提交
1153 1154 1155 1156 1157
	memset(&out_info, 0, sizeof(out_info));
/*	out_info.type = ? */
	out_info.line = port - isi_ports;
	out_info.port = port->card->base;
	out_info.irq = port->card->irq;
A
Alan Cox 已提交
1158
	out_info.flags = port->port.flags;
L
Linus Torvalds 已提交
1159
/*	out_info.baud_base = ? */
A
Alan Cox 已提交
1160 1161
	out_info.close_delay = port->port.close_delay;
	out_info.closing_wait = port->port.closing_wait;
A
Alan Cox 已提交
1162
	mutex_unlock(&port->port.mutex);
1163
	if (copy_to_user(info, &out_info, sizeof(out_info)))
L
Linus Torvalds 已提交
1164 1165
		return -EFAULT;
	return 0;
1166
}
L
Linus Torvalds 已提交
1167

1168
static int isicom_ioctl(struct tty_struct *tty,
1169
	unsigned int cmd, unsigned long arg)
L
Linus Torvalds 已提交
1170
{
1171
	struct isi_port *port = tty->driver_data;
L
Linus Torvalds 已提交
1172 1173 1174 1175 1176
	void __user *argp = (void __user *)arg;

	if (isicom_paranoia_check(port, tty->name, "isicom_ioctl"))
		return -ENODEV;

A
Alan Cox 已提交
1177
	switch (cmd) {
1178 1179 1180 1181
	case TIOCGSERIAL:
		return isicom_get_serial_info(port, argp);

	case TIOCSSERIAL:
A
Alan Cox 已提交
1182
		return isicom_set_serial_info(tty, argp);
1183 1184 1185

	default:
		return -ENOIOCTLCMD;
L
Linus Torvalds 已提交
1186 1187 1188 1189 1190
	}
	return 0;
}

/* set_termios et all */
1191
static void isicom_set_termios(struct tty_struct *tty,
A
Alan Cox 已提交
1192
	struct ktermios *old_termios)
L
Linus Torvalds 已提交
1193
{
1194
	struct isi_port *port = tty->driver_data;
1195
	unsigned long flags;
1196

L
Linus Torvalds 已提交
1197 1198
	if (isicom_paranoia_check(port, tty->name, "isicom_set_termios"))
		return;
1199

L
Linus Torvalds 已提交
1200
	if (tty->termios->c_cflag == old_termios->c_cflag &&
1201
			tty->termios->c_iflag == old_termios->c_iflag)
L
Linus Torvalds 已提交
1202
		return;
1203

1204
	spin_lock_irqsave(&port->card->card_lock, flags);
A
Alan Cox 已提交
1205
	isicom_config_port(tty);
1206
	spin_unlock_irqrestore(&port->card->card_lock, flags);
1207

L
Linus Torvalds 已提交
1208
	if ((old_termios->c_cflag & CRTSCTS) &&
1209
			!(tty->termios->c_cflag & CRTSCTS)) {
L
Linus Torvalds 已提交
1210
		tty->hw_stopped = 0;
1211 1212
		isicom_start(tty);
	}
L
Linus Torvalds 已提交
1213 1214 1215
}

/* throttle et all */
1216
static void isicom_throttle(struct tty_struct *tty)
L
Linus Torvalds 已提交
1217
{
1218
	struct isi_port *port = tty->driver_data;
1219 1220
	struct isi_board *card = port->card;

L
Linus Torvalds 已提交
1221 1222
	if (isicom_paranoia_check(port, tty->name, "isicom_throttle"))
		return;
1223

L
Linus Torvalds 已提交
1224 1225 1226 1227 1228 1229
	/* tell the card that this port cannot handle any more data for now */
	card->port_status &= ~(1 << port->channel);
	outw(card->port_status, card->base + 0x02);
}

/* unthrottle et all */
1230
static void isicom_unthrottle(struct tty_struct *tty)
L
Linus Torvalds 已提交
1231
{
1232
	struct isi_port *port = tty->driver_data;
1233 1234
	struct isi_board *card = port->card;

L
Linus Torvalds 已提交
1235 1236
	if (isicom_paranoia_check(port, tty->name, "isicom_unthrottle"))
		return;
1237

L
Linus Torvalds 已提交
1238 1239 1240 1241 1242 1243
	/* tell the card that this port is ready to accept more data */
	card->port_status |= (1 << port->channel);
	outw(card->port_status, card->base + 0x02);
}

/* stop et all */
1244
static void isicom_stop(struct tty_struct *tty)
L
Linus Torvalds 已提交
1245
{
1246
	struct isi_port *port = tty->driver_data;
L
Linus Torvalds 已提交
1247 1248 1249

	if (isicom_paranoia_check(port, tty->name, "isicom_stop"))
		return;
1250

L
Linus Torvalds 已提交
1251 1252 1253 1254 1255 1256
	/* this tells the transmitter not to consider this port for
	   data output to the card. */
	port->status &= ~ISI_TXOK;
}

/* start et all */
1257
static void isicom_start(struct tty_struct *tty)
L
Linus Torvalds 已提交
1258
{
1259
	struct isi_port *port = tty->driver_data;
1260

L
Linus Torvalds 已提交
1261 1262
	if (isicom_paranoia_check(port, tty->name, "isicom_start"))
		return;
1263

L
Linus Torvalds 已提交
1264 1265 1266 1267 1268
	/* this tells the transmitter to consider this port for
	   data output to the card. */
	port->status |= ISI_TXOK;
}

1269
static void isicom_hangup(struct tty_struct *tty)
L
Linus Torvalds 已提交
1270
{
1271
	struct isi_port *port = tty->driver_data;
1272

L
Linus Torvalds 已提交
1273 1274
	if (isicom_paranoia_check(port, tty->name, "isicom_hangup"))
		return;
1275
	tty_port_hangup(&port->port);
L
Linus Torvalds 已提交
1276 1277 1278
}


1279 1280 1281
/*
 * Driver init and deinit functions
 */
L
Linus Torvalds 已提交
1282

J
Jeff Dike 已提交
1283
static const struct tty_operations isicom_ops = {
1284 1285 1286 1287 1288 1289
	.open			= isicom_open,
	.close			= isicom_close,
	.write			= isicom_write,
	.put_char		= isicom_put_char,
	.flush_chars		= isicom_flush_chars,
	.write_room		= isicom_write_room,
L
Linus Torvalds 已提交
1290
	.chars_in_buffer	= isicom_chars_in_buffer,
1291 1292 1293 1294 1295 1296 1297 1298 1299 1300
	.ioctl			= isicom_ioctl,
	.set_termios		= isicom_set_termios,
	.throttle		= isicom_throttle,
	.unthrottle		= isicom_unthrottle,
	.stop			= isicom_stop,
	.start			= isicom_start,
	.hangup			= isicom_hangup,
	.flush_buffer		= isicom_flush_buffer,
	.tiocmget		= isicom_tiocmget,
	.tiocmset		= isicom_tiocmset,
1301
	.break_ctl		= isicom_send_break,
L
Linus Torvalds 已提交
1302 1303
};

1304 1305
static const struct tty_port_operations isicom_port_ops = {
	.carrier_raised		= isicom_carrier_raised,
1306
	.dtr_rts		= isicom_dtr_rts,
1307 1308
	.activate		= isicom_activate,
	.shutdown		= isicom_shutdown,
1309 1310
};

1311 1312
static int __devinit reset_card(struct pci_dev *pdev,
	const unsigned int card, unsigned int *signature)
L
Linus Torvalds 已提交
1313
{
1314 1315
	struct isi_board *board = pci_get_drvdata(pdev);
	unsigned long base = board->base;
1316
	unsigned int sig, portcount = 0;
1317
	int retval = 0;
1318

1319 1320
	dev_dbg(&pdev->dev, "ISILoad:Resetting Card%d at 0x%lx\n", card + 1,
		base);
1321

1322
	inw(base + 0x8);
1323

1324
	msleep(10);
1325 1326 1327

	outw(0, base + 0x8); /* Reset */

1328
	msleep(1000);
1329

1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341
	sig = inw(base + 0x4) & 0xff;

	if (sig != 0xa5 && sig != 0xbb && sig != 0xcc && sig != 0xdd &&
			sig != 0xee) {
		dev_warn(&pdev->dev, "ISILoad:Card%u reset failure (Possible "
			"bad I/O Port Address 0x%lx).\n", card + 1, base);
		dev_dbg(&pdev->dev, "Sig=0x%x\n", sig);
		retval = -EIO;
		goto end;
	}

	msleep(10);
1342

J
Jiri Slaby 已提交
1343
	portcount = inw(base + 0x2);
1344
	if (!(inw(base + 0xe) & 0x1) || (portcount != 0 && portcount != 4 &&
1345
				portcount != 8 && portcount != 16)) {
1346
		dev_err(&pdev->dev, "ISILoad:PCI Card%d reset failure.\n",
1347
			card + 1);
J
Jiri Slaby 已提交
1348 1349
		retval = -EIO;
		goto end;
1350 1351
	}

1352
	switch (sig) {
1353 1354 1355
	case 0xa5:
	case 0xbb:
	case 0xdd:
J
Jiri Slaby 已提交
1356
		board->port_count = (portcount == 4) ? 4 : 8;
1357 1358 1359
		board->shift_count = 12;
		break;
	case 0xcc:
1360
	case 0xee:
1361 1362 1363
		board->port_count = 16;
		board->shift_count = 11;
		break;
1364
	}
1365
	dev_info(&pdev->dev, "-Done\n");
1366
	*signature = sig;
1367

1368 1369
end:
	return retval;
L
Linus Torvalds 已提交
1370 1371
}

1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408
static int __devinit load_firmware(struct pci_dev *pdev,
	const unsigned int index, const unsigned int signature)
{
	struct isi_board *board = pci_get_drvdata(pdev);
	const struct firmware *fw;
	unsigned long base = board->base;
	unsigned int a;
	u16 word_count, status;
	int retval = -EIO;
	char *name;
	u8 *data;

	struct stframe {
		u16	addr;
		u16	count;
		u8	data[0];
	} *frame;

	switch (signature) {
	case 0xa5:
		name = "isi608.bin";
		break;
	case 0xbb:
		name = "isi608em.bin";
		break;
	case 0xcc:
		name = "isi616em.bin";
		break;
	case 0xdd:
		name = "isi4608.bin";
		break;
	case 0xee:
		name = "isi4616.bin";
		break;
	default:
		dev_err(&pdev->dev, "Unknown signature.\n");
		goto end;
A
Alan Cox 已提交
1409
	}
1410 1411 1412 1413 1414

	retval = request_firmware(&fw, name, &pdev->dev);
	if (retval)
		goto end;

1415 1416
	retval = -EIO;

1417 1418
	for (frame = (struct stframe *)fw->data;
			frame < (struct stframe *)(fw->data + fw->size);
1419 1420
			frame = (struct stframe *)((u8 *)(frame + 1) +
				frame->count)) {
1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436
		if (WaitTillCardIsFree(base))
			goto errrelfw;

		outw(0xf0, base);	/* start upload sequence */
		outw(0x00, base);
		outw(frame->addr, base); /* lsb of address */

		word_count = frame->count / 2 + frame->count % 2;
		outw(word_count, base);
		InterruptTheCard(base);

		udelay(100); /* 0x2f */

		if (WaitTillCardIsFree(base))
			goto errrelfw;

A
Alan Cox 已提交
1437 1438
		status = inw(base + 0x4);
		if (status != 0) {
1439
			dev_warn(&pdev->dev, "Card%d rejected load header:\n"
1440 1441 1442 1443
				 "Address:0x%x\n"
				 "Count:0x%x\n"
				 "Status:0x%x\n",
				 index + 1, frame->addr, frame->count, status);
1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454
			goto errrelfw;
		}
		outsw(base, frame->data, word_count);

		InterruptTheCard(base);

		udelay(50); /* 0x0f */

		if (WaitTillCardIsFree(base))
			goto errrelfw;

A
Alan Cox 已提交
1455 1456
		status = inw(base + 0x4);
		if (status != 0) {
1457 1458 1459 1460
			dev_err(&pdev->dev, "Card%d got out of sync.Card "
				"Status:0x%x\n", index + 1, status);
			goto errrelfw;
		}
A
Alan Cox 已提交
1461
	}
1462 1463 1464

/* XXX: should we test it by reading it back and comparing with original like
 * in load firmware package? */
1465 1466 1467 1468
	for (frame = (struct stframe *)fw->data;
			frame < (struct stframe *)(fw->data + fw->size);
			frame = (struct stframe *)((u8 *)(frame + 1) +
				frame->count)) {
1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484
		if (WaitTillCardIsFree(base))
			goto errrelfw;

		outw(0xf1, base); /* start download sequence */
		outw(0x00, base);
		outw(frame->addr, base); /* lsb of address */

		word_count = (frame->count >> 1) + frame->count % 2;
		outw(word_count + 1, base);
		InterruptTheCard(base);

		udelay(50); /* 0xf */

		if (WaitTillCardIsFree(base))
			goto errrelfw;

A
Alan Cox 已提交
1485 1486
		status = inw(base + 0x4);
		if (status != 0) {
1487
			dev_warn(&pdev->dev, "Card%d rejected verify header:\n"
1488 1489 1490 1491
				 "Address:0x%x\n"
				 "Count:0x%x\n"
				 "Status: 0x%x\n",
				 index + 1, frame->addr, frame->count, status);
1492 1493 1494 1495
			goto errrelfw;
		}

		data = kmalloc(word_count * 2, GFP_KERNEL);
1496 1497 1498 1499 1500
		if (data == NULL) {
			dev_err(&pdev->dev, "Card%d, firmware upload "
				"failed, not enough memory\n", index + 1);
			goto errrelfw;
		}
1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518
		inw(base);
		insw(base, data, word_count);
		InterruptTheCard(base);

		for (a = 0; a < frame->count; a++)
			if (data[a] != frame->data[a]) {
				kfree(data);
				dev_err(&pdev->dev, "Card%d, firmware upload "
					"failed\n", index + 1);
				goto errrelfw;
			}
		kfree(data);

		udelay(50); /* 0xf */

		if (WaitTillCardIsFree(base))
			goto errrelfw;

A
Alan Cox 已提交
1519 1520
		status = inw(base + 0x4);
		if (status != 0) {
1521 1522 1523 1524 1525 1526
			dev_err(&pdev->dev, "Card%d verify got out of sync. "
				"Card Status:0x%x\n", index + 1, status);
			goto errrelfw;
		}
	}

1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537
	/* xfer ctrl */
	if (WaitTillCardIsFree(base))
		goto errrelfw;

	outw(0xf2, base);
	outw(0x800, base);
	outw(0x0, base);
	outw(0x0, base);
	InterruptTheCard(base);
	outw(0x0, base + 0x4); /* for ISI4608 cards */

1538 1539 1540 1541 1542 1543 1544 1545 1546
	board->status |= FIRMWARE_LOADED;
	retval = 0;

errrelfw:
	release_firmware(fw);
end:
	return retval;
}

L
Linus Torvalds 已提交
1547 1548 1549
/*
 *	Insmod can set static symbols so keep these static
 */
1550
static unsigned int card_count;
1551 1552 1553 1554

static int __devinit isicom_probe(struct pci_dev *pdev,
	const struct pci_device_id *ent)
{
J
Jiri Slaby 已提交
1555
	unsigned int uninitialized_var(signature), index;
1556 1557 1558
	int retval = -EPERM;
	struct isi_board *board = NULL;

1559
	if (card_count >= BOARD_COUNT)
1560 1561
		goto err;

1562 1563 1564 1565 1566 1567
	retval = pci_enable_device(pdev);
	if (retval) {
		dev_err(&pdev->dev, "failed to enable\n");
		goto err;
	}

1568 1569 1570
	dev_info(&pdev->dev, "ISI PCI Card(Device ID 0x%x)\n", ent->device);

	/* allot the first empty slot in the array */
1571
	for (index = 0; index < BOARD_COUNT; index++) {
1572 1573 1574 1575
		if (isi_card[index].base == 0) {
			board = &isi_card[index];
			break;
		}
1576 1577 1578 1579 1580
	}
	if (index == BOARD_COUNT) {
		retval = -ENODEV;
		goto err_disable;
	}
1581

1582
	board->index = index;
1583 1584
	board->base = pci_resource_start(pdev, 3);
	board->irq = pdev->irq;
1585
	card_count++;
1586 1587 1588

	pci_set_drvdata(pdev, board);

1589 1590
	retval = pci_request_region(pdev, 3, ISICOM_NAME);
	if (retval) {
J
Jiri Slaby 已提交
1591 1592 1593 1594
		dev_err(&pdev->dev, "I/O Region 0x%lx-0x%lx is busy. Card%d "
			"will be disabled.\n", board->base, board->base + 15,
			index + 1);
		retval = -EBUSY;
1595
		goto errdec;
A
Alan Cox 已提交
1596
	}
1597

J
Jiri Slaby 已提交
1598
	retval = request_irq(board->irq, isicom_interrupt,
Y
Yong Zhang 已提交
1599
			IRQF_SHARED, ISICOM_NAME, board);
J
Jiri Slaby 已提交
1600 1601 1602
	if (retval < 0) {
		dev_err(&pdev->dev, "Could not install handler at Irq %d. "
			"Card%d will be disabled.\n", board->irq, index + 1);
1603
		goto errunrr;
J
Jiri Slaby 已提交
1604
	}
1605 1606 1607 1608 1609

	retval = reset_card(pdev, index, &signature);
	if (retval < 0)
		goto errunri;

1610 1611 1612 1613
	retval = load_firmware(pdev, index, signature);
	if (retval < 0)
		goto errunri;

1614 1615 1616 1617
	for (index = 0; index < board->port_count; index++)
		tty_register_device(isicom_normal, board->index * 16 + index,
				&pdev->dev);

1618 1619 1620 1621 1622
	return 0;

errunri:
	free_irq(board->irq, board);
errunrr:
1623
	pci_release_region(pdev, 3);
1624
errdec:
1625
	board->base = 0;
1626
	card_count--;
1627
err_disable:
1628
	pci_disable_device(pdev);
1629
err:
1630 1631 1632 1633 1634 1635
	return retval;
}

static void __devexit isicom_remove(struct pci_dev *pdev)
{
	struct isi_board *board = pci_get_drvdata(pdev);
1636 1637 1638 1639
	unsigned int i;

	for (i = 0; i < board->port_count; i++)
		tty_unregister_device(isicom_normal, board->index * 16 + i);
1640 1641

	free_irq(board->irq, board);
1642
	pci_release_region(pdev, 3);
1643 1644
	board->base = 0;
	card_count--;
1645
	pci_disable_device(pdev);
1646
}
L
Linus Torvalds 已提交
1647

1648
static int __init isicom_init(void)
L
Linus Torvalds 已提交
1649
{
1650 1651
	int retval, idx, channel;
	struct isi_port *port;
1652

A
Alan Cox 已提交
1653
	for (idx = 0; idx < BOARD_COUNT; idx++) {
1654 1655 1656 1657
		port = &isi_ports[idx * 16];
		isi_card[idx].ports = port;
		spin_lock_init(&isi_card[idx].card_lock);
		for (channel = 0; channel < 16; channel++, port++) {
A
Alan Cox 已提交
1658
			tty_port_init(&port->port);
1659
			port->port.ops = &isicom_port_ops;
1660 1661 1662
			port->magic = ISICOM_MAGIC;
			port->card = &isi_card[idx];
			port->channel = channel;
A
Alan Cox 已提交
1663 1664
			port->port.close_delay = 50 * HZ/100;
			port->port.closing_wait = 3000 * HZ/100;
1665 1666
			port->status = 0;
			/*  . . .  */
A
Alan Cox 已提交
1667
		}
1668 1669
		isi_card[idx].base = 0;
		isi_card[idx].irq = 0;
L
Linus Torvalds 已提交
1670
	}
1671

J
Jiri Slaby 已提交
1672 1673 1674 1675
	/* tty driver structure initialization */
	isicom_normal = alloc_tty_driver(PORT_COUNT);
	if (!isicom_normal) {
		retval = -ENOMEM;
1676
		goto error;
J
Jiri Slaby 已提交
1677 1678 1679 1680 1681 1682 1683 1684 1685 1686
	}

	isicom_normal->name 			= "ttyM";
	isicom_normal->major			= ISICOM_NMAJOR;
	isicom_normal->minor_start		= 0;
	isicom_normal->type			= TTY_DRIVER_TYPE_SERIAL;
	isicom_normal->subtype			= SERIAL_TYPE_NORMAL;
	isicom_normal->init_termios		= tty_std_termios;
	isicom_normal->init_termios.c_cflag	= B9600 | CS8 | CREAD | HUPCL |
		CLOCAL;
1687
	isicom_normal->flags			= TTY_DRIVER_REAL_RAW |
1688
		TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_HARDWARE_BREAK;
J
Jiri Slaby 已提交
1689 1690 1691 1692
	tty_set_operations(isicom_normal, &isicom_ops);

	retval = tty_register_driver(isicom_normal);
	if (retval) {
1693
		pr_debug("Couldn't register the dialin driver\n");
J
Jiri Slaby 已提交
1694 1695
		goto err_puttty;
	}
L
Linus Torvalds 已提交
1696

1697
	retval = pci_register_driver(&isicom_driver);
L
Linus Torvalds 已提交
1698
	if (retval < 0) {
1699
		pr_err("Unable to register pci driver.\n");
J
Jiri Slaby 已提交
1700
		goto err_unrtty;
L
Linus Torvalds 已提交
1701
	}
1702

J
Jiri Slaby 已提交
1703
	mod_timer(&tx, jiffies + 1);
1704

L
Linus Torvalds 已提交
1705
	return 0;
J
Jiri Slaby 已提交
1706 1707 1708 1709
err_unrtty:
	tty_unregister_driver(isicom_normal);
err_puttty:
	put_tty_driver(isicom_normal);
1710 1711
error:
	return retval;
L
Linus Torvalds 已提交
1712 1713 1714 1715
}

static void __exit isicom_exit(void)
{
J
Jiri Slaby 已提交
1716
	del_timer_sync(&tx);
1717

1718
	pci_unregister_driver(&isicom_driver);
J
Jiri Slaby 已提交
1719 1720
	tty_unregister_driver(isicom_normal);
	put_tty_driver(isicom_normal);
L
Linus Torvalds 已提交
1721 1722
}

1723
module_init(isicom_init);
L
Linus Torvalds 已提交
1724
module_exit(isicom_exit);
1725 1726 1727 1728

MODULE_AUTHOR("MultiTech");
MODULE_DESCRIPTION("Driver for the ISI series of cards by MultiTech");
MODULE_LICENSE("GPL");
1729 1730 1731 1732 1733
MODULE_FIRMWARE("isi608.bin");
MODULE_FIRMWARE("isi608em.bin");
MODULE_FIRMWARE("isi616em.bin");
MODULE_FIRMWARE("isi4608.bin");
MODULE_FIRMWARE("isi4616.bin");