blob: 49f88c9006cb1ffed9ed0d5043cca20eb20b7d31 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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.
Jiri Slabyd8d16e42006-01-09 20:54:21 -080023 * This is to prevent the firmware
Linus Torvalds1da177e2005-04-16 15:20:36 -070024 * 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
Jiri Slabyd8d16e42006-01-09 20:54:21 -080034 * when the last port on the card is
Linus Torvalds1da177e2005-04-16 15:20:36 -070035 * closed.
36 *
37 * 10/5/00 sameer Signal mask setup command added
Jiri Slabyd8d16e42006-01-09 20:54:21 -080038 * to isicom_setup_port and
Linus Torvalds1da177e2005-04-16 15:20:36 -070039 * isicom_shutdown_port.
40 *
41 * 24/5/00 sameer The driver is now SMP aware.
Jiri Slabyd8d16e42006-01-09 20:54:21 -080042 *
43 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070044 * 27/11/00 Vinayak P Risbud Fixed the Driver Crash Problem
Jiri Slabyd8d16e42006-01-09 20:54:21 -080045 *
46 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070047 * 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 *
Jiri Slabyd8d16e42006-01-09 20:54:21 -080053 * 11/04/01 Kevin Fixed firmware load problem with
Linus Torvalds1da177e2005-04-16 15:20:36 -070054 * ISIHP-4X card
Jiri Slabyd8d16e42006-01-09 20:54:21 -080055 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070056 * 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
Jiri Slabyd8d16e42006-01-09 20:54:21 -080065 * info during insmod as well as module
Linus Torvalds1da177e2005-04-16 15:20:36 -070066 * listing by lsmod.
Jiri Slabyd8d16e42006-01-09 20:54:21 -080067 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070068 * 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.
Jiri Slabyd8d16e42006-01-09 20:54:21 -080076 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070077 * 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 *
Jiri Slabyd8d16e42006-01-09 20:54:21 -080082 * 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
Linus Torvalds1da177e2005-04-16 15:20:36 -070089 * 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 *
Jiri Slabyd8d16e42006-01-09 20:54:21 -080096 * To use this driver you also need the support package. You
Linus Torvalds1da177e2005-04-16 15:20:36 -070097 * can find this in RPM format on
98 * ftp://ftp.linux.org.uk/pub/linux/alan
Jiri Slabyd8d16e42006-01-09 20:54:21 -080099 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100 * 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>
Alan Cox33f0f882006-01-09 20:54:13 -0800118#include <linux/tty_flip.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119#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
Jiri Slabyaaa246e2006-01-09 20:54:23 -0800138#define InterruptTheCard(base) outw(0, (base) + 0xc)
139#define ClearInterrupt(base) inw((base) + 0x0a)
140
141#ifdef DEBUG
142#define pr_dbg(str...) printk(KERN_DEBUG "ISICOM: " str)
143#define isicom_paranoia_check(a, b, c) __isicom_paranoia_check((a), (b), (c))
144#else
145#define pr_dbg(str...) do { } while (0)
146#define isicom_paranoia_check(a, b, c) 0
147#endif
148
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149static struct pci_device_id isicom_pci_tbl[] = {
150 { VENDOR_ID, 0x2028, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
151 { VENDOR_ID, 0x2051, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
152 { VENDOR_ID, 0x2052, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
153 { VENDOR_ID, 0x2053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
154 { VENDOR_ID, 0x2054, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
155 { VENDOR_ID, 0x2055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
156 { VENDOR_ID, 0x2056, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
157 { VENDOR_ID, 0x2057, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
158 { VENDOR_ID, 0x2058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
159 { 0 }
160};
161MODULE_DEVICE_TABLE(pci, isicom_pci_tbl);
162
163static int prev_card = 3; /* start servicing isi_card[0] */
164static struct tty_driver *isicom_normal;
165
166static struct timer_list tx;
167static char re_schedule = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168
169static int ISILoad_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
170
171static void isicom_tx(unsigned long _data);
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800172static void isicom_start(struct tty_struct *tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800174static unsigned char *tmp_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175
176/* baud index mappings from linux defns to isi */
177
178static signed char linuxb_to_isib[] = {
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800179 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13, 15, 16, 17, 18, 19
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180};
181
182struct isi_board {
Jiri Slaby8070e352006-01-09 20:54:22 -0800183 unsigned long base;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 unsigned char irq;
185 unsigned char port_count;
186 unsigned short status;
187 unsigned short port_status; /* each bit represents a single port */
188 unsigned short shift_count;
189 struct isi_port * ports;
190 signed char count;
191 unsigned char isa;
192 spinlock_t card_lock; /* Card wide lock 11/5/00 -sameer */
193 unsigned long flags;
194};
195
196struct isi_port {
197 unsigned short magic;
198 unsigned int flags;
199 int count;
200 int blocked_open;
201 int close_delay;
Jiri Slaby8070e352006-01-09 20:54:22 -0800202 u16 channel;
203 u16 status;
204 u16 closing_wait;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 struct isi_board * card;
206 struct tty_struct * tty;
207 wait_queue_head_t close_wait;
208 wait_queue_head_t open_wait;
209 struct work_struct hangup_tq;
210 struct work_struct bh_tqueue;
211 unsigned char * xmit_buf;
212 int xmit_head;
213 int xmit_tail;
214 int xmit_cnt;
215};
216
217static struct isi_board isi_card[BOARD_COUNT];
218static struct isi_port isi_ports[PORT_COUNT];
219
220/*
221 * Locking functions for card level locking. We need to own both
222 * the kernel lock for the card and have the card in a position that
223 * it wants to talk.
224 */
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800225
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226static int lock_card(struct isi_board *card)
227{
228 char retries;
Jiri Slaby8070e352006-01-09 20:54:22 -0800229 unsigned long base = card->base;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230
231 for (retries = 0; retries < 100; retries++) {
232 spin_lock_irqsave(&card->card_lock, card->flags);
233 if (inw(base + 0xe) & 0x1) {
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800234 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 } else {
236 spin_unlock_irqrestore(&card->card_lock, card->flags);
237 udelay(1000); /* 1ms */
238 }
239 }
Jiri Slaby8070e352006-01-09 20:54:22 -0800240 printk(KERN_WARNING "ISICOM: Failed to lock Card (0x%lx)\n", card->base);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 return 0; /* Failed to aquire the card! */
242}
243
244static int lock_card_at_interrupt(struct isi_board *card)
245{
246 unsigned char retries;
Jiri Slaby8070e352006-01-09 20:54:22 -0800247 unsigned long base = card->base;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248
249 for (retries = 0; retries < 200; retries++) {
250 spin_lock_irqsave(&card->card_lock, card->flags);
251
252 if (inw(base + 0xe) & 0x1)
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800253 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 else
255 spin_unlock_irqrestore(&card->card_lock, card->flags);
256 }
257 /* Failing in interrupt is an acceptable event */
258 return 0; /* Failed to aquire the card! */
259}
260
261static void unlock_card(struct isi_board *card)
262{
263 spin_unlock_irqrestore(&card->card_lock, card->flags);
264}
265
266/*
267 * ISI Card specific ops ...
268 */
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800269
270static void raise_dtr(struct isi_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271{
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800272 struct isi_board *card = port->card;
Jiri Slaby8070e352006-01-09 20:54:22 -0800273 unsigned long base = card->base;
274 u16 channel = port->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275
276 if (!lock_card(card))
277 return;
278
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800279 outw(0x8000 | (channel << card->shift_count) | 0x02, base);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 outw(0x0504, base);
281 InterruptTheCard(base);
282 port->status |= ISI_DTR;
283 unlock_card(card);
284}
285
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800286static inline void drop_dtr(struct isi_port *port)
287{
288 struct isi_board *card = port->card;
Jiri Slaby8070e352006-01-09 20:54:22 -0800289 unsigned long base = card->base;
290 u16 channel = port->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291
292 if (!lock_card(card))
293 return;
294
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800295 outw(0x8000 | (channel << card->shift_count) | 0x02, base);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 outw(0x0404, base);
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800297 InterruptTheCard(base);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 port->status &= ~ISI_DTR;
299 unlock_card(card);
300}
301
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800302static inline void raise_rts(struct isi_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303{
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800304 struct isi_board *card = port->card;
Jiri Slaby8070e352006-01-09 20:54:22 -0800305 unsigned long base = card->base;
306 u16 channel = port->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307
308 if (!lock_card(card))
309 return;
310
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800311 outw(0x8000 | (channel << card->shift_count) | 0x02, base);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 outw(0x0a04, base);
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800313 InterruptTheCard(base);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 port->status |= ISI_RTS;
315 unlock_card(card);
316}
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800317static inline void drop_rts(struct isi_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318{
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800319 struct isi_board *card = port->card;
Jiri Slaby8070e352006-01-09 20:54:22 -0800320 unsigned long base = card->base;
321 u16 channel = port->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322
323 if (!lock_card(card))
324 return;
325
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800326 outw(0x8000 | (channel << card->shift_count) | 0x02, base);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 outw(0x0804, base);
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800328 InterruptTheCard(base);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 port->status &= ~ISI_RTS;
330 unlock_card(card);
331}
332
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800333static inline void raise_dtr_rts(struct isi_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334{
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800335 struct isi_board *card = port->card;
Jiri Slaby8070e352006-01-09 20:54:22 -0800336 unsigned long base = card->base;
337 u16 channel = port->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338
339 if (!lock_card(card))
340 return;
341
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800342 outw(0x8000 | (channel << card->shift_count) | 0x02, base);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 outw(0x0f04, base);
344 InterruptTheCard(base);
345 port->status |= (ISI_DTR | ISI_RTS);
346 unlock_card(card);
347}
348
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800349static void drop_dtr_rts(struct isi_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350{
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800351 struct isi_board *card = port->card;
Jiri Slaby8070e352006-01-09 20:54:22 -0800352 unsigned long base = card->base;
353 u16 channel = port->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354
355 if (!lock_card(card))
356 return;
357
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800358 outw(0x8000 | (channel << card->shift_count) | 0x02, base);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 outw(0x0c04, base);
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800360 InterruptTheCard(base);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 port->status &= ~(ISI_RTS | ISI_DTR);
362 unlock_card(card);
363}
364
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800365static inline void kill_queue(struct isi_port *port, short queue)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366{
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800367 struct isi_board *card = port->card;
Jiri Slaby8070e352006-01-09 20:54:22 -0800368 unsigned long base = card->base;
369 u16 channel = port->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370
371 if (!lock_card(card))
372 return;
373
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800374 outw(0x8000 | (channel << card->shift_count) | 0x02, base);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 outw((queue << 8) | 0x06, base);
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800376 InterruptTheCard(base);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 unlock_card(card);
378}
379
380
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800381/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 * Firmware loader driver specific routines. This needs to mostly die
383 * and be replaced with request_firmware.
384 */
385
386static struct file_operations ISILoad_fops = {
387 .owner = THIS_MODULE,
388 .ioctl = ISILoad_ioctl,
389};
390
391static struct miscdevice isiloader_device = {
392 ISILOAD_MISC_MINOR, "isictl", &ISILoad_fops
393};
394
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800395
Jiri Slaby8070e352006-01-09 20:54:22 -0800396static inline int WaitTillCardIsFree(unsigned long base)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397{
398 unsigned long count=0;
399 while( (!(inw(base+0xe) & 0x1)) && (count++ < 6000000));
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800400 if (inw(base+0xe)&0x1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 return 0;
402 else
403 return 1;
404}
405
406static int ISILoad_ioctl(struct inode *inode, struct file *filp,
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800407 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408{
409 unsigned int card, i, j, signature, status, portcount = 0;
Jiri Slaby8070e352006-01-09 20:54:22 -0800410 unsigned long t, base;
411 u16 word_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 bin_frame frame;
413 void __user *argp = (void __user *)arg;
414 /* exec_record exec_rec; */
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800415
416 if (get_user(card, (int __user *)argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 return -EFAULT;
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800418
419 if (card < 0 || card >= BOARD_COUNT)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 return -ENXIO;
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800421
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 base=isi_card[card].base;
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800423
424 if (base==0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 return -ENXIO; /* disabled or not used */
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800426
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 switch(cmd) {
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800428 case MIOCTL_RESET_CARD:
429 if (!capable(CAP_SYS_ADMIN))
430 return -EPERM;
Jiri Slaby8070e352006-01-09 20:54:22 -0800431 printk(KERN_DEBUG "ISILoad:Resetting Card%d at 0x%lx ",card+1,base);
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800432
433 inw(base+0x8);
434
435 for (t=jiffies+HZ/100;time_before(jiffies, t););
436
437 outw(0,base+0x8); /* Reset */
438
439 for (j=1;j<=3;j++) {
440 for (t=jiffies+HZ;time_before(jiffies, t););
441 printk(".");
442 }
443 signature=(inw(base+0x4)) & 0xff;
444 if (isi_card[card].isa) {
445
446 if (!(inw(base+0xe) & 0x1) || (inw(base+0x2))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447#ifdef ISICOM_DEBUG
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800448 printk("\nbase+0x2=0x%x , base+0xe=0x%x",inw(base+0x2),inw(base+0xe));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449#endif
Jiri Slaby8070e352006-01-09 20:54:22 -0800450 printk("\nISILoad:ISA Card%d reset failure (Possible bad I/O Port Address 0x%lx).\n",card+1,base);
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800451 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 }
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800453 }
454 else {
455 portcount = inw(base+0x2);
456 if (!(inw(base+0xe) & 0x1) || ((portcount!=0) && (portcount!=4) && (portcount!=8))) {
457#ifdef ISICOM_DEBUG
458 printk("\nbase+0x2=0x%x , base+0xe=0x%x",inw(base+0x2),inw(base+0xe));
459#endif
Jiri Slaby8070e352006-01-09 20:54:22 -0800460 printk("\nISILoad:PCI Card%d reset failure (Possible bad I/O Port Address 0x%lx).\n",card+1,base);
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800461 return -EIO;
462 }
463 }
464 switch(signature) {
465 case 0xa5:
466 case 0xbb:
467 case 0xdd:
468 if (isi_card[card].isa)
469 isi_card[card].port_count = 8;
470 else {
471 if (portcount == 4)
472 isi_card[card].port_count = 4;
473 else
474 isi_card[card].port_count = 8;
475 }
476 isi_card[card].shift_count = 12;
477 break;
478
479 case 0xcc: isi_card[card].port_count = 16;
480 isi_card[card].shift_count = 11;
481 break;
482
Jiri Slaby8070e352006-01-09 20:54:22 -0800483 default: printk("ISILoad:Card%d reset failure (Possible bad I/O Port Address 0x%lx).\n",card+1,base);
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800484#ifdef ISICOM_DEBUG
485 printk("Sig=0x%x\n",signature);
486#endif
487 return -EIO;
488 }
489 printk("-Done\n");
490 return put_user(signature,(unsigned __user *)argp);
491
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 case MIOCTL_LOAD_FIRMWARE:
493 if (!capable(CAP_SYS_ADMIN))
494 return -EPERM;
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800495
496 if (copy_from_user(&frame, argp, sizeof(bin_frame)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 return -EFAULT;
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800498
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 if (WaitTillCardIsFree(base))
500 return -EIO;
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800501
502 outw(0xf0,base); /* start upload sequence */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 outw(0x00,base);
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800504 outw((frame.addr), base); /* lsb of adderess */
505
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 word_count=(frame.count >> 1) + frame.count % 2;
507 outw(word_count, base);
508 InterruptTheCard(base);
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800509
510 for (i=0;i<=0x2f;i++); /* a wee bit of delay */
511
512 if (WaitTillCardIsFree(base))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 return -EIO;
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800514
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 if ((status=inw(base+0x4))!=0) {
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800516 printk(KERN_WARNING "ISILoad:Card%d rejected load header:\nAddress:0x%x \nCount:0x%x \nStatus:0x%x \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 card+1, frame.addr, frame.count, status);
518 return -EIO;
519 }
520 outsw(base, (void *) frame.bin_data, word_count);
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800521
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 InterruptTheCard(base);
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800523
524 for (i=0;i<=0x0f;i++); /* another wee bit of delay */
525
526 if (WaitTillCardIsFree(base))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 return -EIO;
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800528
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 if ((status=inw(base+0x4))!=0) {
530 printk(KERN_ERR "ISILoad:Card%d got out of sync.Card Status:0x%x\n",card+1, status);
531 return -EIO;
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800532 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 return 0;
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800534
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 case MIOCTL_READ_FIRMWARE:
536 if (!capable(CAP_SYS_ADMIN))
537 return -EPERM;
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800538
539 if (copy_from_user(&frame, argp, sizeof(bin_header)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 return -EFAULT;
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800541
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 if (WaitTillCardIsFree(base))
543 return -EIO;
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800544
545 outw(0xf1,base); /* start download sequence */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 outw(0x00,base);
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800547 outw((frame.addr), base); /* lsb of adderess */
548
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 word_count=(frame.count >> 1) + frame.count % 2;
550 outw(word_count+1, base);
551 InterruptTheCard(base);
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800552
553 for (i=0;i<=0xf;i++); /* a wee bit of delay */
554
555 if (WaitTillCardIsFree(base))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 return -EIO;
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800557
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 if ((status=inw(base+0x4))!=0) {
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800559 printk(KERN_WARNING "ISILoad:Card%d rejected verify header:\nAddress:0x%x \nCount:0x%x \nStatus:0x%x \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 card+1, frame.addr, frame.count, status);
561 return -EIO;
562 }
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800563
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 inw(base);
565 insw(base, frame.bin_data, word_count);
566 InterruptTheCard(base);
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800567
568 for (i=0;i<=0x0f;i++); /* another wee bit of delay */
569
570 if (WaitTillCardIsFree(base))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 return -EIO;
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800572
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 if ((status=inw(base+0x4))!=0) {
574 printk(KERN_ERR "ISILoad:Card%d verify got out of sync.Card Status:0x%x\n",card+1, status);
575 return -EIO;
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800576 }
577
578 if (copy_to_user(argp, &frame, sizeof(bin_frame)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 return -EFAULT;
580 return 0;
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800581
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 case MIOCTL_XFER_CTRL:
583 if (!capable(CAP_SYS_ADMIN))
584 return -EPERM;
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800585 if (WaitTillCardIsFree(base))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 return -EIO;
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800587
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 outw(0xf2, base);
589 outw(0x800, base);
590 outw(0x0, base);
591 outw(0x0, base);
592 InterruptTheCard(base);
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800593 outw(0x0, base+0x4); /* for ISI4608 cards */
594
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 isi_card[card].status |= FIRMWARE_LOADED;
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800596 return 0;
597
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 default:
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800599#ifdef ISICOM_DEBUG
600 printk(KERN_DEBUG "ISILoad: Received Ioctl cmd 0x%x.\n", cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601#endif
602 return -ENOIOCTLCMD;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604}
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800605
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606
607/*
608 * ISICOM Driver specific routines ...
609 *
610 */
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800611
Jiri Slabyaaa246e2006-01-09 20:54:23 -0800612static inline int __isicom_paranoia_check(struct isi_port const *port,
613 char *name, const char *routine)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 if (!port) {
Jiri Slabyaaa246e2006-01-09 20:54:23 -0800616 printk(KERN_WARNING "ISICOM: Warning: bad isicom magic for "
617 "dev %s in %s.\n", name, routine);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 return 1;
619 }
620 if (port->magic != ISICOM_MAGIC) {
Jiri Slabyaaa246e2006-01-09 20:54:23 -0800621 printk(KERN_WARNING "ISICOM: Warning: NULL isicom port for "
622 "dev %s in %s.\n", name, routine);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 return 1;
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800624 }
Jiri Slabyaaa246e2006-01-09 20:54:23 -0800625
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 return 0;
627}
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800628
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629/*
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800630 * Transmitter.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 *
632 * We shovel data into the card buffers on a regular basis. The card
633 * will do the rest of the work for us.
634 */
635
636static void isicom_tx(unsigned long _data)
637{
638 short count = (BOARD_COUNT-1), card, base;
639 short txcount, wrd, residue, word_count, cnt;
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800640 struct isi_port *port;
641 struct tty_struct *tty;
642
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 /* find next active board */
644 card = (prev_card + 1) & 0x0003;
645 while(count-- > 0) {
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800646 if (isi_card[card].status & BOARD_ACTIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 break;
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800648 card = (card + 1) & 0x0003;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 }
650 if (!(isi_card[card].status & BOARD_ACTIVE))
651 goto sched_again;
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800652
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 prev_card = card;
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800654
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 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) ||
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800663 !(port->status & ISI_TXOK))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 unlock_card(&isi_card[card]);
665 continue;
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800666
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 tty = port->tty;
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800668
669
670 if (tty == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 unlock_card(&isi_card[card]);
672 continue;
673 }
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800674
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 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]);
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800682 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 }
Jiri Slabyaaa246e2006-01-09 20:54:23 -0800684 pr_dbg("txing %d bytes, port%d.\n", txcount,
685 port->channel + 1);
686 outw((port->channel << isi_card[card].shift_count) | txcount,
687 base);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 residue = NO;
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800689 wrd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 while (1) {
691 cnt = min_t(int, txcount, (SERIAL_XMIT_SIZE - port->xmit_tail));
692 if (residue == YES) {
693 residue = NO;
694 if (cnt > 0) {
695 wrd |= (port->xmit_buf[port->xmit_tail] << 8);
696 port->xmit_tail = (port->xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1);
697 port->xmit_cnt--;
698 txcount--;
699 cnt--;
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800700 outw(wrd, base);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 }
702 else {
703 outw(wrd, base);
704 break;
705 }
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800706 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 if (cnt <= 0) break;
708 word_count = cnt >> 1;
709 outsw(base, port->xmit_buf+port->xmit_tail, word_count);
710 port->xmit_tail = (port->xmit_tail + (word_count << 1)) &
711 (SERIAL_XMIT_SIZE - 1);
712 txcount -= (word_count << 1);
713 port->xmit_cnt -= (word_count << 1);
714 if (cnt & 0x0001) {
715 residue = YES;
716 wrd = port->xmit_buf[port->xmit_tail];
717 port->xmit_tail = (port->xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1);
718 port->xmit_cnt--;
719 txcount--;
720 }
721 }
722
723 InterruptTheCard(base);
724 if (port->xmit_cnt <= 0)
725 port->status &= ~ISI_TXOK;
726 if (port->xmit_cnt <= WAKEUP_CHARS)
727 schedule_work(&port->bh_tqueue);
728 unlock_card(&isi_card[card]);
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800729 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800731 /* schedule another tx for hopefully in about 10ms */
732sched_again:
Jiri Slabyaaa246e2006-01-09 20:54:23 -0800733 if (!re_schedule) {
734 re_schedule = 2;
735 return;
736 }
737
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 init_timer(&tx);
739 tx.expires = jiffies + HZ/100;
740 tx.data = 0;
741 tx.function = isicom_tx;
742 add_timer(&tx);
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800743
744 return;
745}
746
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747/* Interrupt handlers */
748
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800749
750static void isicom_bottomhalf(void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751{
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800752 struct isi_port *port = (struct isi_port *) data;
753 struct tty_struct *tty = port->tty;
754
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 if (!tty)
756 return;
757
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800758 tty_wakeup(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 wake_up_interruptible(&tty->write_wait);
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800760}
761
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762/*
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800763 * Main interrupt handler routine
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 */
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800765
Jiri Slaby8070e352006-01-09 20:54:22 -0800766static irqreturn_t isicom_interrupt(int irq, void *dev_id, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767{
Jiri Slaby8070e352006-01-09 20:54:22 -0800768 struct isi_board *card = dev_id;
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800769 struct isi_port *port;
770 struct tty_struct *tty;
Jiri Slaby8070e352006-01-09 20:54:22 -0800771 unsigned long base;
772 u16 header, word_count, count, channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 short byte_count;
Alan Cox33f0f882006-01-09 20:54:13 -0800774 unsigned char *rp;
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800775
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 if (!card || !(card->status & FIRMWARE_LOADED))
777 return IRQ_NONE;
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800778
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 base = card->base;
780 spin_lock(&card->card_lock);
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800781
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 if (card->isa == NO) {
783 /*
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800784 * disable any interrupts from the PCI card and lower the
785 * interrupt line
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 */
787 outw(0x8000, base+0x04);
788 ClearInterrupt(base);
789 }
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800790
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 inw(base); /* get the dummy word out */
792 header = inw(base);
793 channel = (header & 0x7800) >> card->shift_count;
794 byte_count = header & 0xff;
795
796 if (channel + 1 > card->port_count) {
Jiri Slaby8070e352006-01-09 20:54:22 -0800797 printk(KERN_WARNING "ISICOM: isicom_interrupt(0x%lx): %d(channel) > port_count.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 base, channel+1);
799 if (card->isa)
800 ClearInterrupt(base);
801 else
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800802 outw(0x0000, base+0x04); /* enable interrupts */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 spin_unlock(&card->card_lock);
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800804 return IRQ_HANDLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 }
806 port = card->ports + channel;
807 if (!(port->flags & ASYNC_INITIALIZED)) {
808 if (card->isa)
809 ClearInterrupt(base);
810 else
811 outw(0x0000, base+0x04); /* enable interrupts */
812 return IRQ_HANDLED;
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800813 }
814
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 tty = port->tty;
816 if (tty == NULL) {
817 word_count = byte_count >> 1;
818 while(byte_count > 1) {
819 inw(base);
820 byte_count -= 2;
821 }
822 if (byte_count & 0x01)
823 inw(base);
824 if (card->isa == YES)
825 ClearInterrupt(base);
826 else
827 outw(0x0000, base+0x04); /* enable interrupts */
828 spin_unlock(&card->card_lock);
829 return IRQ_HANDLED;
830 }
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800831
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 if (header & 0x8000) { /* Status Packet */
833 header = inw(base);
834 switch(header & 0xff) {
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800835 case 0: /* Change in EIA signals */
836
837 if (port->flags & ASYNC_CHECK_CD) {
838 if (port->status & ISI_DCD) {
839 if (!(header & ISI_DCD)) {
840 /* Carrier has been lost */
Jiri Slabyaaa246e2006-01-09 20:54:23 -0800841 pr_dbg("interrupt: DCD->low.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 port->status &= ~ISI_DCD;
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800843 schedule_work(&port->hangup_tq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 }
845 }
846 else {
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800847 if (header & ISI_DCD) {
848 /* Carrier has been detected */
Jiri Slabyaaa246e2006-01-09 20:54:23 -0800849 pr_dbg("interrupt: DCD->high.\n");
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800850 port->status |= ISI_DCD;
851 wake_up_interruptible(&port->open_wait);
852 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 }
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800854 }
855 else {
856 if (header & ISI_DCD)
857 port->status |= ISI_DCD;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 else
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800859 port->status &= ~ISI_DCD;
860 }
861
862 if (port->flags & ASYNC_CTS_FLOW) {
863 if (port->tty->hw_stopped) {
864 if (header & ISI_CTS) {
865 port->tty->hw_stopped = 0;
866 /* start tx ing */
867 port->status |= (ISI_TXOK | ISI_CTS);
868 schedule_work(&port->bh_tqueue);
869 }
870 }
871 else {
872 if (!(header & ISI_CTS)) {
873 port->tty->hw_stopped = 1;
874 /* stop tx ing */
875 port->status &= ~(ISI_TXOK | ISI_CTS);
876 }
877 }
878 }
879 else {
880 if (header & ISI_CTS)
881 port->status |= ISI_CTS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 else
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800883 port->status &= ~ISI_CTS;
884 }
885
886 if (header & ISI_DSR)
887 port->status |= ISI_DSR;
888 else
889 port->status &= ~ISI_DSR;
890
891 if (header & ISI_RI)
892 port->status |= ISI_RI;
893 else
894 port->status &= ~ISI_RI;
895
896 break;
897
898 case 1: /* Received Break !!! */
899 tty_insert_flip_char(tty, 0, TTY_BREAK);
900 if (port->flags & ASYNC_SAK)
901 do_SAK(tty);
902 tty_flip_buffer_push(tty);
903 break;
904
905 case 2: /* Statistics */
Jiri Slabyaaa246e2006-01-09 20:54:23 -0800906 pr_dbg("isicom_interrupt: stats!!!.\n");
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800907 break;
908
909 default:
Jiri Slabyaaa246e2006-01-09 20:54:23 -0800910 pr_dbg("Intr: Unknown code in status packet.\n");
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800911 break;
912 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 }
914 else { /* Data Packet */
Alan Cox33f0f882006-01-09 20:54:13 -0800915
916 count = tty_prepare_flip_string(tty, &rp, byte_count & ~1);
Jiri Slabyaaa246e2006-01-09 20:54:23 -0800917 pr_dbg("Intr: Can rx %d of %d bytes.\n", count, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 word_count = count >> 1;
Alan Cox33f0f882006-01-09 20:54:13 -0800919 insw(base, rp, word_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 byte_count -= (word_count << 1);
921 if (count & 0x0001) {
Alan Cox33f0f882006-01-09 20:54:13 -0800922 tty_insert_flip_char(tty, inw(base) & 0xff, TTY_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 byte_count -= 2;
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800924 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 if (byte_count > 0) {
Jiri Slabyaaa246e2006-01-09 20:54:23 -0800926 pr_dbg("Intr(0x%lx:%d): Flip buffer overflow! dropping "
927 "bytes...\n", base, channel + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 while(byte_count > 0) { /* drain out unread xtra data */
929 inw(base);
930 byte_count -= 2;
931 }
932 }
Alan Cox33f0f882006-01-09 20:54:13 -0800933 tty_flip_buffer_push(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 }
935 if (card->isa == YES)
936 ClearInterrupt(base);
937 else
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800938 outw(0x0000, base+0x04); /* enable interrupts */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 return IRQ_HANDLED;
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800940}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800942static void isicom_config_port(struct isi_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943{
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800944 struct isi_board *card = port->card;
945 struct tty_struct *tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 unsigned long baud;
Jiri Slaby8070e352006-01-09 20:54:22 -0800947 unsigned long base = card->base;
948 u16 channel_setup, channel = port->channel,
949 shift_count = card->shift_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 unsigned char flow_ctrl;
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800951
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 if (!(tty = port->tty) || !tty->termios)
953 return;
954 baud = C_BAUD(tty);
955 if (baud & CBAUDEX) {
956 baud &= ~CBAUDEX;
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800957
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 /* if CBAUDEX bit is on and the baud is set to either 50 or 75
959 * then the card is programmed for 57.6Kbps or 115Kbps
960 * respectively.
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800961 */
962
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 if (baud < 1 || baud > 2)
964 port->tty->termios->c_cflag &= ~CBAUDEX;
965 else
966 baud += 15;
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800967 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 if (baud == 15) {
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800969
970 /* the ASYNC_SPD_HI and ASYNC_SPD_VHI options are set
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 * by the set_serial_info ioctl ... this is done by
972 * the 'setserial' utility.
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800973 */
974
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800976 baud++; /* 57.6 Kbps */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800978 baud +=2; /* 115 Kbps */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 }
980 if (linuxb_to_isib[baud] == -1) {
981 /* hang up */
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800982 drop_dtr(port);
983 return;
984 }
985 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 raise_dtr(port);
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800987
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 if (lock_card(card)) {
989 outw(0x8000 | (channel << shift_count) |0x03, base);
990 outw(linuxb_to_isib[baud] << 8 | 0x03, base);
991 channel_setup = 0;
992 switch(C_CSIZE(tty)) {
Jiri Slabyd8d16e42006-01-09 20:54:21 -0800993 case CS5:
994 channel_setup |= ISICOM_CS5;
995 break;
996 case CS6:
997 channel_setup |= ISICOM_CS6;
998 break;
999 case CS7:
1000 channel_setup |= ISICOM_CS7;
1001 break;
1002 case CS8:
1003 channel_setup |= ISICOM_CS8;
1004 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 }
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001006
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 if (C_CSTOPB(tty))
1008 channel_setup |= ISICOM_2SB;
1009 if (C_PARENB(tty)) {
1010 channel_setup |= ISICOM_EVPAR;
1011 if (C_PARODD(tty))
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001012 channel_setup |= ISICOM_ODPAR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 }
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001014 outw(channel_setup, base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 InterruptTheCard(base);
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001016 unlock_card(card);
1017 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 if (C_CLOCAL(tty))
1019 port->flags &= ~ASYNC_CHECK_CD;
1020 else
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001021 port->flags |= ASYNC_CHECK_CD;
1022
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 /* flow control settings ...*/
1024 flow_ctrl = 0;
1025 port->flags &= ~ASYNC_CTS_FLOW;
1026 if (C_CRTSCTS(tty)) {
1027 port->flags |= ASYNC_CTS_FLOW;
1028 flow_ctrl |= ISICOM_CTSRTS;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001029 }
1030 if (I_IXON(tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 flow_ctrl |= ISICOM_RESPOND_XONXOFF;
1032 if (I_IXOFF(tty))
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001033 flow_ctrl |= ISICOM_INITIATE_XONXOFF;
1034
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 if (lock_card(card)) {
1036 outw(0x8000 | (channel << shift_count) |0x04, base);
1037 outw(flow_ctrl << 8 | 0x05, base);
1038 outw((STOP_CHAR(tty)) << 8 | (START_CHAR(tty)), base);
1039 InterruptTheCard(base);
1040 unlock_card(card);
1041 }
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001042
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 /* rx enabled -> enable port for rx on the card */
1044 if (C_CREAD(tty)) {
1045 card->port_status |= (1 << channel);
1046 outw(card->port_status, base + 0x02);
1047 }
1048}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001050/* open et all */
1051
1052static inline void isicom_setup_board(struct isi_board *bp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053{
1054 int channel;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001055 struct isi_port *port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 unsigned long flags;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001057
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 spin_lock_irqsave(&bp->card_lock, flags);
1059 if (bp->status & BOARD_ACTIVE) {
1060 spin_unlock_irqrestore(&bp->card_lock, flags);
1061 return;
1062 }
1063 port = bp->ports;
1064 bp->status |= BOARD_ACTIVE;
1065 spin_unlock_irqrestore(&bp->card_lock, flags);
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001066 for (channel = 0; channel < bp->port_count; channel++, port++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 drop_dtr_rts(port);
1068 return;
1069}
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001070
1071static int isicom_setup_port(struct isi_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072{
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001073 struct isi_board *card = port->card;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 unsigned long flags;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001075
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 if (port->flags & ASYNC_INITIALIZED) {
1077 return 0;
1078 }
1079 if (!port->xmit_buf) {
1080 unsigned long page;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001081
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 if (!(page = get_zeroed_page(GFP_KERNEL)))
1083 return -ENOMEM;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001084
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 if (port->xmit_buf) {
1086 free_page(page);
1087 return -ERESTARTSYS;
1088 }
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001089 port->xmit_buf = (unsigned char *) page;
1090 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091
1092 spin_lock_irqsave(&card->card_lock, flags);
1093 if (port->tty)
1094 clear_bit(TTY_IO_ERROR, &port->tty->flags);
1095 if (port->count == 1)
1096 card->count++;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001097
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001099
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 /* discard any residual data */
1101 kill_queue(port, ISICOM_KILLTX | ISICOM_KILLRX);
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001102
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 isicom_config_port(port);
1104 port->flags |= ASYNC_INITIALIZED;
1105 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001106
1107 return 0;
1108}
1109
1110static int block_til_ready(struct tty_struct *tty, struct file *filp, struct isi_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111{
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001112 struct isi_board *card = port->card;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 int do_clocal = 0, retval;
1114 unsigned long flags;
1115 DECLARE_WAITQUEUE(wait, current);
1116
1117 /* block if port is in the process of being closed */
1118
1119 if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
Jiri Slabyaaa246e2006-01-09 20:54:23 -08001120 pr_dbg("block_til_ready: close in progress.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 interruptible_sleep_on(&port->close_wait);
1122 if (port->flags & ASYNC_HUP_NOTIFY)
1123 return -EAGAIN;
1124 else
1125 return -ERESTARTSYS;
1126 }
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001127
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 /* if non-blocking mode is set ... */
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001129
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) {
Jiri Slabyaaa246e2006-01-09 20:54:23 -08001131 pr_dbg("block_til_ready: non-block mode.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 port->flags |= ASYNC_NORMAL_ACTIVE;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001133 return 0;
1134 }
1135
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 if (C_CLOCAL(tty))
1137 do_clocal = 1;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001138
1139 /* block waiting for DCD to be asserted, and while
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 callout dev is busy */
1141 retval = 0;
1142 add_wait_queue(&port->open_wait, &wait);
1143
1144 spin_lock_irqsave(&card->card_lock, flags);
1145 if (!tty_hung_up_p(filp))
1146 port->count--;
1147 port->blocked_open++;
1148 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001149
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 while (1) {
1151 raise_dtr_rts(port);
1152
1153 set_current_state(TASK_INTERRUPTIBLE);
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001154 if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 if (port->flags & ASYNC_HUP_NOTIFY)
1156 retval = -EAGAIN;
1157 else
1158 retval = -ERESTARTSYS;
1159 break;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001160 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 if (!(port->flags & ASYNC_CLOSING) &&
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001162 (do_clocal || (port->status & ISI_DCD))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 break;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001164 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 if (signal_pending(current)) {
1166 retval = -ERESTARTSYS;
1167 break;
1168 }
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001169 schedule();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 }
1171 set_current_state(TASK_RUNNING);
1172 remove_wait_queue(&port->open_wait, &wait);
1173 spin_lock_irqsave(&card->card_lock, flags);
1174 if (!tty_hung_up_p(filp))
1175 port->count++;
1176 port->blocked_open--;
1177 spin_unlock_irqrestore(&card->card_lock, flags);
1178 if (retval)
1179 return retval;
1180 port->flags |= ASYNC_NORMAL_ACTIVE;
1181 return 0;
1182}
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001183
1184static int isicom_open(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185{
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001186 struct isi_port *port;
1187 struct isi_board *card;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 unsigned int line, board;
1189 int error;
1190
1191 line = tty->index;
1192 if (line < 0 || line > PORT_COUNT-1)
1193 return -ENODEV;
1194 board = BOARD(line);
1195 card = &isi_card[board];
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001196
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 if (!(card->status & FIRMWARE_LOADED))
1198 return -ENODEV;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001199
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 /* open on a port greater than the port count for the card !!! */
1201 if (line > ((board * 16) + card->port_count - 1))
1202 return -ENODEV;
1203
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001204 port = &isi_ports[line];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 if (isicom_paranoia_check(port, tty->name, "isicom_open"))
1206 return -ENODEV;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001207
1208 isicom_setup_board(card);
1209
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 port->count++;
1211 tty->driver_data = port;
1212 port->tty = tty;
1213 if ((error = isicom_setup_port(port))!=0)
1214 return error;
1215 if ((error = block_til_ready(tty, filp, port))!=0)
1216 return error;
1217
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001218 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219}
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001220
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221/* close et all */
1222
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001223static inline void isicom_shutdown_board(struct isi_board *bp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224{
1225 unsigned long flags;
1226
1227 spin_lock_irqsave(&bp->card_lock, flags);
1228 if (bp->status & BOARD_ACTIVE) {
1229 bp->status &= ~BOARD_ACTIVE;
1230 }
1231 spin_unlock_irqrestore(&bp->card_lock, flags);
1232}
1233
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001234static void isicom_shutdown_port(struct isi_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235{
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001236 struct isi_board *card = port->card;
1237 struct tty_struct *tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238 unsigned long flags;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001239
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 tty = port->tty;
1241
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001242 spin_lock_irqsave(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 if (!(port->flags & ASYNC_INITIALIZED)) {
1244 spin_unlock_irqrestore(&card->card_lock, flags);
1245 return;
1246 }
1247 if (port->xmit_buf) {
1248 free_page((unsigned long) port->xmit_buf);
1249 port->xmit_buf = NULL;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001250 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 port->flags &= ~ASYNC_INITIALIZED;
1252 /* 3rd October 2000 : Vinayak P Risbud */
1253 port->tty = NULL;
1254 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001255
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 /*Fix done by Anil .S on 30-04-2001
1257 remote login through isi port has dtr toggle problem
1258 due to which the carrier drops before the password prompt
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001259 appears on the remote end. Now we drop the dtr only if the
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 HUPCL(Hangup on close) flag is set for the tty*/
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001261
1262 if (C_HUPCL(tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 /* drop dtr on this port */
1264 drop_dtr(port);
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001265
1266 /* any other port uninits */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267 if (tty)
1268 set_bit(TTY_IO_ERROR, &tty->flags);
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001269
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270 if (--card->count < 0) {
Jiri Slabyaaa246e2006-01-09 20:54:23 -08001271 pr_dbg("isicom_shutdown_port: bad board(0x%lx) count %d.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 card->base, card->count);
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001273 card->count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 }
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001275
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 /* last port was closed , shutdown that boad too */
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001277 if (C_HUPCL(tty)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 if (!card->count)
1279 isicom_shutdown_board(card);
1280 }
1281}
1282
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001283static void isicom_close(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284{
Jiri Slaby8070e352006-01-09 20:54:22 -08001285 struct isi_port *port = tty->driver_data;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001286 struct isi_board *card = port->card;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 unsigned long flags;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001288
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 if (!port)
1290 return;
1291 if (isicom_paranoia_check(port, tty->name, "isicom_close"))
1292 return;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001293
Jiri Slabyaaa246e2006-01-09 20:54:23 -08001294 pr_dbg("Close start!!!.\n");
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001295
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 spin_lock_irqsave(&card->card_lock, flags);
1297 if (tty_hung_up_p(filp)) {
1298 spin_unlock_irqrestore(&card->card_lock, flags);
1299 return;
1300 }
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001301
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 if (tty->count == 1 && port->count != 1) {
Jiri Slaby8070e352006-01-09 20:54:22 -08001303 printk(KERN_WARNING "ISICOM:(0x%lx) isicom_close: bad port count"
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 "tty->count = 1 port count = %d.\n",
1305 card->base, port->count);
1306 port->count = 1;
1307 }
1308 if (--port->count < 0) {
Jiri Slaby8070e352006-01-09 20:54:22 -08001309 printk(KERN_WARNING "ISICOM:(0x%lx) isicom_close: bad port count for"
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001310 "channel%d = %d", card->base, port->channel,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 port->count);
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001312 port->count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 }
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001314
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 if (port->count) {
1316 spin_unlock_irqrestore(&card->card_lock, flags);
1317 return;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001318 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 port->flags |= ASYNC_CLOSING;
1320 tty->closing = 1;
1321 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001322
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
1324 tty_wait_until_sent(tty, port->closing_wait);
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001325 /* indicate to the card that no more data can be received
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 on this port */
1327 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001328 if (port->flags & ASYNC_INITIALIZED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 card->port_status &= ~(1 << port->channel);
1330 outw(card->port_status, card->base + 0x02);
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001331 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 isicom_shutdown_port(port);
1333 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001334
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 if (tty->driver->flush_buffer)
1336 tty->driver->flush_buffer(tty);
1337 tty_ldisc_flush(tty);
1338
1339 spin_lock_irqsave(&card->card_lock, flags);
1340 tty->closing = 0;
1341
1342 if (port->blocked_open) {
1343 spin_unlock_irqrestore(&card->card_lock, flags);
1344 if (port->close_delay) {
Jiri Slabyaaa246e2006-01-09 20:54:23 -08001345 pr_dbg("scheduling until time out.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 msleep_interruptible(jiffies_to_msecs(port->close_delay));
1347 }
1348 spin_lock_irqsave(&card->card_lock, flags);
1349 wake_up_interruptible(&port->open_wait);
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001350 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
1352 wake_up_interruptible(&port->close_wait);
1353 spin_unlock_irqrestore(&card->card_lock, flags);
1354}
1355
1356/* write et all */
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001357static int isicom_write(struct tty_struct *tty, const unsigned char *buf,
1358 int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359{
Jiri Slaby8070e352006-01-09 20:54:22 -08001360 struct isi_port *port = tty->driver_data;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001361 struct isi_board *card = port->card;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 unsigned long flags;
1363 int cnt, total = 0;
1364
1365 if (isicom_paranoia_check(port, tty->name, "isicom_write"))
1366 return 0;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001367
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 if (!tty || !port->xmit_buf || !tmp_buf)
1369 return 0;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001370
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001372
1373 while(1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 cnt = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001375 SERIAL_XMIT_SIZE - port->xmit_head));
1376 if (cnt <= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377 break;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001378
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 memcpy(port->xmit_buf + port->xmit_head, buf, cnt);
1380 port->xmit_head = (port->xmit_head + cnt) & (SERIAL_XMIT_SIZE - 1);
1381 port->xmit_cnt += cnt;
1382 buf += cnt;
1383 count -= cnt;
1384 total += cnt;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001385 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped)
1387 port->status |= ISI_TXOK;
1388 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001389 return total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390}
1391
1392/* put_char et all */
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001393static void isicom_put_char(struct tty_struct *tty, unsigned char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394{
Jiri Slaby8070e352006-01-09 20:54:22 -08001395 struct isi_port *port = tty->driver_data;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001396 struct isi_board *card = port->card;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 unsigned long flags;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001398
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 if (isicom_paranoia_check(port, tty->name, "isicom_put_char"))
1400 return;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001401
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 if (!tty || !port->xmit_buf)
1403 return;
1404
1405 spin_lock_irqsave(&card->card_lock, flags);
1406 if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
1407 spin_unlock_irqrestore(&card->card_lock, flags);
1408 return;
1409 }
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001410
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 port->xmit_buf[port->xmit_head++] = ch;
1412 port->xmit_head &= (SERIAL_XMIT_SIZE - 1);
1413 port->xmit_cnt++;
1414 spin_unlock_irqrestore(&card->card_lock, flags);
1415}
1416
1417/* flush_chars et all */
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001418static void isicom_flush_chars(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419{
Jiri Slaby8070e352006-01-09 20:54:22 -08001420 struct isi_port *port = tty->driver_data;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001421
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 if (isicom_paranoia_check(port, tty->name, "isicom_flush_chars"))
1423 return;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001424
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || !port->xmit_buf)
1426 return;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001427
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 /* this tells the transmitter to consider this port for
1429 data output to the card ... that's the best we can do. */
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001430 port->status |= ISI_TXOK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431}
1432
1433/* write_room et all */
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001434static int isicom_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435{
Jiri Slaby8070e352006-01-09 20:54:22 -08001436 struct isi_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 int free;
1438
1439 if (isicom_paranoia_check(port, tty->name, "isicom_write_room"))
1440 return 0;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001441
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 free = SERIAL_XMIT_SIZE - port->xmit_cnt - 1;
1443 if (free < 0)
1444 free = 0;
1445 return free;
1446}
1447
1448/* chars_in_buffer et all */
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001449static int isicom_chars_in_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450{
Jiri Slaby8070e352006-01-09 20:54:22 -08001451 struct isi_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 if (isicom_paranoia_check(port, tty->name, "isicom_chars_in_buffer"))
1453 return 0;
1454 return port->xmit_cnt;
1455}
1456
1457/* ioctl et all */
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001458static inline void isicom_send_break(struct isi_port *port, unsigned long length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459{
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001460 struct isi_board *card = port->card;
Jiri Slaby8070e352006-01-09 20:54:22 -08001461 unsigned long base = card->base;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001462
1463 if (!lock_card(card))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 return;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001465
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 outw(0x8000 | ((port->channel) << (card->shift_count)) | 0x3, base);
1467 outw((length & 0xff) << 8 | 0x00, base);
1468 outw((length & 0xff00), base);
1469 InterruptTheCard(base);
1470
1471 unlock_card(card);
1472}
1473
1474static int isicom_tiocmget(struct tty_struct *tty, struct file *file)
1475{
Jiri Slaby8070e352006-01-09 20:54:22 -08001476 struct isi_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 /* just send the port status */
Jiri Slaby8070e352006-01-09 20:54:22 -08001478 u16 status = port->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479
1480 if (isicom_paranoia_check(port, tty->name, "isicom_ioctl"))
1481 return -ENODEV;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001482
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 return ((status & ISI_RTS) ? TIOCM_RTS : 0) |
1484 ((status & ISI_DTR) ? TIOCM_DTR : 0) |
1485 ((status & ISI_DCD) ? TIOCM_CAR : 0) |
1486 ((status & ISI_DSR) ? TIOCM_DSR : 0) |
1487 ((status & ISI_CTS) ? TIOCM_CTS : 0) |
1488 ((status & ISI_RI ) ? TIOCM_RI : 0);
1489}
1490
1491static int isicom_tiocmset(struct tty_struct *tty, struct file *file,
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001492 unsigned int set, unsigned int clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493{
Jiri Slaby8070e352006-01-09 20:54:22 -08001494 struct isi_port *port = tty->driver_data;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001495
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 if (isicom_paranoia_check(port, tty->name, "isicom_ioctl"))
1497 return -ENODEV;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001498
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 if (set & TIOCM_RTS)
1500 raise_rts(port);
1501 if (set & TIOCM_DTR)
1502 raise_dtr(port);
1503
1504 if (clear & TIOCM_RTS)
1505 drop_rts(port);
1506 if (clear & TIOCM_DTR)
1507 drop_dtr(port);
1508
1509 return 0;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001510}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001512static int isicom_set_serial_info(struct isi_port *port,
1513 struct serial_struct __user *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514{
1515 struct serial_struct newinfo;
1516 int reconfig_port;
1517
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001518 if (copy_from_user(&newinfo, info, sizeof(newinfo)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519 return -EFAULT;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001520
1521 reconfig_port = ((port->flags & ASYNC_SPD_MASK) !=
1522 (newinfo.flags & ASYNC_SPD_MASK));
1523
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 if (!capable(CAP_SYS_ADMIN)) {
1525 if ((newinfo.close_delay != port->close_delay) ||
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001526 (newinfo.closing_wait != port->closing_wait) ||
1527 ((newinfo.flags & ~ASYNC_USR_MASK) !=
1528 (port->flags & ~ASYNC_USR_MASK)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 return -EPERM;
1530 port->flags = ((port->flags & ~ ASYNC_USR_MASK) |
1531 (newinfo.flags & ASYNC_USR_MASK));
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001532 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 else {
1534 port->close_delay = newinfo.close_delay;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001535 port->closing_wait = newinfo.closing_wait;
1536 port->flags = ((port->flags & ~ASYNC_FLAGS) |
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 (newinfo.flags & ASYNC_FLAGS));
1538 }
1539 if (reconfig_port) {
1540 isicom_config_port(port);
1541 }
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001542 return 0;
1543}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001545static int isicom_get_serial_info(struct isi_port *port,
1546 struct serial_struct __user *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547{
1548 struct serial_struct out_info;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001549
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 memset(&out_info, 0, sizeof(out_info));
1551/* out_info.type = ? */
1552 out_info.line = port - isi_ports;
1553 out_info.port = port->card->base;
1554 out_info.irq = port->card->irq;
1555 out_info.flags = port->flags;
1556/* out_info.baud_base = ? */
1557 out_info.close_delay = port->close_delay;
1558 out_info.closing_wait = port->closing_wait;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001559 if (copy_to_user(info, &out_info, sizeof(out_info)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 return -EFAULT;
1561 return 0;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001562}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001564static int isicom_ioctl(struct tty_struct *tty, struct file *filp,
1565 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566{
Jiri Slaby8070e352006-01-09 20:54:22 -08001567 struct isi_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 void __user *argp = (void __user *)arg;
1569 int retval;
1570
1571 if (isicom_paranoia_check(port, tty->name, "isicom_ioctl"))
1572 return -ENODEV;
1573
1574 switch(cmd) {
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001575 case TCSBRK:
1576 retval = tty_check_change(tty);
1577 if (retval)
1578 return retval;
1579 tty_wait_until_sent(tty, 0);
1580 if (!arg)
1581 isicom_send_break(port, HZ/4);
1582 return 0;
1583
1584 case TCSBRKP:
1585 retval = tty_check_change(tty);
1586 if (retval)
1587 return retval;
1588 tty_wait_until_sent(tty, 0);
1589 isicom_send_break(port, arg ? arg * (HZ/10) : HZ/4);
1590 return 0;
1591
1592 case TIOCGSOFTCAR:
1593 return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *)argp);
1594
1595 case TIOCSSOFTCAR:
1596 if (get_user(arg, (unsigned long __user *) argp))
1597 return -EFAULT;
1598 tty->termios->c_cflag =
1599 ((tty->termios->c_cflag & ~CLOCAL) |
1600 (arg ? CLOCAL : 0));
1601 return 0;
1602
1603 case TIOCGSERIAL:
1604 return isicom_get_serial_info(port, argp);
1605
1606 case TIOCSSERIAL:
1607 return isicom_set_serial_info(port, argp);
1608
1609 default:
1610 return -ENOIOCTLCMD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 }
1612 return 0;
1613}
1614
1615/* set_termios et all */
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001616static void isicom_set_termios(struct tty_struct *tty,
1617 struct termios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618{
Jiri Slaby8070e352006-01-09 20:54:22 -08001619 struct isi_port *port = tty->driver_data;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001620
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 if (isicom_paranoia_check(port, tty->name, "isicom_set_termios"))
1622 return;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001623
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 if (tty->termios->c_cflag == old_termios->c_cflag &&
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001625 tty->termios->c_iflag == old_termios->c_iflag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626 return;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001627
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 isicom_config_port(port);
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001629
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630 if ((old_termios->c_cflag & CRTSCTS) &&
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001631 !(tty->termios->c_cflag & CRTSCTS)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632 tty->hw_stopped = 0;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001633 isicom_start(tty);
1634 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635}
1636
1637/* throttle et all */
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001638static void isicom_throttle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639{
Jiri Slaby8070e352006-01-09 20:54:22 -08001640 struct isi_port *port = tty->driver_data;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001641 struct isi_board *card = port->card;
1642
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 if (isicom_paranoia_check(port, tty->name, "isicom_throttle"))
1644 return;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001645
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646 /* tell the card that this port cannot handle any more data for now */
1647 card->port_status &= ~(1 << port->channel);
1648 outw(card->port_status, card->base + 0x02);
1649}
1650
1651/* unthrottle et all */
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001652static void isicom_unthrottle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653{
Jiri Slaby8070e352006-01-09 20:54:22 -08001654 struct isi_port *port = tty->driver_data;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001655 struct isi_board *card = port->card;
1656
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657 if (isicom_paranoia_check(port, tty->name, "isicom_unthrottle"))
1658 return;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001659
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 /* tell the card that this port is ready to accept more data */
1661 card->port_status |= (1 << port->channel);
1662 outw(card->port_status, card->base + 0x02);
1663}
1664
1665/* stop et all */
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001666static void isicom_stop(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667{
Jiri Slaby8070e352006-01-09 20:54:22 -08001668 struct isi_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669
1670 if (isicom_paranoia_check(port, tty->name, "isicom_stop"))
1671 return;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001672
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 /* this tells the transmitter not to consider this port for
1674 data output to the card. */
1675 port->status &= ~ISI_TXOK;
1676}
1677
1678/* start et all */
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001679static void isicom_start(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680{
Jiri Slaby8070e352006-01-09 20:54:22 -08001681 struct isi_port *port = tty->driver_data;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001682
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 if (isicom_paranoia_check(port, tty->name, "isicom_start"))
1684 return;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001685
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 /* this tells the transmitter to consider this port for
1687 data output to the card. */
1688 port->status |= ISI_TXOK;
1689}
1690
1691/* hangup et all */
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001692static void do_isicom_hangup(void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693{
Jiri Slaby8070e352006-01-09 20:54:22 -08001694 struct isi_port *port = data;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001695 struct tty_struct *tty;
1696
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 tty = port->tty;
1698 if (tty)
1699 tty_hangup(tty);
1700}
1701
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001702static void isicom_hangup(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703{
Jiri Slaby8070e352006-01-09 20:54:22 -08001704 struct isi_port *port = tty->driver_data;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001705
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706 if (isicom_paranoia_check(port, tty->name, "isicom_hangup"))
1707 return;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001708
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 isicom_shutdown_port(port);
1710 port->count = 0;
1711 port->flags &= ~ASYNC_NORMAL_ACTIVE;
1712 port->tty = NULL;
1713 wake_up_interruptible(&port->open_wait);
1714}
1715
1716/* flush_buffer et all */
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001717static void isicom_flush_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718{
Jiri Slaby8070e352006-01-09 20:54:22 -08001719 struct isi_port *port = tty->driver_data;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001720 struct isi_board *card = port->card;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 unsigned long flags;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001722
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 if (isicom_paranoia_check(port, tty->name, "isicom_flush_buffer"))
1724 return;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001725
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726 spin_lock_irqsave(&card->card_lock, flags);
1727 port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
1728 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001729
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 wake_up_interruptible(&tty->write_wait);
1731 tty_wakeup(tty);
1732}
1733
1734
Adrian Bunk4b849722005-06-25 14:58:52 -07001735static int __devinit register_ioregion(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736{
1737 int count, done=0;
1738 for (count=0; count < BOARD_COUNT; count++ ) {
1739 if (isi_card[count].base)
1740 if (!request_region(isi_card[count].base,16,ISICOM_NAME)) {
Jiri Slaby8070e352006-01-09 20:54:22 -08001741 printk(KERN_DEBUG "ISICOM: I/O Region 0x%lx-0x%lx is busy. Card%d will be disabled.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742 isi_card[count].base,isi_card[count].base+15,count+1);
1743 isi_card[count].base=0;
1744 done++;
1745 }
1746 }
1747 return done;
1748}
1749
Adrian Bunk4b849722005-06-25 14:58:52 -07001750static void unregister_ioregion(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751{
1752 int count;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001753 for (count=0; count < BOARD_COUNT; count++ )
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754 if (isi_card[count].base) {
1755 release_region(isi_card[count].base,16);
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001756#ifdef ISICOM_DEBUG
Jiri Slaby8070e352006-01-09 20:54:22 -08001757 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);
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001758#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 }
1760}
1761
1762static struct tty_operations isicom_ops = {
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001763 .open = isicom_open,
1764 .close = isicom_close,
1765 .write = isicom_write,
1766 .put_char = isicom_put_char,
1767 .flush_chars = isicom_flush_chars,
1768 .write_room = isicom_write_room,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 .chars_in_buffer = isicom_chars_in_buffer,
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001770 .ioctl = isicom_ioctl,
1771 .set_termios = isicom_set_termios,
1772 .throttle = isicom_throttle,
1773 .unthrottle = isicom_unthrottle,
1774 .stop = isicom_stop,
1775 .start = isicom_start,
1776 .hangup = isicom_hangup,
1777 .flush_buffer = isicom_flush_buffer,
1778 .tiocmget = isicom_tiocmget,
1779 .tiocmset = isicom_tiocmset,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780};
1781
Jiri Slabyaaa246e2006-01-09 20:54:23 -08001782static int __devinit isicom_register_tty_driver(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783{
Jiri Slabyaaa246e2006-01-09 20:54:23 -08001784 int error = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785
1786 /* tty driver structure initialization */
1787 isicom_normal = alloc_tty_driver(PORT_COUNT);
1788 if (!isicom_normal)
Jiri Slabyaaa246e2006-01-09 20:54:23 -08001789 goto end;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790
Jiri Slabyaaa246e2006-01-09 20:54:23 -08001791 isicom_normal->owner = THIS_MODULE;
1792 isicom_normal->name = "ttyM";
1793 isicom_normal->devfs_name = "isicom/";
1794 isicom_normal->major = ISICOM_NMAJOR;
1795 isicom_normal->minor_start = 0;
1796 isicom_normal->type = TTY_DRIVER_TYPE_SERIAL;
1797 isicom_normal->subtype = SERIAL_TYPE_NORMAL;
1798 isicom_normal->init_termios = tty_std_termios;
1799 isicom_normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL |
1800 CLOCAL;
1801 isicom_normal->flags = TTY_DRIVER_REAL_RAW;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 tty_set_operations(isicom_normal, &isicom_ops);
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001803
Jiri Slabyaaa246e2006-01-09 20:54:23 -08001804 if ((error = tty_register_driver(isicom_normal))) {
1805 pr_dbg("Couldn't register the dialin driver, error=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806 error);
1807 put_tty_driver(isicom_normal);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 }
Jiri Slabyaaa246e2006-01-09 20:54:23 -08001809end:
1810 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811}
1812
Jiri Slabyaaa246e2006-01-09 20:54:23 -08001813static void isicom_unregister_tty_driver(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814{
Jiri Slabyaaa246e2006-01-09 20:54:23 -08001815 int error;
1816
1817 if ((error = tty_unregister_driver(isicom_normal)))
1818 pr_dbg("couldn't unregister normal driver, error=%d.\n", error);
1819
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 put_tty_driver(isicom_normal);
1821}
1822
Adrian Bunk4b849722005-06-25 14:58:52 -07001823static int __devinit register_isr(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824{
1825 int count, done=0;
1826 unsigned long irqflags;
1827
1828 for (count=0; count < BOARD_COUNT; count++ ) {
1829 if (isi_card[count].base) {
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001830 irqflags = (isi_card[count].isa == YES) ?
1831 SA_INTERRUPT :
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 (SA_INTERRUPT | SA_SHIRQ);
1833
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001834 if (request_irq(isi_card[count].irq,
1835 isicom_interrupt,
1836 irqflags,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 ISICOM_NAME, &isi_card[count])) {
1838
1839 printk(KERN_WARNING "ISICOM: Could not"
1840 " install handler at Irq %d."
1841 " Card%d will be disabled.\n",
1842 isi_card[count].irq, count+1);
1843
1844 release_region(isi_card[count].base,16);
1845 isi_card[count].base=0;
1846 }
1847 else
1848 done++;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001849 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 }
1851 return done;
1852}
1853
1854static void __exit unregister_isr(void)
1855{
1856 int count;
1857
1858 for (count=0; count < BOARD_COUNT; count++ ) {
1859 if (isi_card[count].base)
1860 free_irq(isi_card[count].irq, &isi_card[count]);
1861 }
1862}
1863
Adrian Bunk4b849722005-06-25 14:58:52 -07001864static int __devinit isicom_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865{
1866 int card, channel, base;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001867 struct isi_port *port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 unsigned long page;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001869
1870 if (!tmp_buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 page = get_zeroed_page(GFP_KERNEL);
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001872 if (!page) {
1873#ifdef ISICOM_DEBUG
1874 printk(KERN_DEBUG "ISICOM: Couldn't allocate page for tmp_buf.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875#else
1876 printk(KERN_ERR "ISICOM: Not enough memory...\n");
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001877#endif
1878 return 0;
1879 }
1880 tmp_buf = (unsigned char *) page;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 }
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001882
1883 if (!register_ioregion())
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 {
1885 printk(KERN_ERR "ISICOM: All required I/O space found busy.\n");
1886 free_page((unsigned long)tmp_buf);
1887 return 0;
1888 }
Jiri Slabyaaa246e2006-01-09 20:54:23 -08001889 if (isicom_register_tty_driver())
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890 {
1891 unregister_ioregion();
1892 free_page((unsigned long)tmp_buf);
1893 return 0;
1894 }
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001895 if (!register_isr())
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 {
Jiri Slabyaaa246e2006-01-09 20:54:23 -08001897 isicom_unregister_tty_driver();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898 /* ioports already uregistered in register_isr */
1899 free_page((unsigned long)tmp_buf);
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001900 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901 }
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001902
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903 memset(isi_ports, 0, sizeof(isi_ports));
1904 for (card = 0; card < BOARD_COUNT; card++) {
1905 port = &isi_ports[card * 16];
1906 isi_card[card].ports = port;
1907 spin_lock_init(&isi_card[card].card_lock);
1908 base = isi_card[card].base;
1909 for (channel = 0; channel < 16; channel++, port++) {
1910 port->magic = ISICOM_MAGIC;
1911 port->card = &isi_card[card];
1912 port->channel = channel;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001913 port->close_delay = 50 * HZ/100;
1914 port->closing_wait = 3000 * HZ/100;
1915 INIT_WORK(&port->hangup_tq, do_isicom_hangup, port);
1916 INIT_WORK(&port->bh_tqueue, isicom_bottomhalf, port);
1917 port->status = 0;
1918 init_waitqueue_head(&port->open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919 init_waitqueue_head(&port->close_wait);
1920 /* . . . */
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001921 }
1922 }
1923
1924 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925}
1926
1927/*
1928 * Insmod can set static symbols so keep these static
1929 */
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001930
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931static int io[4];
1932static int irq[4];
1933
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934static int __devinit isicom_setup(void)
1935{
1936 struct pci_dev *dev = NULL;
1937 int retval, card, idx, count;
1938 unsigned char pciirq;
1939 unsigned int ioaddr;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001940
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941 card = 0;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001942 for (idx=0; idx < BOARD_COUNT; idx++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 if (io[idx]) {
1944 isi_card[idx].base=io[idx];
1945 isi_card[idx].irq=irq[idx];
1946 isi_card[idx].isa=YES;
1947 card++;
1948 }
1949 else {
1950 isi_card[idx].base = 0;
1951 isi_card[idx].irq = 0;
1952 }
1953 }
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001954
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955 for (idx=0 ;idx < card; idx++) {
1956 if (!((isi_card[idx].irq==2)||(isi_card[idx].irq==3)||
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001957 (isi_card[idx].irq==4)||(isi_card[idx].irq==5)||
1958 (isi_card[idx].irq==7)||(isi_card[idx].irq==10)||
1959 (isi_card[idx].irq==11)||(isi_card[idx].irq==12)||
1960 (isi_card[idx].irq==15))) {
1961
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962 if (isi_card[idx].base) {
1963 printk(KERN_ERR "ISICOM: Irq %d unsupported. Disabling Card%d...\n",
1964 isi_card[idx].irq, idx+1);
1965 isi_card[idx].base=0;
1966 card--;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001967 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968 }
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001969 }
1970
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971 if (card < BOARD_COUNT) {
1972 for (idx=0; idx < DEVID_COUNT; idx++) {
1973 dev = NULL;
1974 for (;;){
1975 if (!(dev = pci_find_device(VENDOR_ID, isicom_pci_tbl[idx].device, dev)))
1976 break;
1977 if (card >= BOARD_COUNT)
1978 break;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001979
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980 if (pci_enable_device(dev))
1981 break;
1982
1983 /* found a PCI ISI card! */
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001984 ioaddr = pci_resource_start (dev, 3);
1985 /* i.e at offset 0x1c in the
1986 * PCI configuration register
1987 * space.
1988 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989 pciirq = dev->irq;
1990 printk(KERN_INFO "ISI PCI Card(Device ID 0x%x)\n", isicom_pci_tbl[idx].device);
1991 /*
1992 * allot the first empty slot in the array
Jiri Slabyd8d16e42006-01-09 20:54:21 -08001993 */
1994 for (count=0; count < BOARD_COUNT; count++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995 if (isi_card[count].base == 0) {
1996 isi_card[count].base = ioaddr;
1997 isi_card[count].irq = pciirq;
1998 isi_card[count].isa = NO;
1999 card++;
2000 break;
2001 }
2002 }
Jiri Slabyd8d16e42006-01-09 20:54:21 -08002003 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004 if (card >= BOARD_COUNT) break;
2005 }
2006 }
Jiri Slabyd8d16e42006-01-09 20:54:21 -08002007
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008 if (!(isi_card[0].base || isi_card[1].base || isi_card[2].base || isi_card[3].base)) {
Jiri Slabyd8d16e42006-01-09 20:54:21 -08002009 printk(KERN_ERR "ISICOM: No valid card configuration. Driver cannot be initialized...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 return -EIO;
Jiri Slabyd8d16e42006-01-09 20:54:21 -08002011 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012
2013 retval = misc_register(&isiloader_device);
2014 if (retval < 0) {
2015 printk(KERN_ERR "ISICOM: Unable to register firmware loader driver.\n");
2016 return retval;
2017 }
Jiri Slabyd8d16e42006-01-09 20:54:21 -08002018
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019 if (!isicom_init()) {
Jiri Slabyd8d16e42006-01-09 20:54:21 -08002020 if (misc_deregister(&isiloader_device))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021 printk(KERN_ERR "ISICOM: Unable to unregister Firmware Loader driver\n");
2022 return -EIO;
2023 }
Jiri Slabyd8d16e42006-01-09 20:54:21 -08002024
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025 init_timer(&tx);
2026 tx.expires = jiffies + 1;
2027 tx.data = 0;
2028 tx.function = isicom_tx;
2029 re_schedule = 1;
2030 add_timer(&tx);
Jiri Slabyd8d16e42006-01-09 20:54:21 -08002031
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032 return 0;
2033}
2034
2035static void __exit isicom_exit(void)
2036{
Jiri Slabyaaa246e2006-01-09 20:54:23 -08002037 unsigned int index = 0;
2038
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039 re_schedule = 0;
Jiri Slabyaaa246e2006-01-09 20:54:23 -08002040
2041 while (re_schedule != 2 && index++ < 100)
2042 msleep(10);
2043
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044 unregister_isr();
Jiri Slabyaaa246e2006-01-09 20:54:23 -08002045 isicom_unregister_tty_driver();
Jiri Slabyd8d16e42006-01-09 20:54:21 -08002046 unregister_ioregion();
2047 if (tmp_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048 free_page((unsigned long)tmp_buf);
2049 if (misc_deregister(&isiloader_device))
2050 printk(KERN_ERR "ISICOM: Unable to unregister Firmware Loader driver\n");
2051}
2052
2053module_init(isicom_setup);
2054module_exit(isicom_exit);
Jiri Slabyaaa246e2006-01-09 20:54:23 -08002055
2056MODULE_AUTHOR("MultiTech");
2057MODULE_DESCRIPTION("Driver for the ISI series of cards by MultiTech");
2058MODULE_LICENSE("GPL");
2059module_param_array(io, int, NULL, 0);
2060MODULE_PARM_DESC(io, "I/O ports for the cards");
2061module_param_array(irq, int, NULL, 0);
2062MODULE_PARM_DESC(irq, "Interrupts for the cards");