x86: make headers files the same in io_apic_xx.c
[deliverable/linux.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
d450b5a0
AC
424 tty = tty_port_tty_get(&port->port);
425 if (tty == NULL)
426 goto put_unlock;
427
251b8dd7 428 for (; count > 0; count--, port++) {
1da177e4 429 /* port not active or tx disabled to force flow control */
f1d03228 430 if (!(port->port.flags & ASYNC_INITIALIZED) ||
d8d16e47 431 !(port->status & ISI_TXOK))
1da177e4 432 continue;
d8d16e47 433
1da177e4 434 txcount = min_t(short, TX_SIZE, port->xmit_cnt);
5b21f9dd 435 if (txcount <= 0 || tty->stopped || tty->hw_stopped)
1da177e4 436 continue;
5b21f9dd
JS
437
438 if (!(inw(base + 0x02) & (1 << port->channel)))
d8d16e47 439 continue;
5b21f9dd 440
aaa246ea
JS
441 pr_dbg("txing %d bytes, port%d.\n", txcount,
442 port->channel + 1);
443 outw((port->channel << isi_card[card].shift_count) | txcount,
444 base);
1da177e4 445 residue = NO;
d8d16e47 446 wrd = 0;
1da177e4 447 while (1) {
a547dfe9
JS
448 cnt = min_t(int, txcount, (SERIAL_XMIT_SIZE
449 - port->xmit_tail));
1da177e4
LT
450 if (residue == YES) {
451 residue = NO;
452 if (cnt > 0) {
f1d03228 453 wrd |= (port->port.xmit_buf[port->xmit_tail]
a547dfe9
JS
454 << 8);
455 port->xmit_tail = (port->xmit_tail + 1)
456 & (SERIAL_XMIT_SIZE - 1);
1da177e4
LT
457 port->xmit_cnt--;
458 txcount--;
459 cnt--;
d8d16e47 460 outw(wrd, base);
a547dfe9 461 } else {
1da177e4
LT
462 outw(wrd, base);
463 break;
464 }
d8d16e47 465 }
251b8dd7
AC
466 if (cnt <= 0)
467 break;
1da177e4 468 word_count = cnt >> 1;
f1d03228 469 outsw(base, port->port.xmit_buf+port->xmit_tail, word_count);
a547dfe9
JS
470 port->xmit_tail = (port->xmit_tail
471 + (word_count << 1)) & (SERIAL_XMIT_SIZE - 1);
1da177e4
LT
472 txcount -= (word_count << 1);
473 port->xmit_cnt -= (word_count << 1);
474 if (cnt & 0x0001) {
475 residue = YES;
f1d03228 476 wrd = port->port.xmit_buf[port->xmit_tail];
a547dfe9
JS
477 port->xmit_tail = (port->xmit_tail + 1)
478 & (SERIAL_XMIT_SIZE - 1);
1da177e4
LT
479 port->xmit_cnt--;
480 txcount--;
481 }
482 }
483
484 InterruptTheCard(base);
485 if (port->xmit_cnt <= 0)
486 port->status &= ~ISI_TXOK;
487 if (port->xmit_cnt <= WAKEUP_CHARS)
0aa5de85 488 tty_wakeup(tty);
d8d16e47 489 }
1da177e4 490
d450b5a0
AC
491put_unlock:
492 tty_kref_put(tty);
5b21f9dd
JS
493unlock:
494 spin_unlock_irqrestore(&isi_card[card].card_lock, flags);
d8d16e47
JS
495 /* schedule another tx for hopefully in about 10ms */
496sched_again:
34b55b86 497 mod_timer(&tx, jiffies + msecs_to_jiffies(10));
d8d16e47
JS
498}
499
1da177e4 500/*
d8d16e47 501 * Main interrupt handler routine
1da177e4 502 */
d8d16e47 503
7d12e780 504static irqreturn_t isicom_interrupt(int irq, void *dev_id)
1da177e4 505{
8070e35c 506 struct isi_board *card = dev_id;
d8d16e47
JS
507 struct isi_port *port;
508 struct tty_struct *tty;
8070e35c
JS
509 unsigned long base;
510 u16 header, word_count, count, channel;
1da177e4 511 short byte_count;
33f0f88f 512 unsigned char *rp;
d8d16e47 513
1da177e4
LT
514 if (!card || !(card->status & FIRMWARE_LOADED))
515 return IRQ_NONE;
d8d16e47 516
1da177e4 517 base = card->base;
cb4a10cc
JS
518
519 /* did the card interrupt us? */
520 if (!(inw(base + 0x0e) & 0x02))
521 return IRQ_NONE;
522
1da177e4 523 spin_lock(&card->card_lock);
d8d16e47 524
18234f88
JS
525 /*
526 * disable any interrupts from the PCI card and lower the
527 * interrupt line
528 */
529 outw(0x8000, base+0x04);
530 ClearInterrupt(base);
d8d16e47 531
1da177e4
LT
532 inw(base); /* get the dummy word out */
533 header = inw(base);
534 channel = (header & 0x7800) >> card->shift_count;
535 byte_count = header & 0xff;
536
537 if (channel + 1 > card->port_count) {
a547dfe9
JS
538 printk(KERN_WARNING "ISICOM: isicom_interrupt(0x%lx): "
539 "%d(channel) > port_count.\n", base, channel+1);
18234f88 540 outw(0x0000, base+0x04); /* enable interrupts */
1da177e4 541 spin_unlock(&card->card_lock);
d8d16e47 542 return IRQ_HANDLED;
1da177e4
LT
543 }
544 port = card->ports + channel;
f1d03228 545 if (!(port->port.flags & ASYNC_INITIALIZED)) {
18234f88 546 outw(0x0000, base+0x04); /* enable interrupts */
174f1307 547 spin_unlock(&card->card_lock);
1da177e4 548 return IRQ_HANDLED;
d8d16e47
JS
549 }
550
d450b5a0 551 tty = tty_port_tty_get(&port->port);
1da177e4
LT
552 if (tty == NULL) {
553 word_count = byte_count >> 1;
251b8dd7 554 while (byte_count > 1) {
1da177e4
LT
555 inw(base);
556 byte_count -= 2;
557 }
558 if (byte_count & 0x01)
559 inw(base);
18234f88 560 outw(0x0000, base+0x04); /* enable interrupts */
1da177e4
LT
561 spin_unlock(&card->card_lock);
562 return IRQ_HANDLED;
563 }
d8d16e47 564
1da177e4
LT
565 if (header & 0x8000) { /* Status Packet */
566 header = inw(base);
251b8dd7 567 switch (header & 0xff) {
d8d16e47 568 case 0: /* Change in EIA signals */
f1d03228 569 if (port->port.flags & ASYNC_CHECK_CD) {
d8d16e47
JS
570 if (port->status & ISI_DCD) {
571 if (!(header & ISI_DCD)) {
572 /* Carrier has been lost */
a547dfe9
JS
573 pr_dbg("interrupt: DCD->low.\n"
574 );
d8d16e47 575 port->status &= ~ISI_DCD;
0aa5de85 576 tty_hangup(tty);
1da177e4 577 }
a547dfe9
JS
578 } else if (header & ISI_DCD) {
579 /* Carrier has been detected */
580 pr_dbg("interrupt: DCD->high.\n");
581 port->status |= ISI_DCD;
f1d03228 582 wake_up_interruptible(&port->port.open_wait);
1da177e4 583 }
a547dfe9 584 } else {
d8d16e47
JS
585 if (header & ISI_DCD)
586 port->status |= ISI_DCD;
587 else
588 port->status &= ~ISI_DCD;
589 }
590
f1d03228 591 if (port->port.flags & ASYNC_CTS_FLOW) {
d450b5a0 592 if (tty->hw_stopped) {
d8d16e47 593 if (header & ISI_CTS) {
f1d03228 594 port->port.tty->hw_stopped = 0;
d8d16e47 595 /* start tx ing */
a547dfe9
JS
596 port->status |= (ISI_TXOK
597 | ISI_CTS);
0aa5de85 598 tty_wakeup(tty);
1da177e4 599 }
a547dfe9 600 } else if (!(header & ISI_CTS)) {
d450b5a0 601 tty->hw_stopped = 1;
a547dfe9
JS
602 /* stop tx ing */
603 port->status &= ~(ISI_TXOK | ISI_CTS);
1da177e4 604 }
a547dfe9 605 } else {
d8d16e47
JS
606 if (header & ISI_CTS)
607 port->status |= ISI_CTS;
1da177e4 608 else
d8d16e47
JS
609 port->status &= ~ISI_CTS;
610 }
611
612 if (header & ISI_DSR)
613 port->status |= ISI_DSR;
614 else
615 port->status &= ~ISI_DSR;
616
617 if (header & ISI_RI)
618 port->status |= ISI_RI;
619 else
620 port->status &= ~ISI_RI;
621
622 break;
623
a547dfe9 624 case 1: /* Received Break !!! */
d8d16e47 625 tty_insert_flip_char(tty, 0, TTY_BREAK);
f1d03228 626 if (port->port.flags & ASYNC_SAK)
d8d16e47
JS
627 do_SAK(tty);
628 tty_flip_buffer_push(tty);
629 break;
630
631 case 2: /* Statistics */
aaa246ea 632 pr_dbg("isicom_interrupt: stats!!!.\n");
d8d16e47
JS
633 break;
634
635 default:
aaa246ea 636 pr_dbg("Intr: Unknown code in status packet.\n");
d8d16e47
JS
637 break;
638 }
a547dfe9 639 } else { /* Data Packet */
33f0f88f
AC
640
641 count = tty_prepare_flip_string(tty, &rp, byte_count & ~1);
aaa246ea 642 pr_dbg("Intr: Can rx %d of %d bytes.\n", count, byte_count);
1da177e4 643 word_count = count >> 1;
33f0f88f 644 insw(base, rp, word_count);
1da177e4
LT
645 byte_count -= (word_count << 1);
646 if (count & 0x0001) {
a547dfe9
JS
647 tty_insert_flip_char(tty, inw(base) & 0xff,
648 TTY_NORMAL);
1da177e4 649 byte_count -= 2;
d8d16e47 650 }
1da177e4 651 if (byte_count > 0) {
aaa246ea
JS
652 pr_dbg("Intr(0x%lx:%d): Flip buffer overflow! dropping "
653 "bytes...\n", base, channel + 1);
251b8dd7
AC
654 /* drain out unread xtra data */
655 while (byte_count > 0) {
1da177e4
LT
656 inw(base);
657 byte_count -= 2;
658 }
659 }
33f0f88f 660 tty_flip_buffer_push(tty);
1da177e4 661 }
18234f88 662 outw(0x0000, base+0x04); /* enable interrupts */
174f1307 663 spin_unlock(&card->card_lock);
d450b5a0 664 tty_kref_put(tty);
a547dfe9 665
1da177e4 666 return IRQ_HANDLED;
d8d16e47 667}
1da177e4 668
d450b5a0 669static void isicom_config_port(struct tty_struct *tty)
1da177e4 670{
d450b5a0 671 struct isi_port *port = tty->driver_data;
d8d16e47 672 struct isi_board *card = port->card;
1da177e4 673 unsigned long baud;
8070e35c
JS
674 unsigned long base = card->base;
675 u16 channel_setup, channel = port->channel,
676 shift_count = card->shift_count;
1da177e4 677 unsigned char flow_ctrl;
d8d16e47 678
251b8dd7 679 /* FIXME: Switch to new tty baud API */
1da177e4
LT
680 baud = C_BAUD(tty);
681 if (baud & CBAUDEX) {
682 baud &= ~CBAUDEX;
d8d16e47 683
1da177e4
LT
684 /* if CBAUDEX bit is on and the baud is set to either 50 or 75
685 * then the card is programmed for 57.6Kbps or 115Kbps
686 * respectively.
d8d16e47
JS
687 */
688
7edc136a
JS
689 /* 1,2,3,4 => 57.6, 115.2, 230, 460 kbps resp. */
690 if (baud < 1 || baud > 4)
d450b5a0 691 tty->termios->c_cflag &= ~CBAUDEX;
1da177e4
LT
692 else
693 baud += 15;
d8d16e47 694 }
1da177e4 695 if (baud == 15) {
d8d16e47
JS
696
697 /* the ASYNC_SPD_HI and ASYNC_SPD_VHI options are set
1da177e4
LT
698 * by the set_serial_info ioctl ... this is done by
699 * the 'setserial' utility.
d8d16e47
JS
700 */
701
f1d03228 702 if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
d8d16e47 703 baud++; /* 57.6 Kbps */
f1d03228 704 if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
251b8dd7 705 baud += 2; /* 115 Kbps */
f1d03228 706 if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
7edc136a 707 baud += 3; /* 230 kbps*/
f1d03228 708 if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
7edc136a 709 baud += 4; /* 460 kbps*/
1da177e4
LT
710 }
711 if (linuxb_to_isib[baud] == -1) {
712 /* hang up */
d8d16e47
JS
713 drop_dtr(port);
714 return;
251b8dd7 715 } else
1da177e4 716 raise_dtr(port);
d8d16e47 717
cfe7c09a 718 if (WaitTillCardIsFree(base) == 0) {
251b8dd7 719 outw(0x8000 | (channel << shift_count) | 0x03, base);
1da177e4
LT
720 outw(linuxb_to_isib[baud] << 8 | 0x03, base);
721 channel_setup = 0;
251b8dd7 722 switch (C_CSIZE(tty)) {
d8d16e47
JS
723 case CS5:
724 channel_setup |= ISICOM_CS5;
725 break;
726 case CS6:
727 channel_setup |= ISICOM_CS6;
728 break;
729 case CS7:
730 channel_setup |= ISICOM_CS7;
731 break;
732 case CS8:
733 channel_setup |= ISICOM_CS8;
734 break;
1da177e4 735 }
d8d16e47 736
1da177e4
LT
737 if (C_CSTOPB(tty))
738 channel_setup |= ISICOM_2SB;
739 if (C_PARENB(tty)) {
740 channel_setup |= ISICOM_EVPAR;
741 if (C_PARODD(tty))
d8d16e47 742 channel_setup |= ISICOM_ODPAR;
1da177e4 743 }
d8d16e47 744 outw(channel_setup, base);
1da177e4 745 InterruptTheCard(base);
d8d16e47 746 }
1da177e4 747 if (C_CLOCAL(tty))
f1d03228 748 port->port.flags &= ~ASYNC_CHECK_CD;
1da177e4 749 else
f1d03228 750 port->port.flags |= ASYNC_CHECK_CD;
d8d16e47 751
1da177e4
LT
752 /* flow control settings ...*/
753 flow_ctrl = 0;
f1d03228 754 port->port.flags &= ~ASYNC_CTS_FLOW;
1da177e4 755 if (C_CRTSCTS(tty)) {
f1d03228 756 port->port.flags |= ASYNC_CTS_FLOW;
1da177e4 757 flow_ctrl |= ISICOM_CTSRTS;
d8d16e47
JS
758 }
759 if (I_IXON(tty))
1da177e4
LT
760 flow_ctrl |= ISICOM_RESPOND_XONXOFF;
761 if (I_IXOFF(tty))
d8d16e47
JS
762 flow_ctrl |= ISICOM_INITIATE_XONXOFF;
763
cfe7c09a 764 if (WaitTillCardIsFree(base) == 0) {
251b8dd7 765 outw(0x8000 | (channel << shift_count) | 0x04, base);
1da177e4
LT
766 outw(flow_ctrl << 8 | 0x05, base);
767 outw((STOP_CHAR(tty)) << 8 | (START_CHAR(tty)), base);
768 InterruptTheCard(base);
1da177e4 769 }
d8d16e47 770
1da177e4
LT
771 /* rx enabled -> enable port for rx on the card */
772 if (C_CREAD(tty)) {
773 card->port_status |= (1 << channel);
774 outw(card->port_status, base + 0x02);
775 }
776}
1da177e4 777
d8d16e47
JS
778/* open et all */
779
780static inline void isicom_setup_board(struct isi_board *bp)
1da177e4
LT
781{
782 int channel;
d8d16e47 783 struct isi_port *port;
1da177e4 784 unsigned long flags;
d8d16e47 785
1da177e4
LT
786 spin_lock_irqsave(&bp->card_lock, flags);
787 if (bp->status & BOARD_ACTIVE) {
788 spin_unlock_irqrestore(&bp->card_lock, flags);
789 return;
790 }
791 port = bp->ports;
792 bp->status |= BOARD_ACTIVE;
d8d16e47 793 for (channel = 0; channel < bp->port_count; channel++, port++)
1da177e4 794 drop_dtr_rts(port);
cfe7c09a 795 spin_unlock_irqrestore(&bp->card_lock, flags);
1da177e4 796}
d8d16e47 797
d450b5a0 798static int isicom_setup_port(struct tty_struct *tty)
1da177e4 799{
d450b5a0 800 struct isi_port *port = tty->driver_data;
d8d16e47 801 struct isi_board *card = port->card;
1da177e4 802 unsigned long flags;
d8d16e47 803
f1d03228 804 if (port->port.flags & ASYNC_INITIALIZED)
1da177e4 805 return 0;
f1d03228
AC
806 if (tty_port_alloc_xmit_buf(&port->port) < 0)
807 return -ENOMEM;
1da177e4
LT
808
809 spin_lock_irqsave(&card->card_lock, flags);
d450b5a0 810 clear_bit(TTY_IO_ERROR, &tty->flags);
f1d03228 811 if (port->port.count == 1)
1da177e4 812 card->count++;
d8d16e47 813
1da177e4 814 port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
d8d16e47 815
1da177e4 816 /* discard any residual data */
cfe7c09a
JS
817 if (WaitTillCardIsFree(card->base) == 0) {
818 outw(0x8000 | (port->channel << card->shift_count) | 0x02,
819 card->base);
820 outw(((ISICOM_KILLTX | ISICOM_KILLRX) << 8) | 0x06, card->base);
821 InterruptTheCard(card->base);
822 }
d8d16e47 823
d450b5a0 824 isicom_config_port(tty);
f1d03228 825 port->port.flags |= ASYNC_INITIALIZED;
1da177e4 826 spin_unlock_irqrestore(&card->card_lock, flags);
d8d16e47
JS
827
828 return 0;
829}
830
a547dfe9
JS
831static int block_til_ready(struct tty_struct *tty, struct file *filp,
832 struct isi_port *port)
1da177e4 833{
d8d16e47 834 struct isi_board *card = port->card;
1da177e4
LT
835 int do_clocal = 0, retval;
836 unsigned long flags;
837 DECLARE_WAITQUEUE(wait, current);
838
839 /* block if port is in the process of being closed */
840
f1d03228 841 if (tty_hung_up_p(filp) || port->port.flags & ASYNC_CLOSING) {
aaa246ea 842 pr_dbg("block_til_ready: close in progress.\n");
f1d03228
AC
843 interruptible_sleep_on(&port->port.close_wait);
844 if (port->port.flags & ASYNC_HUP_NOTIFY)
1da177e4
LT
845 return -EAGAIN;
846 else
847 return -ERESTARTSYS;
848 }
d8d16e47 849
1da177e4 850 /* if non-blocking mode is set ... */
d8d16e47 851
a547dfe9
JS
852 if ((filp->f_flags & O_NONBLOCK) ||
853 (tty->flags & (1 << TTY_IO_ERROR))) {
aaa246ea 854 pr_dbg("block_til_ready: non-block mode.\n");
f1d03228 855 port->port.flags |= ASYNC_NORMAL_ACTIVE;
d8d16e47
JS
856 return 0;
857 }
858
1da177e4
LT
859 if (C_CLOCAL(tty))
860 do_clocal = 1;
d8d16e47
JS
861
862 /* block waiting for DCD to be asserted, and while
1da177e4
LT
863 callout dev is busy */
864 retval = 0;
f1d03228 865 add_wait_queue(&port->port.open_wait, &wait);
1da177e4
LT
866
867 spin_lock_irqsave(&card->card_lock, flags);
868 if (!tty_hung_up_p(filp))
f1d03228
AC
869 port->port.count--;
870 port->port.blocked_open++;
1da177e4 871 spin_unlock_irqrestore(&card->card_lock, flags);
d8d16e47 872
1da177e4
LT
873 while (1) {
874 raise_dtr_rts(port);
875
876 set_current_state(TASK_INTERRUPTIBLE);
f1d03228
AC
877 if (tty_hung_up_p(filp) || !(port->port.flags & ASYNC_INITIALIZED)) {
878 if (port->port.flags & ASYNC_HUP_NOTIFY)
1da177e4
LT
879 retval = -EAGAIN;
880 else
881 retval = -ERESTARTSYS;
882 break;
d8d16e47 883 }
f1d03228 884 if (!(port->port.flags & ASYNC_CLOSING) &&
d8d16e47 885 (do_clocal || (port->status & ISI_DCD))) {
1da177e4 886 break;
d8d16e47 887 }
1da177e4
LT
888 if (signal_pending(current)) {
889 retval = -ERESTARTSYS;
890 break;
891 }
d8d16e47 892 schedule();
1da177e4
LT
893 }
894 set_current_state(TASK_RUNNING);
f1d03228 895 remove_wait_queue(&port->port.open_wait, &wait);
1da177e4
LT
896 spin_lock_irqsave(&card->card_lock, flags);
897 if (!tty_hung_up_p(filp))
f1d03228
AC
898 port->port.count++;
899 port->port.blocked_open--;
1da177e4
LT
900 spin_unlock_irqrestore(&card->card_lock, flags);
901 if (retval)
902 return retval;
f1d03228 903 port->port.flags |= ASYNC_NORMAL_ACTIVE;
1da177e4
LT
904 return 0;
905}
d8d16e47
JS
906
907static int isicom_open(struct tty_struct *tty, struct file *filp)
1da177e4 908{
d8d16e47
JS
909 struct isi_port *port;
910 struct isi_board *card;
17c4edf0
JS
911 unsigned int board;
912 int error, line;
1da177e4
LT
913
914 line = tty->index;
915 if (line < 0 || line > PORT_COUNT-1)
916 return -ENODEV;
917 board = BOARD(line);
918 card = &isi_card[board];
d8d16e47 919
1da177e4
LT
920 if (!(card->status & FIRMWARE_LOADED))
921 return -ENODEV;
d8d16e47 922
1da177e4
LT
923 /* open on a port greater than the port count for the card !!! */
924 if (line > ((board * 16) + card->port_count - 1))
925 return -ENODEV;
926
d8d16e47 927 port = &isi_ports[line];
1da177e4
LT
928 if (isicom_paranoia_check(port, tty->name, "isicom_open"))
929 return -ENODEV;
d8d16e47
JS
930
931 isicom_setup_board(card);
932
f1d03228 933 port->port.count++;
1da177e4 934 tty->driver_data = port;
d450b5a0
AC
935 tty_port_tty_set(&port->port, tty);
936 error = isicom_setup_port(tty);
251b8dd7
AC
937 if (error == 0)
938 error = block_til_ready(tty, filp, port);
939 return error;
1da177e4 940}
d8d16e47 941
1da177e4
LT
942/* close et all */
943
d8d16e47 944static inline void isicom_shutdown_board(struct isi_board *bp)
1da177e4 945{
251b8dd7 946 if (bp->status & BOARD_ACTIVE)
1da177e4 947 bp->status &= ~BOARD_ACTIVE;
1da177e4
LT
948}
949
cfe7c09a 950/* card->lock HAS to be held */
d8d16e47 951static void isicom_shutdown_port(struct isi_port *port)
1da177e4 952{
d8d16e47
JS
953 struct isi_board *card = port->card;
954 struct tty_struct *tty;
d8d16e47 955
d450b5a0 956 tty = tty_port_tty_get(&port->port);
1da177e4 957
d450b5a0
AC
958 if (!(port->port.flags & ASYNC_INITIALIZED)) {
959 tty_kref_put(tty);
1da177e4 960 return;
d450b5a0 961 }
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 */
d450b5a0 966 tty_port_tty_set(&port->port, 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 */
6d889724 1184static int isicom_send_break(struct tty_struct *tty, int length)
1da177e4 1185{
6d889724 1186 struct isi_port *port = tty->driver_data;
d8d16e47 1187 struct isi_board *card = port->card;
8070e35c 1188 unsigned long base = card->base;
d8d16e47 1189
6d889724
AC
1190 if (length == -1)
1191 return -EOPNOTSUPP;
1192
d8d16e47 1193 if (!lock_card(card))
6d889724 1194 return -EINVAL;
d8d16e47 1195
1da177e4
LT
1196 outw(0x8000 | ((port->channel) << (card->shift_count)) | 0x3, base);
1197 outw((length & 0xff) << 8 | 0x00, base);
1198 outw((length & 0xff00), base);
1199 InterruptTheCard(base);
1200
1201 unlock_card(card);
6d889724 1202 return 0;
1da177e4
LT
1203}
1204
1205static int isicom_tiocmget(struct tty_struct *tty, struct file *file)
1206{
8070e35c 1207 struct isi_port *port = tty->driver_data;
1da177e4 1208 /* just send the port status */
8070e35c 1209 u16 status = port->status;
1da177e4
LT
1210
1211 if (isicom_paranoia_check(port, tty->name, "isicom_ioctl"))
1212 return -ENODEV;
d8d16e47 1213
1da177e4
LT
1214 return ((status & ISI_RTS) ? TIOCM_RTS : 0) |
1215 ((status & ISI_DTR) ? TIOCM_DTR : 0) |
1216 ((status & ISI_DCD) ? TIOCM_CAR : 0) |
1217 ((status & ISI_DSR) ? TIOCM_DSR : 0) |
1218 ((status & ISI_CTS) ? TIOCM_CTS : 0) |
1219 ((status & ISI_RI ) ? TIOCM_RI : 0);
1220}
1221
1222static int isicom_tiocmset(struct tty_struct *tty, struct file *file,
d8d16e47 1223 unsigned int set, unsigned int clear)
1da177e4 1224{
8070e35c 1225 struct isi_port *port = tty->driver_data;
cfe7c09a 1226 unsigned long flags;
d8d16e47 1227
1da177e4
LT
1228 if (isicom_paranoia_check(port, tty->name, "isicom_ioctl"))
1229 return -ENODEV;
d8d16e47 1230
cfe7c09a 1231 spin_lock_irqsave(&port->card->card_lock, flags);
1da177e4
LT
1232 if (set & TIOCM_RTS)
1233 raise_rts(port);
1234 if (set & TIOCM_DTR)
1235 raise_dtr(port);
1236
1237 if (clear & TIOCM_RTS)
1238 drop_rts(port);
1239 if (clear & TIOCM_DTR)
1240 drop_dtr(port);
cfe7c09a 1241 spin_unlock_irqrestore(&port->card->card_lock, flags);
1da177e4
LT
1242
1243 return 0;
d8d16e47 1244}
1da177e4 1245
d450b5a0
AC
1246static int isicom_set_serial_info(struct tty_struct *tty,
1247 struct serial_struct __user *info)
1da177e4 1248{
d450b5a0 1249 struct isi_port *port = tty->driver_data;
1da177e4
LT
1250 struct serial_struct newinfo;
1251 int reconfig_port;
1252
d8d16e47 1253 if (copy_from_user(&newinfo, info, sizeof(newinfo)))
1da177e4 1254 return -EFAULT;
d8d16e47 1255
1eac4947
AC
1256 lock_kernel();
1257
f1d03228 1258 reconfig_port = ((port->port.flags & ASYNC_SPD_MASK) !=
d8d16e47
JS
1259 (newinfo.flags & ASYNC_SPD_MASK));
1260
1da177e4 1261 if (!capable(CAP_SYS_ADMIN)) {
44b7d1b3
AC
1262 if ((newinfo.close_delay != port->port.close_delay) ||
1263 (newinfo.closing_wait != port->port.closing_wait) ||
d8d16e47 1264 ((newinfo.flags & ~ASYNC_USR_MASK) !=
f1d03228 1265 (port->port.flags & ~ASYNC_USR_MASK))) {
1eac4947 1266 unlock_kernel();
1da177e4 1267 return -EPERM;
1eac4947 1268 }
f1d03228 1269 port->port.flags = ((port->port.flags & ~ASYNC_USR_MASK) |
1da177e4 1270 (newinfo.flags & ASYNC_USR_MASK));
251b8dd7 1271 } else {
44b7d1b3
AC
1272 port->port.close_delay = newinfo.close_delay;
1273 port->port.closing_wait = newinfo.closing_wait;
f1d03228 1274 port->port.flags = ((port->port.flags & ~ASYNC_FLAGS) |
1da177e4
LT
1275 (newinfo.flags & ASYNC_FLAGS));
1276 }
1277 if (reconfig_port) {
cfe7c09a
JS
1278 unsigned long flags;
1279 spin_lock_irqsave(&port->card->card_lock, flags);
d450b5a0 1280 isicom_config_port(tty);
cfe7c09a 1281 spin_unlock_irqrestore(&port->card->card_lock, flags);
1da177e4 1282 }
1eac4947 1283 unlock_kernel();
d8d16e47
JS
1284 return 0;
1285}
1da177e4 1286
d8d16e47
JS
1287static int isicom_get_serial_info(struct isi_port *port,
1288 struct serial_struct __user *info)
1da177e4
LT
1289{
1290 struct serial_struct out_info;
d8d16e47 1291
1eac4947 1292 lock_kernel();
1da177e4
LT
1293 memset(&out_info, 0, sizeof(out_info));
1294/* out_info.type = ? */
1295 out_info.line = port - isi_ports;
1296 out_info.port = port->card->base;
1297 out_info.irq = port->card->irq;
f1d03228 1298 out_info.flags = port->port.flags;
1da177e4 1299/* out_info.baud_base = ? */
44b7d1b3
AC
1300 out_info.close_delay = port->port.close_delay;
1301 out_info.closing_wait = port->port.closing_wait;
1eac4947 1302 unlock_kernel();
d8d16e47 1303 if (copy_to_user(info, &out_info, sizeof(out_info)))
1da177e4
LT
1304 return -EFAULT;
1305 return 0;
d8d16e47 1306}
1da177e4 1307
d8d16e47
JS
1308static int isicom_ioctl(struct tty_struct *tty, struct file *filp,
1309 unsigned int cmd, unsigned long arg)
1da177e4 1310{
8070e35c 1311 struct isi_port *port = tty->driver_data;
1da177e4 1312 void __user *argp = (void __user *)arg;
1da177e4
LT
1313
1314 if (isicom_paranoia_check(port, tty->name, "isicom_ioctl"))
1315 return -ENODEV;
1316
251b8dd7 1317 switch (cmd) {
d8d16e47
JS
1318 case TIOCGSERIAL:
1319 return isicom_get_serial_info(port, argp);
1320
1321 case TIOCSSERIAL:
d450b5a0 1322 return isicom_set_serial_info(tty, argp);
d8d16e47
JS
1323
1324 default:
1325 return -ENOIOCTLCMD;
1da177e4
LT
1326 }
1327 return 0;
1328}
1329
1330/* set_termios et all */
d8d16e47 1331static void isicom_set_termios(struct tty_struct *tty,
606d099c 1332 struct ktermios *old_termios)
1da177e4 1333{
8070e35c 1334 struct isi_port *port = tty->driver_data;
cfe7c09a 1335 unsigned long flags;
d8d16e47 1336
1da177e4
LT
1337 if (isicom_paranoia_check(port, tty->name, "isicom_set_termios"))
1338 return;
d8d16e47 1339
1da177e4 1340 if (tty->termios->c_cflag == old_termios->c_cflag &&
d8d16e47 1341 tty->termios->c_iflag == old_termios->c_iflag)
1da177e4 1342 return;
d8d16e47 1343
cfe7c09a 1344 spin_lock_irqsave(&port->card->card_lock, flags);
d450b5a0 1345 isicom_config_port(tty);
cfe7c09a 1346 spin_unlock_irqrestore(&port->card->card_lock, flags);
d8d16e47 1347
1da177e4 1348 if ((old_termios->c_cflag & CRTSCTS) &&
d8d16e47 1349 !(tty->termios->c_cflag & CRTSCTS)) {
1da177e4 1350 tty->hw_stopped = 0;
d8d16e47
JS
1351 isicom_start(tty);
1352 }
1da177e4
LT
1353}
1354
1355/* throttle et all */
d8d16e47 1356static void isicom_throttle(struct tty_struct *tty)
1da177e4 1357{
8070e35c 1358 struct isi_port *port = tty->driver_data;
d8d16e47
JS
1359 struct isi_board *card = port->card;
1360
1da177e4
LT
1361 if (isicom_paranoia_check(port, tty->name, "isicom_throttle"))
1362 return;
d8d16e47 1363
1da177e4
LT
1364 /* tell the card that this port cannot handle any more data for now */
1365 card->port_status &= ~(1 << port->channel);
1366 outw(card->port_status, card->base + 0x02);
1367}
1368
1369/* unthrottle et all */
d8d16e47 1370static void isicom_unthrottle(struct tty_struct *tty)
1da177e4 1371{
8070e35c 1372 struct isi_port *port = tty->driver_data;
d8d16e47
JS
1373 struct isi_board *card = port->card;
1374
1da177e4
LT
1375 if (isicom_paranoia_check(port, tty->name, "isicom_unthrottle"))
1376 return;
d8d16e47 1377
1da177e4
LT
1378 /* tell the card that this port is ready to accept more data */
1379 card->port_status |= (1 << port->channel);
1380 outw(card->port_status, card->base + 0x02);
1381}
1382
1383/* stop et all */
d8d16e47 1384static void isicom_stop(struct tty_struct *tty)
1da177e4 1385{
8070e35c 1386 struct isi_port *port = tty->driver_data;
1da177e4
LT
1387
1388 if (isicom_paranoia_check(port, tty->name, "isicom_stop"))
1389 return;
d8d16e47 1390
1da177e4
LT
1391 /* this tells the transmitter not to consider this port for
1392 data output to the card. */
1393 port->status &= ~ISI_TXOK;
1394}
1395
1396/* start et all */
d8d16e47 1397static void isicom_start(struct tty_struct *tty)
1da177e4 1398{
8070e35c 1399 struct isi_port *port = tty->driver_data;
d8d16e47 1400
1da177e4
LT
1401 if (isicom_paranoia_check(port, tty->name, "isicom_start"))
1402 return;
d8d16e47 1403
1da177e4
LT
1404 /* this tells the transmitter to consider this port for
1405 data output to the card. */
1406 port->status |= ISI_TXOK;
1407}
1408
d8d16e47 1409static void isicom_hangup(struct tty_struct *tty)
1da177e4 1410{
8070e35c 1411 struct isi_port *port = tty->driver_data;
cfe7c09a 1412 unsigned long flags;
d8d16e47 1413
1da177e4
LT
1414 if (isicom_paranoia_check(port, tty->name, "isicom_hangup"))
1415 return;
d8d16e47 1416
cfe7c09a 1417 spin_lock_irqsave(&port->card->card_lock, flags);
1da177e4 1418 isicom_shutdown_port(port);
cfe7c09a
JS
1419 spin_unlock_irqrestore(&port->card->card_lock, flags);
1420
f1d03228
AC
1421 port->port.count = 0;
1422 port->port.flags &= ~ASYNC_NORMAL_ACTIVE;
d450b5a0 1423 tty_port_tty_set(&port->port, NULL);
f1d03228 1424 wake_up_interruptible(&port->port.open_wait);
1da177e4
LT
1425}
1426
1da177e4 1427
9ac0948b
JS
1428/*
1429 * Driver init and deinit functions
1430 */
1da177e4 1431
b68e31d0 1432static const struct tty_operations isicom_ops = {
d8d16e47
JS
1433 .open = isicom_open,
1434 .close = isicom_close,
1435 .write = isicom_write,
1436 .put_char = isicom_put_char,
1437 .flush_chars = isicom_flush_chars,
1438 .write_room = isicom_write_room,
1da177e4 1439 .chars_in_buffer = isicom_chars_in_buffer,
d8d16e47
JS
1440 .ioctl = isicom_ioctl,
1441 .set_termios = isicom_set_termios,
1442 .throttle = isicom_throttle,
1443 .unthrottle = isicom_unthrottle,
1444 .stop = isicom_stop,
1445 .start = isicom_start,
1446 .hangup = isicom_hangup,
1447 .flush_buffer = isicom_flush_buffer,
1448 .tiocmget = isicom_tiocmget,
1449 .tiocmset = isicom_tiocmset,
6d889724 1450 .break_ctl = isicom_send_break,
1da177e4
LT
1451};
1452
9ac0948b
JS
1453static int __devinit reset_card(struct pci_dev *pdev,
1454 const unsigned int card, unsigned int *signature)
1da177e4 1455{
9ac0948b
JS
1456 struct isi_board *board = pci_get_drvdata(pdev);
1457 unsigned long base = board->base;
f0a0ba6d 1458 unsigned int sig, portcount = 0;
9ac0948b 1459 int retval = 0;
d8d16e47 1460
9ac0948b
JS
1461 dev_dbg(&pdev->dev, "ISILoad:Resetting Card%d at 0x%lx\n", card + 1,
1462 base);
d8d16e47 1463
9ac0948b 1464 inw(base + 0x8);
d8d16e47 1465
f0a0ba6d 1466 msleep(10);
9ac0948b
JS
1467
1468 outw(0, base + 0x8); /* Reset */
1469
f0a0ba6d 1470 msleep(1000);
9ac0948b 1471
f0a0ba6d
JS
1472 sig = inw(base + 0x4) & 0xff;
1473
1474 if (sig != 0xa5 && sig != 0xbb && sig != 0xcc && sig != 0xdd &&
1475 sig != 0xee) {
1476 dev_warn(&pdev->dev, "ISILoad:Card%u reset failure (Possible "
1477 "bad I/O Port Address 0x%lx).\n", card + 1, base);
1478 dev_dbg(&pdev->dev, "Sig=0x%x\n", sig);
1479 retval = -EIO;
1480 goto end;
1481 }
1482
1483 msleep(10);
9ac0948b 1484
18234f88 1485 portcount = inw(base + 0x2);
07fb6f26 1486 if (!(inw(base + 0xe) & 0x1) || (portcount != 0 && portcount != 4 &&
f0a0ba6d 1487 portcount != 8 && portcount != 16)) {
898eb71c 1488 dev_err(&pdev->dev, "ISILoad:PCI Card%d reset failure.\n",
f0a0ba6d 1489 card + 1);
18234f88
JS
1490 retval = -EIO;
1491 goto end;
9ac0948b
JS
1492 }
1493
f0a0ba6d 1494 switch (sig) {
9ac0948b
JS
1495 case 0xa5:
1496 case 0xbb:
1497 case 0xdd:
18234f88 1498 board->port_count = (portcount == 4) ? 4 : 8;
9ac0948b
JS
1499 board->shift_count = 12;
1500 break;
1501 case 0xcc:
f0a0ba6d 1502 case 0xee:
9ac0948b
JS
1503 board->port_count = 16;
1504 board->shift_count = 11;
1505 break;
d8d16e47 1506 }
9ac0948b 1507 dev_info(&pdev->dev, "-Done\n");
f0a0ba6d 1508 *signature = sig;
d8d16e47 1509
9ac0948b
JS
1510end:
1511 return retval;
1da177e4
LT
1512}
1513
e65c1db1
JS
1514static int __devinit load_firmware(struct pci_dev *pdev,
1515 const unsigned int index, const unsigned int signature)
1516{
1517 struct isi_board *board = pci_get_drvdata(pdev);
1518 const struct firmware *fw;
1519 unsigned long base = board->base;
1520 unsigned int a;
1521 u16 word_count, status;
1522 int retval = -EIO;
1523 char *name;
1524 u8 *data;
1525
1526 struct stframe {
1527 u16 addr;
1528 u16 count;
1529 u8 data[0];
1530 } *frame;
1531
1532 switch (signature) {
1533 case 0xa5:
1534 name = "isi608.bin";
1535 break;
1536 case 0xbb:
1537 name = "isi608em.bin";
1538 break;
1539 case 0xcc:
1540 name = "isi616em.bin";
1541 break;
1542 case 0xdd:
1543 name = "isi4608.bin";
1544 break;
1545 case 0xee:
1546 name = "isi4616.bin";
1547 break;
1548 default:
1549 dev_err(&pdev->dev, "Unknown signature.\n");
1550 goto end;
251b8dd7 1551 }
e65c1db1
JS
1552
1553 retval = request_firmware(&fw, name, &pdev->dev);
1554 if (retval)
1555 goto end;
1556
e4e04088
JS
1557 retval = -EIO;
1558
e65c1db1
JS
1559 for (frame = (struct stframe *)fw->data;
1560 frame < (struct stframe *)(fw->data + fw->size);
e4e04088
JS
1561 frame = (struct stframe *)((u8 *)(frame + 1) +
1562 frame->count)) {
e65c1db1
JS
1563 if (WaitTillCardIsFree(base))
1564 goto errrelfw;
1565
1566 outw(0xf0, base); /* start upload sequence */
1567 outw(0x00, base);
1568 outw(frame->addr, base); /* lsb of address */
1569
1570 word_count = frame->count / 2 + frame->count % 2;
1571 outw(word_count, base);
1572 InterruptTheCard(base);
1573
1574 udelay(100); /* 0x2f */
1575
1576 if (WaitTillCardIsFree(base))
1577 goto errrelfw;
1578
251b8dd7
AC
1579 status = inw(base + 0x4);
1580 if (status != 0) {
e65c1db1 1581 dev_warn(&pdev->dev, "Card%d rejected load header:\n"
898eb71c
JP
1582 KERN_WARNING "Address:0x%x\n"
1583 KERN_WARNING "Count:0x%x\n"
1584 KERN_WARNING "Status:0x%x\n",
e65c1db1
JS
1585 index + 1, frame->addr, frame->count, status);
1586 goto errrelfw;
1587 }
1588 outsw(base, frame->data, word_count);
1589
1590 InterruptTheCard(base);
1591
1592 udelay(50); /* 0x0f */
1593
1594 if (WaitTillCardIsFree(base))
1595 goto errrelfw;
1596
251b8dd7
AC
1597 status = inw(base + 0x4);
1598 if (status != 0) {
e65c1db1
JS
1599 dev_err(&pdev->dev, "Card%d got out of sync.Card "
1600 "Status:0x%x\n", index + 1, status);
1601 goto errrelfw;
1602 }
251b8dd7 1603 }
e65c1db1 1604
e65c1db1
JS
1605/* XXX: should we test it by reading it back and comparing with original like
1606 * in load firmware package? */
e4e04088
JS
1607 for (frame = (struct stframe *)fw->data;
1608 frame < (struct stframe *)(fw->data + fw->size);
1609 frame = (struct stframe *)((u8 *)(frame + 1) +
1610 frame->count)) {
e65c1db1
JS
1611 if (WaitTillCardIsFree(base))
1612 goto errrelfw;
1613
1614 outw(0xf1, base); /* start download sequence */
1615 outw(0x00, base);
1616 outw(frame->addr, base); /* lsb of address */
1617
1618 word_count = (frame->count >> 1) + frame->count % 2;
1619 outw(word_count + 1, base);
1620 InterruptTheCard(base);
1621
1622 udelay(50); /* 0xf */
1623
1624 if (WaitTillCardIsFree(base))
1625 goto errrelfw;
1626
251b8dd7
AC
1627 status = inw(base + 0x4);
1628 if (status != 0) {
e65c1db1 1629 dev_warn(&pdev->dev, "Card%d rejected verify header:\n"
898eb71c
JP
1630 KERN_WARNING "Address:0x%x\n"
1631 KERN_WARNING "Count:0x%x\n"
1632 KERN_WARNING "Status: 0x%x\n",
e65c1db1
JS
1633 index + 1, frame->addr, frame->count, status);
1634 goto errrelfw;
1635 }
1636
1637 data = kmalloc(word_count * 2, GFP_KERNEL);
f0671378
JS
1638 if (data == NULL) {
1639 dev_err(&pdev->dev, "Card%d, firmware upload "
1640 "failed, not enough memory\n", index + 1);
1641 goto errrelfw;
1642 }
e65c1db1
JS
1643 inw(base);
1644 insw(base, data, word_count);
1645 InterruptTheCard(base);
1646
1647 for (a = 0; a < frame->count; a++)
1648 if (data[a] != frame->data[a]) {
1649 kfree(data);
1650 dev_err(&pdev->dev, "Card%d, firmware upload "
1651 "failed\n", index + 1);
1652 goto errrelfw;
1653 }
1654 kfree(data);
1655
1656 udelay(50); /* 0xf */
1657
1658 if (WaitTillCardIsFree(base))
1659 goto errrelfw;
1660
251b8dd7
AC
1661 status = inw(base + 0x4);
1662 if (status != 0) {
e65c1db1
JS
1663 dev_err(&pdev->dev, "Card%d verify got out of sync. "
1664 "Card Status:0x%x\n", index + 1, status);
1665 goto errrelfw;
1666 }
1667 }
1668
e4e04088
JS
1669 /* xfer ctrl */
1670 if (WaitTillCardIsFree(base))
1671 goto errrelfw;
1672
1673 outw(0xf2, base);
1674 outw(0x800, base);
1675 outw(0x0, base);
1676 outw(0x0, base);
1677 InterruptTheCard(base);
1678 outw(0x0, base + 0x4); /* for ISI4608 cards */
1679
e65c1db1
JS
1680 board->status |= FIRMWARE_LOADED;
1681 retval = 0;
1682
1683errrelfw:
1684 release_firmware(fw);
1685end:
1686 return retval;
1687}
1688
1da177e4
LT
1689/*
1690 * Insmod can set static symbols so keep these static
1691 */
1ed0c0b7 1692static unsigned int card_count;
9ac0948b
JS
1693
1694static int __devinit isicom_probe(struct pci_dev *pdev,
1695 const struct pci_device_id *ent)
1696{
4969b3a4 1697 unsigned int signature, index;
9ac0948b 1698 int retval = -EPERM;
9ac0948b
JS
1699 struct isi_board *board = NULL;
1700
1ed0c0b7 1701 if (card_count >= BOARD_COUNT)
9ac0948b
JS
1702 goto err;
1703
e1e5770b
JS
1704 retval = pci_enable_device(pdev);
1705 if (retval) {
1706 dev_err(&pdev->dev, "failed to enable\n");
1707 goto err;
1708 }
1709
9ac0948b
JS
1710 dev_info(&pdev->dev, "ISI PCI Card(Device ID 0x%x)\n", ent->device);
1711
1712 /* allot the first empty slot in the array */
1713 for (index = 0; index < BOARD_COUNT; index++)
1714 if (isi_card[index].base == 0) {
1715 board = &isi_card[index];
1716 break;
1717 }
1718
938a7023 1719 board->index = index;
4969b3a4
JS
1720 board->base = pci_resource_start(pdev, 3);
1721 board->irq = pdev->irq;
1ed0c0b7 1722 card_count++;
9ac0948b
JS
1723
1724 pci_set_drvdata(pdev, board);
1725
78028da9
JS
1726 retval = pci_request_region(pdev, 3, ISICOM_NAME);
1727 if (retval) {
09a4a112
JS
1728 dev_err(&pdev->dev, "I/O Region 0x%lx-0x%lx is busy. Card%d "
1729 "will be disabled.\n", board->base, board->base + 15,
1730 index + 1);
1731 retval = -EBUSY;
1ed0c0b7 1732 goto errdec;
251b8dd7 1733 }
9ac0948b 1734
09a4a112
JS
1735 retval = request_irq(board->irq, isicom_interrupt,
1736 IRQF_SHARED | IRQF_DISABLED, ISICOM_NAME, board);
1737 if (retval < 0) {
1738 dev_err(&pdev->dev, "Could not install handler at Irq %d. "
1739 "Card%d will be disabled.\n", board->irq, index + 1);
9ac0948b 1740 goto errunrr;
09a4a112 1741 }
9ac0948b
JS
1742
1743 retval = reset_card(pdev, index, &signature);
1744 if (retval < 0)
1745 goto errunri;
1746
e65c1db1
JS
1747 retval = load_firmware(pdev, index, signature);
1748 if (retval < 0)
1749 goto errunri;
1750
938a7023
JS
1751 for (index = 0; index < board->port_count; index++)
1752 tty_register_device(isicom_normal, board->index * 16 + index,
1753 &pdev->dev);
1754
9ac0948b
JS
1755 return 0;
1756
1757errunri:
1758 free_irq(board->irq, board);
1759errunrr:
78028da9 1760 pci_release_region(pdev, 3);
1ed0c0b7 1761errdec:
9ac0948b 1762 board->base = 0;
1ed0c0b7 1763 card_count--;
e1e5770b 1764 pci_disable_device(pdev);
1ed0c0b7 1765err:
9ac0948b
JS
1766 return retval;
1767}
1768
1769static void __devexit isicom_remove(struct pci_dev *pdev)
1770{
1771 struct isi_board *board = pci_get_drvdata(pdev);
938a7023
JS
1772 unsigned int i;
1773
1774 for (i = 0; i < board->port_count; i++)
1775 tty_unregister_device(isicom_normal, board->index * 16 + i);
9ac0948b
JS
1776
1777 free_irq(board->irq, board);
78028da9 1778 pci_release_region(pdev, 3);
1ed0c0b7
JS
1779 board->base = 0;
1780 card_count--;
e1e5770b 1781 pci_disable_device(pdev);
9ac0948b 1782}
1da177e4 1783
ca262005 1784static int __init isicom_init(void)
1da177e4 1785{
9ac0948b
JS
1786 int retval, idx, channel;
1787 struct isi_port *port;
d8d16e47 1788
251b8dd7 1789 for (idx = 0; idx < BOARD_COUNT; idx++) {
9ac0948b
JS
1790 port = &isi_ports[idx * 16];
1791 isi_card[idx].ports = port;
1792 spin_lock_init(&isi_card[idx].card_lock);
1793 for (channel = 0; channel < 16; channel++, port++) {
44b7d1b3 1794 tty_port_init(&port->port);
9ac0948b
JS
1795 port->magic = ISICOM_MAGIC;
1796 port->card = &isi_card[idx];
1797 port->channel = channel;
44b7d1b3
AC
1798 port->port.close_delay = 50 * HZ/100;
1799 port->port.closing_wait = 3000 * HZ/100;
9ac0948b 1800 port->status = 0;
9ac0948b 1801 /* . . . */
251b8dd7 1802 }
9ac0948b
JS
1803 isi_card[idx].base = 0;
1804 isi_card[idx].irq = 0;
1da177e4 1805 }
d8d16e47 1806
09a4a112
JS
1807 /* tty driver structure initialization */
1808 isicom_normal = alloc_tty_driver(PORT_COUNT);
1809 if (!isicom_normal) {
1810 retval = -ENOMEM;
9ac0948b 1811 goto error;
09a4a112
JS
1812 }
1813
1814 isicom_normal->owner = THIS_MODULE;
1815 isicom_normal->name = "ttyM";
1816 isicom_normal->major = ISICOM_NMAJOR;
1817 isicom_normal->minor_start = 0;
1818 isicom_normal->type = TTY_DRIVER_TYPE_SERIAL;
1819 isicom_normal->subtype = SERIAL_TYPE_NORMAL;
1820 isicom_normal->init_termios = tty_std_termios;
1821 isicom_normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL |
1822 CLOCAL;
938a7023 1823 isicom_normal->flags = TTY_DRIVER_REAL_RAW |
6d889724 1824 TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_HARDWARE_BREAK;
09a4a112
JS
1825 tty_set_operations(isicom_normal, &isicom_ops);
1826
1827 retval = tty_register_driver(isicom_normal);
1828 if (retval) {
1829 pr_dbg("Couldn't register the dialin driver\n");
1830 goto err_puttty;
1831 }
1da177e4 1832
9ac0948b 1833 retval = pci_register_driver(&isicom_driver);
1da177e4 1834 if (retval < 0) {
9ac0948b 1835 printk(KERN_ERR "ISICOM: Unable to register pci driver.\n");
09a4a112 1836 goto err_unrtty;
1da177e4 1837 }
d8d16e47 1838
34b55b86 1839 mod_timer(&tx, jiffies + 1);
d8d16e47 1840
1da177e4 1841 return 0;
09a4a112
JS
1842err_unrtty:
1843 tty_unregister_driver(isicom_normal);
1844err_puttty:
1845 put_tty_driver(isicom_normal);
9ac0948b
JS
1846error:
1847 return retval;
1da177e4
LT
1848}
1849
1850static void __exit isicom_exit(void)
1851{
e327325f 1852 del_timer_sync(&tx);
aaa246ea 1853
9ac0948b 1854 pci_unregister_driver(&isicom_driver);
09a4a112
JS
1855 tty_unregister_driver(isicom_normal);
1856 put_tty_driver(isicom_normal);
1da177e4
LT
1857}
1858
ca262005 1859module_init(isicom_init);
1da177e4 1860module_exit(isicom_exit);
aaa246ea
JS
1861
1862MODULE_AUTHOR("MultiTech");
1863MODULE_DESCRIPTION("Driver for the ISI series of cards by MultiTech");
1864MODULE_LICENSE("GPL");
This page took 0.605196 seconds and 5 git commands to generate.