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