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