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