Merge branch 'for-2.6.28' of git://linux-nfs.org/~bfields/linux
[linux-2.6-block.git] / drivers / char / isicom.c
CommitLineData
1da177e4
LT
1/*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version
5 * 2 of the License, or (at your option) any later version.
6 *
7 * Original driver code supplied by Multi-Tech
8 *
9 * Changes
8eb04cf3
AC
10 * 1/9/98 alan@lxorguk.ukuu.org.uk
11 * Merge to 2.0.x kernel tree
1da177e4
LT
12 * Obtain and use official major/minors
13 * Loader switched to a misc device
14 * (fixed range check bug as a side effect)
15 * Printk clean up
8eb04cf3
AC
16 * 9/12/98 alan@lxorguk.ukuu.org.uk
17 * Rough port to 2.1.x
1da177e4
LT
18 *
19 * 10/6/99 sameer Merged the ISA and PCI drivers to
20 * a new unified driver.
21 *
22 * 3/9/99 sameer Added support for ISI4616 cards.
23 *
24 * 16/9/99 sameer We do not force RTS low anymore.
d8d16e47 25 * This is to prevent the firmware
1da177e4
LT
26 * from getting confused.
27 *
28 * 26/10/99 sameer Cosmetic changes:The driver now
29 * dumps the Port Count information
30 * along with I/O address and IRQ.
31 *
32 * 13/12/99 sameer Fixed the problem with IRQ sharing.
33 *
34 * 10/5/00 sameer Fixed isicom_shutdown_board()
35 * to not lower DTR on all the ports
d8d16e47 36 * when the last port on the card is
1da177e4
LT
37 * closed.
38 *
39 * 10/5/00 sameer Signal mask setup command added
d8d16e47 40 * to isicom_setup_port and
1da177e4
LT
41 * isicom_shutdown_port.
42 *
43 * 24/5/00 sameer The driver is now SMP aware.
d8d16e47
JS
44 *
45 *
1da177e4 46 * 27/11/00 Vinayak P Risbud Fixed the Driver Crash Problem
d8d16e47
JS
47 *
48 *
1da177e4
LT
49 * 03/01/01 anil .s Added support for resetting the
50 * internal modems on ISI cards.
51 *
52 * 08/02/01 anil .s Upgraded the driver for kernel
53 * 2.4.x
54 *
d8d16e47 55 * 11/04/01 Kevin Fixed firmware load problem with
1da177e4 56 * ISIHP-4X card
d8d16e47 57 *
1da177e4
LT
58 * 30/04/01 anil .s Fixed the remote login through
59 * ISI port problem. Now the link
60 * does not go down before password
61 * prompt.
62 *
63 * 03/05/01 anil .s Fixed the problem with IRQ sharing
64 * among ISI-PCI cards.
65 *
66 * 03/05/01 anil .s Added support to display the version
d8d16e47 67 * info during insmod as well as module
1da177e4 68 * listing by lsmod.
d8d16e47 69 *
1da177e4
LT
70 * 10/05/01 anil .s Done the modifications to the source
71 * file and Install script so that the
72 * same installation can be used for
73 * 2.2.x and 2.4.x kernel.
74 *
75 * 06/06/01 anil .s Now we drop both dtr and rts during
76 * shutdown_port as well as raise them
77 * during isicom_config_port.
d8d16e47 78 *
1da177e4
LT
79 * 09/06/01 acme@conectiva.com.br use capable, not suser, do
80 * restore_flags on failure in
81 * isicom_send_break, verify put_user
82 * result
83 *
d8d16e47
JS
84 * 11/02/03 ranjeeth Added support for 230 Kbps and 460 Kbps
85 * Baud index extended to 21
86 *
87 * 20/03/03 ranjeeth Made to work for Linux Advanced server.
88 * Taken care of license warning.
89 *
90 * 10/12/03 Ravindra Made to work for Fedora Core 1 of
1da177e4
LT
91 * Red Hat Distribution
92 *
93 * 06/01/05 Alan Cox Merged the ISI and base kernel strands
94 * into a single 2.6 driver
95 *
96 * ***********************************************************
97 *
d8d16e47 98 * To use this driver you also need the support package. You
1da177e4
LT
99 * can find this in RPM format on
100 * ftp://ftp.linux.org.uk/pub/linux/alan
d8d16e47 101 *
1da177e4
LT
102 * You can find the original tools for this direct from Multitech
103 * ftp://ftp.multitech.com/ISI-Cards/
104 *
105 * Having installed the cards the module options (/etc/modprobe.conf)
106 *
107 * options isicom io=card1,card2,card3,card4 irq=card1,card2,card3,card4
108 *
109 * Omit those entries for boards you don't have installed.
110 *
111 * TODO
1da177e4
LT
112 * Merge testing
113 * 64-bit verification
114 */
115
116#include <linux/module.h>
e65c1db1 117#include <linux/firmware.h>
1da177e4
LT
118#include <linux/kernel.h>
119#include <linux/tty.h>
33f0f88f 120#include <linux/tty_flip.h>
1da177e4
LT
121#include <linux/termios.h>
122#include <linux/fs.h>
123#include <linux/sched.h>
124#include <linux/serial.h>
125#include <linux/mm.h>
1da177e4
LT
126#include <linux/interrupt.h>
127#include <linux/timer.h>
128#include <linux/delay.h>
129#include <linux/ioport.h>
130
251b8dd7
AC
131#include <linux/uaccess.h>
132#include <linux/io.h>
1da177e4
LT
133#include <asm/system.h>
134
135#include <linux/pci.h>
136
137#include <linux/isicom.h>
138
aaa246ea
JS
139#define InterruptTheCard(base) outw(0, (base) + 0xc)
140#define ClearInterrupt(base) inw((base) + 0x0a)
141
73b52572 142#define pr_dbg(str...) pr_debug("ISICOM: " str)
aaa246ea 143#ifdef DEBUG
aaa246ea
JS
144#define isicom_paranoia_check(a, b, c) __isicom_paranoia_check((a), (b), (c))
145#else
aaa246ea
JS
146#define isicom_paranoia_check(a, b, c) 0
147#endif
148
9ac0948b
JS
149static int isicom_probe(struct pci_dev *, const struct pci_device_id *);
150static void __devexit isicom_remove(struct pci_dev *);
151
1da177e4 152static struct pci_device_id isicom_pci_tbl[] = {
9ac0948b
JS
153 { PCI_DEVICE(VENDOR_ID, 0x2028) },
154 { PCI_DEVICE(VENDOR_ID, 0x2051) },
155 { PCI_DEVICE(VENDOR_ID, 0x2052) },
156 { PCI_DEVICE(VENDOR_ID, 0x2053) },
157 { PCI_DEVICE(VENDOR_ID, 0x2054) },
158 { PCI_DEVICE(VENDOR_ID, 0x2055) },
159 { PCI_DEVICE(VENDOR_ID, 0x2056) },
160 { PCI_DEVICE(VENDOR_ID, 0x2057) },
161 { PCI_DEVICE(VENDOR_ID, 0x2058) },
1da177e4
LT
162 { 0 }
163};
164MODULE_DEVICE_TABLE(pci, isicom_pci_tbl);
165
9ac0948b
JS
166static struct pci_driver isicom_driver = {
167 .name = "isicom",
168 .id_table = isicom_pci_tbl,
169 .probe = isicom_probe,
170 .remove = __devexit_p(isicom_remove)
171};
172
1da177e4
LT
173static int prev_card = 3; /* start servicing isi_card[0] */
174static struct tty_driver *isicom_normal;
175
1da177e4 176static void isicom_tx(unsigned long _data);
d8d16e47 177static void isicom_start(struct tty_struct *tty);
1da177e4 178
34b55b86
JS
179static DEFINE_TIMER(tx, isicom_tx, 0, 0);
180
1da177e4
LT
181/* baud index mappings from linux defns to isi */
182
183static signed char linuxb_to_isib[] = {
7edc136a 184 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13, 15, 16, 17, 18, 19, 20, 21
1da177e4
LT
185};
186
187struct isi_board {
8070e35c 188 unsigned long base;
4969b3a4 189 int irq;
1da177e4
LT
190 unsigned char port_count;
191 unsigned short status;
a547dfe9 192 unsigned short port_status; /* each bit for each port */
1da177e4 193 unsigned short shift_count;
251b8dd7 194 struct isi_port *ports;
1da177e4 195 signed char count;
1da177e4
LT
196 spinlock_t card_lock; /* Card wide lock 11/5/00 -sameer */
197 unsigned long flags;
938a7023 198 unsigned int index;
1da177e4
LT
199};
200
201struct isi_port {
202 unsigned short magic;
f1d03228 203 struct tty_port port;
8070e35c
JS
204 u16 channel;
205 u16 status;
251b8dd7 206 struct isi_board *card;
251b8dd7 207 unsigned char *xmit_buf;
1da177e4
LT
208 int xmit_head;
209 int xmit_tail;
210 int xmit_cnt;
211};
212
213static struct isi_board isi_card[BOARD_COUNT];
214static struct isi_port isi_ports[PORT_COUNT];
215
216/*
217 * Locking functions for card level locking. We need to own both
218 * the kernel lock for the card and have the card in a position that
219 * it wants to talk.
220 */
d8d16e47 221
4969b3a4 222static inline int WaitTillCardIsFree(unsigned long base)
cfe7c09a
JS
223{
224 unsigned int count = 0;
225 unsigned int a = in_atomic(); /* do we run under spinlock? */
226
227 while (!(inw(base + 0xe) & 0x1) && count++ < 100)
228 if (a)
229 mdelay(1);
230 else
231 msleep(1);
232
233 return !(inw(base + 0xe) & 0x1);
234}
235
1da177e4
LT
236static int lock_card(struct isi_board *card)
237{
8070e35c 238 unsigned long base = card->base;
5b21f9dd 239 unsigned int retries, a;
1da177e4 240
5b21f9dd 241 for (retries = 0; retries < 10; retries++) {
1da177e4 242 spin_lock_irqsave(&card->card_lock, card->flags);
5b21f9dd
JS
243 for (a = 0; a < 10; a++) {
244 if (inw(base + 0xe) & 0x1)
245 return 1;
246 udelay(10);
1da177e4 247 }
5b21f9dd
JS
248 spin_unlock_irqrestore(&card->card_lock, card->flags);
249 msleep(10);
1da177e4 250 }
a547dfe9
JS
251 printk(KERN_WARNING "ISICOM: Failed to lock Card (0x%lx)\n",
252 card->base);
253
0418726b 254 return 0; /* Failed to acquire the card! */
1da177e4
LT
255}
256
1da177e4
LT
257static void unlock_card(struct isi_board *card)
258{
259 spin_unlock_irqrestore(&card->card_lock, card->flags);
260}
261
262/*
263 * ISI Card specific ops ...
264 */
d8d16e47 265
cfe7c09a 266/* card->lock HAS to be held */
d8d16e47 267static void raise_dtr(struct isi_port *port)
1da177e4 268{
d8d16e47 269 struct isi_board *card = port->card;
8070e35c
JS
270 unsigned long base = card->base;
271 u16 channel = port->channel;
1da177e4 272
cfe7c09a 273 if (WaitTillCardIsFree(base))
1da177e4
LT
274 return;
275
d8d16e47 276 outw(0x8000 | (channel << card->shift_count) | 0x02, base);
1da177e4
LT
277 outw(0x0504, base);
278 InterruptTheCard(base);
279 port->status |= ISI_DTR;
1da177e4
LT
280}
281
cfe7c09a 282/* card->lock HAS to be held */
d8d16e47
JS
283static inline void drop_dtr(struct isi_port *port)
284{
285 struct isi_board *card = port->card;
8070e35c
JS
286 unsigned long base = card->base;
287 u16 channel = port->channel;
1da177e4 288
cfe7c09a 289 if (WaitTillCardIsFree(base))
1da177e4
LT
290 return;
291
d8d16e47 292 outw(0x8000 | (channel << card->shift_count) | 0x02, base);
1da177e4 293 outw(0x0404, base);
d8d16e47 294 InterruptTheCard(base);
1da177e4 295 port->status &= ~ISI_DTR;
1da177e4
LT
296}
297
cfe7c09a 298/* card->lock HAS to be held */
d8d16e47 299static inline void raise_rts(struct isi_port *port)
1da177e4 300{
d8d16e47 301 struct isi_board *card = port->card;
8070e35c
JS
302 unsigned long base = card->base;
303 u16 channel = port->channel;
1da177e4 304
cfe7c09a 305 if (WaitTillCardIsFree(base))
1da177e4
LT
306 return;
307
d8d16e47 308 outw(0x8000 | (channel << card->shift_count) | 0x02, base);
1da177e4 309 outw(0x0a04, base);
d8d16e47 310 InterruptTheCard(base);
1da177e4 311 port->status |= ISI_RTS;
1da177e4 312}
cfe7c09a
JS
313
314/* card->lock HAS to be held */
d8d16e47 315static inline void drop_rts(struct isi_port *port)
1da177e4 316{
d8d16e47 317 struct isi_board *card = port->card;
8070e35c
JS
318 unsigned long base = card->base;
319 u16 channel = port->channel;
1da177e4 320
cfe7c09a 321 if (WaitTillCardIsFree(base))
1da177e4
LT
322 return;
323
d8d16e47 324 outw(0x8000 | (channel << card->shift_count) | 0x02, base);
1da177e4 325 outw(0x0804, base);
d8d16e47 326 InterruptTheCard(base);
1da177e4 327 port->status &= ~ISI_RTS;
1da177e4
LT
328}
329
cfe7c09a 330/* card->lock MUST NOT be held */
d8d16e47 331static inline void raise_dtr_rts(struct isi_port *port)
1da177e4 332{
d8d16e47 333 struct isi_board *card = port->card;
8070e35c
JS
334 unsigned long base = card->base;
335 u16 channel = port->channel;
1da177e4
LT
336
337 if (!lock_card(card))
338 return;
339
d8d16e47 340 outw(0x8000 | (channel << card->shift_count) | 0x02, base);
1da177e4
LT
341 outw(0x0f04, base);
342 InterruptTheCard(base);
343 port->status |= (ISI_DTR | ISI_RTS);
344 unlock_card(card);
345}
346
cfe7c09a 347/* card->lock HAS to be held */
d8d16e47 348static void drop_dtr_rts(struct isi_port *port)
1da177e4 349{
d8d16e47 350 struct isi_board *card = port->card;
8070e35c
JS
351 unsigned long base = card->base;
352 u16 channel = port->channel;
1da177e4 353
cfe7c09a 354 if (WaitTillCardIsFree(base))
1da177e4
LT
355 return;
356
d8d16e47 357 outw(0x8000 | (channel << card->shift_count) | 0x02, base);
1da177e4 358 outw(0x0c04, base);
d8d16e47 359 InterruptTheCard(base);
1da177e4 360 port->status &= ~(ISI_RTS | ISI_DTR);
1da177e4
LT
361}
362
1da177e4
LT
363/*
364 * ISICOM Driver specific routines ...
365 *
366 */
d8d16e47 367
aaa246ea
JS
368static inline int __isicom_paranoia_check(struct isi_port const *port,
369 char *name, const char *routine)
1da177e4 370{
1da177e4 371 if (!port) {
aaa246ea
JS
372 printk(KERN_WARNING "ISICOM: Warning: bad isicom magic for "
373 "dev %s in %s.\n", name, routine);
1da177e4
LT
374 return 1;
375 }
376 if (port->magic != ISICOM_MAGIC) {
aaa246ea
JS
377 printk(KERN_WARNING "ISICOM: Warning: NULL isicom port for "
378 "dev %s in %s.\n", name, routine);
1da177e4 379 return 1;
d8d16e47 380 }
aaa246ea 381
1da177e4
LT
382 return 0;
383}
d8d16e47 384
1da177e4 385/*
d8d16e47 386 * Transmitter.
1da177e4
LT
387 *
388 * We shovel data into the card buffers on a regular basis. The card
389 * will do the rest of the work for us.
390 */
391
392static void isicom_tx(unsigned long _data)
393{
4969b3a4 394 unsigned long flags, base;
5b21f9dd 395 unsigned int retries;
4969b3a4 396 short count = (BOARD_COUNT-1), card;
1da177e4 397 short txcount, wrd, residue, word_count, cnt;
d8d16e47
JS
398 struct isi_port *port;
399 struct tty_struct *tty;
400
1da177e4
LT
401 /* find next active board */
402 card = (prev_card + 1) & 0x0003;
251b8dd7 403 while (count-- > 0) {
d8d16e47 404 if (isi_card[card].status & BOARD_ACTIVE)
1da177e4 405 break;
d8d16e47 406 card = (card + 1) & 0x0003;
1da177e4
LT
407 }
408 if (!(isi_card[card].status & BOARD_ACTIVE))
409 goto sched_again;
d8d16e47 410
1da177e4 411 prev_card = card;
d8d16e47 412
1da177e4
LT
413 count = isi_card[card].port_count;
414 port = isi_card[card].ports;
415 base = isi_card[card].base;
5b21f9dd
JS
416
417 spin_lock_irqsave(&isi_card[card].card_lock, flags);
418 for (retries = 0; retries < 100; retries++) {
419 if (inw(base + 0xe) & 0x1)
420 break;
421 udelay(2);
422 }
423 if (retries >= 100)
424 goto unlock;
425
d450b5a0
AC
426 tty = tty_port_tty_get(&port->port);
427 if (tty == NULL)
428 goto put_unlock;
429
251b8dd7 430 for (; count > 0; count--, port++) {
1da177e4 431 /* port not active or tx disabled to force flow control */
f1d03228 432 if (!(port->port.flags & ASYNC_INITIALIZED) ||
d8d16e47 433 !(port->status & ISI_TXOK))
1da177e4 434 continue;
d8d16e47 435
1da177e4 436 txcount = min_t(short, TX_SIZE, port->xmit_cnt);
5b21f9dd 437 if (txcount <= 0 || tty->stopped || tty->hw_stopped)
1da177e4 438 continue;
5b21f9dd
JS
439
440 if (!(inw(base + 0x02) & (1 << port->channel)))
d8d16e47 441 continue;
5b21f9dd 442
aaa246ea
JS
443 pr_dbg("txing %d bytes, port%d.\n", txcount,
444 port->channel + 1);
445 outw((port->channel << isi_card[card].shift_count) | txcount,
446 base);
1da177e4 447 residue = NO;
d8d16e47 448 wrd = 0;
1da177e4 449 while (1) {
a547dfe9
JS
450 cnt = min_t(int, txcount, (SERIAL_XMIT_SIZE
451 - port->xmit_tail));
1da177e4
LT
452 if (residue == YES) {
453 residue = NO;
454 if (cnt > 0) {
f1d03228 455 wrd |= (port->port.xmit_buf[port->xmit_tail]
a547dfe9
JS
456 << 8);
457 port->xmit_tail = (port->xmit_tail + 1)
458 & (SERIAL_XMIT_SIZE - 1);
1da177e4
LT
459 port->xmit_cnt--;
460 txcount--;
461 cnt--;
d8d16e47 462 outw(wrd, base);
a547dfe9 463 } else {
1da177e4
LT
464 outw(wrd, base);
465 break;
466 }
d8d16e47 467 }
251b8dd7
AC
468 if (cnt <= 0)
469 break;
1da177e4 470 word_count = cnt >> 1;
f1d03228 471 outsw(base, port->port.xmit_buf+port->xmit_tail, word_count);
a547dfe9
JS
472 port->xmit_tail = (port->xmit_tail
473 + (word_count << 1)) & (SERIAL_XMIT_SIZE - 1);
1da177e4
LT
474 txcount -= (word_count << 1);
475 port->xmit_cnt -= (word_count << 1);
476 if (cnt & 0x0001) {
477 residue = YES;
f1d03228 478 wrd = port->port.xmit_buf[port->xmit_tail];
a547dfe9
JS
479 port->xmit_tail = (port->xmit_tail + 1)
480 & (SERIAL_XMIT_SIZE - 1);
1da177e4
LT
481 port->xmit_cnt--;
482 txcount--;
483 }
484 }
485
486 InterruptTheCard(base);
487 if (port->xmit_cnt <= 0)
488 port->status &= ~ISI_TXOK;
489 if (port->xmit_cnt <= WAKEUP_CHARS)
0aa5de85 490 tty_wakeup(tty);
d8d16e47 491 }
1da177e4 492
d450b5a0
AC
493put_unlock:
494 tty_kref_put(tty);
5b21f9dd
JS
495unlock:
496 spin_unlock_irqrestore(&isi_card[card].card_lock, flags);
d8d16e47
JS
497 /* schedule another tx for hopefully in about 10ms */
498sched_again:
34b55b86 499 mod_timer(&tx, jiffies + msecs_to_jiffies(10));
d8d16e47
JS
500}
501
1da177e4 502/*
d8d16e47 503 * Main interrupt handler routine
1da177e4 504 */
d8d16e47 505
7d12e780 506static irqreturn_t isicom_interrupt(int irq, void *dev_id)
1da177e4 507{
8070e35c 508 struct isi_board *card = dev_id;
d8d16e47
JS
509 struct isi_port *port;
510 struct tty_struct *tty;
8070e35c
JS
511 unsigned long base;
512 u16 header, word_count, count, channel;
1da177e4 513 short byte_count;
33f0f88f 514 unsigned char *rp;
d8d16e47 515
1da177e4
LT
516 if (!card || !(card->status & FIRMWARE_LOADED))
517 return IRQ_NONE;
d8d16e47 518
1da177e4 519 base = card->base;
cb4a10cc
JS
520
521 /* did the card interrupt us? */
522 if (!(inw(base + 0x0e) & 0x02))
523 return IRQ_NONE;
524
1da177e4 525 spin_lock(&card->card_lock);
d8d16e47 526
18234f88
JS
527 /*
528 * disable any interrupts from the PCI card and lower the
529 * interrupt line
530 */
531 outw(0x8000, base+0x04);
532 ClearInterrupt(base);
d8d16e47 533
1da177e4
LT
534 inw(base); /* get the dummy word out */
535 header = inw(base);
536 channel = (header & 0x7800) >> card->shift_count;
537 byte_count = header & 0xff;
538
539 if (channel + 1 > card->port_count) {
a547dfe9
JS
540 printk(KERN_WARNING "ISICOM: isicom_interrupt(0x%lx): "
541 "%d(channel) > port_count.\n", base, channel+1);
18234f88 542 outw(0x0000, base+0x04); /* enable interrupts */
1da177e4 543 spin_unlock(&card->card_lock);
d8d16e47 544 return IRQ_HANDLED;
1da177e4
LT
545 }
546 port = card->ports + channel;
f1d03228 547 if (!(port->port.flags & ASYNC_INITIALIZED)) {
18234f88 548 outw(0x0000, base+0x04); /* enable interrupts */
174f1307 549 spin_unlock(&card->card_lock);
1da177e4 550 return IRQ_HANDLED;
d8d16e47
JS
551 }
552
d450b5a0 553 tty = tty_port_tty_get(&port->port);
1da177e4
LT
554 if (tty == NULL) {
555 word_count = byte_count >> 1;
251b8dd7 556 while (byte_count > 1) {
1da177e4
LT
557 inw(base);
558 byte_count -= 2;
559 }
560 if (byte_count & 0x01)
561 inw(base);
18234f88 562 outw(0x0000, base+0x04); /* enable interrupts */
1da177e4
LT
563 spin_unlock(&card->card_lock);
564 return IRQ_HANDLED;
565 }
d8d16e47 566
1da177e4
LT
567 if (header & 0x8000) { /* Status Packet */
568 header = inw(base);
251b8dd7 569 switch (header & 0xff) {
d8d16e47 570 case 0: /* Change in EIA signals */
f1d03228 571 if (port->port.flags & ASYNC_CHECK_CD) {
d8d16e47
JS
572 if (port->status & ISI_DCD) {
573 if (!(header & ISI_DCD)) {
574 /* Carrier has been lost */
a547dfe9
JS
575 pr_dbg("interrupt: DCD->low.\n"
576 );
d8d16e47 577 port->status &= ~ISI_DCD;
0aa5de85 578 tty_hangup(tty);
1da177e4 579 }
a547dfe9
JS
580 } else if (header & ISI_DCD) {
581 /* Carrier has been detected */
582 pr_dbg("interrupt: DCD->high.\n");
583 port->status |= ISI_DCD;
f1d03228 584 wake_up_interruptible(&port->port.open_wait);
1da177e4 585 }
a547dfe9 586 } else {
d8d16e47
JS
587 if (header & ISI_DCD)
588 port->status |= ISI_DCD;
589 else
590 port->status &= ~ISI_DCD;
591 }
592
f1d03228 593 if (port->port.flags & ASYNC_CTS_FLOW) {
d450b5a0 594 if (tty->hw_stopped) {
d8d16e47 595 if (header & ISI_CTS) {
f1d03228 596 port->port.tty->hw_stopped = 0;
d8d16e47 597 /* start tx ing */
a547dfe9
JS
598 port->status |= (ISI_TXOK
599 | ISI_CTS);
0aa5de85 600 tty_wakeup(tty);
1da177e4 601 }
a547dfe9 602 } else if (!(header & ISI_CTS)) {
d450b5a0 603 tty->hw_stopped = 1;
a547dfe9
JS
604 /* stop tx ing */
605 port->status &= ~(ISI_TXOK | ISI_CTS);
1da177e4 606 }
a547dfe9 607 } else {
d8d16e47
JS
608 if (header & ISI_CTS)
609 port->status |= ISI_CTS;
1da177e4 610 else
d8d16e47
JS
611 port->status &= ~ISI_CTS;
612 }
613
614 if (header & ISI_DSR)
615 port->status |= ISI_DSR;
616 else
617 port->status &= ~ISI_DSR;
618
619 if (header & ISI_RI)
620 port->status |= ISI_RI;
621 else
622 port->status &= ~ISI_RI;
623
624 break;
625
a547dfe9 626 case 1: /* Received Break !!! */
d8d16e47 627 tty_insert_flip_char(tty, 0, TTY_BREAK);
f1d03228 628 if (port->port.flags & ASYNC_SAK)
d8d16e47
JS
629 do_SAK(tty);
630 tty_flip_buffer_push(tty);
631 break;
632
633 case 2: /* Statistics */
aaa246ea 634 pr_dbg("isicom_interrupt: stats!!!.\n");
d8d16e47
JS
635 break;
636
637 default:
aaa246ea 638 pr_dbg("Intr: Unknown code in status packet.\n");
d8d16e47
JS
639 break;
640 }
a547dfe9 641 } else { /* Data Packet */
33f0f88f
AC
642
643 count = tty_prepare_flip_string(tty, &rp, byte_count & ~1);
aaa246ea 644 pr_dbg("Intr: Can rx %d of %d bytes.\n", count, byte_count);
1da177e4 645 word_count = count >> 1;
33f0f88f 646 insw(base, rp, word_count);
1da177e4
LT
647 byte_count -= (word_count << 1);
648 if (count & 0x0001) {
a547dfe9
JS
649 tty_insert_flip_char(tty, inw(base) & 0xff,
650 TTY_NORMAL);
1da177e4 651 byte_count -= 2;
d8d16e47 652 }
1da177e4 653 if (byte_count > 0) {
aaa246ea
JS
654 pr_dbg("Intr(0x%lx:%d): Flip buffer overflow! dropping "
655 "bytes...\n", base, channel + 1);
251b8dd7
AC
656 /* drain out unread xtra data */
657 while (byte_count > 0) {
1da177e4
LT
658 inw(base);
659 byte_count -= 2;
660 }
661 }
33f0f88f 662 tty_flip_buffer_push(tty);
1da177e4 663 }
18234f88 664 outw(0x0000, base+0x04); /* enable interrupts */
174f1307 665 spin_unlock(&card->card_lock);
d450b5a0 666 tty_kref_put(tty);
a547dfe9 667
1da177e4 668 return IRQ_HANDLED;
d8d16e47 669}
1da177e4 670
d450b5a0 671static void isicom_config_port(struct tty_struct *tty)
1da177e4 672{
d450b5a0 673 struct isi_port *port = tty->driver_data;
d8d16e47 674 struct isi_board *card = port->card;
1da177e4 675 unsigned long baud;
8070e35c
JS
676 unsigned long base = card->base;
677 u16 channel_setup, channel = port->channel,
678 shift_count = card->shift_count;
1da177e4 679 unsigned char flow_ctrl;
d8d16e47 680
251b8dd7 681 /* FIXME: Switch to new tty baud API */
1da177e4
LT
682 baud = C_BAUD(tty);
683 if (baud & CBAUDEX) {
684 baud &= ~CBAUDEX;
d8d16e47 685
1da177e4
LT
686 /* if CBAUDEX bit is on and the baud is set to either 50 or 75
687 * then the card is programmed for 57.6Kbps or 115Kbps
688 * respectively.
d8d16e47
JS
689 */
690
7edc136a
JS
691 /* 1,2,3,4 => 57.6, 115.2, 230, 460 kbps resp. */
692 if (baud < 1 || baud > 4)
d450b5a0 693 tty->termios->c_cflag &= ~CBAUDEX;
1da177e4
LT
694 else
695 baud += 15;
d8d16e47 696 }
1da177e4 697 if (baud == 15) {
d8d16e47
JS
698
699 /* the ASYNC_SPD_HI and ASYNC_SPD_VHI options are set
1da177e4
LT
700 * by the set_serial_info ioctl ... this is done by
701 * the 'setserial' utility.
d8d16e47
JS
702 */
703
f1d03228 704 if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
d8d16e47 705 baud++; /* 57.6 Kbps */
f1d03228 706 if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
251b8dd7 707 baud += 2; /* 115 Kbps */
f1d03228 708 if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
7edc136a 709 baud += 3; /* 230 kbps*/
f1d03228 710 if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
7edc136a 711 baud += 4; /* 460 kbps*/
1da177e4
LT
712 }
713 if (linuxb_to_isib[baud] == -1) {
714 /* hang up */
d8d16e47
JS
715 drop_dtr(port);
716 return;
251b8dd7 717 } else
1da177e4 718 raise_dtr(port);
d8d16e47 719
cfe7c09a 720 if (WaitTillCardIsFree(base) == 0) {
251b8dd7 721 outw(0x8000 | (channel << shift_count) | 0x03, base);
1da177e4
LT
722 outw(linuxb_to_isib[baud] << 8 | 0x03, base);
723 channel_setup = 0;
251b8dd7 724 switch (C_CSIZE(tty)) {
d8d16e47
JS
725 case CS5:
726 channel_setup |= ISICOM_CS5;
727 break;
728 case CS6:
729 channel_setup |= ISICOM_CS6;
730 break;
731 case CS7:
732 channel_setup |= ISICOM_CS7;
733 break;
734 case CS8:
735 channel_setup |= ISICOM_CS8;
736 break;
1da177e4 737 }
d8d16e47 738
1da177e4
LT
739 if (C_CSTOPB(tty))
740 channel_setup |= ISICOM_2SB;
741 if (C_PARENB(tty)) {
742 channel_setup |= ISICOM_EVPAR;
743 if (C_PARODD(tty))
d8d16e47 744 channel_setup |= ISICOM_ODPAR;
1da177e4 745 }
d8d16e47 746 outw(channel_setup, base);
1da177e4 747 InterruptTheCard(base);
d8d16e47 748 }
1da177e4 749 if (C_CLOCAL(tty))
f1d03228 750 port->port.flags &= ~ASYNC_CHECK_CD;
1da177e4 751 else
f1d03228 752 port->port.flags |= ASYNC_CHECK_CD;
d8d16e47 753
1da177e4
LT
754 /* flow control settings ...*/
755 flow_ctrl = 0;
f1d03228 756 port->port.flags &= ~ASYNC_CTS_FLOW;
1da177e4 757 if (C_CRTSCTS(tty)) {
f1d03228 758 port->port.flags |= ASYNC_CTS_FLOW;
1da177e4 759 flow_ctrl |= ISICOM_CTSRTS;
d8d16e47
JS
760 }
761 if (I_IXON(tty))
1da177e4
LT
762 flow_ctrl |= ISICOM_RESPOND_XONXOFF;
763 if (I_IXOFF(tty))
d8d16e47
JS
764 flow_ctrl |= ISICOM_INITIATE_XONXOFF;
765
cfe7c09a 766 if (WaitTillCardIsFree(base) == 0) {
251b8dd7 767 outw(0x8000 | (channel << shift_count) | 0x04, base);
1da177e4
LT
768 outw(flow_ctrl << 8 | 0x05, base);
769 outw((STOP_CHAR(tty)) << 8 | (START_CHAR(tty)), base);
770 InterruptTheCard(base);
1da177e4 771 }
d8d16e47 772
1da177e4
LT
773 /* rx enabled -> enable port for rx on the card */
774 if (C_CREAD(tty)) {
775 card->port_status |= (1 << channel);
776 outw(card->port_status, base + 0x02);
777 }
778}
1da177e4 779
d8d16e47
JS
780/* open et all */
781
782static inline void isicom_setup_board(struct isi_board *bp)
1da177e4
LT
783{
784 int channel;
d8d16e47 785 struct isi_port *port;
1da177e4 786 unsigned long flags;
d8d16e47 787
1da177e4
LT
788 spin_lock_irqsave(&bp->card_lock, flags);
789 if (bp->status & BOARD_ACTIVE) {
790 spin_unlock_irqrestore(&bp->card_lock, flags);
791 return;
792 }
793 port = bp->ports;
794 bp->status |= BOARD_ACTIVE;
d8d16e47 795 for (channel = 0; channel < bp->port_count; channel++, port++)
1da177e4 796 drop_dtr_rts(port);
cfe7c09a 797 spin_unlock_irqrestore(&bp->card_lock, flags);
1da177e4 798}
d8d16e47 799
d450b5a0 800static int isicom_setup_port(struct tty_struct *tty)
1da177e4 801{
d450b5a0 802 struct isi_port *port = tty->driver_data;
d8d16e47 803 struct isi_board *card = port->card;
1da177e4 804 unsigned long flags;
d8d16e47 805
f1d03228 806 if (port->port.flags & ASYNC_INITIALIZED)
1da177e4 807 return 0;
f1d03228
AC
808 if (tty_port_alloc_xmit_buf(&port->port) < 0)
809 return -ENOMEM;
1da177e4
LT
810
811 spin_lock_irqsave(&card->card_lock, flags);
d450b5a0 812 clear_bit(TTY_IO_ERROR, &tty->flags);
f1d03228 813 if (port->port.count == 1)
1da177e4 814 card->count++;
d8d16e47 815
1da177e4 816 port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
d8d16e47 817
1da177e4 818 /* discard any residual data */
cfe7c09a
JS
819 if (WaitTillCardIsFree(card->base) == 0) {
820 outw(0x8000 | (port->channel << card->shift_count) | 0x02,
821 card->base);
822 outw(((ISICOM_KILLTX | ISICOM_KILLRX) << 8) | 0x06, card->base);
823 InterruptTheCard(card->base);
824 }
d8d16e47 825
d450b5a0 826 isicom_config_port(tty);
f1d03228 827 port->port.flags |= ASYNC_INITIALIZED;
1da177e4 828 spin_unlock_irqrestore(&card->card_lock, flags);
d8d16e47
JS
829
830 return 0;
831}
832
a547dfe9
JS
833static int block_til_ready(struct tty_struct *tty, struct file *filp,
834 struct isi_port *port)
1da177e4 835{
d8d16e47 836 struct isi_board *card = port->card;
1da177e4
LT
837 int do_clocal = 0, retval;
838 unsigned long flags;
839 DECLARE_WAITQUEUE(wait, current);
840
841 /* block if port is in the process of being closed */
842
f1d03228 843 if (tty_hung_up_p(filp) || port->port.flags & ASYNC_CLOSING) {
aaa246ea 844 pr_dbg("block_til_ready: close in progress.\n");
f1d03228
AC
845 interruptible_sleep_on(&port->port.close_wait);
846 if (port->port.flags & ASYNC_HUP_NOTIFY)
1da177e4
LT
847 return -EAGAIN;
848 else
849 return -ERESTARTSYS;
850 }
d8d16e47 851
1da177e4 852 /* if non-blocking mode is set ... */
d8d16e47 853
a547dfe9
JS
854 if ((filp->f_flags & O_NONBLOCK) ||
855 (tty->flags & (1 << TTY_IO_ERROR))) {
aaa246ea 856 pr_dbg("block_til_ready: non-block mode.\n");
f1d03228 857 port->port.flags |= ASYNC_NORMAL_ACTIVE;
d8d16e47
JS
858 return 0;
859 }
860
1da177e4
LT
861 if (C_CLOCAL(tty))
862 do_clocal = 1;
d8d16e47
JS
863
864 /* block waiting for DCD to be asserted, and while
1da177e4
LT
865 callout dev is busy */
866 retval = 0;
f1d03228 867 add_wait_queue(&port->port.open_wait, &wait);
1da177e4
LT
868
869 spin_lock_irqsave(&card->card_lock, flags);
870 if (!tty_hung_up_p(filp))
f1d03228
AC
871 port->port.count--;
872 port->port.blocked_open++;
1da177e4 873 spin_unlock_irqrestore(&card->card_lock, flags);
d8d16e47 874
1da177e4
LT
875 while (1) {
876 raise_dtr_rts(port);
877
878 set_current_state(TASK_INTERRUPTIBLE);
f1d03228
AC
879 if (tty_hung_up_p(filp) || !(port->port.flags & ASYNC_INITIALIZED)) {
880 if (port->port.flags & ASYNC_HUP_NOTIFY)
1da177e4
LT
881 retval = -EAGAIN;
882 else
883 retval = -ERESTARTSYS;
884 break;
d8d16e47 885 }
f1d03228 886 if (!(port->port.flags & ASYNC_CLOSING) &&
d8d16e47 887 (do_clocal || (port->status & ISI_DCD))) {
1da177e4 888 break;
d8d16e47 889 }
1da177e4
LT
890 if (signal_pending(current)) {
891 retval = -ERESTARTSYS;
892 break;
893 }
d8d16e47 894 schedule();
1da177e4
LT
895 }
896 set_current_state(TASK_RUNNING);
f1d03228 897 remove_wait_queue(&port->port.open_wait, &wait);
1da177e4
LT
898 spin_lock_irqsave(&card->card_lock, flags);
899 if (!tty_hung_up_p(filp))
f1d03228
AC
900 port->port.count++;
901 port->port.blocked_open--;
1da177e4
LT
902 spin_unlock_irqrestore(&card->card_lock, flags);
903 if (retval)
904 return retval;
f1d03228 905 port->port.flags |= ASYNC_NORMAL_ACTIVE;
1da177e4
LT
906 return 0;
907}
d8d16e47
JS
908
909static int isicom_open(struct tty_struct *tty, struct file *filp)
1da177e4 910{
d8d16e47
JS
911 struct isi_port *port;
912 struct isi_board *card;
17c4edf0
JS
913 unsigned int board;
914 int error, line;
1da177e4
LT
915
916 line = tty->index;
917 if (line < 0 || line > PORT_COUNT-1)
918 return -ENODEV;
919 board = BOARD(line);
920 card = &isi_card[board];
d8d16e47 921
1da177e4
LT
922 if (!(card->status & FIRMWARE_LOADED))
923 return -ENODEV;
d8d16e47 924
1da177e4
LT
925 /* open on a port greater than the port count for the card !!! */
926 if (line > ((board * 16) + card->port_count - 1))
927 return -ENODEV;
928
d8d16e47 929 port = &isi_ports[line];
1da177e4
LT
930 if (isicom_paranoia_check(port, tty->name, "isicom_open"))
931 return -ENODEV;
d8d16e47
JS
932
933 isicom_setup_board(card);
934
f1d03228 935 port->port.count++;
1da177e4 936 tty->driver_data = port;
d450b5a0
AC
937 tty_port_tty_set(&port->port, tty);
938 error = isicom_setup_port(tty);
251b8dd7
AC
939 if (error == 0)
940 error = block_til_ready(tty, filp, port);
941 return error;
1da177e4 942}
d8d16e47 943
1da177e4
LT
944/* close et all */
945
d8d16e47 946static inline void isicom_shutdown_board(struct isi_board *bp)
1da177e4 947{
251b8dd7 948 if (bp->status & BOARD_ACTIVE)
1da177e4 949 bp->status &= ~BOARD_ACTIVE;
1da177e4
LT
950}
951
cfe7c09a 952/* card->lock HAS to be held */
d8d16e47 953static void isicom_shutdown_port(struct isi_port *port)
1da177e4 954{
d8d16e47
JS
955 struct isi_board *card = port->card;
956 struct tty_struct *tty;
d8d16e47 957
d450b5a0 958 tty = tty_port_tty_get(&port->port);
1da177e4 959
d450b5a0
AC
960 if (!(port->port.flags & ASYNC_INITIALIZED)) {
961 tty_kref_put(tty);
1da177e4 962 return;
d450b5a0 963 }
cfe7c09a 964
f1d03228
AC
965 tty_port_free_xmit_buf(&port->port);
966 port->port.flags &= ~ASYNC_INITIALIZED;
1da177e4 967 /* 3rd October 2000 : Vinayak P Risbud */
d450b5a0 968 tty_port_tty_set(&port->port, NULL);
d8d16e47 969
1da177e4
LT
970 /*Fix done by Anil .S on 30-04-2001
971 remote login through isi port has dtr toggle problem
972 due to which the carrier drops before the password prompt
d8d16e47 973 appears on the remote end. Now we drop the dtr only if the
1da177e4 974 HUPCL(Hangup on close) flag is set for the tty*/
d8d16e47
JS
975
976 if (C_HUPCL(tty))
1da177e4
LT
977 /* drop dtr on this port */
978 drop_dtr(port);
d8d16e47
JS
979
980 /* any other port uninits */
1da177e4
LT
981 if (tty)
982 set_bit(TTY_IO_ERROR, &tty->flags);
d8d16e47 983
1da177e4 984 if (--card->count < 0) {
aaa246ea 985 pr_dbg("isicom_shutdown_port: bad board(0x%lx) count %d.\n",
1da177e4 986 card->base, card->count);
d8d16e47 987 card->count = 0;
1da177e4 988 }
d8d16e47 989
a547dfe9 990 /* last port was closed, shutdown that boad too */
d8d16e47 991 if (C_HUPCL(tty)) {
1da177e4
LT
992 if (!card->count)
993 isicom_shutdown_board(card);
994 }
995}
996
978e595f
AC
997static void isicom_flush_buffer(struct tty_struct *tty)
998{
999 struct isi_port *port = tty->driver_data;
1000 struct isi_board *card = port->card;
1001 unsigned long flags;
1002
1003 if (isicom_paranoia_check(port, tty->name, "isicom_flush_buffer"))
1004 return;
1005
1006 spin_lock_irqsave(&card->card_lock, flags);
1007 port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
1008 spin_unlock_irqrestore(&card->card_lock, flags);
1009
1010 tty_wakeup(tty);
1011}
1012
d8d16e47 1013static void isicom_close(struct tty_struct *tty, struct file *filp)
1da177e4 1014{
8070e35c 1015 struct isi_port *port = tty->driver_data;
c387fd85 1016 struct isi_board *card;
1da177e4 1017 unsigned long flags;
d8d16e47 1018
1da177e4
LT
1019 if (!port)
1020 return;
c387fd85 1021 card = port->card;
1da177e4
LT
1022 if (isicom_paranoia_check(port, tty->name, "isicom_close"))
1023 return;
d8d16e47 1024
aaa246ea 1025 pr_dbg("Close start!!!.\n");
d8d16e47 1026
1da177e4
LT
1027 spin_lock_irqsave(&card->card_lock, flags);
1028 if (tty_hung_up_p(filp)) {
1029 spin_unlock_irqrestore(&card->card_lock, flags);
1030 return;
1031 }
d8d16e47 1032
f1d03228 1033 if (tty->count == 1 && port->port.count != 1) {
a547dfe9
JS
1034 printk(KERN_WARNING "ISICOM:(0x%lx) isicom_close: bad port "
1035 "count tty->count = 1 port count = %d.\n",
f1d03228
AC
1036 card->base, port->port.count);
1037 port->port.count = 1;
1da177e4 1038 }
f1d03228 1039 if (--port->port.count < 0) {
a547dfe9
JS
1040 printk(KERN_WARNING "ISICOM:(0x%lx) isicom_close: bad port "
1041 "count for channel%d = %d", card->base, port->channel,
f1d03228
AC
1042 port->port.count);
1043 port->port.count = 0;
1da177e4 1044 }
d8d16e47 1045
f1d03228 1046 if (port->port.count) {
1da177e4
LT
1047 spin_unlock_irqrestore(&card->card_lock, flags);
1048 return;
d8d16e47 1049 }
f1d03228 1050 port->port.flags |= ASYNC_CLOSING;
1da177e4
LT
1051 tty->closing = 1;
1052 spin_unlock_irqrestore(&card->card_lock, flags);
d8d16e47 1053
44b7d1b3
AC
1054 if (port->port.closing_wait != ASYNC_CLOSING_WAIT_NONE)
1055 tty_wait_until_sent(tty, port->port.closing_wait);
d8d16e47 1056 /* indicate to the card that no more data can be received
1da177e4
LT
1057 on this port */
1058 spin_lock_irqsave(&card->card_lock, flags);
f1d03228 1059 if (port->port.flags & ASYNC_INITIALIZED) {
1da177e4
LT
1060 card->port_status &= ~(1 << port->channel);
1061 outw(card->port_status, card->base + 0x02);
d8d16e47 1062 }
1da177e4
LT
1063 isicom_shutdown_port(port);
1064 spin_unlock_irqrestore(&card->card_lock, flags);
d8d16e47 1065
978e595f 1066 isicom_flush_buffer(tty);
1da177e4
LT
1067 tty_ldisc_flush(tty);
1068
1069 spin_lock_irqsave(&card->card_lock, flags);
1070 tty->closing = 0;
1071
f1d03228 1072 if (port->port.blocked_open) {
1da177e4 1073 spin_unlock_irqrestore(&card->card_lock, flags);
44b7d1b3 1074 if (port->port.close_delay) {
aaa246ea 1075 pr_dbg("scheduling until time out.\n");
a547dfe9 1076 msleep_interruptible(
44b7d1b3 1077 jiffies_to_msecs(port->port.close_delay));
1da177e4
LT
1078 }
1079 spin_lock_irqsave(&card->card_lock, flags);
f1d03228 1080 wake_up_interruptible(&port->port.open_wait);
d8d16e47 1081 }
f1d03228
AC
1082 port->port.flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
1083 wake_up_interruptible(&port->port.close_wait);
1da177e4
LT
1084 spin_unlock_irqrestore(&card->card_lock, flags);
1085}
1086
1087/* write et all */
d8d16e47
JS
1088static int isicom_write(struct tty_struct *tty, const unsigned char *buf,
1089 int count)
1da177e4 1090{
8070e35c 1091 struct isi_port *port = tty->driver_data;
d8d16e47 1092 struct isi_board *card = port->card;
1da177e4
LT
1093 unsigned long flags;
1094 int cnt, total = 0;
1095
1096 if (isicom_paranoia_check(port, tty->name, "isicom_write"))
1097 return 0;
d8d16e47 1098
1da177e4 1099 spin_lock_irqsave(&card->card_lock, flags);
d8d16e47 1100
251b8dd7 1101 while (1) {
a547dfe9
JS
1102 cnt = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt
1103 - 1, SERIAL_XMIT_SIZE - port->xmit_head));
d8d16e47 1104 if (cnt <= 0)
1da177e4 1105 break;
d8d16e47 1106
f1d03228 1107 memcpy(port->port.xmit_buf + port->xmit_head, buf, cnt);
a547dfe9
JS
1108 port->xmit_head = (port->xmit_head + cnt) & (SERIAL_XMIT_SIZE
1109 - 1);
1da177e4
LT
1110 port->xmit_cnt += cnt;
1111 buf += cnt;
1112 count -= cnt;
1113 total += cnt;
d8d16e47 1114 }
1da177e4
LT
1115 if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped)
1116 port->status |= ISI_TXOK;
1117 spin_unlock_irqrestore(&card->card_lock, flags);
d8d16e47 1118 return total;
1da177e4
LT
1119}
1120
1121/* put_char et all */
f34d7a5b 1122static int isicom_put_char(struct tty_struct *tty, unsigned char ch)
1da177e4 1123{
8070e35c 1124 struct isi_port *port = tty->driver_data;
d8d16e47 1125 struct isi_board *card = port->card;
1da177e4 1126 unsigned long flags;
d8d16e47 1127
1da177e4 1128 if (isicom_paranoia_check(port, tty->name, "isicom_put_char"))
f34d7a5b 1129 return 0;
d8d16e47 1130
1da177e4 1131 spin_lock_irqsave(&card->card_lock, flags);
f34d7a5b
AC
1132 if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
1133 spin_unlock_irqrestore(&card->card_lock, flags);
1134 return 0;
1135 }
d8d16e47 1136
f1d03228 1137 port->port.xmit_buf[port->xmit_head++] = ch;
1da177e4
LT
1138 port->xmit_head &= (SERIAL_XMIT_SIZE - 1);
1139 port->xmit_cnt++;
1140 spin_unlock_irqrestore(&card->card_lock, flags);
f34d7a5b 1141 return 1;
1da177e4
LT
1142}
1143
1144/* flush_chars et all */
d8d16e47 1145static void isicom_flush_chars(struct tty_struct *tty)
1da177e4 1146{
8070e35c 1147 struct isi_port *port = tty->driver_data;
d8d16e47 1148
1da177e4
LT
1149 if (isicom_paranoia_check(port, tty->name, "isicom_flush_chars"))
1150 return;
d8d16e47 1151
a547dfe9 1152 if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
f1d03228 1153 !port->port.xmit_buf)
1da177e4 1154 return;
d8d16e47 1155
1da177e4
LT
1156 /* this tells the transmitter to consider this port for
1157 data output to the card ... that's the best we can do. */
d8d16e47 1158 port->status |= ISI_TXOK;
1da177e4
LT
1159}
1160
1161/* write_room et all */
d8d16e47 1162static int isicom_write_room(struct tty_struct *tty)
1da177e4 1163{
8070e35c 1164 struct isi_port *port = tty->driver_data;
1da177e4
LT
1165 int free;
1166
1167 if (isicom_paranoia_check(port, tty->name, "isicom_write_room"))
1168 return 0;
d8d16e47 1169
1da177e4
LT
1170 free = SERIAL_XMIT_SIZE - port->xmit_cnt - 1;
1171 if (free < 0)
1172 free = 0;
1173 return free;
1174}
1175
1176/* chars_in_buffer et all */
d8d16e47 1177static int isicom_chars_in_buffer(struct tty_struct *tty)
1da177e4 1178{
8070e35c 1179 struct isi_port *port = tty->driver_data;
1da177e4
LT
1180 if (isicom_paranoia_check(port, tty->name, "isicom_chars_in_buffer"))
1181 return 0;
1182 return port->xmit_cnt;
1183}
1184
1185/* ioctl et all */
6d889724 1186static int isicom_send_break(struct tty_struct *tty, int length)
1da177e4 1187{
6d889724 1188 struct isi_port *port = tty->driver_data;
d8d16e47 1189 struct isi_board *card = port->card;
8070e35c 1190 unsigned long base = card->base;
d8d16e47 1191
6d889724
AC
1192 if (length == -1)
1193 return -EOPNOTSUPP;
1194
d8d16e47 1195 if (!lock_card(card))
6d889724 1196 return -EINVAL;
d8d16e47 1197
1da177e4
LT
1198 outw(0x8000 | ((port->channel) << (card->shift_count)) | 0x3, base);
1199 outw((length & 0xff) << 8 | 0x00, base);
1200 outw((length & 0xff00), base);
1201 InterruptTheCard(base);
1202
1203 unlock_card(card);
6d889724 1204 return 0;
1da177e4
LT
1205}
1206
1207static int isicom_tiocmget(struct tty_struct *tty, struct file *file)
1208{
8070e35c 1209 struct isi_port *port = tty->driver_data;
1da177e4 1210 /* just send the port status */
8070e35c 1211 u16 status = port->status;
1da177e4
LT
1212
1213 if (isicom_paranoia_check(port, tty->name, "isicom_ioctl"))
1214 return -ENODEV;
d8d16e47 1215
1da177e4
LT
1216 return ((status & ISI_RTS) ? TIOCM_RTS : 0) |
1217 ((status & ISI_DTR) ? TIOCM_DTR : 0) |
1218 ((status & ISI_DCD) ? TIOCM_CAR : 0) |
1219 ((status & ISI_DSR) ? TIOCM_DSR : 0) |
1220 ((status & ISI_CTS) ? TIOCM_CTS : 0) |
1221 ((status & ISI_RI ) ? TIOCM_RI : 0);
1222}
1223
1224static int isicom_tiocmset(struct tty_struct *tty, struct file *file,
d8d16e47 1225 unsigned int set, unsigned int clear)
1da177e4 1226{
8070e35c 1227 struct isi_port *port = tty->driver_data;
cfe7c09a 1228 unsigned long flags;
d8d16e47 1229
1da177e4
LT
1230 if (isicom_paranoia_check(port, tty->name, "isicom_ioctl"))
1231 return -ENODEV;
d8d16e47 1232
cfe7c09a 1233 spin_lock_irqsave(&port->card->card_lock, flags);
1da177e4
LT
1234 if (set & TIOCM_RTS)
1235 raise_rts(port);
1236 if (set & TIOCM_DTR)
1237 raise_dtr(port);
1238
1239 if (clear & TIOCM_RTS)
1240 drop_rts(port);
1241 if (clear & TIOCM_DTR)
1242 drop_dtr(port);
cfe7c09a 1243 spin_unlock_irqrestore(&port->card->card_lock, flags);
1da177e4
LT
1244
1245 return 0;
d8d16e47 1246}
1da177e4 1247
d450b5a0
AC
1248static int isicom_set_serial_info(struct tty_struct *tty,
1249 struct serial_struct __user *info)
1da177e4 1250{
d450b5a0 1251 struct isi_port *port = tty->driver_data;
1da177e4
LT
1252 struct serial_struct newinfo;
1253 int reconfig_port;
1254
d8d16e47 1255 if (copy_from_user(&newinfo, info, sizeof(newinfo)))
1da177e4 1256 return -EFAULT;
d8d16e47 1257
1eac4947
AC
1258 lock_kernel();
1259
f1d03228 1260 reconfig_port = ((port->port.flags & ASYNC_SPD_MASK) !=
d8d16e47
JS
1261 (newinfo.flags & ASYNC_SPD_MASK));
1262
1da177e4 1263 if (!capable(CAP_SYS_ADMIN)) {
44b7d1b3
AC
1264 if ((newinfo.close_delay != port->port.close_delay) ||
1265 (newinfo.closing_wait != port->port.closing_wait) ||
d8d16e47 1266 ((newinfo.flags & ~ASYNC_USR_MASK) !=
f1d03228 1267 (port->port.flags & ~ASYNC_USR_MASK))) {
1eac4947 1268 unlock_kernel();
1da177e4 1269 return -EPERM;
1eac4947 1270 }
f1d03228 1271 port->port.flags = ((port->port.flags & ~ASYNC_USR_MASK) |
1da177e4 1272 (newinfo.flags & ASYNC_USR_MASK));
251b8dd7 1273 } else {
44b7d1b3
AC
1274 port->port.close_delay = newinfo.close_delay;
1275 port->port.closing_wait = newinfo.closing_wait;
f1d03228 1276 port->port.flags = ((port->port.flags & ~ASYNC_FLAGS) |
1da177e4
LT
1277 (newinfo.flags & ASYNC_FLAGS));
1278 }
1279 if (reconfig_port) {
cfe7c09a
JS
1280 unsigned long flags;
1281 spin_lock_irqsave(&port->card->card_lock, flags);
d450b5a0 1282 isicom_config_port(tty);
cfe7c09a 1283 spin_unlock_irqrestore(&port->card->card_lock, flags);
1da177e4 1284 }
1eac4947 1285 unlock_kernel();
d8d16e47
JS
1286 return 0;
1287}
1da177e4 1288
d8d16e47
JS
1289static int isicom_get_serial_info(struct isi_port *port,
1290 struct serial_struct __user *info)
1da177e4
LT
1291{
1292 struct serial_struct out_info;
d8d16e47 1293
1eac4947 1294 lock_kernel();
1da177e4
LT
1295 memset(&out_info, 0, sizeof(out_info));
1296/* out_info.type = ? */
1297 out_info.line = port - isi_ports;
1298 out_info.port = port->card->base;
1299 out_info.irq = port->card->irq;
f1d03228 1300 out_info.flags = port->port.flags;
1da177e4 1301/* out_info.baud_base = ? */
44b7d1b3
AC
1302 out_info.close_delay = port->port.close_delay;
1303 out_info.closing_wait = port->port.closing_wait;
1eac4947 1304 unlock_kernel();
d8d16e47 1305 if (copy_to_user(info, &out_info, sizeof(out_info)))
1da177e4
LT
1306 return -EFAULT;
1307 return 0;
d8d16e47 1308}
1da177e4 1309
d8d16e47
JS
1310static int isicom_ioctl(struct tty_struct *tty, struct file *filp,
1311 unsigned int cmd, unsigned long arg)
1da177e4 1312{
8070e35c 1313 struct isi_port *port = tty->driver_data;
1da177e4 1314 void __user *argp = (void __user *)arg;
1da177e4
LT
1315
1316 if (isicom_paranoia_check(port, tty->name, "isicom_ioctl"))
1317 return -ENODEV;
1318
251b8dd7 1319 switch (cmd) {
d8d16e47
JS
1320 case TIOCGSERIAL:
1321 return isicom_get_serial_info(port, argp);
1322
1323 case TIOCSSERIAL:
d450b5a0 1324 return isicom_set_serial_info(tty, argp);
d8d16e47
JS
1325
1326 default:
1327 return -ENOIOCTLCMD;
1da177e4
LT
1328 }
1329 return 0;
1330}
1331
1332/* set_termios et all */
d8d16e47 1333static void isicom_set_termios(struct tty_struct *tty,
606d099c 1334 struct ktermios *old_termios)
1da177e4 1335{
8070e35c 1336 struct isi_port *port = tty->driver_data;
cfe7c09a 1337 unsigned long flags;
d8d16e47 1338
1da177e4
LT
1339 if (isicom_paranoia_check(port, tty->name, "isicom_set_termios"))
1340 return;
d8d16e47 1341
1da177e4 1342 if (tty->termios->c_cflag == old_termios->c_cflag &&
d8d16e47 1343 tty->termios->c_iflag == old_termios->c_iflag)
1da177e4 1344 return;
d8d16e47 1345
cfe7c09a 1346 spin_lock_irqsave(&port->card->card_lock, flags);
d450b5a0 1347 isicom_config_port(tty);
cfe7c09a 1348 spin_unlock_irqrestore(&port->card->card_lock, flags);
d8d16e47 1349
1da177e4 1350 if ((old_termios->c_cflag & CRTSCTS) &&
d8d16e47 1351 !(tty->termios->c_cflag & CRTSCTS)) {
1da177e4 1352 tty->hw_stopped = 0;
d8d16e47
JS
1353 isicom_start(tty);
1354 }
1da177e4
LT
1355}
1356
1357/* throttle et all */
d8d16e47 1358static void isicom_throttle(struct tty_struct *tty)
1da177e4 1359{
8070e35c 1360 struct isi_port *port = tty->driver_data;
d8d16e47
JS
1361 struct isi_board *card = port->card;
1362
1da177e4
LT
1363 if (isicom_paranoia_check(port, tty->name, "isicom_throttle"))
1364 return;
d8d16e47 1365
1da177e4
LT
1366 /* tell the card that this port cannot handle any more data for now */
1367 card->port_status &= ~(1 << port->channel);
1368 outw(card->port_status, card->base + 0x02);
1369}
1370
1371/* unthrottle et all */
d8d16e47 1372static void isicom_unthrottle(struct tty_struct *tty)
1da177e4 1373{
8070e35c 1374 struct isi_port *port = tty->driver_data;
d8d16e47
JS
1375 struct isi_board *card = port->card;
1376
1da177e4
LT
1377 if (isicom_paranoia_check(port, tty->name, "isicom_unthrottle"))
1378 return;
d8d16e47 1379
1da177e4
LT
1380 /* tell the card that this port is ready to accept more data */
1381 card->port_status |= (1 << port->channel);
1382 outw(card->port_status, card->base + 0x02);
1383}
1384
1385/* stop et all */
d8d16e47 1386static void isicom_stop(struct tty_struct *tty)
1da177e4 1387{
8070e35c 1388 struct isi_port *port = tty->driver_data;
1da177e4
LT
1389
1390 if (isicom_paranoia_check(port, tty->name, "isicom_stop"))
1391 return;
d8d16e47 1392
1da177e4
LT
1393 /* this tells the transmitter not to consider this port for
1394 data output to the card. */
1395 port->status &= ~ISI_TXOK;
1396}
1397
1398/* start et all */
d8d16e47 1399static void isicom_start(struct tty_struct *tty)
1da177e4 1400{
8070e35c 1401 struct isi_port *port = tty->driver_data;
d8d16e47 1402
1da177e4
LT
1403 if (isicom_paranoia_check(port, tty->name, "isicom_start"))
1404 return;
d8d16e47 1405
1da177e4
LT
1406 /* this tells the transmitter to consider this port for
1407 data output to the card. */
1408 port->status |= ISI_TXOK;
1409}
1410
d8d16e47 1411static void isicom_hangup(struct tty_struct *tty)
1da177e4 1412{
8070e35c 1413 struct isi_port *port = tty->driver_data;
cfe7c09a 1414 unsigned long flags;
d8d16e47 1415
1da177e4
LT
1416 if (isicom_paranoia_check(port, tty->name, "isicom_hangup"))
1417 return;
d8d16e47 1418
cfe7c09a 1419 spin_lock_irqsave(&port->card->card_lock, flags);
1da177e4 1420 isicom_shutdown_port(port);
cfe7c09a
JS
1421 spin_unlock_irqrestore(&port->card->card_lock, flags);
1422
f1d03228
AC
1423 port->port.count = 0;
1424 port->port.flags &= ~ASYNC_NORMAL_ACTIVE;
d450b5a0 1425 tty_port_tty_set(&port->port, NULL);
f1d03228 1426 wake_up_interruptible(&port->port.open_wait);
1da177e4
LT
1427}
1428
1da177e4 1429
9ac0948b
JS
1430/*
1431 * Driver init and deinit functions
1432 */
1da177e4 1433
b68e31d0 1434static const struct tty_operations isicom_ops = {
d8d16e47
JS
1435 .open = isicom_open,
1436 .close = isicom_close,
1437 .write = isicom_write,
1438 .put_char = isicom_put_char,
1439 .flush_chars = isicom_flush_chars,
1440 .write_room = isicom_write_room,
1da177e4 1441 .chars_in_buffer = isicom_chars_in_buffer,
d8d16e47
JS
1442 .ioctl = isicom_ioctl,
1443 .set_termios = isicom_set_termios,
1444 .throttle = isicom_throttle,
1445 .unthrottle = isicom_unthrottle,
1446 .stop = isicom_stop,
1447 .start = isicom_start,
1448 .hangup = isicom_hangup,
1449 .flush_buffer = isicom_flush_buffer,
1450 .tiocmget = isicom_tiocmget,
1451 .tiocmset = isicom_tiocmset,
6d889724 1452 .break_ctl = isicom_send_break,
1da177e4
LT
1453};
1454
9ac0948b
JS
1455static int __devinit reset_card(struct pci_dev *pdev,
1456 const unsigned int card, unsigned int *signature)
1da177e4 1457{
9ac0948b
JS
1458 struct isi_board *board = pci_get_drvdata(pdev);
1459 unsigned long base = board->base;
f0a0ba6d 1460 unsigned int sig, portcount = 0;
9ac0948b 1461 int retval = 0;
d8d16e47 1462
9ac0948b
JS
1463 dev_dbg(&pdev->dev, "ISILoad:Resetting Card%d at 0x%lx\n", card + 1,
1464 base);
d8d16e47 1465
9ac0948b 1466 inw(base + 0x8);
d8d16e47 1467
f0a0ba6d 1468 msleep(10);
9ac0948b
JS
1469
1470 outw(0, base + 0x8); /* Reset */
1471
f0a0ba6d 1472 msleep(1000);
9ac0948b 1473
f0a0ba6d
JS
1474 sig = inw(base + 0x4) & 0xff;
1475
1476 if (sig != 0xa5 && sig != 0xbb && sig != 0xcc && sig != 0xdd &&
1477 sig != 0xee) {
1478 dev_warn(&pdev->dev, "ISILoad:Card%u reset failure (Possible "
1479 "bad I/O Port Address 0x%lx).\n", card + 1, base);
1480 dev_dbg(&pdev->dev, "Sig=0x%x\n", sig);
1481 retval = -EIO;
1482 goto end;
1483 }
1484
1485 msleep(10);
9ac0948b 1486
18234f88 1487 portcount = inw(base + 0x2);
07fb6f26 1488 if (!(inw(base + 0xe) & 0x1) || (portcount != 0 && portcount != 4 &&
f0a0ba6d 1489 portcount != 8 && portcount != 16)) {
898eb71c 1490 dev_err(&pdev->dev, "ISILoad:PCI Card%d reset failure.\n",
f0a0ba6d 1491 card + 1);
18234f88
JS
1492 retval = -EIO;
1493 goto end;
9ac0948b
JS
1494 }
1495
f0a0ba6d 1496 switch (sig) {
9ac0948b
JS
1497 case 0xa5:
1498 case 0xbb:
1499 case 0xdd:
18234f88 1500 board->port_count = (portcount == 4) ? 4 : 8;
9ac0948b
JS
1501 board->shift_count = 12;
1502 break;
1503 case 0xcc:
f0a0ba6d 1504 case 0xee:
9ac0948b
JS
1505 board->port_count = 16;
1506 board->shift_count = 11;
1507 break;
d8d16e47 1508 }
9ac0948b 1509 dev_info(&pdev->dev, "-Done\n");
f0a0ba6d 1510 *signature = sig;
d8d16e47 1511
9ac0948b
JS
1512end:
1513 return retval;
1da177e4
LT
1514}
1515
e65c1db1
JS
1516static int __devinit load_firmware(struct pci_dev *pdev,
1517 const unsigned int index, const unsigned int signature)
1518{
1519 struct isi_board *board = pci_get_drvdata(pdev);
1520 const struct firmware *fw;
1521 unsigned long base = board->base;
1522 unsigned int a;
1523 u16 word_count, status;
1524 int retval = -EIO;
1525 char *name;
1526 u8 *data;
1527
1528 struct stframe {
1529 u16 addr;
1530 u16 count;
1531 u8 data[0];
1532 } *frame;
1533
1534 switch (signature) {
1535 case 0xa5:
1536 name = "isi608.bin";
1537 break;
1538 case 0xbb:
1539 name = "isi608em.bin";
1540 break;
1541 case 0xcc:
1542 name = "isi616em.bin";
1543 break;
1544 case 0xdd:
1545 name = "isi4608.bin";
1546 break;
1547 case 0xee:
1548 name = "isi4616.bin";
1549 break;
1550 default:
1551 dev_err(&pdev->dev, "Unknown signature.\n");
1552 goto end;
251b8dd7 1553 }
e65c1db1
JS
1554
1555 retval = request_firmware(&fw, name, &pdev->dev);
1556 if (retval)
1557 goto end;
1558
e4e04088
JS
1559 retval = -EIO;
1560
e65c1db1
JS
1561 for (frame = (struct stframe *)fw->data;
1562 frame < (struct stframe *)(fw->data + fw->size);
e4e04088
JS
1563 frame = (struct stframe *)((u8 *)(frame + 1) +
1564 frame->count)) {
e65c1db1
JS
1565 if (WaitTillCardIsFree(base))
1566 goto errrelfw;
1567
1568 outw(0xf0, base); /* start upload sequence */
1569 outw(0x00, base);
1570 outw(frame->addr, base); /* lsb of address */
1571
1572 word_count = frame->count / 2 + frame->count % 2;
1573 outw(word_count, base);
1574 InterruptTheCard(base);
1575
1576 udelay(100); /* 0x2f */
1577
1578 if (WaitTillCardIsFree(base))
1579 goto errrelfw;
1580
251b8dd7
AC
1581 status = inw(base + 0x4);
1582 if (status != 0) {
e65c1db1 1583 dev_warn(&pdev->dev, "Card%d rejected load header:\n"
898eb71c
JP
1584 KERN_WARNING "Address:0x%x\n"
1585 KERN_WARNING "Count:0x%x\n"
1586 KERN_WARNING "Status:0x%x\n",
e65c1db1
JS
1587 index + 1, frame->addr, frame->count, status);
1588 goto errrelfw;
1589 }
1590 outsw(base, frame->data, word_count);
1591
1592 InterruptTheCard(base);
1593
1594 udelay(50); /* 0x0f */
1595
1596 if (WaitTillCardIsFree(base))
1597 goto errrelfw;
1598
251b8dd7
AC
1599 status = inw(base + 0x4);
1600 if (status != 0) {
e65c1db1
JS
1601 dev_err(&pdev->dev, "Card%d got out of sync.Card "
1602 "Status:0x%x\n", index + 1, status);
1603 goto errrelfw;
1604 }
251b8dd7 1605 }
e65c1db1 1606
e65c1db1
JS
1607/* XXX: should we test it by reading it back and comparing with original like
1608 * in load firmware package? */
e4e04088
JS
1609 for (frame = (struct stframe *)fw->data;
1610 frame < (struct stframe *)(fw->data + fw->size);
1611 frame = (struct stframe *)((u8 *)(frame + 1) +
1612 frame->count)) {
e65c1db1
JS
1613 if (WaitTillCardIsFree(base))
1614 goto errrelfw;
1615
1616 outw(0xf1, base); /* start download sequence */
1617 outw(0x00, base);
1618 outw(frame->addr, base); /* lsb of address */
1619
1620 word_count = (frame->count >> 1) + frame->count % 2;
1621 outw(word_count + 1, base);
1622 InterruptTheCard(base);
1623
1624 udelay(50); /* 0xf */
1625
1626 if (WaitTillCardIsFree(base))
1627 goto errrelfw;
1628
251b8dd7
AC
1629 status = inw(base + 0x4);
1630 if (status != 0) {
e65c1db1 1631 dev_warn(&pdev->dev, "Card%d rejected verify header:\n"
898eb71c
JP
1632 KERN_WARNING "Address:0x%x\n"
1633 KERN_WARNING "Count:0x%x\n"
1634 KERN_WARNING "Status: 0x%x\n",
e65c1db1
JS
1635 index + 1, frame->addr, frame->count, status);
1636 goto errrelfw;
1637 }
1638
1639 data = kmalloc(word_count * 2, GFP_KERNEL);
f0671378
JS
1640 if (data == NULL) {
1641 dev_err(&pdev->dev, "Card%d, firmware upload "
1642 "failed, not enough memory\n", index + 1);
1643 goto errrelfw;
1644 }
e65c1db1
JS
1645 inw(base);
1646 insw(base, data, word_count);
1647 InterruptTheCard(base);
1648
1649 for (a = 0; a < frame->count; a++)
1650 if (data[a] != frame->data[a]) {
1651 kfree(data);
1652 dev_err(&pdev->dev, "Card%d, firmware upload "
1653 "failed\n", index + 1);
1654 goto errrelfw;
1655 }
1656 kfree(data);
1657
1658 udelay(50); /* 0xf */
1659
1660 if (WaitTillCardIsFree(base))
1661 goto errrelfw;
1662
251b8dd7
AC
1663 status = inw(base + 0x4);
1664 if (status != 0) {
e65c1db1
JS
1665 dev_err(&pdev->dev, "Card%d verify got out of sync. "
1666 "Card Status:0x%x\n", index + 1, status);
1667 goto errrelfw;
1668 }
1669 }
1670
e4e04088
JS
1671 /* xfer ctrl */
1672 if (WaitTillCardIsFree(base))
1673 goto errrelfw;
1674
1675 outw(0xf2, base);
1676 outw(0x800, base);
1677 outw(0x0, base);
1678 outw(0x0, base);
1679 InterruptTheCard(base);
1680 outw(0x0, base + 0x4); /* for ISI4608 cards */
1681
e65c1db1
JS
1682 board->status |= FIRMWARE_LOADED;
1683 retval = 0;
1684
1685errrelfw:
1686 release_firmware(fw);
1687end:
1688 return retval;
1689}
1690
1da177e4
LT
1691/*
1692 * Insmod can set static symbols so keep these static
1693 */
1ed0c0b7 1694static unsigned int card_count;
9ac0948b
JS
1695
1696static int __devinit isicom_probe(struct pci_dev *pdev,
1697 const struct pci_device_id *ent)
1698{
4969b3a4 1699 unsigned int signature, index;
9ac0948b 1700 int retval = -EPERM;
9ac0948b
JS
1701 struct isi_board *board = NULL;
1702
1ed0c0b7 1703 if (card_count >= BOARD_COUNT)
9ac0948b
JS
1704 goto err;
1705
e1e5770b
JS
1706 retval = pci_enable_device(pdev);
1707 if (retval) {
1708 dev_err(&pdev->dev, "failed to enable\n");
1709 goto err;
1710 }
1711
9ac0948b
JS
1712 dev_info(&pdev->dev, "ISI PCI Card(Device ID 0x%x)\n", ent->device);
1713
1714 /* allot the first empty slot in the array */
1715 for (index = 0; index < BOARD_COUNT; index++)
1716 if (isi_card[index].base == 0) {
1717 board = &isi_card[index];
1718 break;
1719 }
1720
938a7023 1721 board->index = index;
4969b3a4
JS
1722 board->base = pci_resource_start(pdev, 3);
1723 board->irq = pdev->irq;
1ed0c0b7 1724 card_count++;
9ac0948b
JS
1725
1726 pci_set_drvdata(pdev, board);
1727
78028da9
JS
1728 retval = pci_request_region(pdev, 3, ISICOM_NAME);
1729 if (retval) {
09a4a112
JS
1730 dev_err(&pdev->dev, "I/O Region 0x%lx-0x%lx is busy. Card%d "
1731 "will be disabled.\n", board->base, board->base + 15,
1732 index + 1);
1733 retval = -EBUSY;
1ed0c0b7 1734 goto errdec;
251b8dd7 1735 }
9ac0948b 1736
09a4a112
JS
1737 retval = request_irq(board->irq, isicom_interrupt,
1738 IRQF_SHARED | IRQF_DISABLED, ISICOM_NAME, board);
1739 if (retval < 0) {
1740 dev_err(&pdev->dev, "Could not install handler at Irq %d. "
1741 "Card%d will be disabled.\n", board->irq, index + 1);
9ac0948b 1742 goto errunrr;
09a4a112 1743 }
9ac0948b
JS
1744
1745 retval = reset_card(pdev, index, &signature);
1746 if (retval < 0)
1747 goto errunri;
1748
e65c1db1
JS
1749 retval = load_firmware(pdev, index, signature);
1750 if (retval < 0)
1751 goto errunri;
1752
938a7023
JS
1753 for (index = 0; index < board->port_count; index++)
1754 tty_register_device(isicom_normal, board->index * 16 + index,
1755 &pdev->dev);
1756
9ac0948b
JS
1757 return 0;
1758
1759errunri:
1760 free_irq(board->irq, board);
1761errunrr:
78028da9 1762 pci_release_region(pdev, 3);
1ed0c0b7 1763errdec:
9ac0948b 1764 board->base = 0;
1ed0c0b7 1765 card_count--;
e1e5770b 1766 pci_disable_device(pdev);
1ed0c0b7 1767err:
9ac0948b
JS
1768 return retval;
1769}
1770
1771static void __devexit isicom_remove(struct pci_dev *pdev)
1772{
1773 struct isi_board *board = pci_get_drvdata(pdev);
938a7023
JS
1774 unsigned int i;
1775
1776 for (i = 0; i < board->port_count; i++)
1777 tty_unregister_device(isicom_normal, board->index * 16 + i);
9ac0948b
JS
1778
1779 free_irq(board->irq, board);
78028da9 1780 pci_release_region(pdev, 3);
1ed0c0b7
JS
1781 board->base = 0;
1782 card_count--;
e1e5770b 1783 pci_disable_device(pdev);
9ac0948b 1784}
1da177e4 1785
ca262005 1786static int __init isicom_init(void)
1da177e4 1787{
9ac0948b
JS
1788 int retval, idx, channel;
1789 struct isi_port *port;
d8d16e47 1790
251b8dd7 1791 for (idx = 0; idx < BOARD_COUNT; idx++) {
9ac0948b
JS
1792 port = &isi_ports[idx * 16];
1793 isi_card[idx].ports = port;
1794 spin_lock_init(&isi_card[idx].card_lock);
1795 for (channel = 0; channel < 16; channel++, port++) {
44b7d1b3 1796 tty_port_init(&port->port);
9ac0948b
JS
1797 port->magic = ISICOM_MAGIC;
1798 port->card = &isi_card[idx];
1799 port->channel = channel;
44b7d1b3
AC
1800 port->port.close_delay = 50 * HZ/100;
1801 port->port.closing_wait = 3000 * HZ/100;
9ac0948b 1802 port->status = 0;
9ac0948b 1803 /* . . . */
251b8dd7 1804 }
9ac0948b
JS
1805 isi_card[idx].base = 0;
1806 isi_card[idx].irq = 0;
1da177e4 1807 }
d8d16e47 1808
09a4a112
JS
1809 /* tty driver structure initialization */
1810 isicom_normal = alloc_tty_driver(PORT_COUNT);
1811 if (!isicom_normal) {
1812 retval = -ENOMEM;
9ac0948b 1813 goto error;
09a4a112
JS
1814 }
1815
1816 isicom_normal->owner = THIS_MODULE;
1817 isicom_normal->name = "ttyM";
1818 isicom_normal->major = ISICOM_NMAJOR;
1819 isicom_normal->minor_start = 0;
1820 isicom_normal->type = TTY_DRIVER_TYPE_SERIAL;
1821 isicom_normal->subtype = SERIAL_TYPE_NORMAL;
1822 isicom_normal->init_termios = tty_std_termios;
1823 isicom_normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL |
1824 CLOCAL;
938a7023 1825 isicom_normal->flags = TTY_DRIVER_REAL_RAW |
6d889724 1826 TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_HARDWARE_BREAK;
09a4a112
JS
1827 tty_set_operations(isicom_normal, &isicom_ops);
1828
1829 retval = tty_register_driver(isicom_normal);
1830 if (retval) {
1831 pr_dbg("Couldn't register the dialin driver\n");
1832 goto err_puttty;
1833 }
1da177e4 1834
9ac0948b 1835 retval = pci_register_driver(&isicom_driver);
1da177e4 1836 if (retval < 0) {
9ac0948b 1837 printk(KERN_ERR "ISICOM: Unable to register pci driver.\n");
09a4a112 1838 goto err_unrtty;
1da177e4 1839 }
d8d16e47 1840
34b55b86 1841 mod_timer(&tx, jiffies + 1);
d8d16e47 1842
1da177e4 1843 return 0;
09a4a112
JS
1844err_unrtty:
1845 tty_unregister_driver(isicom_normal);
1846err_puttty:
1847 put_tty_driver(isicom_normal);
9ac0948b
JS
1848error:
1849 return retval;
1da177e4
LT
1850}
1851
1852static void __exit isicom_exit(void)
1853{
e327325f 1854 del_timer_sync(&tx);
aaa246ea 1855
9ac0948b 1856 pci_unregister_driver(&isicom_driver);
09a4a112
JS
1857 tty_unregister_driver(isicom_normal);
1858 put_tty_driver(isicom_normal);
1da177e4
LT
1859}
1860
ca262005 1861module_init(isicom_init);
1da177e4 1862module_exit(isicom_exit);
aaa246ea
JS
1863
1864MODULE_AUTHOR("MultiTech");
1865MODULE_DESCRIPTION("Driver for the ISI series of cards by MultiTech");
1866MODULE_LICENSE("GPL");