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