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