11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	This program is free software; you can redistribute it and/or
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	modify it under the terms of the GNU General Public License
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	as published by the Free Software Foundation; either version
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	2 of the License, or (at your option) any later version.
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Original driver code supplied by Multi-Tech
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Changes
108eb04cf3402c59e84af9d2e86149edb4044f9a9eAlan Cox *	1/9/98	alan@lxorguk.ukuu.org.uk
118eb04cf3402c59e84af9d2e86149edb4044f9a9eAlan Cox *					Merge to 2.0.x kernel tree
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *					Obtain and use official major/minors
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *					Loader switched to a misc device
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *					(fixed range check bug as a side effect)
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *					Printk clean up
168eb04cf3402c59e84af9d2e86149edb4044f9a9eAlan Cox *	9/12/98	alan@lxorguk.ukuu.org.uk
178eb04cf3402c59e84af9d2e86149edb4044f9a9eAlan Cox *					Rough port to 2.1.x
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	10/6/99 sameer			Merged the ISA and PCI drivers to
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *					a new unified driver.
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	3/9/99	sameer			Added support for ISI4616 cards.
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	16/9/99	sameer			We do not force RTS low anymore.
25d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby *					This is to prevent the firmware
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *					from getting confused.
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	26/10/99 sameer			Cosmetic changes:The driver now
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *					dumps the Port Count information
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *					along with I/O address and IRQ.
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	13/12/99 sameer			Fixed the problem with IRQ sharing.
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	10/5/00  sameer			Fixed isicom_shutdown_board()
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *					to not lower DTR on all the ports
36d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby *					when the last port on the card is
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *					closed.
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	10/5/00  sameer			Signal mask setup command added
40d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby *					to  isicom_setup_port and
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *					isicom_shutdown_port.
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	24/5/00  sameer			The driver is now SMP aware.
44d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby *
45d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby *
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	27/11/00 Vinayak P Risbud	Fixed the Driver Crash Problem
47d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby *
48d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby *
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	03/01/01  anil .s		Added support for resetting the
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *					internal modems on ISI cards.
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	08/02/01  anil .s		Upgraded the driver for kernel
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *					2.4.x
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
55d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby *	11/04/01  Kevin			Fixed firmware load problem with
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *					ISIHP-4X card
57d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby *
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	30/04/01  anil .s		Fixed the remote login through
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *					ISI port problem. Now the link
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *					does not go down before password
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *					prompt.
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	03/05/01  anil .s		Fixed the problem with IRQ sharing
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *					among ISI-PCI cards.
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	03/05/01  anil .s		Added support to display the version
67d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby *					info during insmod as well as module
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *					listing by lsmod.
69d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby *
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	10/05/01  anil .s		Done the modifications to the source
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *					file and Install script so that the
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *					same installation can be used for
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *					2.2.x and 2.4.x kernel.
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	06/06/01  anil .s		Now we drop both dtr and rts during
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *					shutdown_port as well as raise them
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *					during isicom_config_port.
78d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby *
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	09/06/01 acme@conectiva.com.br	use capable, not suser, do
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *					restore_flags on failure in
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *					isicom_send_break, verify put_user
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *					result
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
84d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby *	11/02/03  ranjeeth		Added support for 230 Kbps and 460 Kbps
85d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby *					Baud index extended to 21
86d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby *
87d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby *	20/03/03  ranjeeth		Made to work for Linux Advanced server.
88d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby *					Taken care of license warning.
89d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby *
90d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby *	10/12/03  Ravindra		Made to work for Fedora Core 1 of
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *					Red Hat Distribution
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	06/01/05  Alan Cox 		Merged the ISI and base kernel strands
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *					into a single 2.6 driver
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	***********************************************************
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
98d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby *	To use this driver you also need the support package. You
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	can find this in RPM format on
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		ftp://ftp.linux.org.uk/pub/linux/alan
101d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby *
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	You can find the original tools for this direct from Multitech
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		ftp://ftp.multitech.com/ISI-Cards/
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
105970e2486492aa1eb47a436a5a4c81e92558986a9Lucas De Marchi *	Having installed the cards the module options (/etc/modprobe.d/)
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	options isicom   io=card1,card2,card3,card4 irq=card1,card2,card3,card4
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Omit those entries for boards you don't have installed.
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	TODO
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		Merge testing
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		64-bit verification
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
116db91340b2e874693f14e9e937152e7433d7ac753Joe Perches#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
117db91340b2e874693f14e9e937152e7433d7ac753Joe Perches
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
119e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby#include <linux/firmware.h>
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty.h>
12233f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox#include <linux/tty_flip.h>
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/termios.h>
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fs.h>
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sched.h>
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/serial.h>
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h>
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/timer.h>
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h>
1325a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
134251b8dd7eee30fda089a1dc088abf4fc9a0dee9cAlan Cox#include <linux/uaccess.h>
135251b8dd7eee30fda089a1dc088abf4fc9a0dee9cAlan Cox#include <linux/io.h>
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h>
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/isicom.h>
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
141aaa246ea78c68cd205f505070650cda7c5a95d34Jiri Slaby#define InterruptTheCard(base) outw(0, (base) + 0xc)
142aaa246ea78c68cd205f505070650cda7c5a95d34Jiri Slaby#define ClearInterrupt(base) inw((base) + 0x0a)
143aaa246ea78c68cd205f505070650cda7c5a95d34Jiri Slaby
144aaa246ea78c68cd205f505070650cda7c5a95d34Jiri Slaby#ifdef DEBUG
145aaa246ea78c68cd205f505070650cda7c5a95d34Jiri Slaby#define isicom_paranoia_check(a, b, c) __isicom_paranoia_check((a), (b), (c))
146aaa246ea78c68cd205f505070650cda7c5a95d34Jiri Slaby#else
147aaa246ea78c68cd205f505070650cda7c5a95d34Jiri Slaby#define isicom_paranoia_check(a, b, c) 0
148aaa246ea78c68cd205f505070650cda7c5a95d34Jiri Slaby#endif
149aaa246ea78c68cd205f505070650cda7c5a95d34Jiri Slaby
1509ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slabystatic int isicom_probe(struct pci_dev *, const struct pci_device_id *);
1519ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slabystatic void __devexit isicom_remove(struct pci_dev *);
1529ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pci_device_id isicom_pci_tbl[] = {
1549ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	{ PCI_DEVICE(VENDOR_ID, 0x2028) },
1559ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	{ PCI_DEVICE(VENDOR_ID, 0x2051) },
1569ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	{ PCI_DEVICE(VENDOR_ID, 0x2052) },
1579ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	{ PCI_DEVICE(VENDOR_ID, 0x2053) },
1589ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	{ PCI_DEVICE(VENDOR_ID, 0x2054) },
1599ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	{ PCI_DEVICE(VENDOR_ID, 0x2055) },
1609ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	{ PCI_DEVICE(VENDOR_ID, 0x2056) },
1619ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	{ PCI_DEVICE(VENDOR_ID, 0x2057) },
1629ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	{ PCI_DEVICE(VENDOR_ID, 0x2058) },
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0 }
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DEVICE_TABLE(pci, isicom_pci_tbl);
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1679ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slabystatic struct pci_driver isicom_driver = {
1689ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	.name		= "isicom",
1699ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	.id_table	= isicom_pci_tbl,
1709ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	.probe		= isicom_probe,
1719ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	.remove		= __devexit_p(isicom_remove)
1729ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby};
1739ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int prev_card = 3;	/*	start servicing isi_card[0]	*/
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct tty_driver *isicom_normal;
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void isicom_tx(unsigned long _data);
178d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slabystatic void isicom_start(struct tty_struct *tty);
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18034b55b865ed12494e23b09b5d2e8da22047fd6a7Jiri Slabystatic DEFINE_TIMER(tx, isicom_tx, 0, 0);
18134b55b865ed12494e23b09b5d2e8da22047fd6a7Jiri Slaby
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*   baud index mappings from linux defns to isi */
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic signed char linuxb_to_isib[] = {
1857edc136ab688f751037a86e8a051151d7962d33fJiri Slaby	-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13, 15, 16, 17, 18, 19, 20, 21
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct	isi_board {
1898070e35c6524e0f254cd69f493c50811e8e5b856Jiri Slaby	unsigned long		base;
1904969b3a43dd9e234b363f7bf52d0f6c4b6139eeaJiri Slaby	int			irq;
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char		port_count;
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned short		status;
193a547dfe9563c49fd0f9743640e01d1d652119ec7Jiri Slaby	unsigned short		port_status; /* each bit for each port */
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned short		shift_count;
195251b8dd7eee30fda089a1dc088abf4fc9a0dee9cAlan Cox	struct isi_port		*ports;
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	signed char		count;
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spinlock_t		card_lock; /* Card wide lock 11/5/00 -sameer */
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
199938a7023bbbc626b0ab7ece13fe8cb26cfcc486bJiri Slaby	unsigned int		index;
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct	isi_port {
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned short		magic;
204f1d03228ea85877584d41bccf62841e7ca47043cAlan Cox	struct tty_port		port;
2058070e35c6524e0f254cd69f493c50811e8e5b856Jiri Slaby	u16			channel;
2068070e35c6524e0f254cd69f493c50811e8e5b856Jiri Slaby	u16			status;
207251b8dd7eee30fda089a1dc088abf4fc9a0dee9cAlan Cox	struct isi_board	*card;
208251b8dd7eee30fda089a1dc088abf4fc9a0dee9cAlan Cox	unsigned char		*xmit_buf;
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			xmit_head;
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			xmit_tail;
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			xmit_cnt;
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct isi_board isi_card[BOARD_COUNT];
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct isi_port  isi_ports[PORT_COUNT];
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Locking functions for card level locking. We need to own both
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	the kernel lock for the card and have the card in a position that
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	it wants to talk.
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
222d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
2234969b3a43dd9e234b363f7bf52d0f6c4b6139eeaJiri Slabystatic inline int WaitTillCardIsFree(unsigned long base)
224cfe7c09ac2be2a89aa46bb23d480d9d908e8c041Jiri Slaby{
225cfe7c09ac2be2a89aa46bb23d480d9d908e8c041Jiri Slaby	unsigned int count = 0;
226cfe7c09ac2be2a89aa46bb23d480d9d908e8c041Jiri Slaby	unsigned int a = in_atomic(); /* do we run under spinlock? */
227cfe7c09ac2be2a89aa46bb23d480d9d908e8c041Jiri Slaby
228cfe7c09ac2be2a89aa46bb23d480d9d908e8c041Jiri Slaby	while (!(inw(base + 0xe) & 0x1) && count++ < 100)
229cfe7c09ac2be2a89aa46bb23d480d9d908e8c041Jiri Slaby		if (a)
230cfe7c09ac2be2a89aa46bb23d480d9d908e8c041Jiri Slaby			mdelay(1);
231cfe7c09ac2be2a89aa46bb23d480d9d908e8c041Jiri Slaby		else
232cfe7c09ac2be2a89aa46bb23d480d9d908e8c041Jiri Slaby			msleep(1);
233cfe7c09ac2be2a89aa46bb23d480d9d908e8c041Jiri Slaby
234cfe7c09ac2be2a89aa46bb23d480d9d908e8c041Jiri Slaby	return !(inw(base + 0xe) & 0x1);
235cfe7c09ac2be2a89aa46bb23d480d9d908e8c041Jiri Slaby}
236cfe7c09ac2be2a89aa46bb23d480d9d908e8c041Jiri Slaby
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lock_card(struct isi_board *card)
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2398070e35c6524e0f254cd69f493c50811e8e5b856Jiri Slaby	unsigned long base = card->base;
2405b21f9dddd0817b761f1407f1950bee4f257411aJiri Slaby	unsigned int retries, a;
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2425b21f9dddd0817b761f1407f1950bee4f257411aJiri Slaby	for (retries = 0; retries < 10; retries++) {
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock_irqsave(&card->card_lock, card->flags);
2445b21f9dddd0817b761f1407f1950bee4f257411aJiri Slaby		for (a = 0; a < 10; a++) {
2455b21f9dddd0817b761f1407f1950bee4f257411aJiri Slaby			if (inw(base + 0xe) & 0x1)
2465b21f9dddd0817b761f1407f1950bee4f257411aJiri Slaby				return 1;
2475b21f9dddd0817b761f1407f1950bee4f257411aJiri Slaby			udelay(10);
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2495b21f9dddd0817b761f1407f1950bee4f257411aJiri Slaby		spin_unlock_irqrestore(&card->card_lock, card->flags);
2505b21f9dddd0817b761f1407f1950bee4f257411aJiri Slaby		msleep(10);
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
252db91340b2e874693f14e9e937152e7433d7ac753Joe Perches	pr_warning("Failed to lock Card (0x%lx)\n", card->base);
253a547dfe9563c49fd0f9743640e01d1d652119ec7Jiri Slaby
2540418726bb5c7b5a70c7e7e82e860d5979d0c78cfAdrian Bunk	return 0;	/* Failed to acquire the card! */
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void unlock_card(struct isi_board *card)
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&card->card_lock, card->flags);
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  ISI Card specific ops ...
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
265d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
266cfe7c09ac2be2a89aa46bb23d480d9d908e8c041Jiri Slaby/* card->lock HAS to be held */
267d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slabystatic void raise_dtr(struct isi_port *port)
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
269d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	struct isi_board *card = port->card;
2708070e35c6524e0f254cd69f493c50811e8e5b856Jiri Slaby	unsigned long base = card->base;
2718070e35c6524e0f254cd69f493c50811e8e5b856Jiri Slaby	u16 channel = port->channel;
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
273cfe7c09ac2be2a89aa46bb23d480d9d908e8c041Jiri Slaby	if (WaitTillCardIsFree(base))
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
276d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	outw(0x8000 | (channel << card->shift_count) | 0x02, base);
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outw(0x0504, base);
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	InterruptTheCard(base);
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->status |= ISI_DTR;
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
282cfe7c09ac2be2a89aa46bb23d480d9d908e8c041Jiri Slaby/* card->lock HAS to be held */
283d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slabystatic inline void drop_dtr(struct isi_port *port)
284d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby{
285d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	struct isi_board *card = port->card;
2868070e35c6524e0f254cd69f493c50811e8e5b856Jiri Slaby	unsigned long base = card->base;
2878070e35c6524e0f254cd69f493c50811e8e5b856Jiri Slaby	u16 channel = port->channel;
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
289cfe7c09ac2be2a89aa46bb23d480d9d908e8c041Jiri Slaby	if (WaitTillCardIsFree(base))
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
292d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	outw(0x8000 | (channel << card->shift_count) | 0x02, base);
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outw(0x0404, base);
294d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	InterruptTheCard(base);
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->status &= ~ISI_DTR;
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
298cfe7c09ac2be2a89aa46bb23d480d9d908e8c041Jiri Slaby/* card->lock HAS to be held */
299d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slabystatic inline void raise_rts(struct isi_port *port)
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
301d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	struct isi_board *card = port->card;
3028070e35c6524e0f254cd69f493c50811e8e5b856Jiri Slaby	unsigned long base = card->base;
3038070e35c6524e0f254cd69f493c50811e8e5b856Jiri Slaby	u16 channel = port->channel;
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
305cfe7c09ac2be2a89aa46bb23d480d9d908e8c041Jiri Slaby	if (WaitTillCardIsFree(base))
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
308d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	outw(0x8000 | (channel << card->shift_count) | 0x02, base);
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outw(0x0a04, base);
310d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	InterruptTheCard(base);
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->status |= ISI_RTS;
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
313cfe7c09ac2be2a89aa46bb23d480d9d908e8c041Jiri Slaby
314cfe7c09ac2be2a89aa46bb23d480d9d908e8c041Jiri Slaby/* card->lock HAS to be held */
315d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slabystatic inline void drop_rts(struct isi_port *port)
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
317d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	struct isi_board *card = port->card;
3188070e35c6524e0f254cd69f493c50811e8e5b856Jiri Slaby	unsigned long base = card->base;
3198070e35c6524e0f254cd69f493c50811e8e5b856Jiri Slaby	u16 channel = port->channel;
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
321cfe7c09ac2be2a89aa46bb23d480d9d908e8c041Jiri Slaby	if (WaitTillCardIsFree(base))
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
324d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	outw(0x8000 | (channel << card->shift_count) | 0x02, base);
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outw(0x0804, base);
326d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	InterruptTheCard(base);
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->status &= ~ISI_RTS;
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
330cfe7c09ac2be2a89aa46bb23d480d9d908e8c041Jiri Slaby/* card->lock MUST NOT be held */
3315d951fb458f847e5485b5251597fbf326000bb3bAlan Cox
332fcc8ac1825d3d0fb81f73bc1a80ebc863168bb56Alan Coxstatic void isicom_dtr_rts(struct tty_port *port, int on)
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3345d951fb458f847e5485b5251597fbf326000bb3bAlan Cox	struct isi_port *ip = container_of(port, struct isi_port, port);
3355d951fb458f847e5485b5251597fbf326000bb3bAlan Cox	struct isi_board *card = ip->card;
3368070e35c6524e0f254cd69f493c50811e8e5b856Jiri Slaby	unsigned long base = card->base;
3375d951fb458f847e5485b5251597fbf326000bb3bAlan Cox	u16 channel = ip->channel;
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!lock_card(card))
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
342fcc8ac1825d3d0fb81f73bc1a80ebc863168bb56Alan Cox	if (on) {
343fcc8ac1825d3d0fb81f73bc1a80ebc863168bb56Alan Cox		outw(0x8000 | (channel << card->shift_count) | 0x02, base);
344fcc8ac1825d3d0fb81f73bc1a80ebc863168bb56Alan Cox		outw(0x0f04, base);
345fcc8ac1825d3d0fb81f73bc1a80ebc863168bb56Alan Cox		InterruptTheCard(base);
346fcc8ac1825d3d0fb81f73bc1a80ebc863168bb56Alan Cox		ip->status |= (ISI_DTR | ISI_RTS);
347fcc8ac1825d3d0fb81f73bc1a80ebc863168bb56Alan Cox	} else {
348fcc8ac1825d3d0fb81f73bc1a80ebc863168bb56Alan Cox		outw(0x8000 | (channel << card->shift_count) | 0x02, base);
349fcc8ac1825d3d0fb81f73bc1a80ebc863168bb56Alan Cox		outw(0x0C04, base);
350fcc8ac1825d3d0fb81f73bc1a80ebc863168bb56Alan Cox		InterruptTheCard(base);
351fcc8ac1825d3d0fb81f73bc1a80ebc863168bb56Alan Cox		ip->status &= ~(ISI_DTR | ISI_RTS);
352fcc8ac1825d3d0fb81f73bc1a80ebc863168bb56Alan Cox	}
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unlock_card(card);
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
356cfe7c09ac2be2a89aa46bb23d480d9d908e8c041Jiri Slaby/* card->lock HAS to be held */
357d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slabystatic void drop_dtr_rts(struct isi_port *port)
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
359d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	struct isi_board *card = port->card;
3608070e35c6524e0f254cd69f493c50811e8e5b856Jiri Slaby	unsigned long base = card->base;
3618070e35c6524e0f254cd69f493c50811e8e5b856Jiri Slaby	u16 channel = port->channel;
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
363cfe7c09ac2be2a89aa46bb23d480d9d908e8c041Jiri Slaby	if (WaitTillCardIsFree(base))
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
366d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	outw(0x8000 | (channel << card->shift_count) | 0x02, base);
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outw(0x0c04, base);
368d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	InterruptTheCard(base);
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->status &= ~(ISI_RTS | ISI_DTR);
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	ISICOM Driver specific routines ...
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
376d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
377aaa246ea78c68cd205f505070650cda7c5a95d34Jiri Slabystatic inline int __isicom_paranoia_check(struct isi_port const *port,
378aaa246ea78c68cd205f505070650cda7c5a95d34Jiri Slaby	char *name, const char *routine)
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!port) {
381db91340b2e874693f14e9e937152e7433d7ac753Joe Perches		pr_warning("Warning: bad isicom magic for dev %s in %s.\n",
382db91340b2e874693f14e9e937152e7433d7ac753Joe Perches			   name, routine);
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (port->magic != ISICOM_MAGIC) {
386db91340b2e874693f14e9e937152e7433d7ac753Joe Perches		pr_warning("Warning: NULL isicom port for dev %s in %s.\n",
387db91340b2e874693f14e9e937152e7433d7ac753Joe Perches			   name, routine);
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
389d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	}
390aaa246ea78c68cd205f505070650cda7c5a95d34Jiri Slaby
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
393d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
395d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby *	Transmitter.
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	We shovel data into the card buffers on a regular basis. The card
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	will do the rest of the work for us.
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void isicom_tx(unsigned long _data)
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4034969b3a43dd9e234b363f7bf52d0f6c4b6139eeaJiri Slaby	unsigned long flags, base;
4045b21f9dddd0817b761f1407f1950bee4f257411aJiri Slaby	unsigned int retries;
4054969b3a43dd9e234b363f7bf52d0f6c4b6139eeaJiri Slaby	short count = (BOARD_COUNT-1), card;
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	short txcount, wrd, residue, word_count, cnt;
407d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	struct isi_port *port;
408d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	struct tty_struct *tty;
409d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*	find next active board	*/
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	card = (prev_card + 1) & 0x0003;
412251b8dd7eee30fda089a1dc088abf4fc9a0dee9cAlan Cox	while (count-- > 0) {
413d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby		if (isi_card[card].status & BOARD_ACTIVE)
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
415d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby		card = (card + 1) & 0x0003;
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(isi_card[card].status & BOARD_ACTIVE))
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto sched_again;
419d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	prev_card = card;
421d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	count = isi_card[card].port_count;
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port = isi_card[card].ports;
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	base = isi_card[card].base;
4255b21f9dddd0817b761f1407f1950bee4f257411aJiri Slaby
4265b21f9dddd0817b761f1407f1950bee4f257411aJiri Slaby	spin_lock_irqsave(&isi_card[card].card_lock, flags);
4275b21f9dddd0817b761f1407f1950bee4f257411aJiri Slaby	for (retries = 0; retries < 100; retries++) {
4285b21f9dddd0817b761f1407f1950bee4f257411aJiri Slaby		if (inw(base + 0xe) & 0x1)
4295b21f9dddd0817b761f1407f1950bee4f257411aJiri Slaby			break;
4305b21f9dddd0817b761f1407f1950bee4f257411aJiri Slaby		udelay(2);
4315b21f9dddd0817b761f1407f1950bee4f257411aJiri Slaby	}
4325b21f9dddd0817b761f1407f1950bee4f257411aJiri Slaby	if (retries >= 100)
4335b21f9dddd0817b761f1407f1950bee4f257411aJiri Slaby		goto unlock;
4345b21f9dddd0817b761f1407f1950bee4f257411aJiri Slaby
435d450b5a0196b6442cf3f29fc611d9c8daa56b559Alan Cox	tty = tty_port_tty_get(&port->port);
436d450b5a0196b6442cf3f29fc611d9c8daa56b559Alan Cox	if (tty == NULL)
437d450b5a0196b6442cf3f29fc611d9c8daa56b559Alan Cox		goto put_unlock;
438d450b5a0196b6442cf3f29fc611d9c8daa56b559Alan Cox
439251b8dd7eee30fda089a1dc088abf4fc9a0dee9cAlan Cox	for (; count > 0; count--, port++) {
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* port not active or tx disabled to force flow control */
441f1d03228ea85877584d41bccf62841e7ca47043cAlan Cox		if (!(port->port.flags & ASYNC_INITIALIZED) ||
442d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby				!(port->status & ISI_TXOK))
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
444d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		txcount = min_t(short, TX_SIZE, port->xmit_cnt);
4465b21f9dddd0817b761f1407f1950bee4f257411aJiri Slaby		if (txcount <= 0 || tty->stopped || tty->hw_stopped)
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
4485b21f9dddd0817b761f1407f1950bee4f257411aJiri Slaby
4495b21f9dddd0817b761f1407f1950bee4f257411aJiri Slaby		if (!(inw(base + 0x02) & (1 << port->channel)))
450d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby			continue;
4515b21f9dddd0817b761f1407f1950bee4f257411aJiri Slaby
452db91340b2e874693f14e9e937152e7433d7ac753Joe Perches		pr_debug("txing %d bytes, port%d.\n",
453db91340b2e874693f14e9e937152e7433d7ac753Joe Perches			 txcount, port->channel + 1);
454aaa246ea78c68cd205f505070650cda7c5a95d34Jiri Slaby		outw((port->channel << isi_card[card].shift_count) | txcount,
455aaa246ea78c68cd205f505070650cda7c5a95d34Jiri Slaby			base);
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		residue = NO;
457d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby		wrd = 0;
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (1) {
459a547dfe9563c49fd0f9743640e01d1d652119ec7Jiri Slaby			cnt = min_t(int, txcount, (SERIAL_XMIT_SIZE
460a547dfe9563c49fd0f9743640e01d1d652119ec7Jiri Slaby					- port->xmit_tail));
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (residue == YES) {
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				residue = NO;
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (cnt > 0) {
464f1d03228ea85877584d41bccf62841e7ca47043cAlan Cox					wrd |= (port->port.xmit_buf[port->xmit_tail]
465a547dfe9563c49fd0f9743640e01d1d652119ec7Jiri Slaby									<< 8);
466a547dfe9563c49fd0f9743640e01d1d652119ec7Jiri Slaby					port->xmit_tail = (port->xmit_tail + 1)
467a547dfe9563c49fd0f9743640e01d1d652119ec7Jiri Slaby						& (SERIAL_XMIT_SIZE - 1);
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					port->xmit_cnt--;
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					txcount--;
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					cnt--;
471d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby					outw(wrd, base);
472a547dfe9563c49fd0f9743640e01d1d652119ec7Jiri Slaby				} else {
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					outw(wrd, base);
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					break;
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
476d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby			}
477251b8dd7eee30fda089a1dc088abf4fc9a0dee9cAlan Cox			if (cnt <= 0)
478251b8dd7eee30fda089a1dc088abf4fc9a0dee9cAlan Cox				break;
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			word_count = cnt >> 1;
480f1d03228ea85877584d41bccf62841e7ca47043cAlan Cox			outsw(base, port->port.xmit_buf+port->xmit_tail, word_count);
481a547dfe9563c49fd0f9743640e01d1d652119ec7Jiri Slaby			port->xmit_tail = (port->xmit_tail
482a547dfe9563c49fd0f9743640e01d1d652119ec7Jiri Slaby				+ (word_count << 1)) & (SERIAL_XMIT_SIZE - 1);
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			txcount -= (word_count << 1);
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			port->xmit_cnt -= (word_count << 1);
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (cnt & 0x0001) {
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				residue = YES;
487f1d03228ea85877584d41bccf62841e7ca47043cAlan Cox				wrd = port->port.xmit_buf[port->xmit_tail];
488a547dfe9563c49fd0f9743640e01d1d652119ec7Jiri Slaby				port->xmit_tail = (port->xmit_tail + 1)
489a547dfe9563c49fd0f9743640e01d1d652119ec7Jiri Slaby					& (SERIAL_XMIT_SIZE - 1);
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				port->xmit_cnt--;
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				txcount--;
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		InterruptTheCard(base);
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (port->xmit_cnt <= 0)
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			port->status &= ~ISI_TXOK;
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (port->xmit_cnt <= WAKEUP_CHARS)
4990aa5de8590d684274f57647a870851f101bb3543Jiri Slaby			tty_wakeup(tty);
500d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	}
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
502d450b5a0196b6442cf3f29fc611d9c8daa56b559Alan Coxput_unlock:
503d450b5a0196b6442cf3f29fc611d9c8daa56b559Alan Cox	tty_kref_put(tty);
5045b21f9dddd0817b761f1407f1950bee4f257411aJiri Slabyunlock:
5055b21f9dddd0817b761f1407f1950bee4f257411aJiri Slaby	spin_unlock_irqrestore(&isi_card[card].card_lock, flags);
506d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	/*	schedule another tx for hopefully in about 10ms	*/
507d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slabysched_again:
50834b55b865ed12494e23b09b5d2e8da22047fd6a7Jiri Slaby	mod_timer(&tx, jiffies + msecs_to_jiffies(10));
509d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby}
510d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
512d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby *	Main interrupt handler routine
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
514d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
5157d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t isicom_interrupt(int irq, void *dev_id)
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5178070e35c6524e0f254cd69f493c50811e8e5b856Jiri Slaby	struct isi_board *card = dev_id;
518d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	struct isi_port *port;
519d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	struct tty_struct *tty;
5208070e35c6524e0f254cd69f493c50811e8e5b856Jiri Slaby	unsigned long base;
5218070e35c6524e0f254cd69f493c50811e8e5b856Jiri Slaby	u16 header, word_count, count, channel;
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	short byte_count;
52333f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox	unsigned char *rp;
524d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!card || !(card->status & FIRMWARE_LOADED))
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return IRQ_NONE;
527d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	base = card->base;
529cb4a10ccb0c5b5b02dec1a4a97cba1e8b2c2a325Jiri Slaby
530cb4a10ccb0c5b5b02dec1a4a97cba1e8b2c2a325Jiri Slaby	/* did the card interrupt us? */
531cb4a10ccb0c5b5b02dec1a4a97cba1e8b2c2a325Jiri Slaby	if (!(inw(base + 0x0e) & 0x02))
532cb4a10ccb0c5b5b02dec1a4a97cba1e8b2c2a325Jiri Slaby		return IRQ_NONE;
533cb4a10ccb0c5b5b02dec1a4a97cba1e8b2c2a325Jiri Slaby
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock(&card->card_lock);
535d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
53618234f88bc27473f15293a03c83bcb53da9018b4Jiri Slaby	/*
53718234f88bc27473f15293a03c83bcb53da9018b4Jiri Slaby	 * disable any interrupts from the PCI card and lower the
53818234f88bc27473f15293a03c83bcb53da9018b4Jiri Slaby	 * interrupt line
53918234f88bc27473f15293a03c83bcb53da9018b4Jiri Slaby	 */
54018234f88bc27473f15293a03c83bcb53da9018b4Jiri Slaby	outw(0x8000, base+0x04);
54118234f88bc27473f15293a03c83bcb53da9018b4Jiri Slaby	ClearInterrupt(base);
542d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	inw(base);		/* get the dummy word out */
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	header = inw(base);
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	channel = (header & 0x7800) >> card->shift_count;
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	byte_count = header & 0xff;
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (channel + 1 > card->port_count) {
549db91340b2e874693f14e9e937152e7433d7ac753Joe Perches		pr_warning("%s(0x%lx): %d(channel) > port_count.\n",
550db91340b2e874693f14e9e937152e7433d7ac753Joe Perches			   __func__, base, channel+1);
55118234f88bc27473f15293a03c83bcb53da9018b4Jiri Slaby		outw(0x0000, base+0x04); /* enable interrupts */
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock(&card->card_lock);
553d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby		return IRQ_HANDLED;
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port = card->ports + channel;
556f1d03228ea85877584d41bccf62841e7ca47043cAlan Cox	if (!(port->port.flags & ASYNC_INITIALIZED)) {
55718234f88bc27473f15293a03c83bcb53da9018b4Jiri Slaby		outw(0x0000, base+0x04); /* enable interrupts */
558174f13076717b8c7b70a18a474a0541a31d24527Jiri Slaby		spin_unlock(&card->card_lock);
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return IRQ_HANDLED;
560d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	}
561d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
562d450b5a0196b6442cf3f29fc611d9c8daa56b559Alan Cox	tty = tty_port_tty_get(&port->port);
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tty == NULL) {
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		word_count = byte_count >> 1;
565251b8dd7eee30fda089a1dc088abf4fc9a0dee9cAlan Cox		while (byte_count > 1) {
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			inw(base);
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			byte_count -= 2;
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (byte_count & 0x01)
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			inw(base);
57118234f88bc27473f15293a03c83bcb53da9018b4Jiri Slaby		outw(0x0000, base+0x04); /* enable interrupts */
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock(&card->card_lock);
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return IRQ_HANDLED;
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
575d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (header & 0x8000) {		/* Status Packet */
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		header = inw(base);
578251b8dd7eee30fda089a1dc088abf4fc9a0dee9cAlan Cox		switch (header & 0xff) {
579d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby		case 0:	/* Change in EIA signals */
580f1d03228ea85877584d41bccf62841e7ca47043cAlan Cox			if (port->port.flags & ASYNC_CHECK_CD) {
581d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby				if (port->status & ISI_DCD) {
582d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby					if (!(header & ISI_DCD)) {
583d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby					/* Carrier has been lost  */
584db91340b2e874693f14e9e937152e7433d7ac753Joe Perches						pr_debug("%s: DCD->low.\n",
585db91340b2e874693f14e9e937152e7433d7ac753Joe Perches							 __func__);
586d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby						port->status &= ~ISI_DCD;
5870aa5de8590d684274f57647a870851f101bb3543Jiri Slaby						tty_hangup(tty);
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
589a547dfe9563c49fd0f9743640e01d1d652119ec7Jiri Slaby				} else if (header & ISI_DCD) {
590a547dfe9563c49fd0f9743640e01d1d652119ec7Jiri Slaby				/* Carrier has been detected */
591db91340b2e874693f14e9e937152e7433d7ac753Joe Perches					pr_debug("%s: DCD->high.\n",
592db91340b2e874693f14e9e937152e7433d7ac753Joe Perches						__func__);
593a547dfe9563c49fd0f9743640e01d1d652119ec7Jiri Slaby					port->status |= ISI_DCD;
594f1d03228ea85877584d41bccf62841e7ca47043cAlan Cox					wake_up_interruptible(&port->port.open_wait);
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
596a547dfe9563c49fd0f9743640e01d1d652119ec7Jiri Slaby			} else {
597d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby				if (header & ISI_DCD)
598d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby					port->status |= ISI_DCD;
599d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby				else
600d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby					port->status &= ~ISI_DCD;
601d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby			}
602d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
603f1d03228ea85877584d41bccf62841e7ca47043cAlan Cox			if (port->port.flags & ASYNC_CTS_FLOW) {
604d450b5a0196b6442cf3f29fc611d9c8daa56b559Alan Cox				if (tty->hw_stopped) {
605d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby					if (header & ISI_CTS) {
606f1d03228ea85877584d41bccf62841e7ca47043cAlan Cox						port->port.tty->hw_stopped = 0;
607d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby						/* start tx ing */
608a547dfe9563c49fd0f9743640e01d1d652119ec7Jiri Slaby						port->status |= (ISI_TXOK
609a547dfe9563c49fd0f9743640e01d1d652119ec7Jiri Slaby							| ISI_CTS);
6100aa5de8590d684274f57647a870851f101bb3543Jiri Slaby						tty_wakeup(tty);
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
612a547dfe9563c49fd0f9743640e01d1d652119ec7Jiri Slaby				} else if (!(header & ISI_CTS)) {
613d450b5a0196b6442cf3f29fc611d9c8daa56b559Alan Cox					tty->hw_stopped = 1;
614a547dfe9563c49fd0f9743640e01d1d652119ec7Jiri Slaby					/* stop tx ing */
615a547dfe9563c49fd0f9743640e01d1d652119ec7Jiri Slaby					port->status &= ~(ISI_TXOK | ISI_CTS);
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
617a547dfe9563c49fd0f9743640e01d1d652119ec7Jiri Slaby			} else {
618d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby				if (header & ISI_CTS)
619d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby					port->status |= ISI_CTS;
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				else
621d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby					port->status &= ~ISI_CTS;
622d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby			}
623d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
624d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby			if (header & ISI_DSR)
625d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby				port->status |= ISI_DSR;
626d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby			else
627d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby				port->status &= ~ISI_DSR;
628d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
629d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby			if (header & ISI_RI)
630d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby				port->status |= ISI_RI;
631d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby			else
632d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby				port->status &= ~ISI_RI;
633d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
634d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby			break;
635d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
636a547dfe9563c49fd0f9743640e01d1d652119ec7Jiri Slaby		case 1:	/* Received Break !!! */
637d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby			tty_insert_flip_char(tty, 0, TTY_BREAK);
638f1d03228ea85877584d41bccf62841e7ca47043cAlan Cox			if (port->port.flags & ASYNC_SAK)
639d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby				do_SAK(tty);
640d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby			tty_flip_buffer_push(tty);
641d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby			break;
642d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
643d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby		case 2:	/* Statistics		 */
644db91340b2e874693f14e9e937152e7433d7ac753Joe Perches			pr_debug("%s: stats!!!\n", __func__);
645d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby			break;
646d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
647d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby		default:
648db91340b2e874693f14e9e937152e7433d7ac753Joe Perches			pr_debug("%s: Unknown code in status packet.\n",
649db91340b2e874693f14e9e937152e7433d7ac753Joe Perches				 __func__);
650d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby			break;
651d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby		}
652a547dfe9563c49fd0f9743640e01d1d652119ec7Jiri Slaby	} else {				/* Data   Packet */
65333f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox
65433f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox		count = tty_prepare_flip_string(tty, &rp, byte_count & ~1);
655db91340b2e874693f14e9e937152e7433d7ac753Joe Perches		pr_debug("%s: Can rx %d of %d bytes.\n",
656db91340b2e874693f14e9e937152e7433d7ac753Joe Perches			 __func__, count, byte_count);
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		word_count = count >> 1;
65833f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox		insw(base, rp, word_count);
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		byte_count -= (word_count << 1);
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (count & 0x0001) {
661a547dfe9563c49fd0f9743640e01d1d652119ec7Jiri Slaby			tty_insert_flip_char(tty,  inw(base) & 0xff,
662a547dfe9563c49fd0f9743640e01d1d652119ec7Jiri Slaby				TTY_NORMAL);
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			byte_count -= 2;
664d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby		}
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (byte_count > 0) {
666db91340b2e874693f14e9e937152e7433d7ac753Joe Perches			pr_debug("%s(0x%lx:%d): Flip buffer overflow! dropping bytes...\n",
667db91340b2e874693f14e9e937152e7433d7ac753Joe Perches				 __func__, base, channel + 1);
668251b8dd7eee30fda089a1dc088abf4fc9a0dee9cAlan Cox		/* drain out unread xtra data */
669251b8dd7eee30fda089a1dc088abf4fc9a0dee9cAlan Cox		while (byte_count > 0) {
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				inw(base);
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				byte_count -= 2;
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
67433f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox		tty_flip_buffer_push(tty);
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
67618234f88bc27473f15293a03c83bcb53da9018b4Jiri Slaby	outw(0x0000, base+0x04); /* enable interrupts */
677174f13076717b8c7b70a18a474a0541a31d24527Jiri Slaby	spin_unlock(&card->card_lock);
678d450b5a0196b6442cf3f29fc611d9c8daa56b559Alan Cox	tty_kref_put(tty);
679a547dfe9563c49fd0f9743640e01d1d652119ec7Jiri Slaby
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return IRQ_HANDLED;
681d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby}
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
683d450b5a0196b6442cf3f29fc611d9c8daa56b559Alan Coxstatic void isicom_config_port(struct tty_struct *tty)
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
685d450b5a0196b6442cf3f29fc611d9c8daa56b559Alan Cox	struct isi_port *port = tty->driver_data;
686d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	struct isi_board *card = port->card;
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long baud;
6888070e35c6524e0f254cd69f493c50811e8e5b856Jiri Slaby	unsigned long base = card->base;
6898070e35c6524e0f254cd69f493c50811e8e5b856Jiri Slaby	u16 channel_setup, channel = port->channel,
6908070e35c6524e0f254cd69f493c50811e8e5b856Jiri Slaby		shift_count = card->shift_count;
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char flow_ctrl;
692d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
693251b8dd7eee30fda089a1dc088abf4fc9a0dee9cAlan Cox	/* FIXME: Switch to new tty baud API */
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	baud = C_BAUD(tty);
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (baud & CBAUDEX) {
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		baud &= ~CBAUDEX;
697d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*  if CBAUDEX bit is on and the baud is set to either 50 or 75
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *  then the card is programmed for 57.6Kbps or 115Kbps
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *  respectively.
701d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby		 */
702d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
7037edc136ab688f751037a86e8a051151d7962d33fJiri Slaby		/* 1,2,3,4 => 57.6, 115.2, 230, 460 kbps resp. */
7047edc136ab688f751037a86e8a051151d7962d33fJiri Slaby		if (baud < 1 || baud > 4)
705d450b5a0196b6442cf3f29fc611d9c8daa56b559Alan Cox			tty->termios->c_cflag &= ~CBAUDEX;
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			baud += 15;
708d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	}
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (baud == 15) {
710d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
711d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby		/*  the ASYNC_SPD_HI and ASYNC_SPD_VHI options are set
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *  by the set_serial_info ioctl ... this is done by
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *  the 'setserial' utility.
714d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby		 */
715d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
716f1d03228ea85877584d41bccf62841e7ca47043cAlan Cox		if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
717d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby			baud++; /*  57.6 Kbps */
718f1d03228ea85877584d41bccf62841e7ca47043cAlan Cox		if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
719251b8dd7eee30fda089a1dc088abf4fc9a0dee9cAlan Cox			baud += 2; /*  115  Kbps */
720f1d03228ea85877584d41bccf62841e7ca47043cAlan Cox		if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
7217edc136ab688f751037a86e8a051151d7962d33fJiri Slaby			baud += 3; /* 230 kbps*/
722f1d03228ea85877584d41bccf62841e7ca47043cAlan Cox		if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
7237edc136ab688f751037a86e8a051151d7962d33fJiri Slaby			baud += 4; /* 460 kbps*/
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (linuxb_to_isib[baud] == -1) {
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* hang up */
727d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby		drop_dtr(port);
728d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby		return;
729251b8dd7eee30fda089a1dc088abf4fc9a0dee9cAlan Cox	} else
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		raise_dtr(port);
731d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
732cfe7c09ac2be2a89aa46bb23d480d9d908e8c041Jiri Slaby	if (WaitTillCardIsFree(base) == 0) {
733251b8dd7eee30fda089a1dc088abf4fc9a0dee9cAlan Cox		outw(0x8000 | (channel << shift_count) | 0x03, base);
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outw(linuxb_to_isib[baud] << 8 | 0x03, base);
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		channel_setup = 0;
736251b8dd7eee30fda089a1dc088abf4fc9a0dee9cAlan Cox		switch (C_CSIZE(tty)) {
737d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby		case CS5:
738d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby			channel_setup |= ISICOM_CS5;
739d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby			break;
740d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby		case CS6:
741d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby			channel_setup |= ISICOM_CS6;
742d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby			break;
743d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby		case CS7:
744d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby			channel_setup |= ISICOM_CS7;
745d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby			break;
746d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby		case CS8:
747d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby			channel_setup |= ISICOM_CS8;
748d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby			break;
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
750d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (C_CSTOPB(tty))
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			channel_setup |= ISICOM_2SB;
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (C_PARENB(tty)) {
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			channel_setup |= ISICOM_EVPAR;
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (C_PARODD(tty))
756d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby				channel_setup |= ISICOM_ODPAR;
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
758d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby		outw(channel_setup, base);
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		InterruptTheCard(base);
760d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	}
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (C_CLOCAL(tty))
762f1d03228ea85877584d41bccf62841e7ca47043cAlan Cox		port->port.flags &= ~ASYNC_CHECK_CD;
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
764f1d03228ea85877584d41bccf62841e7ca47043cAlan Cox		port->port.flags |= ASYNC_CHECK_CD;
765d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* flow control settings ...*/
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	flow_ctrl = 0;
768f1d03228ea85877584d41bccf62841e7ca47043cAlan Cox	port->port.flags &= ~ASYNC_CTS_FLOW;
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (C_CRTSCTS(tty)) {
770f1d03228ea85877584d41bccf62841e7ca47043cAlan Cox		port->port.flags |= ASYNC_CTS_FLOW;
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flow_ctrl |= ISICOM_CTSRTS;
772d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	}
773d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	if (I_IXON(tty))
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flow_ctrl |= ISICOM_RESPOND_XONXOFF;
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (I_IXOFF(tty))
776d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby		flow_ctrl |= ISICOM_INITIATE_XONXOFF;
777d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
778cfe7c09ac2be2a89aa46bb23d480d9d908e8c041Jiri Slaby	if (WaitTillCardIsFree(base) == 0) {
779251b8dd7eee30fda089a1dc088abf4fc9a0dee9cAlan Cox		outw(0x8000 | (channel << shift_count) | 0x04, base);
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outw(flow_ctrl << 8 | 0x05, base);
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outw((STOP_CHAR(tty)) << 8 | (START_CHAR(tty)), base);
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		InterruptTheCard(base);
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
784d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*	rx enabled -> enable port for rx on the card	*/
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (C_CREAD(tty)) {
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		card->port_status |= (1 << channel);
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outw(card->port_status, base + 0x02);
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
792d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby/* open et all */
793d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
794d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slabystatic inline void isicom_setup_board(struct isi_board *bp)
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int channel;
797d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	struct isi_port *port;
798d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
799baaa08acb0ca2df47830b58b5df8b9059cf9ddd2Alan Cox	bp->count++;
8006ed847d8efd08658ece10c9129cd511c8d7452cdAlan Cox	if (!(bp->status & BOARD_INIT)) {
8016ed847d8efd08658ece10c9129cd511c8d7452cdAlan Cox		port = bp->ports;
8026ed847d8efd08658ece10c9129cd511c8d7452cdAlan Cox		for (channel = 0; channel < bp->port_count; channel++, port++)
8036ed847d8efd08658ece10c9129cd511c8d7452cdAlan Cox			drop_dtr_rts(port);
8046ed847d8efd08658ece10c9129cd511c8d7452cdAlan Cox	}
8056ed847d8efd08658ece10c9129cd511c8d7452cdAlan Cox	bp->status |= BOARD_ACTIVE | BOARD_INIT;
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
807d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
8086ed847d8efd08658ece10c9129cd511c8d7452cdAlan Cox/* Activate and thus setup board are protected from races against shutdown
8096ed847d8efd08658ece10c9129cd511c8d7452cdAlan Cox   by the tty_port mutex */
8106ed847d8efd08658ece10c9129cd511c8d7452cdAlan Cox
811baaa08acb0ca2df47830b58b5df8b9059cf9ddd2Alan Coxstatic int isicom_activate(struct tty_port *tport, struct tty_struct *tty)
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
813baaa08acb0ca2df47830b58b5df8b9059cf9ddd2Alan Cox	struct isi_port *port = container_of(tport, struct isi_port, port);
814d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	struct isi_board *card = port->card;
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
816d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
817baaa08acb0ca2df47830b58b5df8b9059cf9ddd2Alan Cox	if (tty_port_alloc_xmit_buf(tport) < 0)
818f1d03228ea85877584d41bccf62841e7ca47043cAlan Cox		return -ENOMEM;
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&card->card_lock, flags);
821baaa08acb0ca2df47830b58b5df8b9059cf9ddd2Alan Cox	isicom_setup_board(card);
822d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
824d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*	discard any residual data	*/
826cfe7c09ac2be2a89aa46bb23d480d9d908e8c041Jiri Slaby	if (WaitTillCardIsFree(card->base) == 0) {
827cfe7c09ac2be2a89aa46bb23d480d9d908e8c041Jiri Slaby		outw(0x8000 | (port->channel << card->shift_count) | 0x02,
828cfe7c09ac2be2a89aa46bb23d480d9d908e8c041Jiri Slaby				card->base);
829cfe7c09ac2be2a89aa46bb23d480d9d908e8c041Jiri Slaby		outw(((ISICOM_KILLTX | ISICOM_KILLRX) << 8) | 0x06, card->base);
830cfe7c09ac2be2a89aa46bb23d480d9d908e8c041Jiri Slaby		InterruptTheCard(card->base);
831cfe7c09ac2be2a89aa46bb23d480d9d908e8c041Jiri Slaby	}
832d450b5a0196b6442cf3f29fc611d9c8daa56b559Alan Cox	isicom_config_port(tty);
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&card->card_lock, flags);
834d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
835d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	return 0;
836d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby}
837d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
83831f35939d1d9bcfb3099b32c67b896d2792603f9Alan Coxstatic int isicom_carrier_raised(struct tty_port *port)
83931f35939d1d9bcfb3099b32c67b896d2792603f9Alan Cox{
84031f35939d1d9bcfb3099b32c67b896d2792603f9Alan Cox	struct isi_port *ip = container_of(port, struct isi_port, port);
84131f35939d1d9bcfb3099b32c67b896d2792603f9Alan Cox	return (ip->status & ISI_DCD)?1 : 0;
84231f35939d1d9bcfb3099b32c67b896d2792603f9Alan Cox}
84331f35939d1d9bcfb3099b32c67b896d2792603f9Alan Cox
84411d85d7b2ecc72fe752bba55389e7d11907528afAlan Coxstatic struct tty_port *isicom_find_port(struct tty_struct *tty)
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
846d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	struct isi_port *port;
847d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	struct isi_board *card;
84817c4edf0c8ee670de7b33d2a24eddd7c6b7edcf6Jiri Slaby	unsigned int board;
84911d85d7b2ecc72fe752bba55389e7d11907528afAlan Cox	int line = tty->index;
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	board = BOARD(line);
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	card = &isi_card[board];
853d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(card->status & FIRMWARE_LOADED))
85511d85d7b2ecc72fe752bba55389e7d11907528afAlan Cox		return NULL;
856d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*  open on a port greater than the port count for the card !!! */
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (line > ((board * 16) + card->port_count - 1))
85911d85d7b2ecc72fe752bba55389e7d11907528afAlan Cox		return NULL;
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
861d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	port = &isi_ports[line];
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (isicom_paranoia_check(port, tty->name, "isicom_open"))
86311d85d7b2ecc72fe752bba55389e7d11907528afAlan Cox		return NULL;
86411d85d7b2ecc72fe752bba55389e7d11907528afAlan Cox
86511d85d7b2ecc72fe752bba55389e7d11907528afAlan Cox	return &port->port;
86611d85d7b2ecc72fe752bba55389e7d11907528afAlan Cox}
867baaa08acb0ca2df47830b58b5df8b9059cf9ddd2Alan Cox
86811d85d7b2ecc72fe752bba55389e7d11907528afAlan Coxstatic int isicom_open(struct tty_struct *tty, struct file *filp)
86911d85d7b2ecc72fe752bba55389e7d11907528afAlan Cox{
87011d85d7b2ecc72fe752bba55389e7d11907528afAlan Cox	struct isi_port *port;
87111d85d7b2ecc72fe752bba55389e7d11907528afAlan Cox	struct tty_port *tport;
872d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
87311d85d7b2ecc72fe752bba55389e7d11907528afAlan Cox	tport = isicom_find_port(tty);
87411d85d7b2ecc72fe752bba55389e7d11907528afAlan Cox	if (tport == NULL)
87511d85d7b2ecc72fe752bba55389e7d11907528afAlan Cox		return -ENODEV;
87611d85d7b2ecc72fe752bba55389e7d11907528afAlan Cox	port = container_of(tport, struct isi_port, port);
877d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
878a2d1e3516c80027b2da17fb0b7ccd36f0ac33aa7Alan Cox	tty->driver_data = port;
879baaa08acb0ca2df47830b58b5df8b9059cf9ddd2Alan Cox	return tty_port_open(tport, tty, filp);
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
881d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* close et all */
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
884cfe7c09ac2be2a89aa46bb23d480d9d908e8c041Jiri Slaby/* card->lock HAS to be held */
885d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slabystatic void isicom_shutdown_port(struct isi_port *port)
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
887d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	struct isi_board *card = port->card;
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (--card->count < 0) {
890db91340b2e874693f14e9e937152e7433d7ac753Joe Perches		pr_debug("%s: bad board(0x%lx) count %d.\n",
891db91340b2e874693f14e9e937152e7433d7ac753Joe Perches			 __func__, card->base, card->count);
892d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby		card->count = 0;
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
894baaa08acb0ca2df47830b58b5df8b9059cf9ddd2Alan Cox	/* last port was closed, shutdown that board too */
8956ed847d8efd08658ece10c9129cd511c8d7452cdAlan Cox	if (!card->count)
8966ed847d8efd08658ece10c9129cd511c8d7452cdAlan Cox		card->status &= BOARD_ACTIVE;
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
899978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Coxstatic void isicom_flush_buffer(struct tty_struct *tty)
900978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox{
901978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	struct isi_port *port = tty->driver_data;
902978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	struct isi_board *card = port->card;
903978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	unsigned long flags;
904978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox
905978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	if (isicom_paranoia_check(port, tty->name, "isicom_flush_buffer"))
906978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox		return;
907978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox
908978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	spin_lock_irqsave(&card->card_lock, flags);
909978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
910978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	spin_unlock_irqrestore(&card->card_lock, flags);
911978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox
912978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox	tty_wakeup(tty);
913978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox}
914978e595f88a1fba5869aa42a4af4fba36f33ecacAlan Cox
915baaa08acb0ca2df47830b58b5df8b9059cf9ddd2Alan Coxstatic void isicom_shutdown(struct tty_port *port)
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9176f6412b4c76441f2060e580b8d5cbda07dabde37Alan Cox	struct isi_port *ip = container_of(port, struct isi_port, port);
9186f6412b4c76441f2060e580b8d5cbda07dabde37Alan Cox	struct isi_board *card = ip->card;
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
920d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
921d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	/* indicate to the card that no more data can be received
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   on this port */
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&card->card_lock, flags);
924baaa08acb0ca2df47830b58b5df8b9059cf9ddd2Alan Cox	card->port_status &= ~(1 << ip->channel);
925baaa08acb0ca2df47830b58b5df8b9059cf9ddd2Alan Cox	outw(card->port_status, card->base + 0x02);
926a6614999e800cf3a134ce93ea46ef837e3c0e76eAlan Cox	isicom_shutdown_port(ip);
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&card->card_lock, flags);
9282493c0c166565e36831196446af594eb07892dafAlan Cox	tty_port_free_xmit_buf(port);
9296f6412b4c76441f2060e580b8d5cbda07dabde37Alan Cox}
930d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
9316f6412b4c76441f2060e580b8d5cbda07dabde37Alan Coxstatic void isicom_close(struct tty_struct *tty, struct file *filp)
9326f6412b4c76441f2060e580b8d5cbda07dabde37Alan Cox{
9336f6412b4c76441f2060e580b8d5cbda07dabde37Alan Cox	struct isi_port *ip = tty->driver_data;
934a2d1e3516c80027b2da17fb0b7ccd36f0ac33aa7Alan Cox	struct tty_port *port;
935a2d1e3516c80027b2da17fb0b7ccd36f0ac33aa7Alan Cox
936a2d1e3516c80027b2da17fb0b7ccd36f0ac33aa7Alan Cox	if (ip == NULL)
937a2d1e3516c80027b2da17fb0b7ccd36f0ac33aa7Alan Cox		return;
938a2d1e3516c80027b2da17fb0b7ccd36f0ac33aa7Alan Cox
939a2d1e3516c80027b2da17fb0b7ccd36f0ac33aa7Alan Cox	port = &ip->port;
9406f6412b4c76441f2060e580b8d5cbda07dabde37Alan Cox	if (isicom_paranoia_check(ip, tty->name, "isicom_close"))
9416f6412b4c76441f2060e580b8d5cbda07dabde37Alan Cox		return;
942baaa08acb0ca2df47830b58b5df8b9059cf9ddd2Alan Cox	tty_port_close(port, tty, filp);
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* write et all */
946d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slabystatic int isicom_write(struct tty_struct *tty,	const unsigned char *buf,
947d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	int count)
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9498070e35c6524e0f254cd69f493c50811e8e5b856Jiri Slaby	struct isi_port *port = tty->driver_data;
950d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	struct isi_board *card = port->card;
9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cnt, total = 0;
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (isicom_paranoia_check(port, tty->name, "isicom_write"))
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
956d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&card->card_lock, flags);
958d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
959251b8dd7eee30fda089a1dc088abf4fc9a0dee9cAlan Cox	while (1) {
960a547dfe9563c49fd0f9743640e01d1d652119ec7Jiri Slaby		cnt = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt
961a547dfe9563c49fd0f9743640e01d1d652119ec7Jiri Slaby				- 1, SERIAL_XMIT_SIZE - port->xmit_head));
962d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby		if (cnt <= 0)
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
964d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
965f1d03228ea85877584d41bccf62841e7ca47043cAlan Cox		memcpy(port->port.xmit_buf + port->xmit_head, buf, cnt);
966a547dfe9563c49fd0f9743640e01d1d652119ec7Jiri Slaby		port->xmit_head = (port->xmit_head + cnt) & (SERIAL_XMIT_SIZE
967a547dfe9563c49fd0f9743640e01d1d652119ec7Jiri Slaby			- 1);
9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		port->xmit_cnt += cnt;
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf += cnt;
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		count -= cnt;
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		total += cnt;
972d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	}
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped)
9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		port->status |= ISI_TXOK;
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&card->card_lock, flags);
976d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	return total;
9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* put_char et all */
980f34d7a5b7010b82fe97da95496b9971435530062Alan Coxstatic int isicom_put_char(struct tty_struct *tty, unsigned char ch)
9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9828070e35c6524e0f254cd69f493c50811e8e5b856Jiri Slaby	struct isi_port *port = tty->driver_data;
983d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	struct isi_board *card = port->card;
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
985d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (isicom_paranoia_check(port, tty->name, "isicom_put_char"))
987f34d7a5b7010b82fe97da95496b9971435530062Alan Cox		return 0;
988d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&card->card_lock, flags);
990f34d7a5b7010b82fe97da95496b9971435530062Alan Cox	if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
991f34d7a5b7010b82fe97da95496b9971435530062Alan Cox		spin_unlock_irqrestore(&card->card_lock, flags);
992f34d7a5b7010b82fe97da95496b9971435530062Alan Cox		return 0;
993f34d7a5b7010b82fe97da95496b9971435530062Alan Cox	}
994d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
995f1d03228ea85877584d41bccf62841e7ca47043cAlan Cox	port->port.xmit_buf[port->xmit_head++] = ch;
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->xmit_head &= (SERIAL_XMIT_SIZE - 1);
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->xmit_cnt++;
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&card->card_lock, flags);
999f34d7a5b7010b82fe97da95496b9971435530062Alan Cox	return 1;
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* flush_chars et all */
1003d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slabystatic void isicom_flush_chars(struct tty_struct *tty)
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10058070e35c6524e0f254cd69f493c50811e8e5b856Jiri Slaby	struct isi_port *port = tty->driver_data;
1006d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (isicom_paranoia_check(port, tty->name, "isicom_flush_chars"))
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
1009d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
1010a547dfe9563c49fd0f9743640e01d1d652119ec7Jiri Slaby	if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
1011f1d03228ea85877584d41bccf62841e7ca47043cAlan Cox			!port->port.xmit_buf)
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
1013d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* this tells the transmitter to consider this port for
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   data output to the card ... that's the best we can do. */
1016d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	port->status |= ISI_TXOK;
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* write_room et all */
1020d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slabystatic int isicom_write_room(struct tty_struct *tty)
10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10228070e35c6524e0f254cd69f493c50811e8e5b856Jiri Slaby	struct isi_port *port = tty->driver_data;
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int free;
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (isicom_paranoia_check(port, tty->name, "isicom_write_room"))
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
1027d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free = SERIAL_XMIT_SIZE - port->xmit_cnt - 1;
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (free < 0)
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		free = 0;
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return free;
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* chars_in_buffer et all */
1035d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slabystatic int isicom_chars_in_buffer(struct tty_struct *tty)
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10378070e35c6524e0f254cd69f493c50811e8e5b856Jiri Slaby	struct isi_port *port = tty->driver_data;
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (isicom_paranoia_check(port, tty->name, "isicom_chars_in_buffer"))
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return port->xmit_cnt;
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ioctl et all */
10446d889724332e875ac07b6c88e08d9564c180824dAlan Coxstatic int isicom_send_break(struct tty_struct *tty, int length)
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10466d889724332e875ac07b6c88e08d9564c180824dAlan Cox	struct isi_port *port = tty->driver_data;
1047d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	struct isi_board *card = port->card;
10488070e35c6524e0f254cd69f493c50811e8e5b856Jiri Slaby	unsigned long base = card->base;
1049d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
10506d889724332e875ac07b6c88e08d9564c180824dAlan Cox	if (length == -1)
10516d889724332e875ac07b6c88e08d9564c180824dAlan Cox		return -EOPNOTSUPP;
10526d889724332e875ac07b6c88e08d9564c180824dAlan Cox
1053d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	if (!lock_card(card))
10546d889724332e875ac07b6c88e08d9564c180824dAlan Cox		return -EINVAL;
1055d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outw(0x8000 | ((port->channel) << (card->shift_count)) | 0x3, base);
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outw((length & 0xff) << 8 | 0x00, base);
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outw((length & 0xff00), base);
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	InterruptTheCard(base);
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unlock_card(card);
10626d889724332e875ac07b6c88e08d9564c180824dAlan Cox	return 0;
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
106560b33c133ca0b7c0b6072c87234b63fee6e80558Alan Coxstatic int isicom_tiocmget(struct tty_struct *tty)
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10678070e35c6524e0f254cd69f493c50811e8e5b856Jiri Slaby	struct isi_port *port = tty->driver_data;
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* just send the port status */
10698070e35c6524e0f254cd69f493c50811e8e5b856Jiri Slaby	u16 status = port->status;
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (isicom_paranoia_check(port, tty->name, "isicom_ioctl"))
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
1073d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return  ((status & ISI_RTS) ? TIOCM_RTS : 0) |
10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		((status & ISI_DTR) ? TIOCM_DTR : 0) |
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		((status & ISI_DCD) ? TIOCM_CAR : 0) |
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		((status & ISI_DSR) ? TIOCM_DSR : 0) |
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		((status & ISI_CTS) ? TIOCM_CTS : 0) |
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		((status & ISI_RI ) ? TIOCM_RI  : 0);
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
108220b9d17715017ae4dd4ec87fabc36d33b9de708eAlan Coxstatic int isicom_tiocmset(struct tty_struct *tty,
108320b9d17715017ae4dd4ec87fabc36d33b9de708eAlan Cox					unsigned int set, unsigned int clear)
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10858070e35c6524e0f254cd69f493c50811e8e5b856Jiri Slaby	struct isi_port *port = tty->driver_data;
1086cfe7c09ac2be2a89aa46bb23d480d9d908e8c041Jiri Slaby	unsigned long flags;
1087d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (isicom_paranoia_check(port, tty->name, "isicom_ioctl"))
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
1090d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
1091cfe7c09ac2be2a89aa46bb23d480d9d908e8c041Jiri Slaby	spin_lock_irqsave(&port->card->card_lock, flags);
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (set & TIOCM_RTS)
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		raise_rts(port);
10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (set & TIOCM_DTR)
10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		raise_dtr(port);
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clear & TIOCM_RTS)
10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		drop_rts(port);
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clear & TIOCM_DTR)
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		drop_dtr(port);
1101cfe7c09ac2be2a89aa46bb23d480d9d908e8c041Jiri Slaby	spin_unlock_irqrestore(&port->card->card_lock, flags);
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1104d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby}
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1106d450b5a0196b6442cf3f29fc611d9c8daa56b559Alan Coxstatic int isicom_set_serial_info(struct tty_struct *tty,
1107d450b5a0196b6442cf3f29fc611d9c8daa56b559Alan Cox					struct serial_struct __user *info)
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1109d450b5a0196b6442cf3f29fc611d9c8daa56b559Alan Cox	struct isi_port *port = tty->driver_data;
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct serial_struct newinfo;
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int reconfig_port;
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1113d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	if (copy_from_user(&newinfo, info, sizeof(newinfo)))
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
1115d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
1116ec82db129e94c7896e732d21f2bb9ab8e7312fe0Alan Cox	mutex_lock(&port->port.mutex);
1117f1d03228ea85877584d41bccf62841e7ca47043cAlan Cox	reconfig_port = ((port->port.flags & ASYNC_SPD_MASK) !=
1118d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby		(newinfo.flags & ASYNC_SPD_MASK));
1119d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!capable(CAP_SYS_ADMIN)) {
112144b7d1b37f786c61d0e382b6f72f605f73de284bAlan Cox		if ((newinfo.close_delay != port->port.close_delay) ||
112244b7d1b37f786c61d0e382b6f72f605f73de284bAlan Cox				(newinfo.closing_wait != port->port.closing_wait) ||
1123d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby				((newinfo.flags & ~ASYNC_USR_MASK) !=
1124f1d03228ea85877584d41bccf62841e7ca47043cAlan Cox				(port->port.flags & ~ASYNC_USR_MASK))) {
1125ec82db129e94c7896e732d21f2bb9ab8e7312fe0Alan Cox			mutex_unlock(&port->port.mutex);
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EPERM;
11271eac494738a0447ef0c423ee2066f85a44ab59f5Alan Cox		}
1128f1d03228ea85877584d41bccf62841e7ca47043cAlan Cox		port->port.flags = ((port->port.flags & ~ASYNC_USR_MASK) |
11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				(newinfo.flags & ASYNC_USR_MASK));
1130251b8dd7eee30fda089a1dc088abf4fc9a0dee9cAlan Cox	} else {
113144b7d1b37f786c61d0e382b6f72f605f73de284bAlan Cox		port->port.close_delay = newinfo.close_delay;
113244b7d1b37f786c61d0e382b6f72f605f73de284bAlan Cox		port->port.closing_wait = newinfo.closing_wait;
1133f1d03228ea85877584d41bccf62841e7ca47043cAlan Cox		port->port.flags = ((port->port.flags & ~ASYNC_FLAGS) |
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				(newinfo.flags & ASYNC_FLAGS));
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (reconfig_port) {
1137cfe7c09ac2be2a89aa46bb23d480d9d908e8c041Jiri Slaby		unsigned long flags;
1138cfe7c09ac2be2a89aa46bb23d480d9d908e8c041Jiri Slaby		spin_lock_irqsave(&port->card->card_lock, flags);
1139d450b5a0196b6442cf3f29fc611d9c8daa56b559Alan Cox		isicom_config_port(tty);
1140cfe7c09ac2be2a89aa46bb23d480d9d908e8c041Jiri Slaby		spin_unlock_irqrestore(&port->card->card_lock, flags);
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1142ec82db129e94c7896e732d21f2bb9ab8e7312fe0Alan Cox	mutex_unlock(&port->port.mutex);
1143d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	return 0;
1144d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby}
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1146d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slabystatic int isicom_get_serial_info(struct isi_port *port,
1147d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	struct serial_struct __user *info)
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct serial_struct out_info;
1150d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
1151ec82db129e94c7896e732d21f2bb9ab8e7312fe0Alan Cox	mutex_lock(&port->port.mutex);
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(&out_info, 0, sizeof(out_info));
11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*	out_info.type = ? */
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	out_info.line = port - isi_ports;
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	out_info.port = port->card->base;
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	out_info.irq = port->card->irq;
1157f1d03228ea85877584d41bccf62841e7ca47043cAlan Cox	out_info.flags = port->port.flags;
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*	out_info.baud_base = ? */
115944b7d1b37f786c61d0e382b6f72f605f73de284bAlan Cox	out_info.close_delay = port->port.close_delay;
116044b7d1b37f786c61d0e382b6f72f605f73de284bAlan Cox	out_info.closing_wait = port->port.closing_wait;
1161ec82db129e94c7896e732d21f2bb9ab8e7312fe0Alan Cox	mutex_unlock(&port->port.mutex);
1162d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	if (copy_to_user(info, &out_info, sizeof(out_info)))
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1165d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby}
11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11676caa76b7786891b42b66a0e61e2c2fff2c884620Alan Coxstatic int isicom_ioctl(struct tty_struct *tty,
1168d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	unsigned int cmd, unsigned long arg)
11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11708070e35c6524e0f254cd69f493c50811e8e5b856Jiri Slaby	struct isi_port *port = tty->driver_data;
11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __user *argp = (void __user *)arg;
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (isicom_paranoia_check(port, tty->name, "isicom_ioctl"))
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1176251b8dd7eee30fda089a1dc088abf4fc9a0dee9cAlan Cox	switch (cmd) {
1177d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	case TIOCGSERIAL:
1178d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby		return isicom_get_serial_info(port, argp);
1179d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
1180d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	case TIOCSSERIAL:
1181d450b5a0196b6442cf3f29fc611d9c8daa56b559Alan Cox		return isicom_set_serial_info(tty, argp);
1182d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
1183d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	default:
1184d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby		return -ENOIOCTLCMD;
11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* set_termios et all */
1190d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slabystatic void isicom_set_termios(struct tty_struct *tty,
1191606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox	struct ktermios *old_termios)
11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11938070e35c6524e0f254cd69f493c50811e8e5b856Jiri Slaby	struct isi_port *port = tty->driver_data;
1194cfe7c09ac2be2a89aa46bb23d480d9d908e8c041Jiri Slaby	unsigned long flags;
1195d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (isicom_paranoia_check(port, tty->name, "isicom_set_termios"))
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
1198d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tty->termios->c_cflag == old_termios->c_cflag &&
1200d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby			tty->termios->c_iflag == old_termios->c_iflag)
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
1202d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
1203cfe7c09ac2be2a89aa46bb23d480d9d908e8c041Jiri Slaby	spin_lock_irqsave(&port->card->card_lock, flags);
1204d450b5a0196b6442cf3f29fc611d9c8daa56b559Alan Cox	isicom_config_port(tty);
1205cfe7c09ac2be2a89aa46bb23d480d9d908e8c041Jiri Slaby	spin_unlock_irqrestore(&port->card->card_lock, flags);
1206d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((old_termios->c_cflag & CRTSCTS) &&
1208d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby			!(tty->termios->c_cflag & CRTSCTS)) {
12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tty->hw_stopped = 0;
1210d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby		isicom_start(tty);
1211d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	}
12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* throttle et all */
1215d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slabystatic void isicom_throttle(struct tty_struct *tty)
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12178070e35c6524e0f254cd69f493c50811e8e5b856Jiri Slaby	struct isi_port *port = tty->driver_data;
1218d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	struct isi_board *card = port->card;
1219d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (isicom_paranoia_check(port, tty->name, "isicom_throttle"))
12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
1222d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* tell the card that this port cannot handle any more data for now */
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	card->port_status &= ~(1 << port->channel);
12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outw(card->port_status, card->base + 0x02);
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* unthrottle et all */
1229d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slabystatic void isicom_unthrottle(struct tty_struct *tty)
12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12318070e35c6524e0f254cd69f493c50811e8e5b856Jiri Slaby	struct isi_port *port = tty->driver_data;
1232d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	struct isi_board *card = port->card;
1233d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (isicom_paranoia_check(port, tty->name, "isicom_unthrottle"))
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
1236d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* tell the card that this port is ready to accept more data */
12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	card->port_status |= (1 << port->channel);
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outw(card->port_status, card->base + 0x02);
12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* stop et all */
1243d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slabystatic void isicom_stop(struct tty_struct *tty)
12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12458070e35c6524e0f254cd69f493c50811e8e5b856Jiri Slaby	struct isi_port *port = tty->driver_data;
12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (isicom_paranoia_check(port, tty->name, "isicom_stop"))
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
1249d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* this tells the transmitter not to consider this port for
12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   data output to the card. */
12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->status &= ~ISI_TXOK;
12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* start et all */
1256d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slabystatic void isicom_start(struct tty_struct *tty)
12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12588070e35c6524e0f254cd69f493c50811e8e5b856Jiri Slaby	struct isi_port *port = tty->driver_data;
1259d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (isicom_paranoia_check(port, tty->name, "isicom_start"))
12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
1262d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* this tells the transmitter to consider this port for
12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   data output to the card. */
12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->status |= ISI_TXOK;
12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1268d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slabystatic void isicom_hangup(struct tty_struct *tty)
12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12708070e35c6524e0f254cd69f493c50811e8e5b856Jiri Slaby	struct isi_port *port = tty->driver_data;
1271d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (isicom_paranoia_check(port, tty->name, "isicom_hangup"))
12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
12743e61696bdc2103107674b06d0daf30b76193e922Alan Cox	tty_port_hangup(&port->port);
12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12789ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby/*
12799ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby * Driver init and deinit functions
12809ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby */
12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1282b68e31d0ebbcc909d1941f9f230c9d062a3a13d3Jeff Dikestatic const struct tty_operations isicom_ops = {
1283d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	.open			= isicom_open,
1284d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	.close			= isicom_close,
1285d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	.write			= isicom_write,
1286d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	.put_char		= isicom_put_char,
1287d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	.flush_chars		= isicom_flush_chars,
1288d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	.write_room		= isicom_write_room,
12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.chars_in_buffer	= isicom_chars_in_buffer,
1290d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	.ioctl			= isicom_ioctl,
1291d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	.set_termios		= isicom_set_termios,
1292d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	.throttle		= isicom_throttle,
1293d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	.unthrottle		= isicom_unthrottle,
1294d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	.stop			= isicom_stop,
1295d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	.start			= isicom_start,
1296d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	.hangup			= isicom_hangup,
1297d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	.flush_buffer		= isicom_flush_buffer,
1298d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	.tiocmget		= isicom_tiocmget,
1299d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	.tiocmset		= isicom_tiocmset,
13006d889724332e875ac07b6c88e08d9564c180824dAlan Cox	.break_ctl		= isicom_send_break,
13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
130331f35939d1d9bcfb3099b32c67b896d2792603f9Alan Coxstatic const struct tty_port_operations isicom_port_ops = {
130431f35939d1d9bcfb3099b32c67b896d2792603f9Alan Cox	.carrier_raised		= isicom_carrier_raised,
1305fcc8ac1825d3d0fb81f73bc1a80ebc863168bb56Alan Cox	.dtr_rts		= isicom_dtr_rts,
1306baaa08acb0ca2df47830b58b5df8b9059cf9ddd2Alan Cox	.activate		= isicom_activate,
1307baaa08acb0ca2df47830b58b5df8b9059cf9ddd2Alan Cox	.shutdown		= isicom_shutdown,
130831f35939d1d9bcfb3099b32c67b896d2792603f9Alan Cox};
130931f35939d1d9bcfb3099b32c67b896d2792603f9Alan Cox
13109ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slabystatic int __devinit reset_card(struct pci_dev *pdev,
13119ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	const unsigned int card, unsigned int *signature)
13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13139ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	struct isi_board *board = pci_get_drvdata(pdev);
13149ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	unsigned long base = board->base;
1315f0a0ba6d69882ae14f24d7eb6e2ae07f30fbd56aJiri Slaby	unsigned int sig, portcount = 0;
13169ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	int retval = 0;
1317d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
13189ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	dev_dbg(&pdev->dev, "ISILoad:Resetting Card%d at 0x%lx\n", card + 1,
13199ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby		base);
1320d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
13219ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	inw(base + 0x8);
1322d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
1323f0a0ba6d69882ae14f24d7eb6e2ae07f30fbd56aJiri Slaby	msleep(10);
13249ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby
13259ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	outw(0, base + 0x8); /* Reset */
13269ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby
1327f0a0ba6d69882ae14f24d7eb6e2ae07f30fbd56aJiri Slaby	msleep(1000);
13289ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby
1329f0a0ba6d69882ae14f24d7eb6e2ae07f30fbd56aJiri Slaby	sig = inw(base + 0x4) & 0xff;
1330f0a0ba6d69882ae14f24d7eb6e2ae07f30fbd56aJiri Slaby
1331f0a0ba6d69882ae14f24d7eb6e2ae07f30fbd56aJiri Slaby	if (sig != 0xa5 && sig != 0xbb && sig != 0xcc && sig != 0xdd &&
1332f0a0ba6d69882ae14f24d7eb6e2ae07f30fbd56aJiri Slaby			sig != 0xee) {
1333f0a0ba6d69882ae14f24d7eb6e2ae07f30fbd56aJiri Slaby		dev_warn(&pdev->dev, "ISILoad:Card%u reset failure (Possible "
1334f0a0ba6d69882ae14f24d7eb6e2ae07f30fbd56aJiri Slaby			"bad I/O Port Address 0x%lx).\n", card + 1, base);
1335f0a0ba6d69882ae14f24d7eb6e2ae07f30fbd56aJiri Slaby		dev_dbg(&pdev->dev, "Sig=0x%x\n", sig);
1336f0a0ba6d69882ae14f24d7eb6e2ae07f30fbd56aJiri Slaby		retval = -EIO;
1337f0a0ba6d69882ae14f24d7eb6e2ae07f30fbd56aJiri Slaby		goto end;
1338f0a0ba6d69882ae14f24d7eb6e2ae07f30fbd56aJiri Slaby	}
1339f0a0ba6d69882ae14f24d7eb6e2ae07f30fbd56aJiri Slaby
1340f0a0ba6d69882ae14f24d7eb6e2ae07f30fbd56aJiri Slaby	msleep(10);
13419ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby
134218234f88bc27473f15293a03c83bcb53da9018b4Jiri Slaby	portcount = inw(base + 0x2);
134307fb6f26bab869fc3bb9df0a785ba734f4c51ac3Julia Lawall	if (!(inw(base + 0xe) & 0x1) || (portcount != 0 && portcount != 4 &&
1344f0a0ba6d69882ae14f24d7eb6e2ae07f30fbd56aJiri Slaby				portcount != 8 && portcount != 16)) {
1345898eb71cb17644964c5895fb190e79e3d0c49679Joe Perches		dev_err(&pdev->dev, "ISILoad:PCI Card%d reset failure.\n",
1346f0a0ba6d69882ae14f24d7eb6e2ae07f30fbd56aJiri Slaby			card + 1);
134718234f88bc27473f15293a03c83bcb53da9018b4Jiri Slaby		retval = -EIO;
134818234f88bc27473f15293a03c83bcb53da9018b4Jiri Slaby		goto end;
13499ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	}
13509ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby
1351f0a0ba6d69882ae14f24d7eb6e2ae07f30fbd56aJiri Slaby	switch (sig) {
13529ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	case 0xa5:
13539ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	case 0xbb:
13549ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	case 0xdd:
135518234f88bc27473f15293a03c83bcb53da9018b4Jiri Slaby		board->port_count = (portcount == 4) ? 4 : 8;
13569ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby		board->shift_count = 12;
13579ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby		break;
13589ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	case 0xcc:
1359f0a0ba6d69882ae14f24d7eb6e2ae07f30fbd56aJiri Slaby	case 0xee:
13609ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby		board->port_count = 16;
13619ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby		board->shift_count = 11;
13629ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby		break;
1363d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby	}
13649ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	dev_info(&pdev->dev, "-Done\n");
1365f0a0ba6d69882ae14f24d7eb6e2ae07f30fbd56aJiri Slaby	*signature = sig;
1366d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
13679ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slabyend:
13689ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	return retval;
13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1371e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slabystatic int __devinit load_firmware(struct pci_dev *pdev,
1372e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby	const unsigned int index, const unsigned int signature)
1373e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby{
1374e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby	struct isi_board *board = pci_get_drvdata(pdev);
1375e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby	const struct firmware *fw;
1376e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby	unsigned long base = board->base;
1377e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby	unsigned int a;
1378e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby	u16 word_count, status;
1379e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby	int retval = -EIO;
1380e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby	char *name;
1381e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby	u8 *data;
1382e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby
1383e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby	struct stframe {
1384e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		u16	addr;
1385e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		u16	count;
1386e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		u8	data[0];
1387e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby	} *frame;
1388e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby
1389e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby	switch (signature) {
1390e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby	case 0xa5:
1391e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		name = "isi608.bin";
1392e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		break;
1393e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby	case 0xbb:
1394e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		name = "isi608em.bin";
1395e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		break;
1396e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby	case 0xcc:
1397e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		name = "isi616em.bin";
1398e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		break;
1399e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby	case 0xdd:
1400e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		name = "isi4608.bin";
1401e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		break;
1402e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby	case 0xee:
1403e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		name = "isi4616.bin";
1404e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		break;
1405e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby	default:
1406e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		dev_err(&pdev->dev, "Unknown signature.\n");
1407e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		goto end;
1408251b8dd7eee30fda089a1dc088abf4fc9a0dee9cAlan Cox	}
1409e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby
1410e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby	retval = request_firmware(&fw, name, &pdev->dev);
1411e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby	if (retval)
1412e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		goto end;
1413e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby
1414e4e040887b8f136d00e253dcf584667d8cd560a6Jiri Slaby	retval = -EIO;
1415e4e040887b8f136d00e253dcf584667d8cd560a6Jiri Slaby
1416e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby	for (frame = (struct stframe *)fw->data;
1417e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby			frame < (struct stframe *)(fw->data + fw->size);
1418e4e040887b8f136d00e253dcf584667d8cd560a6Jiri Slaby			frame = (struct stframe *)((u8 *)(frame + 1) +
1419e4e040887b8f136d00e253dcf584667d8cd560a6Jiri Slaby				frame->count)) {
1420e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		if (WaitTillCardIsFree(base))
1421e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby			goto errrelfw;
1422e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby
1423e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		outw(0xf0, base);	/* start upload sequence */
1424e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		outw(0x00, base);
1425e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		outw(frame->addr, base); /* lsb of address */
1426e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby
1427e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		word_count = frame->count / 2 + frame->count % 2;
1428e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		outw(word_count, base);
1429e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		InterruptTheCard(base);
1430e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby
1431e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		udelay(100); /* 0x2f */
1432e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby
1433e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		if (WaitTillCardIsFree(base))
1434e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby			goto errrelfw;
1435e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby
1436251b8dd7eee30fda089a1dc088abf4fc9a0dee9cAlan Cox		status = inw(base + 0x4);
1437251b8dd7eee30fda089a1dc088abf4fc9a0dee9cAlan Cox		if (status != 0) {
1438e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby			dev_warn(&pdev->dev, "Card%d rejected load header:\n"
1439ad361c9884e809340f6daca80d56a9e9c871690aJoe Perches				 "Address:0x%x\n"
1440ad361c9884e809340f6daca80d56a9e9c871690aJoe Perches				 "Count:0x%x\n"
1441ad361c9884e809340f6daca80d56a9e9c871690aJoe Perches				 "Status:0x%x\n",
1442ad361c9884e809340f6daca80d56a9e9c871690aJoe Perches				 index + 1, frame->addr, frame->count, status);
1443e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby			goto errrelfw;
1444e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		}
1445e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		outsw(base, frame->data, word_count);
1446e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby
1447e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		InterruptTheCard(base);
1448e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby
1449e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		udelay(50); /* 0x0f */
1450e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby
1451e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		if (WaitTillCardIsFree(base))
1452e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby			goto errrelfw;
1453e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby
1454251b8dd7eee30fda089a1dc088abf4fc9a0dee9cAlan Cox		status = inw(base + 0x4);
1455251b8dd7eee30fda089a1dc088abf4fc9a0dee9cAlan Cox		if (status != 0) {
1456e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby			dev_err(&pdev->dev, "Card%d got out of sync.Card "
1457e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby				"Status:0x%x\n", index + 1, status);
1458e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby			goto errrelfw;
1459e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		}
1460251b8dd7eee30fda089a1dc088abf4fc9a0dee9cAlan Cox	}
1461e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby
1462e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby/* XXX: should we test it by reading it back and comparing with original like
1463e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby * in load firmware package? */
1464e4e040887b8f136d00e253dcf584667d8cd560a6Jiri Slaby	for (frame = (struct stframe *)fw->data;
1465e4e040887b8f136d00e253dcf584667d8cd560a6Jiri Slaby			frame < (struct stframe *)(fw->data + fw->size);
1466e4e040887b8f136d00e253dcf584667d8cd560a6Jiri Slaby			frame = (struct stframe *)((u8 *)(frame + 1) +
1467e4e040887b8f136d00e253dcf584667d8cd560a6Jiri Slaby				frame->count)) {
1468e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		if (WaitTillCardIsFree(base))
1469e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby			goto errrelfw;
1470e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby
1471e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		outw(0xf1, base); /* start download sequence */
1472e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		outw(0x00, base);
1473e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		outw(frame->addr, base); /* lsb of address */
1474e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby
1475e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		word_count = (frame->count >> 1) + frame->count % 2;
1476e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		outw(word_count + 1, base);
1477e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		InterruptTheCard(base);
1478e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby
1479e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		udelay(50); /* 0xf */
1480e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby
1481e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		if (WaitTillCardIsFree(base))
1482e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby			goto errrelfw;
1483e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby
1484251b8dd7eee30fda089a1dc088abf4fc9a0dee9cAlan Cox		status = inw(base + 0x4);
1485251b8dd7eee30fda089a1dc088abf4fc9a0dee9cAlan Cox		if (status != 0) {
1486e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby			dev_warn(&pdev->dev, "Card%d rejected verify header:\n"
1487ad361c9884e809340f6daca80d56a9e9c871690aJoe Perches				 "Address:0x%x\n"
1488ad361c9884e809340f6daca80d56a9e9c871690aJoe Perches				 "Count:0x%x\n"
1489ad361c9884e809340f6daca80d56a9e9c871690aJoe Perches				 "Status: 0x%x\n",
1490ad361c9884e809340f6daca80d56a9e9c871690aJoe Perches				 index + 1, frame->addr, frame->count, status);
1491e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby			goto errrelfw;
1492e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		}
1493e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby
1494e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		data = kmalloc(word_count * 2, GFP_KERNEL);
1495f0671378426d9768bf20d5e0f8389374dcdc2abfJiri Slaby		if (data == NULL) {
1496f0671378426d9768bf20d5e0f8389374dcdc2abfJiri Slaby			dev_err(&pdev->dev, "Card%d, firmware upload "
1497f0671378426d9768bf20d5e0f8389374dcdc2abfJiri Slaby				"failed, not enough memory\n", index + 1);
1498f0671378426d9768bf20d5e0f8389374dcdc2abfJiri Slaby			goto errrelfw;
1499f0671378426d9768bf20d5e0f8389374dcdc2abfJiri Slaby		}
1500e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		inw(base);
1501e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		insw(base, data, word_count);
1502e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		InterruptTheCard(base);
1503e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby
1504e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		for (a = 0; a < frame->count; a++)
1505e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby			if (data[a] != frame->data[a]) {
1506e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby				kfree(data);
1507e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby				dev_err(&pdev->dev, "Card%d, firmware upload "
1508e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby					"failed\n", index + 1);
1509e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby				goto errrelfw;
1510e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby			}
1511e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		kfree(data);
1512e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby
1513e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		udelay(50); /* 0xf */
1514e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby
1515e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		if (WaitTillCardIsFree(base))
1516e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby			goto errrelfw;
1517e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby
1518251b8dd7eee30fda089a1dc088abf4fc9a0dee9cAlan Cox		status = inw(base + 0x4);
1519251b8dd7eee30fda089a1dc088abf4fc9a0dee9cAlan Cox		if (status != 0) {
1520e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby			dev_err(&pdev->dev, "Card%d verify got out of sync. "
1521e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby				"Card Status:0x%x\n", index + 1, status);
1522e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby			goto errrelfw;
1523e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		}
1524e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby	}
1525e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby
1526e4e040887b8f136d00e253dcf584667d8cd560a6Jiri Slaby	/* xfer ctrl */
1527e4e040887b8f136d00e253dcf584667d8cd560a6Jiri Slaby	if (WaitTillCardIsFree(base))
1528e4e040887b8f136d00e253dcf584667d8cd560a6Jiri Slaby		goto errrelfw;
1529e4e040887b8f136d00e253dcf584667d8cd560a6Jiri Slaby
1530e4e040887b8f136d00e253dcf584667d8cd560a6Jiri Slaby	outw(0xf2, base);
1531e4e040887b8f136d00e253dcf584667d8cd560a6Jiri Slaby	outw(0x800, base);
1532e4e040887b8f136d00e253dcf584667d8cd560a6Jiri Slaby	outw(0x0, base);
1533e4e040887b8f136d00e253dcf584667d8cd560a6Jiri Slaby	outw(0x0, base);
1534e4e040887b8f136d00e253dcf584667d8cd560a6Jiri Slaby	InterruptTheCard(base);
1535e4e040887b8f136d00e253dcf584667d8cd560a6Jiri Slaby	outw(0x0, base + 0x4); /* for ISI4608 cards */
1536e4e040887b8f136d00e253dcf584667d8cd560a6Jiri Slaby
1537e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby	board->status |= FIRMWARE_LOADED;
1538e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby	retval = 0;
1539e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby
1540e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slabyerrrelfw:
1541e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby	release_firmware(fw);
1542e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slabyend:
1543e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby	return retval;
1544e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby}
1545e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby
15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Insmod can set static symbols so keep these static
15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
15491ed0c0b7306d7c93e83ebe30087a12684b280cdcJiri Slabystatic unsigned int card_count;
15509ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby
15519ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slabystatic int __devinit isicom_probe(struct pci_dev *pdev,
15529ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	const struct pci_device_id *ent)
15539ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby{
15549653a69e923522050e15dab042b163dcc2ed7111Jiri Slaby	unsigned int uninitialized_var(signature), index;
15559ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	int retval = -EPERM;
15569ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	struct isi_board *board = NULL;
15579ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby
15581ed0c0b7306d7c93e83ebe30087a12684b280cdcJiri Slaby	if (card_count >= BOARD_COUNT)
15599ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby		goto err;
15609ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby
1561e1e5770bb63fb9d71619a68f52cb0ba4b2ae58a6Jiri Slaby	retval = pci_enable_device(pdev);
1562e1e5770bb63fb9d71619a68f52cb0ba4b2ae58a6Jiri Slaby	if (retval) {
1563e1e5770bb63fb9d71619a68f52cb0ba4b2ae58a6Jiri Slaby		dev_err(&pdev->dev, "failed to enable\n");
1564e1e5770bb63fb9d71619a68f52cb0ba4b2ae58a6Jiri Slaby		goto err;
1565e1e5770bb63fb9d71619a68f52cb0ba4b2ae58a6Jiri Slaby	}
1566e1e5770bb63fb9d71619a68f52cb0ba4b2ae58a6Jiri Slaby
15679ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	dev_info(&pdev->dev, "ISI PCI Card(Device ID 0x%x)\n", ent->device);
15689ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby
15699ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	/* allot the first empty slot in the array */
157026e1e8d1d1cfa914b95b5dab001a6ed898872755Dan Carpenter	for (index = 0; index < BOARD_COUNT; index++) {
15719ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby		if (isi_card[index].base == 0) {
15729ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby			board = &isi_card[index];
15739ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby			break;
15749ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby		}
157526e1e8d1d1cfa914b95b5dab001a6ed898872755Dan Carpenter	}
157626e1e8d1d1cfa914b95b5dab001a6ed898872755Dan Carpenter	if (index == BOARD_COUNT) {
157726e1e8d1d1cfa914b95b5dab001a6ed898872755Dan Carpenter		retval = -ENODEV;
157826e1e8d1d1cfa914b95b5dab001a6ed898872755Dan Carpenter		goto err_disable;
157926e1e8d1d1cfa914b95b5dab001a6ed898872755Dan Carpenter	}
15809ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby
1581938a7023bbbc626b0ab7ece13fe8cb26cfcc486bJiri Slaby	board->index = index;
15824969b3a43dd9e234b363f7bf52d0f6c4b6139eeaJiri Slaby	board->base = pci_resource_start(pdev, 3);
15834969b3a43dd9e234b363f7bf52d0f6c4b6139eeaJiri Slaby	board->irq = pdev->irq;
15841ed0c0b7306d7c93e83ebe30087a12684b280cdcJiri Slaby	card_count++;
15859ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby
15869ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	pci_set_drvdata(pdev, board);
15879ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby
158878028da91e05146c9ce0c9db2fea53e0cded1e81Jiri Slaby	retval = pci_request_region(pdev, 3, ISICOM_NAME);
158978028da91e05146c9ce0c9db2fea53e0cded1e81Jiri Slaby	if (retval) {
159009a4a112559f4e93bb07d9683972e9064ae0418fJiri Slaby		dev_err(&pdev->dev, "I/O Region 0x%lx-0x%lx is busy. Card%d "
159109a4a112559f4e93bb07d9683972e9064ae0418fJiri Slaby			"will be disabled.\n", board->base, board->base + 15,
159209a4a112559f4e93bb07d9683972e9064ae0418fJiri Slaby			index + 1);
159309a4a112559f4e93bb07d9683972e9064ae0418fJiri Slaby		retval = -EBUSY;
15941ed0c0b7306d7c93e83ebe30087a12684b280cdcJiri Slaby		goto errdec;
1595251b8dd7eee30fda089a1dc088abf4fc9a0dee9cAlan Cox	}
15969ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby
159709a4a112559f4e93bb07d9683972e9064ae0418fJiri Slaby	retval = request_irq(board->irq, isicom_interrupt,
15989cfb5c05fee914cc65d4706801f6bc424082b5f5Yong Zhang			IRQF_SHARED, ISICOM_NAME, board);
159909a4a112559f4e93bb07d9683972e9064ae0418fJiri Slaby	if (retval < 0) {
160009a4a112559f4e93bb07d9683972e9064ae0418fJiri Slaby		dev_err(&pdev->dev, "Could not install handler at Irq %d. "
160109a4a112559f4e93bb07d9683972e9064ae0418fJiri Slaby			"Card%d will be disabled.\n", board->irq, index + 1);
16029ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby		goto errunrr;
160309a4a112559f4e93bb07d9683972e9064ae0418fJiri Slaby	}
16049ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby
16059ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	retval = reset_card(pdev, index, &signature);
16069ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	if (retval < 0)
16079ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby		goto errunri;
16089ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby
1609e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby	retval = load_firmware(pdev, index, signature);
1610e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby	if (retval < 0)
1611e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby		goto errunri;
1612e65c1db19fe8177fa2da53e3e0bddffe585b2d47Jiri Slaby
1613938a7023bbbc626b0ab7ece13fe8cb26cfcc486bJiri Slaby	for (index = 0; index < board->port_count; index++)
1614938a7023bbbc626b0ab7ece13fe8cb26cfcc486bJiri Slaby		tty_register_device(isicom_normal, board->index * 16 + index,
1615938a7023bbbc626b0ab7ece13fe8cb26cfcc486bJiri Slaby				&pdev->dev);
1616938a7023bbbc626b0ab7ece13fe8cb26cfcc486bJiri Slaby
16179ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	return 0;
16189ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby
16199ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slabyerrunri:
16209ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	free_irq(board->irq, board);
16219ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slabyerrunrr:
162278028da91e05146c9ce0c9db2fea53e0cded1e81Jiri Slaby	pci_release_region(pdev, 3);
16231ed0c0b7306d7c93e83ebe30087a12684b280cdcJiri Slabyerrdec:
16249ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	board->base = 0;
16251ed0c0b7306d7c93e83ebe30087a12684b280cdcJiri Slaby	card_count--;
162626e1e8d1d1cfa914b95b5dab001a6ed898872755Dan Carpentererr_disable:
1627e1e5770bb63fb9d71619a68f52cb0ba4b2ae58a6Jiri Slaby	pci_disable_device(pdev);
16281ed0c0b7306d7c93e83ebe30087a12684b280cdcJiri Slabyerr:
16299ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	return retval;
16309ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby}
16319ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby
16329ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slabystatic void __devexit isicom_remove(struct pci_dev *pdev)
16339ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby{
16349ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	struct isi_board *board = pci_get_drvdata(pdev);
1635938a7023bbbc626b0ab7ece13fe8cb26cfcc486bJiri Slaby	unsigned int i;
1636938a7023bbbc626b0ab7ece13fe8cb26cfcc486bJiri Slaby
1637938a7023bbbc626b0ab7ece13fe8cb26cfcc486bJiri Slaby	for (i = 0; i < board->port_count; i++)
1638938a7023bbbc626b0ab7ece13fe8cb26cfcc486bJiri Slaby		tty_unregister_device(isicom_normal, board->index * 16 + i);
16399ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby
16409ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	free_irq(board->irq, board);
164178028da91e05146c9ce0c9db2fea53e0cded1e81Jiri Slaby	pci_release_region(pdev, 3);
16421ed0c0b7306d7c93e83ebe30087a12684b280cdcJiri Slaby	board->base = 0;
16431ed0c0b7306d7c93e83ebe30087a12684b280cdcJiri Slaby	card_count--;
1644e1e5770bb63fb9d71619a68f52cb0ba4b2ae58a6Jiri Slaby	pci_disable_device(pdev);
16459ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby}
16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1647ca26200511776a0b54c5c832efde48ee6445a738Jiri Slabystatic int __init isicom_init(void)
16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16499ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	int retval, idx, channel;
16509ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	struct isi_port *port;
1651d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
1652251b8dd7eee30fda089a1dc088abf4fc9a0dee9cAlan Cox	for (idx = 0; idx < BOARD_COUNT; idx++) {
16539ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby		port = &isi_ports[idx * 16];
16549ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby		isi_card[idx].ports = port;
16559ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby		spin_lock_init(&isi_card[idx].card_lock);
16569ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby		for (channel = 0; channel < 16; channel++, port++) {
165744b7d1b37f786c61d0e382b6f72f605f73de284bAlan Cox			tty_port_init(&port->port);
165831f35939d1d9bcfb3099b32c67b896d2792603f9Alan Cox			port->port.ops = &isicom_port_ops;
16599ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby			port->magic = ISICOM_MAGIC;
16609ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby			port->card = &isi_card[idx];
16619ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby			port->channel = channel;
166244b7d1b37f786c61d0e382b6f72f605f73de284bAlan Cox			port->port.close_delay = 50 * HZ/100;
166344b7d1b37f786c61d0e382b6f72f605f73de284bAlan Cox			port->port.closing_wait = 3000 * HZ/100;
16649ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby			port->status = 0;
16659ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby			/*  . . .  */
1666251b8dd7eee30fda089a1dc088abf4fc9a0dee9cAlan Cox		}
16679ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby		isi_card[idx].base = 0;
16689ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby		isi_card[idx].irq = 0;
16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1670d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
167109a4a112559f4e93bb07d9683972e9064ae0418fJiri Slaby	/* tty driver structure initialization */
167209a4a112559f4e93bb07d9683972e9064ae0418fJiri Slaby	isicom_normal = alloc_tty_driver(PORT_COUNT);
167309a4a112559f4e93bb07d9683972e9064ae0418fJiri Slaby	if (!isicom_normal) {
167409a4a112559f4e93bb07d9683972e9064ae0418fJiri Slaby		retval = -ENOMEM;
16759ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby		goto error;
167609a4a112559f4e93bb07d9683972e9064ae0418fJiri Slaby	}
167709a4a112559f4e93bb07d9683972e9064ae0418fJiri Slaby
167809a4a112559f4e93bb07d9683972e9064ae0418fJiri Slaby	isicom_normal->name 			= "ttyM";
167909a4a112559f4e93bb07d9683972e9064ae0418fJiri Slaby	isicom_normal->major			= ISICOM_NMAJOR;
168009a4a112559f4e93bb07d9683972e9064ae0418fJiri Slaby	isicom_normal->minor_start		= 0;
168109a4a112559f4e93bb07d9683972e9064ae0418fJiri Slaby	isicom_normal->type			= TTY_DRIVER_TYPE_SERIAL;
168209a4a112559f4e93bb07d9683972e9064ae0418fJiri Slaby	isicom_normal->subtype			= SERIAL_TYPE_NORMAL;
168309a4a112559f4e93bb07d9683972e9064ae0418fJiri Slaby	isicom_normal->init_termios		= tty_std_termios;
168409a4a112559f4e93bb07d9683972e9064ae0418fJiri Slaby	isicom_normal->init_termios.c_cflag	= B9600 | CS8 | CREAD | HUPCL |
168509a4a112559f4e93bb07d9683972e9064ae0418fJiri Slaby		CLOCAL;
1686938a7023bbbc626b0ab7ece13fe8cb26cfcc486bJiri Slaby	isicom_normal->flags			= TTY_DRIVER_REAL_RAW |
16876d889724332e875ac07b6c88e08d9564c180824dAlan Cox		TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_HARDWARE_BREAK;
168809a4a112559f4e93bb07d9683972e9064ae0418fJiri Slaby	tty_set_operations(isicom_normal, &isicom_ops);
168909a4a112559f4e93bb07d9683972e9064ae0418fJiri Slaby
169009a4a112559f4e93bb07d9683972e9064ae0418fJiri Slaby	retval = tty_register_driver(isicom_normal);
169109a4a112559f4e93bb07d9683972e9064ae0418fJiri Slaby	if (retval) {
1692db91340b2e874693f14e9e937152e7433d7ac753Joe Perches		pr_debug("Couldn't register the dialin driver\n");
169309a4a112559f4e93bb07d9683972e9064ae0418fJiri Slaby		goto err_puttty;
169409a4a112559f4e93bb07d9683972e9064ae0418fJiri Slaby	}
16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16969ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	retval = pci_register_driver(&isicom_driver);
16971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval < 0) {
1698db91340b2e874693f14e9e937152e7433d7ac753Joe Perches		pr_err("Unable to register pci driver.\n");
169909a4a112559f4e93bb07d9683972e9064ae0418fJiri Slaby		goto err_unrtty;
17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1701d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
170234b55b865ed12494e23b09b5d2e8da22047fd6a7Jiri Slaby	mod_timer(&tx, jiffies + 1);
1703d8d16e47442a84d7fefc7ff839952ddfc919e495Jiri Slaby
17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
170509a4a112559f4e93bb07d9683972e9064ae0418fJiri Slabyerr_unrtty:
170609a4a112559f4e93bb07d9683972e9064ae0418fJiri Slaby	tty_unregister_driver(isicom_normal);
170709a4a112559f4e93bb07d9683972e9064ae0418fJiri Slabyerr_puttty:
170809a4a112559f4e93bb07d9683972e9064ae0418fJiri Slaby	put_tty_driver(isicom_normal);
17099ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slabyerror:
17109ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	return retval;
17111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit isicom_exit(void)
17141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1715e327325f4219e30476c775dbcd8651cd71b5416aJiri Slaby	del_timer_sync(&tx);
1716aaa246ea78c68cd205f505070650cda7c5a95d34Jiri Slaby
17179ac0948b20f76d9659add91f868c57383ea1e4e5Jiri Slaby	pci_unregister_driver(&isicom_driver);
171809a4a112559f4e93bb07d9683972e9064ae0418fJiri Slaby	tty_unregister_driver(isicom_normal);
171909a4a112559f4e93bb07d9683972e9064ae0418fJiri Slaby	put_tty_driver(isicom_normal);
17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1722ca26200511776a0b54c5c832efde48ee6445a738Jiri Slabymodule_init(isicom_init);
17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(isicom_exit);
1724aaa246ea78c68cd205f505070650cda7c5a95d34Jiri Slaby
1725aaa246ea78c68cd205f505070650cda7c5a95d34Jiri SlabyMODULE_AUTHOR("MultiTech");
1726aaa246ea78c68cd205f505070650cda7c5a95d34Jiri SlabyMODULE_DESCRIPTION("Driver for the ISI series of cards by MultiTech");
1727aaa246ea78c68cd205f505070650cda7c5a95d34Jiri SlabyMODULE_LICENSE("GPL");
1728e6c4ef984ebbd1a0458503417da91f3de47cbbe0Ben HutchingsMODULE_FIRMWARE("isi608.bin");
1729e6c4ef984ebbd1a0458503417da91f3de47cbbe0Ben HutchingsMODULE_FIRMWARE("isi608em.bin");
1730e6c4ef984ebbd1a0458503417da91f3de47cbbe0Ben HutchingsMODULE_FIRMWARE("isi616em.bin");
1731e6c4ef984ebbd1a0458503417da91f3de47cbbe0Ben HutchingsMODULE_FIRMWARE("isi4608.bin");
1732e6c4ef984ebbd1a0458503417da91f3de47cbbe0Ben HutchingsMODULE_FIRMWARE("isi4616.bin");
1733