Blame view

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

251b8dd7e   Alan Cox   isicom: bring int...
128
129
  #include <linux/uaccess.h>
  #include <linux/io.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
130
131
132
133
  
  #include <linux/pci.h>
  
  #include <linux/isicom.h>
aaa246ea7   Jiri Slaby   [PATCH] char/isic...
134
135
136
137
  #define InterruptTheCard(base) outw(0, (base) + 0xc)
  #define ClearInterrupt(base) inw((base) + 0x0a)
  
  #ifdef DEBUG
aaa246ea7   Jiri Slaby   [PATCH] char/isic...
138
139
  #define isicom_paranoia_check(a, b, c) __isicom_paranoia_check((a), (b), (c))
  #else
aaa246ea7   Jiri Slaby   [PATCH] char/isic...
140
141
  #define isicom_paranoia_check(a, b, c) 0
  #endif
9ac0948b2   Jiri Slaby   [PATCH] char/isic...
142
  static int isicom_probe(struct pci_dev *, const struct pci_device_id *);
ae8d8a146   Bill Pemberton   tty: remove use o...
143
  static void isicom_remove(struct pci_dev *);
9ac0948b2   Jiri Slaby   [PATCH] char/isic...
144

763653d7d   Arvind Yadav   tty: isicom: cons...
145
  static const struct pci_device_id isicom_pci_tbl[] = {
9ac0948b2   Jiri Slaby   [PATCH] char/isic...
146
147
148
149
150
151
152
153
154
  	{ PCI_DEVICE(VENDOR_ID, 0x2028) },
  	{ PCI_DEVICE(VENDOR_ID, 0x2051) },
  	{ PCI_DEVICE(VENDOR_ID, 0x2052) },
  	{ PCI_DEVICE(VENDOR_ID, 0x2053) },
  	{ PCI_DEVICE(VENDOR_ID, 0x2054) },
  	{ PCI_DEVICE(VENDOR_ID, 0x2055) },
  	{ PCI_DEVICE(VENDOR_ID, 0x2056) },
  	{ PCI_DEVICE(VENDOR_ID, 0x2057) },
  	{ PCI_DEVICE(VENDOR_ID, 0x2058) },
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155
156
157
  	{ 0 }
  };
  MODULE_DEVICE_TABLE(pci, isicom_pci_tbl);
