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