9ac0948b2   Jiri Slaby   [PATCH] char/isic...
158
159
160
161
  static struct pci_driver isicom_driver = {
  	.name		= "isicom",
  	.id_table	= isicom_pci_tbl,
  	.probe		= isicom_probe,
91116cba5   Bill Pemberton   tty: remove use o...
162
  	.remove		= isicom_remove
9ac0948b2   Jiri Slaby   [PATCH] char/isic...
163
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
164
165
  static int prev_card = 3;	/*	start servicing isi_card[0]	*/
  static struct tty_driver *isicom_normal;
24ed960ab   Kees Cook   treewide: Switch ...
166
  static void isicom_tx(struct timer_list *unused);
d8d16e474   Jiri Slaby   [PATCH] char/isic...
167
  static void isicom_start(struct tty_struct *tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168

1d27e3e22   Kees Cook   timer: Remove exp...
169
  static DEFINE_TIMER(tx, isicom_tx);
34b55b865   Jiri Slaby   [PATCH] Char: isi...
170

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
172
173
  /*   baud index mappings from linux defns to isi */
  
  static signed char linuxb_to_isib[] = {
7edc136ab   Jiri Slaby   [PATCH] Char: isi...
174
  	-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13, 15, 16, 17, 18, 19, 20, 21
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
176
177
  };
  
  struct	isi_board {
8070e35c6   Jiri Slaby   [PATCH] char/isic...
178
  	unsigned long		base;
4969b3a43   Jiri Slaby   Char: isicom, pro...
179
  	int			irq;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
181
  	unsigned char		port_count;
  	unsigned short		status;
a547dfe95   Jiri Slaby   [PATCH] char/isic...
182
  	unsigned short		port_status; /* each bit for each port */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
183
  	unsigned short		shift_count;
251b8dd7e   Alan Cox   isicom: bring int...
184
  	struct isi_port		*ports;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
  	signed char		count;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
186
187
  	spinlock_t		card_lock; /* Card wide lock 11/5/00 -sameer */
  	unsigned long		flags;
938a7023b   Jiri Slaby   [PATCH] Char: isi...
188
  	unsigned int		index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189
190
191
192
  };
  
  struct	isi_port {
  	unsigned short		magic;
f1d03228e   Alan Cox   isicom: use tty_port
193
  	struct tty_port		port;
8070e35c6   Jiri Slaby   [PATCH] char/isic...
194
195
  	u16			channel;
  	u16			status;
251b8dd7e   Alan Cox   isicom: bring int...
196
  	struct isi_board	*card;
251b8dd7e   Alan Cox   isicom: bring int...
197
  	unsigned char		*xmit_buf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
199
200
201
202
203
204
205
206
207
208
209
210
  	int			xmit_head;
  	int			xmit_tail;
  	int			xmit_cnt;
  };
  
  static struct isi_board isi_card[BOARD_COUNT];
  static struct isi_port  isi_ports[PORT_COUNT];
  
  /*
   *	Locking functions for card level locking. We need to own both
   *	the kernel lock for the card and have the card in a position that
   *	it wants to talk.
   */
d8d16e474   Jiri Slaby   [PATCH] char/isic...
211

810e20e70   Denys Vlasenko   isicom: Deinline ...
212
  static int WaitTillCardIsFree(unsigned long base)
cfe7c09ac   Jiri Slaby   [PATCH] Char: isi...
213
214
  {
  	unsigned int count = 0;
cfe7c09ac   Jiri Slaby   [PATCH] Char: isi...
215
216
  
  	while (!(inw(base + 0xe) & 0x1) && count++ < 100)
fe8e7acea   Jia-Ju Bai   tty/isicom: Fix a...
217
  		mdelay(1);
cfe7c09ac   Jiri Slaby   [PATCH] Char: isi...
218
219
220
  
  	return !(inw(base + 0xe) & 0x1);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221
222
  static int lock_card(struct isi_board *card)
  {
8070e35c6   Jiri Slaby   [PATCH] char/isic...
223
  	unsigned long base = card->base;
5b21f9ddd   Jiri Slaby   Char: isicom, cle...
224
  	unsigned int retries, a;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225

5b21f9ddd   Jiri Slaby   Char: isicom, cle...
226
  	for (retries = 0; retries < 10; retries++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227
  		spin_lock_irqsave(&card->card_lock, card->flags);
5b21f9ddd   Jiri Slaby   Char: isicom, cle...
228
229
230
231
  		for (a = 0; a < 10; a++) {
  			if (inw(base + 0xe) & 0x1)
  				return 1;
  			udelay(10);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232
  		}
5b21f9ddd   Jiri Slaby   Char: isicom, cle...
233
234
  		spin_unlock_irqrestore(&card->card_lock, card->flags);
  		msleep(10);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235
  	}
e620e5488   Joe Perches   tty: pr_warning->...
236
237
  	pr_warn("Failed to lock Card (0x%lx)
  ", card->base);
a547dfe95   Jiri Slaby   [PATCH] char/isic...
238

0418726bb   Adrian Bunk   typo fixes: aquir...
239
  	return 0;	/* Failed to acquire the card! */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
241
242
243
244
245
246
247
248
  static void unlock_card(struct isi_board *card)
  {
  	spin_unlock_irqrestore(&card->card_lock, card->flags);
  }
  
  /*
   *  ISI Card specific ops ...
   */
d8d16e474   Jiri Slaby   [PATCH] char/isic...
249

cfe7c09ac   Jiri Slaby   [PATCH] Char: isi...
250
  /* card->lock HAS to be held */
d8d16e474   Jiri Slaby   [PATCH] char/isic...
251
  static void raise_dtr(struct isi_port *port)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
252
  {
d8d16e474   Jiri Slaby   [PATCH] char/isic...
253
  	struct isi_board *card = port->card;
8070e35c6   Jiri Slaby   [PATCH] char/isic...
254
255
  	unsigned long base = card->base;
  	u16 channel = port->channel;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
256

cfe7c09ac   Jiri Slaby   [PATCH] Char: isi...
257
  	if (WaitTillCardIsFree(base))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
258
  		return;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
259
  	outw(0x8000 | (channel << card->shift_count) | 0x02, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
260
261
262
  	outw(0x0504, base);
  	InterruptTheCard(base);
  	port->status |= ISI_DTR;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
263
  }
cfe7c09ac   Jiri Slaby   [PATCH] Char: isi...
264
  /* card->lock HAS to be held */
9428d712d   Denys Vlasenko   isicom: Deinline ...
265
  static void drop_dtr(struct isi_port *port)
d8d16e474   Jiri Slaby   [PATCH] char/isic...
266
267
  {
  	struct isi_board *card = port->card;
8070e35c6   Jiri Slaby   [PATCH] char/isic...
268
269
  	unsigned long base = card->base;
  	u16 channel = port->channel;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
270

cfe7c09ac   Jiri Slaby   [PATCH] Char: isi...
271
  	if (WaitTillCardIsFree(base))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
272
  		return;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
273
  	outw(0x8000 | (channel << card->shift_count) | 0x02, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
  	outw(0x0404, base);
d8d16e474   Jiri Slaby   [PATCH] char/isic...
275
  	InterruptTheCard(base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
  	port->status &= ~ISI_DTR;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
277
  }
cfe7c09ac   Jiri Slaby   [PATCH] Char: isi...
278
  /* card->lock HAS to be held */
d8d16e474   Jiri Slaby   [PATCH] char/isic...
279
  static inline void raise_rts(struct isi_port *port)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
280
  {
d8d16e474   Jiri Slaby   [PATCH] char/isic...
281
  	struct isi_board *card = port->card;
8070e35c6   Jiri Slaby   [PATCH] char/isic...
282
283
  	unsigned long base = card->base;
  	u16 channel = port->channel;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
284

cfe7c09ac   Jiri Slaby   [PATCH] Char: isi...
285
  	if (WaitTillCardIsFree(base))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286
  		return;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
287
  	outw(0x8000 | (channel << card->shift_count) | 0x02, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
288
  	outw(0x0a04, base);
d8d16e474   Jiri Slaby   [PATCH] char/isic...
289
  	InterruptTheCard(base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
290
  	port->status |= ISI_RTS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291
  }
cfe7c09ac   Jiri Slaby   [PATCH] Char: isi...
292
293
  
  /* card->lock HAS to be held */
d8d16e474   Jiri Slaby   [PATCH] char/isic...
294
  static inline void drop_rts(struct isi_port *port)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
  {
d8d16e474   Jiri Slaby   [PATCH] char/isic...
296
  	struct isi_board *card = port->card;
8070e35c6   Jiri Slaby   [PATCH] char/isic...
297
298
  	unsigned long base = card->base;
  	u16 channel = port->channel;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
299

cfe7c09ac   Jiri Slaby   [PATCH] Char: isi...
300
  	if (WaitTillCardIsFree(base))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301
  		return;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
302
  	outw(0x8000 | (channel << card->shift_count) | 0x02, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
303
  	outw(0x0804, base);
d8d16e474   Jiri Slaby   [PATCH] char/isic...
304
  	InterruptTheCard(base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305
  	port->status &= ~ISI_RTS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306
  }
cfe7c09ac   Jiri Slaby   [PATCH] Char: isi...
307
  /* card->lock MUST NOT be held */
5d951fb45   Alan Cox   tty: Pull the dtr...
308

fcc8ac182   Alan Cox   tty: Add carrier ...
309
  static void isicom_dtr_rts(struct tty_port *port, int on)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
  {
5d951fb45   Alan Cox   tty: Pull the dtr...
311
312
  	struct isi_port *ip = container_of(port, struct isi_port, port);
  	struct isi_board *card = ip->card;
8070e35c6   Jiri Slaby   [PATCH] char/isic...
313
  	unsigned long base = card->base;
5d951fb45   Alan Cox   tty: Pull the dtr...
314
  	u16 channel = ip->channel;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
315
316
317
  
  	if (!lock_card(card))
  		return;
fcc8ac182   Alan Cox   tty: Add carrier ...
318
319
320
321
322
323
324
325
326
327
328
  	if (on) {
  		outw(0x8000 | (channel << card->shift_count) | 0x02, base);
  		outw(0x0f04, base);
  		InterruptTheCard(base);
  		ip->status |= (ISI_DTR | ISI_RTS);
  	} else {
  		outw(0x8000 | (channel << card->shift_count) | 0x02, base);
  		outw(0x0C04, base);
  		InterruptTheCard(base);
  		ip->status &= ~(ISI_DTR | ISI_RTS);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
329
330
  	unlock_card(card);
  }
cfe7c09ac   Jiri Slaby   [PATCH] Char: isi...
331
  /* card->lock HAS to be held */
d8d16e474   Jiri Slaby   [PATCH] char/isic...
332
  static void drop_dtr_rts(struct isi_port *port)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
333
  {
d8d16e474   Jiri Slaby   [PATCH] char/isic...
334
  	struct isi_board *card = port->card;
8070e35c6   Jiri Slaby   [PATCH] char/isic...
335
336
  	unsigned long base = card->base;
  	u16 channel = port->channel;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
337

cfe7c09ac   Jiri Slaby   [PATCH] Char: isi...
338
  	if (WaitTillCardIsFree(base))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
339
  		return;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
340
  	outw(0x8000 | (channel << card->shift_count) | 0x02, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
341
  	outw(0x0c04, base);
d8d16e474   Jiri Slaby   [PATCH] char/isic...
342
  	InterruptTheCard(base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
343
  	port->status &= ~(ISI_RTS | ISI_DTR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
345
346
347
348
  /*
   *	ISICOM Driver specific routines ...
   *
   */
d8d16e474   Jiri Slaby   [PATCH] char/isic...
349

aaa246ea7   Jiri Slaby   [PATCH] char/isic...
350
351
  static inline int __isicom_paranoia_check(struct isi_port const *port,
  	char *name, const char *routine)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
  	if (!port) {
e620e5488   Joe Perches   tty: pr_warning->...
354
355
356
  		pr_warn("Warning: bad isicom magic for dev %s in %s
  ",
  			name, routine);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
357
358
359
  		return 1;
  	}
  	if (port->magic != ISICOM_MAGIC) {
e620e5488   Joe Perches   tty: pr_warning->...
360
361
362
  		pr_warn("Warning: NULL isicom port for dev %s in %s
  ",
  			name, routine);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
363
  		return 1;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
364
  	}
aaa246ea7   Jiri Slaby   [PATCH] char/isic...
365

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366
367
  	return 0;
  }
d8d16e474   Jiri Slaby   [PATCH] char/isic...
368

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
369
  /*
d8d16e474   Jiri Slaby   [PATCH] char/isic...
370
   *	Transmitter.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
371
372
373
374
   *
   *	We shovel data into the card buffers on a regular basis. The card
   *	will do the rest of the work for us.
   */
24ed960ab   Kees Cook   treewide: Switch ...
375
  static void isicom_tx(struct timer_list *unused)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
376
  {
4969b3a43   Jiri Slaby   Char: isicom, pro...
377
  	unsigned long flags, base;
5b21f9ddd   Jiri Slaby   Char: isicom, cle...
378
  	unsigned int retries;
4969b3a43   Jiri Slaby   Char: isicom, pro...
379
  	short count = (BOARD_COUNT-1), card;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380
  	short txcount, wrd, residue, word_count, cnt;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
381
382
  	struct isi_port *port;
  	struct tty_struct *tty;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
383
384
  	/*	find next active board	*/
  	card = (prev_card + 1) & 0x0003;
251b8dd7e   Alan Cox   isicom: bring int...
385
  	while (count-- > 0) {
d8d16e474   Jiri Slaby   [PATCH] char/isic...
386
  		if (isi_card[card].status & BOARD_ACTIVE)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387
  			break;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
388
  		card = (card + 1) & 0x0003;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
389
390
391
  	}
  	if (!(isi_card[card].status & BOARD_ACTIVE))
  		goto sched_again;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
392

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
393
  	prev_card = card;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
394

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
395
396
397
  	count = isi_card[card].port_count;
  	port = isi_card[card].ports;
  	base = isi_card[card].base;
5b21f9ddd   Jiri Slaby   Char: isicom, cle...
398
399
400
401
402
403
404
405
406
  
  	spin_lock_irqsave(&isi_card[card].card_lock, flags);
  	for (retries = 0; retries < 100; retries++) {
  		if (inw(base + 0xe) & 0x1)
  			break;
  		udelay(2);
  	}
  	if (retries >= 100)
  		goto unlock;
d450b5a01   Alan Cox   tty: kref usage f...
407
408
409
  	tty = tty_port_tty_get(&port->port);
  	if (tty == NULL)
  		goto put_unlock;
251b8dd7e   Alan Cox   isicom: bring int...
410
  	for (; count > 0; count--, port++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411
  		/* port not active or tx disabled to force flow control */
d41861ca1   Peter Hurley   tty: Replace ASYN...
412
413
  		if (!tty_port_initialized(&port->port) ||
  			!(port->status & ISI_TXOK))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
414
  			continue;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
415

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
416
  		txcount = min_t(short, TX_SIZE, port->xmit_cnt);
5b21f9ddd   Jiri Slaby   Char: isicom, cle...
417
  		if (txcount <= 0 || tty->stopped || tty->hw_stopped)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
418
  			continue;
5b21f9ddd   Jiri Slaby   Char: isicom, cle...
419
420
  
  		if (!(inw(base + 0x02) & (1 << port->channel)))
d8d16e474   Jiri Slaby   [PATCH] char/isic...
421
  			continue;
5b21f9ddd   Jiri Slaby   Char: isicom, cle...
422

db91340b2   Joe Perches   serial: isicom.c:...
423
424
425
  		pr_debug("txing %d bytes, port%d.
  ",
  			 txcount, port->channel + 1);
aaa246ea7   Jiri Slaby   [PATCH] char/isic...
426
427
  		outw((port->channel << isi_card[card].shift_count) | txcount,
  			base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
428
  		residue = NO;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
429
  		wrd = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
430
  		while (1) {
a547dfe95   Jiri Slaby   [PATCH] char/isic...
431
432
  			cnt = min_t(int, txcount, (SERIAL_XMIT_SIZE
  					- port->xmit_tail));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
433
434
435
  			if (residue == YES) {
  				residue = NO;
  				if (cnt > 0) {
f1d03228e   Alan Cox   isicom: use tty_port
436
  					wrd |= (port->port.xmit_buf[port->xmit_tail]
a547dfe95   Jiri Slaby   [PATCH] char/isic...
437
438
439
  									<< 8);
  					port->xmit_tail = (port->xmit_tail + 1)
  						& (SERIAL_XMIT_SIZE - 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
440
441
442
  					port->xmit_cnt--;
  					txcount--;
  					cnt--;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
443
  					outw(wrd, base);
a547dfe95   Jiri Slaby   [PATCH] char/isic...
444
  				} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
445
446
447
  					outw(wrd, base);
  					break;
  				}
d8d16e474   Jiri Slaby   [PATCH] char/isic...
448
  			}
251b8dd7e   Alan Cox   isicom: bring int...
449
450
  			if (cnt <= 0)
  				break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
451
  			word_count = cnt >> 1;
f1d03228e   Alan Cox   isicom: use tty_port
452
  			outsw(base, port->port.xmit_buf+port->xmit_tail, word_count);
a547dfe95   Jiri Slaby   [PATCH] char/isic...
453
454
  			port->xmit_tail = (port->xmit_tail
  				+ (word_count << 1)) & (SERIAL_XMIT_SIZE - 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
455
456
457
458
  			txcount -= (word_count << 1);
  			port->xmit_cnt -= (word_count << 1);
  			if (cnt & 0x0001) {
  				residue = YES;
f1d03228e   Alan Cox   isicom: use tty_port
459
  				wrd = port->port.xmit_buf[port->xmit_tail];
a547dfe95   Jiri Slaby   [PATCH] char/isic...
460
461
  				port->xmit_tail = (port->xmit_tail + 1)
  					& (SERIAL_XMIT_SIZE - 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
462
463
464
465
466
467
468
469
470
  				port->xmit_cnt--;
  				txcount--;
  			}
  		}
  
  		InterruptTheCard(base);
  		if (port->xmit_cnt <= 0)
  			port->status &= ~ISI_TXOK;
  		if (port->xmit_cnt <= WAKEUP_CHARS)
0aa5de859   Jiri Slaby   [PATCH] Char: isi...
471
  			tty_wakeup(tty);
d8d16e474   Jiri Slaby   [PATCH] char/isic...
472
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
473

d450b5a01   Alan Cox   tty: kref usage f...
474
475
  put_unlock:
  	tty_kref_put(tty);
5b21f9ddd   Jiri Slaby   Char: isicom, cle...
476
477
  unlock:
  	spin_unlock_irqrestore(&isi_card[card].card_lock, flags);
d8d16e474   Jiri Slaby   [PATCH] char/isic...
478
479
  	/*	schedule another tx for hopefully in about 10ms	*/
  sched_again:
34b55b865   Jiri Slaby   [PATCH] Char: isi...
480
  	mod_timer(&tx, jiffies + msecs_to_jiffies(10));
d8d16e474   Jiri Slaby   [PATCH] char/isic...
481
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482
  /*
d8d16e474   Jiri Slaby   [PATCH] char/isic...
483
   *	Main interrupt handler routine
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
484
   */
d8d16e474   Jiri Slaby   [PATCH] char/isic...
485

7d12e780e   David Howells   IRQ: Maintain reg...
486
  static irqreturn_t isicom_interrupt(int irq, void *dev_id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
487
  {
8070e35c6   Jiri Slaby   [PATCH] char/isic...
488
  	struct isi_board *card = dev_id;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
489
490
  	struct isi_port *port;
  	struct tty_struct *tty;
8070e35c6   Jiri Slaby   [PATCH] char/isic...
491
492
  	unsigned long base;
  	u16 header, word_count, count, channel;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
493
  	short byte_count;
33f0f88f1   Alan Cox   [PATCH] TTY layer...
494
  	unsigned char *rp;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
495

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
496
497
  	if (!card || !(card->status & FIRMWARE_LOADED))
  		return IRQ_NONE;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
498

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
499
  	base = card->base;
cb4a10ccb   Jiri Slaby   [PATCH] Char: isi...
500
501
502
503
  
  	/* did the card interrupt us? */
  	if (!(inw(base + 0x0e) & 0x02))
  		return IRQ_NONE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
504
  	spin_lock(&card->card_lock);
d8d16e474   Jiri Slaby   [PATCH] char/isic...
505

18234f88b   Jiri Slaby   [PATCH] Char: isi...
506
507
508
509
510
511
  	/*
  	 * disable any interrupts from the PCI card and lower the
  	 * interrupt line
  	 */
  	outw(0x8000, base+0x04);
  	ClearInterrupt(base);
d8d16e474   Jiri Slaby   [PATCH] char/isic...
512

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
513
514
515
516
517
518
  	inw(base);		/* get the dummy word out */
  	header = inw(base);
  	channel = (header & 0x7800) >> card->shift_count;
  	byte_count = header & 0xff;
  
  	if (channel + 1 > card->port_count) {
e620e5488   Joe Perches   tty: pr_warning->...
519
520
521
  		pr_warn("%s(0x%lx): %d(channel) > port_count
  ",
  			__func__, base, channel + 1);
18234f88b   Jiri Slaby   [PATCH] Char: isi...
522
  		outw(0x0000, base+0x04); /* enable interrupts */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
523
  		spin_unlock(&card->card_lock);
d8d16e474   Jiri Slaby   [PATCH] char/isic...
524
  		return IRQ_HANDLED;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
525
526
  	}
  	port = card->ports + channel;
d41861ca1   Peter Hurley   tty: Replace ASYN...
527
  	if (!tty_port_initialized(&port->port)) {
18234f88b   Jiri Slaby   [PATCH] Char: isi...
528
  		outw(0x0000, base+0x04); /* enable interrupts */
174f13076   Jiri Slaby   [PATCH] Char: isi...
529
  		spin_unlock(&card->card_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
530
  		return IRQ_HANDLED;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
531
  	}
d450b5a01   Alan Cox   tty: kref usage f...
532
  	tty = tty_port_tty_get(&port->port);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
533
  	if (tty == NULL) {
251b8dd7e   Alan Cox   isicom: bring int...
534
  		while (byte_count > 1) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
535
536
537
538
539
  			inw(base);
  			byte_count -= 2;
  		}
  		if (byte_count & 0x01)
  			inw(base);
18234f88b   Jiri Slaby   [PATCH] Char: isi...
540
  		outw(0x0000, base+0x04); /* enable interrupts */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
541
542
543
  		spin_unlock(&card->card_lock);
  		return IRQ_HANDLED;
  	}
d8d16e474   Jiri Slaby   [PATCH] char/isic...
544

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
545
546
  	if (header & 0x8000) {		/* Status Packet */
  		header = inw(base);
251b8dd7e   Alan Cox   isicom: bring int...
547
  		switch (header & 0xff) {
d8d16e474   Jiri Slaby   [PATCH] char/isic...
548
  		case 0:	/* Change in EIA signals */
2d68655d1   Peter Hurley   tty: Replace ASYN...
549
  			if (tty_port_check_carrier(&port->port)) {
d8d16e474   Jiri Slaby   [PATCH] char/isic...
550
551
552
  				if (port->status & ISI_DCD) {
  					if (!(header & ISI_DCD)) {
  					/* Carrier has been lost  */
db91340b2   Joe Perches   serial: isicom.c:...
553
554
555
  						pr_debug("%s: DCD->low.
  ",
  							 __func__);
d8d16e474   Jiri Slaby   [PATCH] char/isic...
556
  						port->status &= ~ISI_DCD;
0aa5de859   Jiri Slaby   [PATCH] Char: isi...
557
  						tty_hangup(tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
558
  					}
a547dfe95   Jiri Slaby   [PATCH] char/isic...
559
560
  				} else if (header & ISI_DCD) {
  				/* Carrier has been detected */
db91340b2   Joe Perches   serial: isicom.c:...
561
562
563
  					pr_debug("%s: DCD->high.
  ",
  						__func__);
a547dfe95   Jiri Slaby   [PATCH] char/isic...
564
  					port->status |= ISI_DCD;
f1d03228e   Alan Cox   isicom: use tty_port
565
  					wake_up_interruptible(&port->port.open_wait);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
566
  				}
a547dfe95   Jiri Slaby   [PATCH] char/isic...
567
  			} else {
d8d16e474   Jiri Slaby   [PATCH] char/isic...
568
569
570
571
572
  				if (header & ISI_DCD)
  					port->status |= ISI_DCD;
  				else
  					port->status &= ~ISI_DCD;
  			}
f21ec3d2d   Huang Shijie   serial: add a new...
573
  			if (tty_port_cts_enabled(&port->port)) {
d450b5a01   Alan Cox   tty: kref usage f...
574
  				if (tty->hw_stopped) {
d8d16e474   Jiri Slaby   [PATCH] char/isic...
575
  					if (header & ISI_CTS) {
7342c59a4   Jiri Slaby   TTY: isicom, stop...
576
  						tty->hw_stopped = 0;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
577
  						/* start tx ing */
a547dfe95   Jiri Slaby   [PATCH] char/isic...
578
579
  						port->status |= (ISI_TXOK
  							| ISI_CTS);
0aa5de859   Jiri Slaby   [PATCH] Char: isi...
580
  						tty_wakeup(tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
581
  					}
a547dfe95   Jiri Slaby   [PATCH] char/isic...
582
  				} else if (!(header & ISI_CTS)) {
d450b5a01   Alan Cox   tty: kref usage f...
583
  					tty->hw_stopped = 1;
a547dfe95   Jiri Slaby   [PATCH] char/isic...
584
585
  					/* stop tx ing */
  					port->status &= ~(ISI_TXOK | ISI_CTS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
586
  				}
a547dfe95   Jiri Slaby   [PATCH] char/isic...
587
  			} else {
d8d16e474   Jiri Slaby   [PATCH] char/isic...
588
589
  				if (header & ISI_CTS)
  					port->status |= ISI_CTS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
590
  				else
d8d16e474   Jiri Slaby   [PATCH] char/isic...
591
592
593
594
595
596
597
598
599
600
601
602
603
604
  					port->status &= ~ISI_CTS;
  			}
  
  			if (header & ISI_DSR)
  				port->status |= ISI_DSR;
  			else
  				port->status &= ~ISI_DSR;
  
  			if (header & ISI_RI)
  				port->status |= ISI_RI;
  			else
  				port->status &= ~ISI_RI;
  
  			break;
a547dfe95   Jiri Slaby   [PATCH] char/isic...
605
  		case 1:	/* Received Break !!! */
92a19f9ce   Jiri Slaby   TTY: switch tty_i...
606
  			tty_insert_flip_char(&port->port, 0, TTY_BREAK);
f1d03228e   Alan Cox   isicom: use tty_port
607
  			if (port->port.flags & ASYNC_SAK)
d8d16e474   Jiri Slaby   [PATCH] char/isic...
608
  				do_SAK(tty);
2e124b4a3   Jiri Slaby   TTY: switch tty_f...
609
  			tty_flip_buffer_push(&port->port);
d8d16e474   Jiri Slaby   [PATCH] char/isic...
610
611
612
  			break;
  
  		case 2:	/* Statistics		 */
db91340b2   Joe Perches   serial: isicom.c:...
613
614
  			pr_debug("%s: stats!!!
  ", __func__);
d8d16e474   Jiri Slaby   [PATCH] char/isic...
615
616
617
  			break;
  
  		default:
db91340b2   Joe Perches   serial: isicom.c:...
618
619
620
  			pr_debug("%s: Unknown code in status packet.
  ",
  				 __func__);
d8d16e474   Jiri Slaby   [PATCH] char/isic...
621
622
  			break;
  		}
a547dfe95   Jiri Slaby   [PATCH] char/isic...
623
  	} else {				/* Data   Packet */
2f6933571   Jiri Slaby   TTY: convert more...
624
625
  		count = tty_prepare_flip_string(&port->port, &rp,
  				byte_count & ~1);
db91340b2   Joe Perches   serial: isicom.c:...
626
627
628
  		pr_debug("%s: Can rx %d of %d bytes.
  ",
  			 __func__, count, byte_count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
629
  		word_count = count >> 1;
33f0f88f1   Alan Cox   [PATCH] TTY layer...
630
  		insw(base, rp, word_count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
631
632
  		byte_count -= (word_count << 1);
  		if (count & 0x0001) {
92a19f9ce   Jiri Slaby   TTY: switch tty_i...
633
  			tty_insert_flip_char(&port->port, inw(base) & 0xff,
a547dfe95   Jiri Slaby   [PATCH] char/isic...
634
  				TTY_NORMAL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
635
  			byte_count -= 2;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
636
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
637
  		if (byte_count > 0) {
db91340b2   Joe Perches   serial: isicom.c:...
638
639
640
  			pr_debug("%s(0x%lx:%d): Flip buffer overflow! dropping bytes...
  ",
  				 __func__, base, channel + 1);
251b8dd7e   Alan Cox   isicom: bring int...
641
642
  		/* drain out unread xtra data */
  		while (byte_count > 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
643
644
645
646
  				inw(base);
  				byte_count -= 2;
  			}
  		}
2e124b4a3   Jiri Slaby   TTY: switch tty_f...
647
  		tty_flip_buffer_push(&port->port);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
648
  	}
18234f88b   Jiri Slaby   [PATCH] Char: isi...
649
  	outw(0x0000, base+0x04); /* enable interrupts */
174f13076   Jiri Slaby   [PATCH] Char: isi...
650
  	spin_unlock(&card->card_lock);
d450b5a01   Alan Cox   tty: kref usage f...
651
  	tty_kref_put(tty);
a547dfe95   Jiri Slaby   [PATCH] char/isic...
652

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
653
  	return IRQ_HANDLED;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
654
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
655

d450b5a01   Alan Cox   tty: kref usage f...
656
  static void isicom_config_port(struct tty_struct *tty)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
657
  {
d450b5a01   Alan Cox   tty: kref usage f...
658
  	struct isi_port *port = tty->driver_data;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
659
  	struct isi_board *card = port->card;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
660
  	unsigned long baud;
8070e35c6   Jiri Slaby   [PATCH] char/isic...
661
662
663
  	unsigned long base = card->base;
  	u16 channel_setup, channel = port->channel,
  		shift_count = card->shift_count;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
664
  	unsigned char flow_ctrl;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
665

251b8dd7e   Alan Cox   isicom: bring int...
666
  	/* FIXME: Switch to new tty baud API */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
667
668
669
  	baud = C_BAUD(tty);
  	if (baud & CBAUDEX) {
  		baud &= ~CBAUDEX;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
670

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
671
672
673
  		/*  if CBAUDEX bit is on and the baud is set to either 50 or 75
  		 *  then the card is programmed for 57.6Kbps or 115Kbps
  		 *  respectively.
d8d16e474   Jiri Slaby   [PATCH] char/isic...
674
  		 */
7edc136ab   Jiri Slaby   [PATCH] Char: isi...
675
676
  		/* 1,2,3,4 => 57.6, 115.2, 230, 460 kbps resp. */
  		if (baud < 1 || baud > 4)
adc8d746c   Alan Cox   tty: move the ter...
677
  			tty->termios.c_cflag &= ~CBAUDEX;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
678
679
  		else
  			baud += 15;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
680
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
681
  	if (baud == 15) {
d8d16e474   Jiri Slaby   [PATCH] char/isic...
682
683
  
  		/*  the ASYNC_SPD_HI and ASYNC_SPD_VHI options are set
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
684
685
  		 *  by the set_serial_info ioctl ... this is done by
  		 *  the 'setserial' utility.
d8d16e474   Jiri Slaby   [PATCH] char/isic...
686
  		 */
f1d03228e   Alan Cox   isicom: use tty_port
687
  		if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
d8d16e474   Jiri Slaby   [PATCH] char/isic...
688
  			baud++; /*  57.6 Kbps */
f1d03228e   Alan Cox   isicom: use tty_port
689
  		if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
251b8dd7e   Alan Cox   isicom: bring int...
690
  			baud += 2; /*  115  Kbps */
f1d03228e   Alan Cox   isicom: use tty_port
691
  		if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
7edc136ab   Jiri Slaby   [PATCH] Char: isi...
692
  			baud += 3; /* 230 kbps*/
f1d03228e   Alan Cox   isicom: use tty_port
693
  		if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
7edc136ab   Jiri Slaby   [PATCH] Char: isi...
694
  			baud += 4; /* 460 kbps*/
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
695
696
697
  	}
  	if (linuxb_to_isib[baud] == -1) {
  		/* hang up */
d8d16e474   Jiri Slaby   [PATCH] char/isic...
698
699
  		drop_dtr(port);
  		return;
251b8dd7e   Alan Cox   isicom: bring int...
700
  	} else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
701
  		raise_dtr(port);
d8d16e474   Jiri Slaby   [PATCH] char/isic...
702

cfe7c09ac   Jiri Slaby   [PATCH] Char: isi...
703
  	if (WaitTillCardIsFree(base) == 0) {
251b8dd7e   Alan Cox   isicom: bring int...
704
  		outw(0x8000 | (channel << shift_count) | 0x03, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
705
706
  		outw(linuxb_to_isib[baud] << 8 | 0x03, base);
  		channel_setup = 0;
251b8dd7e   Alan Cox   isicom: bring int...
707
  		switch (C_CSIZE(tty)) {
d8d16e474   Jiri Slaby   [PATCH] char/isic...
708
709
710
711
712
713
714
715
716
717
718
719
  		case CS5:
  			channel_setup |= ISICOM_CS5;
  			break;
  		case CS6:
  			channel_setup |= ISICOM_CS6;
  			break;
  		case CS7:
  			channel_setup |= ISICOM_CS7;
  			break;
  		case CS8:
  			channel_setup |= ISICOM_CS8;
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
720
  		}
d8d16e474   Jiri Slaby   [PATCH] char/isic...
721

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
722
723
724
725
726
  		if (C_CSTOPB(tty))
  			channel_setup |= ISICOM_2SB;
  		if (C_PARENB(tty)) {
  			channel_setup |= ISICOM_EVPAR;
  			if (C_PARODD(tty))
d8d16e474   Jiri Slaby   [PATCH] char/isic...
727
  				channel_setup |= ISICOM_ODPAR;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
728
  		}
d8d16e474   Jiri Slaby   [PATCH] char/isic...
729
  		outw(channel_setup, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
730
  		InterruptTheCard(base);
d8d16e474   Jiri Slaby   [PATCH] char/isic...
731
  	}
2d68655d1   Peter Hurley   tty: Replace ASYN...
732
  	tty_port_set_check_carrier(&port->port, !C_CLOCAL(tty));
d8d16e474   Jiri Slaby   [PATCH] char/isic...
733

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
734
735
  	/* flow control settings ...*/
  	flow_ctrl = 0;
5604a98e2   Peter Hurley   tty: Replace ASYN...
736
737
  	tty_port_set_cts_flow(&port->port, C_CRTSCTS(tty));
  	if (C_CRTSCTS(tty))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
738
  		flow_ctrl |= ISICOM_CTSRTS;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
739
  	if (I_IXON(tty))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
740
741
  		flow_ctrl |= ISICOM_RESPOND_XONXOFF;
  	if (I_IXOFF(tty))
d8d16e474   Jiri Slaby   [PATCH] char/isic...
742
  		flow_ctrl |= ISICOM_INITIATE_XONXOFF;
cfe7c09ac   Jiri Slaby   [PATCH] Char: isi...
743
  	if (WaitTillCardIsFree(base) == 0) {
251b8dd7e   Alan Cox   isicom: bring int...
744
  		outw(0x8000 | (channel << shift_count) | 0x04, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
745
746
747
  		outw(flow_ctrl << 8 | 0x05, base);
  		outw((STOP_CHAR(tty)) << 8 | (START_CHAR(tty)), base);
  		InterruptTheCard(base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
748
  	}
d8d16e474   Jiri Slaby   [PATCH] char/isic...
749

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
750
751
752
753
754
755
  	/*	rx enabled -> enable port for rx on the card	*/
  	if (C_CREAD(tty)) {
  		card->port_status |= (1 << channel);
  		outw(card->port_status, base + 0x02);
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
756

d8d16e474   Jiri Slaby   [PATCH] char/isic...
757
758
759
  /* open et all */
  
  static inline void isicom_setup_board(struct isi_board *bp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
760
761
  {
  	int channel;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
762
  	struct isi_port *port;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
763

baaa08acb   Alan Cox   tty: isicom: swit...
764
  	bp->count++;
6ed847d8e   Alan Cox   tty: isicom: sort...
765
766
767
768
769
770
  	if (!(bp->status & BOARD_INIT)) {
  		port = bp->ports;
  		for (channel = 0; channel < bp->port_count; channel++, port++)
  			drop_dtr_rts(port);
  	}
  	bp->status |= BOARD_ACTIVE | BOARD_INIT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
771
  }
d8d16e474   Jiri Slaby   [PATCH] char/isic...
772

6ed847d8e   Alan Cox   tty: isicom: sort...
773
774
  /* Activate and thus setup board are protected from races against shutdown
     by the tty_port mutex */
baaa08acb   Alan Cox   tty: isicom: swit...
775
  static int isicom_activate(struct tty_port *tport, struct tty_struct *tty)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
776
  {
baaa08acb   Alan Cox   tty: isicom: swit...
777
  	struct isi_port *port = container_of(tport, struct isi_port, port);
d8d16e474   Jiri Slaby   [PATCH] char/isic...
778
  	struct isi_board *card = port->card;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
779
  	unsigned long flags;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
780

baaa08acb   Alan Cox   tty: isicom: swit...
781
  	if (tty_port_alloc_xmit_buf(tport) < 0)
f1d03228e   Alan Cox   isicom: use tty_port
782
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
783
784
  
  	spin_lock_irqsave(&card->card_lock, flags);
baaa08acb   Alan Cox   tty: isicom: swit...
785
  	isicom_setup_board(card);
d8d16e474   Jiri Slaby   [PATCH] char/isic...
786

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
787
  	port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
788

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
789
  	/*	discard any residual data	*/
cfe7c09ac   Jiri Slaby   [PATCH] Char: isi...
790
791
792
793
794
795
  	if (WaitTillCardIsFree(card->base) == 0) {
  		outw(0x8000 | (port->channel << card->shift_count) | 0x02,
  				card->base);
  		outw(((ISICOM_KILLTX | ISICOM_KILLRX) << 8) | 0x06, card->base);
  		InterruptTheCard(card->base);
  	}
d450b5a01   Alan Cox   tty: kref usage f...
796
  	isicom_config_port(tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
797
  	spin_unlock_irqrestore(&card->card_lock, flags);
d8d16e474   Jiri Slaby   [PATCH] char/isic...
798
799
800
  
  	return 0;
  }
31f35939d   Alan Cox   tty_port: Add a p...
801
802
803
804
805
  static int isicom_carrier_raised(struct tty_port *port)
  {
  	struct isi_port *ip = container_of(port, struct isi_port, port);
  	return (ip->status & ISI_DCD)?1 : 0;
  }
11d85d7b2   Alan Cox   isicom: split the...
806
  static struct tty_port *isicom_find_port(struct tty_struct *tty)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
807
  {
d8d16e474   Jiri Slaby   [PATCH] char/isic...
808
809
  	struct isi_port *port;
  	struct isi_board *card;
17c4edf0c   Jiri Slaby   [PATCH] Char: isi...
810
  	unsigned int board;
11d85d7b2   Alan Cox   isicom: split the...
811
  	int line = tty->index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
812

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
813
814
  	board = BOARD(line);
  	card = &isi_card[board];
d8d16e474   Jiri Slaby   [PATCH] char/isic...
815

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
816
  	if (!(card->status & FIRMWARE_LOADED))
11d85d7b2   Alan Cox   isicom: split the...
817
  		return NULL;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
818

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
819
820
  	/*  open on a port greater than the port count for the card !!! */
  	if (line > ((board * 16) + card->port_count - 1))
11d85d7b2   Alan Cox   isicom: split the...
821
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
822

d8d16e474   Jiri Slaby   [PATCH] char/isic...
823
  	port = &isi_ports[line];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
824
  	if (isicom_paranoia_check(port, tty->name, "isicom_open"))
11d85d7b2   Alan Cox   isicom: split the...
825
826
827
828
  		return NULL;
  
  	return &port->port;
  }
baaa08acb   Alan Cox   tty: isicom: swit...
829

11d85d7b2   Alan Cox   isicom: split the...
830
831
832
  static int isicom_open(struct tty_struct *tty, struct file *filp)
  {
  	struct isi_port *port;
11d85d7b2   Alan Cox   isicom: split the...
833
  	struct tty_port *tport;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
834

11d85d7b2   Alan Cox   isicom: split the...
835
836
837
838
  	tport = isicom_find_port(tty);
  	if (tport == NULL)
  		return -ENODEV;
  	port = container_of(tport, struct isi_port, port);
d8d16e474   Jiri Slaby   [PATCH] char/isic...
839

a2d1e3516   Alan Cox   tty: Fix regressi...
840
  	tty->driver_data = port;
baaa08acb   Alan Cox   tty: isicom: swit...
841
  	return tty_port_open(tport, tty, filp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
842
  }
d8d16e474   Jiri Slaby   [PATCH] char/isic...
843

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
844
  /* close et all */
cfe7c09ac   Jiri Slaby   [PATCH] Char: isi...
845
  /* card->lock HAS to be held */
d8d16e474   Jiri Slaby   [PATCH] char/isic...
846
  static void isicom_shutdown_port(struct isi_port *port)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
847
  {
d8d16e474   Jiri Slaby   [PATCH] char/isic...
848
  	struct isi_board *card = port->card;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
849

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
850
  	if (--card->count < 0) {
db91340b2   Joe Perches   serial: isicom.c:...
851
852
853
  		pr_debug("%s: bad board(0x%lx) count %d.
  ",
  			 __func__, card->base, card->count);
d8d16e474   Jiri Slaby   [PATCH] char/isic...
854
  		card->count = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
855
  	}
baaa08acb   Alan Cox   tty: isicom: swit...
856
  	/* last port was closed, shutdown that board too */
6ed847d8e   Alan Cox   tty: isicom: sort...
857
858
  	if (!card->count)
  		card->status &= BOARD_ACTIVE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
859
  }
978e595f8   Alan Cox   tty/serial: lay t...
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
  static void isicom_flush_buffer(struct tty_struct *tty)
  {
  	struct isi_port *port = tty->driver_data;
  	struct isi_board *card = port->card;
  	unsigned long flags;
  
  	if (isicom_paranoia_check(port, tty->name, "isicom_flush_buffer"))
  		return;
  
  	spin_lock_irqsave(&card->card_lock, flags);
  	port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
  	spin_unlock_irqrestore(&card->card_lock, flags);
  
  	tty_wakeup(tty);
  }
baaa08acb   Alan Cox   tty: isicom: swit...
875
  static void isicom_shutdown(struct tty_port *port)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
876
  {
6f6412b4c   Alan Cox   isicom: Split the...
877
878
  	struct isi_port *ip = container_of(port, struct isi_port, port);
  	struct isi_board *card = ip->card;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
879
  	unsigned long flags;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
880

d8d16e474   Jiri Slaby   [PATCH] char/isic...
881
  	/* indicate to the card that no more data can be received
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
882
883
  	   on this port */
  	spin_lock_irqsave(&card->card_lock, flags);
baaa08acb   Alan Cox   tty: isicom: swit...
884
885
  	card->port_status &= ~(1 << ip->channel);
  	outw(card->port_status, card->base + 0x02);
a6614999e   Alan Cox   tty: Introduce so...
886
  	isicom_shutdown_port(ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
887
  	spin_unlock_irqrestore(&card->card_lock, flags);
2493c0c16   Alan Cox   tty: isicom: fix ...
888
  	tty_port_free_xmit_buf(port);
6f6412b4c   Alan Cox   isicom: Split the...
889
  }
d8d16e474   Jiri Slaby   [PATCH] char/isic...
890

6f6412b4c   Alan Cox   isicom: Split the...
891
892
893
  static void isicom_close(struct tty_struct *tty, struct file *filp)
  {
  	struct isi_port *ip = tty->driver_data;
a2d1e3516   Alan Cox   tty: Fix regressi...
894
895
896
897
898
899
  	struct tty_port *port;
  
  	if (ip == NULL)
  		return;
  
  	port = &ip->port;
6f6412b4c   Alan Cox   isicom: Split the...
900
901
  	if (isicom_paranoia_check(ip, tty->name, "isicom_close"))
  		return;
baaa08acb   Alan Cox   tty: isicom: swit...
902
  	tty_port_close(port, tty, filp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
903
904
905
  }
  
  /* write et all */
d8d16e474   Jiri Slaby   [PATCH] char/isic...
906
907
  static int isicom_write(struct tty_struct *tty,	const unsigned char *buf,
  	int count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
908
  {
8070e35c6   Jiri Slaby   [PATCH] char/isic...
909
  	struct isi_port *port = tty->driver_data;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
910
  	struct isi_board *card = port->card;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
911
912
913
914
915
  	unsigned long flags;
  	int cnt, total = 0;
  
  	if (isicom_paranoia_check(port, tty->name, "isicom_write"))
  		return 0;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
916

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
917
  	spin_lock_irqsave(&card->card_lock, flags);
d8d16e474   Jiri Slaby   [PATCH] char/isic...
918

251b8dd7e   Alan Cox   isicom: bring int...
919
  	while (1) {
a547dfe95   Jiri Slaby   [PATCH] char/isic...
920
921
  		cnt = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt
  				- 1, SERIAL_XMIT_SIZE - port->xmit_head));
d8d16e474   Jiri Slaby   [PATCH] char/isic...
922
  		if (cnt <= 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
923
  			break;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
924

f1d03228e   Alan Cox   isicom: use tty_port
925
  		memcpy(port->port.xmit_buf + port->xmit_head, buf, cnt);
a547dfe95   Jiri Slaby   [PATCH] char/isic...
926
927
  		port->xmit_head = (port->xmit_head + cnt) & (SERIAL_XMIT_SIZE
  			- 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
928
929
930
931
  		port->xmit_cnt += cnt;
  		buf += cnt;
  		count -= cnt;
  		total += cnt;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
932
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
933
934
935
  	if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped)
  		port->status |= ISI_TXOK;
  	spin_unlock_irqrestore(&card->card_lock, flags);
d8d16e474   Jiri Slaby   [PATCH] char/isic...
936
  	return total;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
937
938
939
  }
  
  /* put_char et all */
f34d7a5b7   Alan Cox   tty: The big oper...
940
  static int isicom_put_char(struct tty_struct *tty, unsigned char ch)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
941
  {
8070e35c6   Jiri Slaby   [PATCH] char/isic...
942
  	struct isi_port *port = tty->driver_data;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
943
  	struct isi_board *card = port->card;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
944
  	unsigned long flags;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
945

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
946
  	if (isicom_paranoia_check(port, tty->name, "isicom_put_char"))
f34d7a5b7   Alan Cox   tty: The big oper...
947
  		return 0;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
948

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
949
  	spin_lock_irqsave(&card->card_lock, flags);
f34d7a5b7   Alan Cox   tty: The big oper...
950
951
952
953
  	if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
  		spin_unlock_irqrestore(&card->card_lock, flags);
  		return 0;
  	}
d8d16e474   Jiri Slaby   [PATCH] char/isic...
954

f1d03228e   Alan Cox   isicom: use tty_port
955
  	port->port.xmit_buf[port->xmit_head++] = ch;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
956
957
958
  	port->xmit_head &= (SERIAL_XMIT_SIZE - 1);
  	port->xmit_cnt++;
  	spin_unlock_irqrestore(&card->card_lock, flags);
f34d7a5b7   Alan Cox   tty: The big oper...
959
  	return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
960
961
962
  }
  
  /* flush_chars et all */
d8d16e474   Jiri Slaby   [PATCH] char/isic...
963
  static void isicom_flush_chars(struct tty_struct *tty)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
964
  {
8070e35c6   Jiri Slaby   [PATCH] char/isic...
965
  	struct isi_port *port = tty->driver_data;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
966

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
967
968
  	if (isicom_paranoia_check(port, tty->name, "isicom_flush_chars"))
  		return;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
969

a547dfe95   Jiri Slaby   [PATCH] char/isic...
970
  	if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
f1d03228e   Alan Cox   isicom: use tty_port
971
  			!port->port.xmit_buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
972
  		return;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
973

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
974
975
  	/* this tells the transmitter to consider this port for
  	   data output to the card ... that's the best we can do. */
d8d16e474   Jiri Slaby   [PATCH] char/isic...
976
  	port->status |= ISI_TXOK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
977
978
979
  }
  
  /* write_room et all */
d8d16e474   Jiri Slaby   [PATCH] char/isic...
980
  static int isicom_write_room(struct tty_struct *tty)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
981
  {
8070e35c6   Jiri Slaby   [PATCH] char/isic...
982
  	struct isi_port *port = tty->driver_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
983
984
985
986
  	int free;
  
  	if (isicom_paranoia_check(port, tty->name, "isicom_write_room"))
  		return 0;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
987

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
988
989
990
991
992
993
994
  	free = SERIAL_XMIT_SIZE - port->xmit_cnt - 1;
  	if (free < 0)
  		free = 0;
  	return free;
  }
  
  /* chars_in_buffer et all */
d8d16e474   Jiri Slaby   [PATCH] char/isic...
995
  static int isicom_chars_in_buffer(struct tty_struct *tty)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
996
  {
8070e35c6   Jiri Slaby   [PATCH] char/isic...
997
  	struct isi_port *port = tty->driver_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
998
999
1000
1001
1002
1003
  	if (isicom_paranoia_check(port, tty->name, "isicom_chars_in_buffer"))
  		return 0;
  	return port->xmit_cnt;
  }
  
  /* ioctl et all */
6d8897243   Alan Cox   isicom: restore u...
1004
  static int isicom_send_break(struct tty_struct *tty, int length)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1005
  {
6d8897243   Alan Cox   isicom: restore u...
1006
  	struct isi_port *port = tty->driver_data;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
1007
  	struct isi_board *card = port->card;
8070e35c6   Jiri Slaby   [PATCH] char/isic...
1008
  	unsigned long base = card->base;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
1009

6d8897243   Alan Cox   isicom: restore u...
1010
1011
  	if (length == -1)
  		return -EOPNOTSUPP;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
1012
  	if (!lock_card(card))
6d8897243   Alan Cox   isicom: restore u...
1013
  		return -EINVAL;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
1014

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1015
1016
  	outw(0x8000 | ((port->channel) << (card->shift_count)) | 0x3, base);
  	outw((length & 0xff) << 8 | 0x00, base);
f3e2d56dc   Arnd Bergmann   tty/isicom: fix b...
1017
  	outw((length & 0xff00u), base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1018
1019
1020
  	InterruptTheCard(base);
  
  	unlock_card(card);
6d8897243   Alan Cox   isicom: restore u...
1021
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1022
  }
60b33c133   Alan Cox   tiocmget: kill of...
1023
  static int isicom_tiocmget(struct tty_struct *tty)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1024
  {
8070e35c6   Jiri Slaby   [PATCH] char/isic...
1025
  	struct isi_port *port = tty->driver_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1026
  	/* just send the port status */
8070e35c6   Jiri Slaby   [PATCH] char/isic...
1027
  	u16 status = port->status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1028
1029
1030
  
  	if (isicom_paranoia_check(port, tty->name, "isicom_ioctl"))
  		return -ENODEV;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
1031

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1032
1033
1034
1035
1036
1037
1038
  	return  ((status & ISI_RTS) ? TIOCM_RTS : 0) |
  		((status & ISI_DTR) ? TIOCM_DTR : 0) |
  		((status & ISI_DCD) ? TIOCM_CAR : 0) |
  		((status & ISI_DSR) ? TIOCM_DSR : 0) |
  		((status & ISI_CTS) ? TIOCM_CTS : 0) |
  		((status & ISI_RI ) ? TIOCM_RI  : 0);
  }
20b9d1771   Alan Cox   tiocmset: kill th...
1039
1040
  static int isicom_tiocmset(struct tty_struct *tty,
  					unsigned int set, unsigned int clear)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1041
  {
8070e35c6   Jiri Slaby   [PATCH] char/isic...
1042
  	struct isi_port *port = tty->driver_data;
cfe7c09ac   Jiri Slaby   [PATCH] Char: isi...
1043
  	unsigned long flags;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
1044

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1045
1046
  	if (isicom_paranoia_check(port, tty->name, "isicom_ioctl"))
  		return -ENODEV;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
1047

cfe7c09ac   Jiri Slaby   [PATCH] Char: isi...
1048
  	spin_lock_irqsave(&port->card->card_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1049
1050
1051
1052
1053
1054
1055
1056
1057
  	if (set & TIOCM_RTS)
  		raise_rts(port);
  	if (set & TIOCM_DTR)
  		raise_dtr(port);
  
  	if (clear & TIOCM_RTS)
  		drop_rts(port);
  	if (clear & TIOCM_DTR)
  		drop_dtr(port);
cfe7c09ac   Jiri Slaby   [PATCH] Char: isi...
1058
  	spin_unlock_irqrestore(&port->card->card_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1059
1060
  
  	return 0;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
1061
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1062

d450b5a01   Alan Cox   tty: kref usage f...
1063
  static int isicom_set_serial_info(struct tty_struct *tty,
b60f38c66   Al Viro   isicom: switch to...
1064
  					struct serial_struct *ss)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1065
  {
d450b5a01   Alan Cox   tty: kref usage f...
1066
  	struct isi_port *port = tty->driver_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1067
  	int reconfig_port;
b60f38c66   Al Viro   isicom: switch to...
1068
1069
  	if (isicom_paranoia_check(port, tty->name, "isicom_ioctl"))
  		return -ENODEV;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
1070

ec82db129   Alan Cox   isicom: kill off ...
1071
  	mutex_lock(&port->port.mutex);
f1d03228e   Alan Cox   isicom: use tty_port
1072
  	reconfig_port = ((port->port.flags & ASYNC_SPD_MASK) !=
b60f38c66   Al Viro   isicom: switch to...
1073
  		(ss->flags & ASYNC_SPD_MASK));
d8d16e474   Jiri Slaby   [PATCH] char/isic...
1074

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1075
  	if (!capable(CAP_SYS_ADMIN)) {
b60f38c66   Al Viro   isicom: switch to...
1076
1077
1078
  		if ((ss->close_delay != port->port.close_delay) ||
  				(ss->closing_wait != port->port.closing_wait) ||
  				((ss->flags & ~ASYNC_USR_MASK) !=
f1d03228e   Alan Cox   isicom: use tty_port
1079
  				(port->port.flags & ~ASYNC_USR_MASK))) {
ec82db129   Alan Cox   isicom: kill off ...
1080
  			mutex_unlock(&port->port.mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1081
  			return -EPERM;
1eac49473   Alan Cox   isicom: prepare f...
1082
  		}
f1d03228e   Alan Cox   isicom: use tty_port
1083
  		port->port.flags = ((port->port.flags & ~ASYNC_USR_MASK) |
b60f38c66   Al Viro   isicom: switch to...
1084
  				(ss->flags & ASYNC_USR_MASK));
251b8dd7e   Alan Cox   isicom: bring int...
1085
  	} else {
b60f38c66   Al Viro   isicom: switch to...
1086
1087
  		port->port.close_delay = ss->close_delay;
  		port->port.closing_wait = ss->closing_wait;
f1d03228e   Alan Cox   isicom: use tty_port
1088
  		port->port.flags = ((port->port.flags & ~ASYNC_FLAGS) |
b60f38c66   Al Viro   isicom: switch to...
1089
  				(ss->flags & ASYNC_FLAGS));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1090
1091
  	}
  	if (reconfig_port) {
cfe7c09ac   Jiri Slaby   [PATCH] Char: isi...
1092
1093
  		unsigned long flags;
  		spin_lock_irqsave(&port->card->card_lock, flags);
d450b5a01   Alan Cox   tty: kref usage f...
1094
  		isicom_config_port(tty);
cfe7c09ac   Jiri Slaby   [PATCH] Char: isi...
1095
  		spin_unlock_irqrestore(&port->card->card_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1096
  	}
ec82db129   Alan Cox   isicom: kill off ...
1097
  	mutex_unlock(&port->port.mutex);
d8d16e474   Jiri Slaby   [PATCH] char/isic...
1098
1099
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1100

b60f38c66   Al Viro   isicom: switch to...
1101
1102
  static int isicom_get_serial_info(struct tty_struct *tty,
  	struct serial_struct *ss)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1103
  {
8070e35c6   Jiri Slaby   [PATCH] char/isic...
1104
  	struct isi_port *port = tty->driver_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1105
1106
1107
  
  	if (isicom_paranoia_check(port, tty->name, "isicom_ioctl"))
  		return -ENODEV;
b60f38c66   Al Viro   isicom: switch to...
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
  	mutex_lock(&port->port.mutex);
  /*	ss->type = ? */
  	ss->line = port - isi_ports;
  	ss->port = port->card->base;
  	ss->irq = port->card->irq;
  	ss->flags = port->port.flags;
  /*	ss->baud_base = ? */
  	ss->close_delay = port->port.close_delay;
  	ss->closing_wait = port->port.closing_wait;
  	mutex_unlock(&port->port.mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1118
1119
1120
1121
  	return 0;
  }
  
  /* set_termios et all */
d8d16e474   Jiri Slaby   [PATCH] char/isic...
1122
  static void isicom_set_termios(struct tty_struct *tty,
606d099cd   Alan Cox   [PATCH] tty: swit...
1123
  	struct ktermios *old_termios)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1124
  {
8070e35c6   Jiri Slaby   [PATCH] char/isic...
1125
  	struct isi_port *port = tty->driver_data;
cfe7c09ac   Jiri Slaby   [PATCH] Char: isi...
1126
  	unsigned long flags;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
1127

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1128
1129
  	if (isicom_paranoia_check(port, tty->name, "isicom_set_termios"))
  		return;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
1130

adc8d746c   Alan Cox   tty: move the ter...
1131
1132
  	if (tty->termios.c_cflag == old_termios->c_cflag &&
  			tty->termios.c_iflag == old_termios->c_iflag)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1133
  		return;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
1134

cfe7c09ac   Jiri Slaby   [PATCH] Char: isi...
1135
  	spin_lock_irqsave(&port->card->card_lock, flags);
d450b5a01   Alan Cox   tty: kref usage f...
1136
  	isicom_config_port(tty);
cfe7c09ac   Jiri Slaby   [PATCH] Char: isi...
1137
  	spin_unlock_irqrestore(&port->card->card_lock, flags);
d8d16e474   Jiri Slaby   [PATCH] char/isic...
1138

9db276f8f   Peter Hurley   tty: Use termios ...
1139
  	if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1140
  		tty->hw_stopped = 0;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
1141
1142
  		isicom_start(tty);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1143
1144
1145
  }
  
  /* throttle et all */
d8d16e474   Jiri Slaby   [PATCH] char/isic...
1146
  static void isicom_throttle(struct tty_struct *tty)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1147
  {
8070e35c6   Jiri Slaby   [PATCH] char/isic...
1148
  	struct isi_port *port = tty->driver_data;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
1149
  	struct isi_board *card = port->card;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1150
1151
  	if (isicom_paranoia_check(port, tty->name, "isicom_throttle"))
  		return;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
1152

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1153
1154
1155
1156
1157
1158
  	/* tell the card that this port cannot handle any more data for now */
  	card->port_status &= ~(1 << port->channel);
  	outw(card->port_status, card->base + 0x02);
  }
  
  /* unthrottle et all */
d8d16e474   Jiri Slaby   [PATCH] char/isic...
1159
  static void isicom_unthrottle(struct tty_struct *tty)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1160
  {
8070e35c6   Jiri Slaby   [PATCH] char/isic...
1161
  	struct isi_port *port = tty->driver_data;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
1162
  	struct isi_board *card = port->card;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1163
1164
  	if (isicom_paranoia_check(port, tty->name, "isicom_unthrottle"))
  		return;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
1165

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1166
1167
1168
1169
1170
1171
  	/* tell the card that this port is ready to accept more data */
  	card->port_status |= (1 << port->channel);
  	outw(card->port_status, card->base + 0x02);
  }
  
  /* stop et all */
d8d16e474   Jiri Slaby   [PATCH] char/isic...
1172
  static void isicom_stop(struct tty_struct *tty)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1173
  {
8070e35c6   Jiri Slaby   [PATCH] char/isic...
1174
  	struct isi_port *port = tty->driver_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1175
1176
1177
  
  	if (isicom_paranoia_check(port, tty->name, "isicom_stop"))
  		return;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
1178

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1179
1180
1181
1182
1183
1184
  	/* this tells the transmitter not to consider this port for
  	   data output to the card. */
  	port->status &= ~ISI_TXOK;
  }
  
  /* start et all */
d8d16e474   Jiri Slaby   [PATCH] char/isic...
1185
  static void isicom_start(struct tty_struct *tty)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1186
  {
8070e35c6   Jiri Slaby   [PATCH] char/isic...
1187
  	struct isi_port *port = tty->driver_data;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
1188

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1189
1190
  	if (isicom_paranoia_check(port, tty->name, "isicom_start"))
  		return;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
1191

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1192
1193
1194
1195
  	/* this tells the transmitter to consider this port for
  	   data output to the card. */
  	port->status |= ISI_TXOK;
  }
d8d16e474   Jiri Slaby   [PATCH] char/isic...
1196
  static void isicom_hangup(struct tty_struct *tty)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1197
  {
8070e35c6   Jiri Slaby   [PATCH] char/isic...
1198
  	struct isi_port *port = tty->driver_data;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
1199

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1200
1201
  	if (isicom_paranoia_check(port, tty->name, "isicom_hangup"))
  		return;
3e61696bd   Alan Cox   isicom: redo lock...
1202
  	tty_port_hangup(&port->port);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1203
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1204

9ac0948b2   Jiri Slaby   [PATCH] char/isic...
1205
1206
1207
  /*
   * Driver init and deinit functions
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1208

b68e31d0e   Jeff Dike   [PATCH] const str...
1209
  static const struct tty_operations isicom_ops = {
d8d16e474   Jiri Slaby   [PATCH] char/isic...
1210
1211
1212
1213
1214
1215
  	.open			= isicom_open,
  	.close			= isicom_close,
  	.write			= isicom_write,
  	.put_char		= isicom_put_char,
  	.flush_chars		= isicom_flush_chars,
  	.write_room		= isicom_write_room,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1216
  	.chars_in_buffer	= isicom_chars_in_buffer,
d8d16e474   Jiri Slaby   [PATCH] char/isic...
1217
1218
1219
1220
1221
1222
1223
1224
1225
  	.set_termios		= isicom_set_termios,
  	.throttle		= isicom_throttle,
  	.unthrottle		= isicom_unthrottle,
  	.stop			= isicom_stop,
  	.start			= isicom_start,
  	.hangup			= isicom_hangup,
  	.flush_buffer		= isicom_flush_buffer,
  	.tiocmget		= isicom_tiocmget,
  	.tiocmset		= isicom_tiocmset,
6d8897243   Alan Cox   isicom: restore u...
1226
  	.break_ctl		= isicom_send_break,
b60f38c66   Al Viro   isicom: switch to...
1227
1228
  	.get_serial		= isicom_get_serial_info,
  	.set_serial		= isicom_set_serial_info,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1229
  };
31f35939d   Alan Cox   tty_port: Add a p...
1230
1231
  static const struct tty_port_operations isicom_port_ops = {
  	.carrier_raised		= isicom_carrier_raised,
fcc8ac182   Alan Cox   tty: Add carrier ...
1232
  	.dtr_rts		= isicom_dtr_rts,
baaa08acb   Alan Cox   tty: isicom: swit...
1233
1234
  	.activate		= isicom_activate,
  	.shutdown		= isicom_shutdown,
31f35939d   Alan Cox   tty_port: Add a p...
1235
  };
9671f0992   Bill Pemberton   tty: remove use o...
1236
  static int reset_card(struct pci_dev *pdev,
9ac0948b2   Jiri Slaby   [PATCH] char/isic...
1237
  	const unsigned int card, unsigned int *signature)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1238
  {
9ac0948b2   Jiri Slaby   [PATCH] char/isic...
1239
1240
  	struct isi_board *board = pci_get_drvdata(pdev);
  	unsigned long base = board->base;
f0a0ba6d6   Jiri Slaby   [PATCH] Char: isi...
1241
  	unsigned int sig, portcount = 0;
9ac0948b2   Jiri Slaby   [PATCH] char/isic...
1242
  	int retval = 0;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
1243

9ac0948b2   Jiri Slaby   [PATCH] char/isic...
1244
1245
1246
  	dev_dbg(&pdev->dev, "ISILoad:Resetting Card%d at 0x%lx
  ", card + 1,
  		base);
d8d16e474   Jiri Slaby   [PATCH] char/isic...
1247

9ac0948b2   Jiri Slaby   [PATCH] char/isic...
1248
  	inw(base + 0x8);
d8d16e474   Jiri Slaby   [PATCH] char/isic...
1249

f0a0ba6d6   Jiri Slaby   [PATCH] Char: isi...
1250
  	msleep(10);
9ac0948b2   Jiri Slaby   [PATCH] char/isic...
1251
1252
  
  	outw(0, base + 0x8); /* Reset */
f0a0ba6d6   Jiri Slaby   [PATCH] Char: isi...
1253
  	msleep(1000);
9ac0948b2   Jiri Slaby   [PATCH] char/isic...
1254

f0a0ba6d6   Jiri Slaby   [PATCH] Char: isi...
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
  	sig = inw(base + 0x4) & 0xff;
  
  	if (sig != 0xa5 && sig != 0xbb && sig != 0xcc && sig != 0xdd &&
  			sig != 0xee) {
  		dev_warn(&pdev->dev, "ISILoad:Card%u reset failure (Possible "
  			"bad I/O Port Address 0x%lx).
  ", card + 1, base);
  		dev_dbg(&pdev->dev, "Sig=0x%x
  ", sig);
  		retval = -EIO;
  		goto end;
  	}
  
  	msleep(10);
9ac0948b2   Jiri Slaby   [PATCH] char/isic...
1269

18234f88b   Jiri Slaby   [PATCH] Char: isi...
1270
  	portcount = inw(base + 0x2);
07fb6f26b   Julia Lawall   drivers/char/isic...
1271
  	if (!(inw(base + 0xe) & 0x1) || (portcount != 0 && portcount != 4 &&
f0a0ba6d6   Jiri Slaby   [PATCH] Char: isi...
1272
  				portcount != 8 && portcount != 16)) {
898eb71cb   Joe Perches   Add missing newli...
1273
1274
  		dev_err(&pdev->dev, "ISILoad:PCI Card%d reset failure.
  ",
f0a0ba6d6   Jiri Slaby   [PATCH] Char: isi...
1275
  			card + 1);
18234f88b   Jiri Slaby   [PATCH] Char: isi...
1276
1277
  		retval = -EIO;
  		goto end;
9ac0948b2   Jiri Slaby   [PATCH] char/isic...
1278
  	}
f0a0ba6d6   Jiri Slaby   [PATCH] Char: isi...
1279
  	switch (sig) {
9ac0948b2   Jiri Slaby   [PATCH] char/isic...
1280
1281
1282
  	case 0xa5:
  	case 0xbb:
  	case 0xdd:
18234f88b   Jiri Slaby   [PATCH] Char: isi...
1283
  		board->port_count = (portcount == 4) ? 4 : 8;
9ac0948b2   Jiri Slaby   [PATCH] char/isic...
1284
1285
1286
  		board->shift_count = 12;
  		break;
  	case 0xcc:
f0a0ba6d6   Jiri Slaby   [PATCH] Char: isi...
1287
  	case 0xee:
9ac0948b2   Jiri Slaby   [PATCH] char/isic...
1288
1289
1290
  		board->port_count = 16;
  		board->shift_count = 11;
  		break;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
1291
  	}
9ac0948b2   Jiri Slaby   [PATCH] char/isic...
1292
1293
  	dev_info(&pdev->dev, "-Done
  ");
f0a0ba6d6   Jiri Slaby   [PATCH] Char: isi...
1294
  	*signature = sig;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
1295

9ac0948b2   Jiri Slaby   [PATCH] char/isic...
1296
1297
  end:
  	return retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1298
  }
9671f0992   Bill Pemberton   tty: remove use o...
1299
  static int load_firmware(struct pci_dev *pdev,
e65c1db19   Jiri Slaby   [PATCH] char/isic...
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
  	const unsigned int index, const unsigned int signature)
  {
  	struct isi_board *board = pci_get_drvdata(pdev);
  	const struct firmware *fw;
  	unsigned long base = board->base;
  	unsigned int a;
  	u16 word_count, status;
  	int retval = -EIO;
  	char *name;
  	u8 *data;
  
  	struct stframe {
  		u16	addr;
  		u16	count;
  		u8	data[0];
  	} *frame;
  
  	switch (signature) {
  	case 0xa5:
  		name = "isi608.bin";
  		break;
  	case 0xbb:
  		name = "isi608em.bin";
  		break;
  	case 0xcc:
  		name = "isi616em.bin";
  		break;
  	case 0xdd:
  		name = "isi4608.bin";
  		break;
  	case 0xee:
  		name = "isi4616.bin";
  		break;
  	default:
  		dev_err(&pdev->dev, "Unknown signature.
  ");
  		goto end;
251b8dd7e   Alan Cox   isicom: bring int...
1337
  	}
e65c1db19   Jiri Slaby   [PATCH] char/isic...
1338
1339
1340
1341
  
  	retval = request_firmware(&fw, name, &pdev->dev);
  	if (retval)
  		goto end;
e4e040887   Jiri Slaby   [PATCH] isicom: c...
1342
  	retval = -EIO;
e65c1db19   Jiri Slaby   [PATCH] char/isic...
1343
1344
  	for (frame = (struct stframe *)fw->data;
  			frame < (struct stframe *)(fw->data + fw->size);
e4e040887   Jiri Slaby   [PATCH] isicom: c...
1345
1346
  			frame = (struct stframe *)((u8 *)(frame + 1) +
  				frame->count)) {
e65c1db19   Jiri Slaby   [PATCH] char/isic...
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
  		if (WaitTillCardIsFree(base))
  			goto errrelfw;
  
  		outw(0xf0, base);	/* start upload sequence */
  		outw(0x00, base);
  		outw(frame->addr, base); /* lsb of address */
  
  		word_count = frame->count / 2 + frame->count % 2;
  		outw(word_count, base);
  		InterruptTheCard(base);
  
  		udelay(100); /* 0x2f */
  
  		if (WaitTillCardIsFree(base))
  			goto errrelfw;
251b8dd7e   Alan Cox   isicom: bring int...
1362
1363
  		status = inw(base + 0x4);
  		if (status != 0) {
e65c1db19   Jiri Slaby   [PATCH] char/isic...
1364
1365
  			dev_warn(&pdev->dev, "Card%d rejected load header:
  "
ad361c988   Joe Perches   Remove multiple K...
1366
1367
1368
1369
1370
1371
1372
  				 "Address:0x%x
  "
  				 "Count:0x%x
  "
  				 "Status:0x%x
  ",
  				 index + 1, frame->addr, frame->count, status);
e65c1db19   Jiri Slaby   [PATCH] char/isic...
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
  			goto errrelfw;
  		}
  		outsw(base, frame->data, word_count);
  
  		InterruptTheCard(base);
  
  		udelay(50); /* 0x0f */
  
  		if (WaitTillCardIsFree(base))
  			goto errrelfw;
251b8dd7e   Alan Cox   isicom: bring int...
1383
1384
  		status = inw(base + 0x4);
  		if (status != 0) {
e65c1db19   Jiri Slaby   [PATCH] char/isic...
1385
1386
1387
1388
1389
  			dev_err(&pdev->dev, "Card%d got out of sync.Card "
  				"Status:0x%x
  ", index + 1, status);
  			goto errrelfw;
  		}
251b8dd7e   Alan Cox   isicom: bring int...
1390
  	}
e65c1db19   Jiri Slaby   [PATCH] char/isic...
1391

e65c1db19   Jiri Slaby   [PATCH] char/isic...
1392
1393
  /* XXX: should we test it by reading it back and comparing with original like
   * in load firmware package? */
e4e040887   Jiri Slaby   [PATCH] isicom: c...
1394
1395
1396
1397
  	for (frame = (struct stframe *)fw->data;
  			frame < (struct stframe *)(fw->data + fw->size);
  			frame = (struct stframe *)((u8 *)(frame + 1) +
  				frame->count)) {
e65c1db19   Jiri Slaby   [PATCH] char/isic...
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
  		if (WaitTillCardIsFree(base))
  			goto errrelfw;
  
  		outw(0xf1, base); /* start download sequence */
  		outw(0x00, base);
  		outw(frame->addr, base); /* lsb of address */
  
  		word_count = (frame->count >> 1) + frame->count % 2;
  		outw(word_count + 1, base);
  		InterruptTheCard(base);
  
  		udelay(50); /* 0xf */
  
  		if (WaitTillCardIsFree(base))
  			goto errrelfw;
251b8dd7e   Alan Cox   isicom: bring int...
1413
1414
  		status = inw(base + 0x4);
  		if (status != 0) {
e65c1db19   Jiri Slaby   [PATCH] char/isic...
1415
1416
  			dev_warn(&pdev->dev, "Card%d rejected verify header:
  "
ad361c988   Joe Perches   Remove multiple K...
1417
1418
1419
1420
1421
1422
1423
  				 "Address:0x%x
  "
  				 "Count:0x%x
  "
  				 "Status: 0x%x
  ",
  				 index + 1, frame->addr, frame->count, status);
e65c1db19   Jiri Slaby   [PATCH] char/isic...
1424
1425
  			goto errrelfw;
  		}
6da2ec560   Kees Cook   treewide: kmalloc...
1426
  		data = kmalloc_array(word_count, 2, GFP_KERNEL);
f06713784   Jiri Slaby   [PATCH] Char: isi...
1427
1428
1429
1430
1431
1432
  		if (data == NULL) {
  			dev_err(&pdev->dev, "Card%d, firmware upload "
  				"failed, not enough memory
  ", index + 1);
  			goto errrelfw;
  		}
e65c1db19   Jiri Slaby   [PATCH] char/isic...
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
  		inw(base);
  		insw(base, data, word_count);
  		InterruptTheCard(base);
  
  		for (a = 0; a < frame->count; a++)
  			if (data[a] != frame->data[a]) {
  				kfree(data);
  				dev_err(&pdev->dev, "Card%d, firmware upload "
  					"failed
  ", index + 1);
  				goto errrelfw;
  			}
  		kfree(data);
  
  		udelay(50); /* 0xf */
  
  		if (WaitTillCardIsFree(base))
  			goto errrelfw;
251b8dd7e   Alan Cox   isicom: bring int...
1451
1452
  		status = inw(base + 0x4);
  		if (status != 0) {
e65c1db19   Jiri Slaby   [PATCH] char/isic...
1453
1454
1455
1456
1457
1458
  			dev_err(&pdev->dev, "Card%d verify got out of sync. "
  				"Card Status:0x%x
  ", index + 1, status);
  			goto errrelfw;
  		}
  	}
e4e040887   Jiri Slaby   [PATCH] isicom: c...
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
  	/* xfer ctrl */
  	if (WaitTillCardIsFree(base))
  		goto errrelfw;
  
  	outw(0xf2, base);
  	outw(0x800, base);
  	outw(0x0, base);
  	outw(0x0, base);
  	InterruptTheCard(base);
  	outw(0x0, base + 0x4); /* for ISI4608 cards */
e65c1db19   Jiri Slaby   [PATCH] char/isic...
1469
1470
1471
1472
1473
1474
1475
1476
  	board->status |= FIRMWARE_LOADED;
  	retval = 0;
  
  errrelfw:
  	release_firmware(fw);
  end:
  	return retval;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1477
1478
1479
  /*
   *	Insmod can set static symbols so keep these static
   */
1ed0c0b73   Jiri Slaby   [PATCH] Char: isi...
1480
  static unsigned int card_count;
9ac0948b2   Jiri Slaby   [PATCH] char/isic...
1481

9671f0992   Bill Pemberton   tty: remove use o...
1482
  static int isicom_probe(struct pci_dev *pdev,
9ac0948b2   Jiri Slaby   [PATCH] char/isic...
1483
1484
  	const struct pci_device_id *ent)
  {
3f649ab72   Kees Cook   treewide: Remove ...
1485
  	unsigned int signature, index;
9ac0948b2   Jiri Slaby   [PATCH] char/isic...
1486
  	int retval = -EPERM;
9ac0948b2   Jiri Slaby   [PATCH] char/isic...
1487
  	struct isi_board *board = NULL;
1ed0c0b73   Jiri Slaby   [PATCH] Char: isi...
1488
  	if (card_count >= BOARD_COUNT)
9ac0948b2   Jiri Slaby   [PATCH] char/isic...
1489
  		goto err;
e1e5770bb   Jiri Slaby   tty: isicom, enab...
1490
1491
1492
1493
1494
1495
  	retval = pci_enable_device(pdev);
  	if (retval) {
  		dev_err(&pdev->dev, "failed to enable
  ");
  		goto err;
  	}
9ac0948b2   Jiri Slaby   [PATCH] char/isic...
1496
1497
1498
1499
  	dev_info(&pdev->dev, "ISI PCI Card(Device ID 0x%x)
  ", ent->device);
  
  	/* allot the first empty slot in the array */
26e1e8d1d   Dan Carpenter   serial: isicomm: ...
1500
  	for (index = 0; index < BOARD_COUNT; index++) {
9ac0948b2   Jiri Slaby   [PATCH] char/isic...
1501
1502
1503
1504
  		if (isi_card[index].base == 0) {
  			board = &isi_card[index];
  			break;
  		}
26e1e8d1d   Dan Carpenter   serial: isicomm: ...
1505
1506
1507
1508
1509
  	}
  	if (index == BOARD_COUNT) {
  		retval = -ENODEV;
  		goto err_disable;
  	}
9ac0948b2   Jiri Slaby   [PATCH] char/isic...
1510

938a7023b   Jiri Slaby   [PATCH] Char: isi...
1511
  	board->index = index;
4969b3a43   Jiri Slaby   Char: isicom, pro...
1512
1513
  	board->base = pci_resource_start(pdev, 3);
  	board->irq = pdev->irq;
1ed0c0b73   Jiri Slaby   [PATCH] Char: isi...
1514
  	card_count++;
9ac0948b2   Jiri Slaby   [PATCH] char/isic...
1515
1516
  
  	pci_set_drvdata(pdev, board);
78028da91   Jiri Slaby   [PATCH] Char: isi...
1517
1518
  	retval = pci_request_region(pdev, 3, ISICOM_NAME);
  	if (retval) {
09a4a1125   Jiri Slaby   [PATCH] Char: isi...
1519
1520
1521
1522
1523
  		dev_err(&pdev->dev, "I/O Region 0x%lx-0x%lx is busy. Card%d "
  			"will be disabled.
  ", board->base, board->base + 15,
  			index + 1);
  		retval = -EBUSY;
1ed0c0b73   Jiri Slaby   [PATCH] Char: isi...
1524
  		goto errdec;
251b8dd7e   Alan Cox   isicom: bring int...
1525
  	}
9ac0948b2   Jiri Slaby   [PATCH] char/isic...
1526

09a4a1125   Jiri Slaby   [PATCH] Char: isi...
1527
  	retval = request_irq(board->irq, isicom_interrupt,
9cfb5c05f   Yong Zhang   TTY: irq: Remove ...
1528
  			IRQF_SHARED, ISICOM_NAME, board);
09a4a1125   Jiri Slaby   [PATCH] Char: isi...
1529
1530
1531
1532
  	if (retval < 0) {
  		dev_err(&pdev->dev, "Could not install handler at Irq %d. "
  			"Card%d will be disabled.
  ", board->irq, index + 1);
9ac0948b2   Jiri Slaby   [PATCH] char/isic...
1533
  		goto errunrr;
09a4a1125   Jiri Slaby   [PATCH] Char: isi...
1534
  	}
9ac0948b2   Jiri Slaby   [PATCH] char/isic...
1535
1536
1537
1538
  
  	retval = reset_card(pdev, index, &signature);
  	if (retval < 0)
  		goto errunri;
e65c1db19   Jiri Slaby   [PATCH] char/isic...
1539
1540
1541
  	retval = load_firmware(pdev, index, signature);
  	if (retval < 0)
  		goto errunri;
d0f59141c   Jiri Slaby   TTY: isicom, fix ...
1542
1543
1544
1545
1546
1547
1548
1549
1550
  	for (index = 0; index < board->port_count; index++) {
  		struct tty_port *tport = &board->ports[index].port;
  		tty_port_init(tport);
  		tport->ops = &isicom_port_ops;
  		tport->close_delay = 50 * HZ/100;
  		tport->closing_wait = 3000 * HZ/100;
  		tty_port_register_device(tport, isicom_normal,
  				board->index * 16 + index, &pdev->dev);
  	}
938a7023b   Jiri Slaby   [PATCH] Char: isi...
1551

9ac0948b2   Jiri Slaby   [PATCH] char/isic...
1552
1553
1554
1555
1556
  	return 0;
  
  errunri:
  	free_irq(board->irq, board);
  errunrr:
78028da91   Jiri Slaby   [PATCH] Char: isi...
1557
  	pci_release_region(pdev, 3);
1ed0c0b73   Jiri Slaby   [PATCH] Char: isi...
1558
  errdec:
9ac0948b2   Jiri Slaby   [PATCH] char/isic...
1559
  	board->base = 0;
1ed0c0b73   Jiri Slaby   [PATCH] Char: isi...
1560
  	card_count--;
26e1e8d1d   Dan Carpenter   serial: isicomm: ...
1561
  err_disable:
e1e5770bb   Jiri Slaby   tty: isicom, enab...
1562
  	pci_disable_device(pdev);
1ed0c0b73   Jiri Slaby   [PATCH] Char: isi...
1563
  err:
9ac0948b2   Jiri Slaby   [PATCH] char/isic...
1564
1565
  	return retval;
  }
ae8d8a146   Bill Pemberton   tty: remove use o...
1566
  static void isicom_remove(struct pci_dev *pdev)
9ac0948b2   Jiri Slaby   [PATCH] char/isic...
1567
1568
  {
  	struct isi_board *board = pci_get_drvdata(pdev);
938a7023b   Jiri Slaby   [PATCH] Char: isi...
1569
  	unsigned int i;
d0f59141c   Jiri Slaby   TTY: isicom, fix ...
1570
  	for (i = 0; i < board->port_count; i++) {
938a7023b   Jiri Slaby   [PATCH] Char: isi...
1571
  		tty_unregister_device(isicom_normal, board->index * 16 + i);
d0f59141c   Jiri Slaby   TTY: isicom, fix ...
1572
1573
  		tty_port_destroy(&board->ports[i].port);
  	}
9ac0948b2   Jiri Slaby   [PATCH] char/isic...
1574
1575
  
  	free_irq(board->irq, board);
78028da91   Jiri Slaby   [PATCH] Char: isi...
1576
  	pci_release_region(pdev, 3);
1ed0c0b73   Jiri Slaby   [PATCH] Char: isi...
1577
1578
  	board->base = 0;
  	card_count--;
e1e5770bb   Jiri Slaby   tty: isicom, enab...
1579
  	pci_disable_device(pdev);
9ac0948b2   Jiri Slaby   [PATCH] char/isic...
1580
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1581

ca2620051   Jiri Slaby   [PATCH] Char: isi...
1582
  static int __init isicom_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1583
  {
9ac0948b2   Jiri Slaby   [PATCH] char/isic...
1584
1585
  	int retval, idx, channel;
  	struct isi_port *port;
d8d16e474   Jiri Slaby   [PATCH] char/isic...
1586

251b8dd7e   Alan Cox   isicom: bring int...
1587
  	for (idx = 0; idx < BOARD_COUNT; idx++) {
9ac0948b2   Jiri Slaby   [PATCH] char/isic...
1588
1589
1590
1591
1592
1593
1594
  		port = &isi_ports[idx * 16];
  		isi_card[idx].ports = port;
  		spin_lock_init(&isi_card[idx].card_lock);
  		for (channel = 0; channel < 16; channel++, port++) {
  			port->magic = ISICOM_MAGIC;
  			port->card = &isi_card[idx];
  			port->channel = channel;
9ac0948b2   Jiri Slaby   [PATCH] char/isic...
1595
  			port->status = 0;
9ac0948b2   Jiri Slaby   [PATCH] char/isic...
1596
  			/*  . . .  */
251b8dd7e   Alan Cox   isicom: bring int...
1597
  		}
9ac0948b2   Jiri Slaby   [PATCH] char/isic...
1598
1599
  		isi_card[idx].base = 0;
  		isi_card[idx].irq = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1600
  	}
d8d16e474   Jiri Slaby   [PATCH] char/isic...
1601

09a4a1125   Jiri Slaby   [PATCH] Char: isi...
1602
1603
1604
1605
  	/* tty driver structure initialization */
  	isicom_normal = alloc_tty_driver(PORT_COUNT);
  	if (!isicom_normal) {
  		retval = -ENOMEM;
9ac0948b2   Jiri Slaby   [PATCH] char/isic...
1606
  		goto error;
09a4a1125   Jiri Slaby   [PATCH] Char: isi...
1607
  	}
09a4a1125   Jiri Slaby   [PATCH] Char: isi...
1608
1609
1610
1611
1612
1613
1614
1615
  	isicom_normal->name 			= "ttyM";
  	isicom_normal->major			= ISICOM_NMAJOR;
  	isicom_normal->minor_start		= 0;
  	isicom_normal->type			= TTY_DRIVER_TYPE_SERIAL;
  	isicom_normal->subtype			= SERIAL_TYPE_NORMAL;
  	isicom_normal->init_termios		= tty_std_termios;
  	isicom_normal->init_termios.c_cflag	= B9600 | CS8 | CREAD | HUPCL |
  		CLOCAL;
938a7023b   Jiri Slaby   [PATCH] Char: isi...
1616
  	isicom_normal->flags			= TTY_DRIVER_REAL_RAW |
6d8897243   Alan Cox   isicom: restore u...
1617
  		TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_HARDWARE_BREAK;
09a4a1125   Jiri Slaby   [PATCH] Char: isi...
1618
1619
1620
1621
  	tty_set_operations(isicom_normal, &isicom_ops);
  
  	retval = tty_register_driver(isicom_normal);
  	if (retval) {
db91340b2   Joe Perches   serial: isicom.c:...
1622
1623
  		pr_debug("Couldn't register the dialin driver
  ");
09a4a1125   Jiri Slaby   [PATCH] Char: isi...
1624
1625
  		goto err_puttty;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1626

9ac0948b2   Jiri Slaby   [PATCH] char/isic...
1627
  	retval = pci_register_driver(&isicom_driver);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1628
  	if (retval < 0) {
db91340b2   Joe Perches   serial: isicom.c:...
1629
1630
  		pr_err("Unable to register pci driver.
  ");
09a4a1125   Jiri Slaby   [PATCH] Char: isi...
1631
  		goto err_unrtty;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1632
  	}
d8d16e474   Jiri Slaby   [PATCH] char/isic...
1633

34b55b865   Jiri Slaby   [PATCH] Char: isi...
1634
  	mod_timer(&tx, jiffies + 1);
d8d16e474   Jiri Slaby   [PATCH] char/isic...
1635

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1636
  	return 0;
09a4a1125   Jiri Slaby   [PATCH] Char: isi...
1637
1638
1639
1640
  err_unrtty:
  	tty_unregister_driver(isicom_normal);
  err_puttty:
  	put_tty_driver(isicom_normal);
9ac0948b2   Jiri Slaby   [PATCH] char/isic...
1641
1642
  error:
  	return retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1643
1644
1645
1646
  }
  
  static void __exit isicom_exit(void)
  {
e327325f4   Jiri Slaby   Char: isicom, del...
1647
  	del_timer_sync(&tx);
aaa246ea7   Jiri Slaby   [PATCH] char/isic...
1648

9ac0948b2   Jiri Slaby   [PATCH] char/isic...
1649
  	pci_unregister_driver(&isicom_driver);
09a4a1125   Jiri Slaby   [PATCH] Char: isi...
1650
1651
  	tty_unregister_driver(isicom_normal);
  	put_tty_driver(isicom_normal);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1652
  }
ca2620051   Jiri Slaby   [PATCH] Char: isi...
1653
  module_init(isicom_init);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1654
  module_exit(isicom_exit);
aaa246ea7   Jiri Slaby   [PATCH] char/isic...
1655
1656
1657
1658
  
  MODULE_AUTHOR("MultiTech");
  MODULE_DESCRIPTION("Driver for the ISI series of cards by MultiTech");
  MODULE_LICENSE("GPL");
e6c4ef984   Ben Hutchings   tty: declare MODU...
1659
1660
1661
1662
1663
  MODULE_FIRMWARE("isi608.bin");
  MODULE_FIRMWARE("isi608em.bin");
  MODULE_FIRMWARE("isi616em.bin");
  MODULE_FIRMWARE("isi4608.bin");
  MODULE_FIRMWARE("isi4616.bin");