Merge branch 'upstream' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/libata-dev
[linux-2.6] / drivers / char / specialix.c
1 /*
2  *      specialix.c  -- specialix IO8+ multiport serial driver.
3  *
4  *      Copyright (C) 1997  Roger Wolff (R.E.Wolff@BitWizard.nl)
5  *      Copyright (C) 1994-1996  Dmitry Gorodchanin (pgmdsg@ibi.com)
6  *
7  *      Specialix pays for the development and support of this driver.
8  *      Please DO contact io8-linux@specialix.co.uk if you require
9  *      support. But please read the documentation (specialix.txt)
10  *      first.
11  *
12  *      This driver was developped in the BitWizard linux device
13  *      driver service. If you require a linux device driver for your
14  *      product, please contact devices@BitWizard.nl for a quote.
15  *
16  *      This code is firmly based on the riscom/8 serial driver,
17  *      written by Dmitry Gorodchanin. The specialix IO8+ card
18  *      programming information was obtained from the CL-CD1865 Data
19  *      Book, and Specialix document number 6200059: IO8+ Hardware
20  *      Functional Specification.
21  *
22  *      This program is free software; you can redistribute it and/or
23  *      modify it under the terms of the GNU General Public License as
24  *      published by the Free Software Foundation; either version 2 of
25  *      the License, or (at your option) any later version.
26  *
27  *      This program is distributed in the hope that it will be
28  *      useful, but WITHOUT ANY WARRANTY; without even the implied
29  *      warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
30  *      PURPOSE.  See the GNU General Public License for more details.
31  *
32  *      You should have received a copy of the GNU General Public
33  *      License along with this program; if not, write to the Free
34  *      Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
35  *      USA.
36  *
37  * Revision history:
38  *
39  * Revision 1.0:  April 1st 1997.
40  *                Initial release for alpha testing.
41  * Revision 1.1:  April 14th 1997. 
42  *                Incorporated Richard Hudsons suggestions, 
43  *                removed some debugging printk's.
44  * Revision 1.2:  April 15th 1997.
45  *                Ported to 2.1.x kernels.
46  * Revision 1.3:  April 17th 1997 
47  *                Backported to 2.0. (Compatibility macros). 
48  * Revision 1.4:  April 18th 1997
49  *                Fixed DTR/RTS bug that caused the card to indicate 
50  *                "don't send data" to a modem after the password prompt.  
51  *                Fixed bug for premature (fake) interrupts.
52  * Revision 1.5:  April 19th 1997
53  *                fixed a minor typo in the header file, cleanup a little. 
54  *                performance warnings are now MAXed at once per minute.
55  * Revision 1.6:  May 23 1997
56  *                Changed the specialix=... format to include interrupt.
57  * Revision 1.7:  May 27 1997
58  *                Made many more debug printk's a compile time option.
59  * Revision 1.8:  Jul 1  1997
60  *                port to linux-2.1.43 kernel.
61  * Revision 1.9:  Oct 9  1998
62  *                Added stuff for the IO8+/PCI version.
63  * Revision 1.10: Oct 22  1999 / Jan 21 2000. 
64  *                Added stuff for setserial. 
65  *                Nicolas Mailhot (Nicolas.Mailhot@email.enst.fr)
66  * 
67  */
68
69 #define VERSION "1.11"
70
71
72 /*
73  * There is a bunch of documentation about the card, jumpers, config
74  * settings, restrictions, cables, device names and numbers in
75  * Documentation/specialix.txt
76  */
77
78 #include <linux/config.h>
79 #include <linux/module.h>
80
81 #include <asm/io.h>
82 #include <linux/kernel.h>
83 #include <linux/sched.h>
84 #include <linux/ioport.h>
85 #include <linux/interrupt.h>
86 #include <linux/errno.h>
87 #include <linux/tty.h>
88 #include <linux/mm.h>
89 #include <linux/serial.h>
90 #include <linux/fcntl.h>
91 #include <linux/major.h>
92 #include <linux/delay.h>
93 #include <linux/version.h>
94 #include <linux/pci.h>
95 #include <linux/init.h>
96 #include <asm/uaccess.h>
97
98 #include "specialix_io8.h"
99 #include "cd1865.h"
100
101
102 /*
103    This driver can spew a whole lot of debugging output at you. If you
104    need maximum performance, you should disable the DEBUG define. To
105    aid in debugging in the field, I'm leaving the compile-time debug
106    features enabled, and disable them "runtime". That allows me to
107    instruct people with problems to enable debugging without requiring
108    them to recompile...
109 */
110 #define DEBUG
111
112 static int sx_debug;
113 static int sx_rxfifo = SPECIALIX_RXFIFO;
114
115 #ifdef DEBUG
116 #define dprintk(f, str...) if (sx_debug & f) printk (str)
117 #else
118 #define dprintk(f, str...) /* nothing */
119 #endif
120
121 #define SX_DEBUG_FLOW    0x0001
122 #define SX_DEBUG_DATA    0x0002
123 #define SX_DEBUG_PROBE   0x0004
124 #define SX_DEBUG_CHAN    0x0008
125 #define SX_DEBUG_INIT    0x0010
126 #define SX_DEBUG_RX      0x0020
127 #define SX_DEBUG_TX      0x0040
128 #define SX_DEBUG_IRQ     0x0080
129 #define SX_DEBUG_OPEN    0x0100
130 #define SX_DEBUG_TERMIOS 0x0200
131 #define SX_DEBUG_SIGNALS 0x0400
132 #define SX_DEBUG_FIFO    0x0800
133
134
135 #define func_enter() dprintk (SX_DEBUG_FLOW, "io8: enter %s\n",__FUNCTION__)
136 #define func_exit()  dprintk (SX_DEBUG_FLOW, "io8: exit  %s\n", __FUNCTION__)
137
138 #define jiffies_from_ms(a) ((((a) * HZ)/1000)+1)
139
140
141 /* Configurable options: */
142
143 /* Am I paranoid or not ? ;-) */
144 #define SPECIALIX_PARANOIA_CHECK
145
146 /* Do I trust the IRQ from the card? (enabeling it doesn't seem to help)
147    When the IRQ routine leaves the chip in a state that is keeps on
148    requiring attention, the timer doesn't help either. */
149 #undef SPECIALIX_TIMER
150
151 #ifdef SPECIALIX_TIMER
152 static int sx_poll = HZ;
153 #endif
154
155
156
157 /* 
158  * The following defines are mostly for testing purposes. But if you need
159  * some nice reporting in your syslog, you can define them also.
160  */
161 #undef SX_REPORT_FIFO
162 #undef SX_REPORT_OVERRUN
163
164
165
166 #ifdef CONFIG_SPECIALIX_RTSCTS
167 #define SX_CRTSCTS(bla) 1
168 #else
169 #define SX_CRTSCTS(tty) C_CRTSCTS(tty)
170 #endif
171
172
173 /* Used to be outb (0xff, 0x80); */
174 #define short_pause() udelay (1)
175
176
177 #define SPECIALIX_LEGAL_FLAGS \
178         (ASYNC_HUP_NOTIFY   | ASYNC_SAK          | ASYNC_SPLIT_TERMIOS   | \
179          ASYNC_SPD_HI       | ASYNC_SPEED_VHI    | ASYNC_SESSION_LOCKOUT | \
180          ASYNC_PGRP_LOCKOUT | ASYNC_CALLOUT_NOHUP)
181
182 #undef RS_EVENT_WRITE_WAKEUP
183 #define RS_EVENT_WRITE_WAKEUP   0
184
185 static struct tty_driver *specialix_driver;
186 static unsigned char * tmp_buf;
187 static DECLARE_MUTEX(tmp_buf_sem);
188
189 static unsigned long baud_table[] =  {
190         0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
191         9600, 19200, 38400, 57600, 115200, 0, 
192 };
193
194 static struct specialix_board sx_board[SX_NBOARD] =  {
195         { 0, SX_IOBASE1,  9, },
196         { 0, SX_IOBASE2, 11, },
197         { 0, SX_IOBASE3, 12, },
198         { 0, SX_IOBASE4, 15, },
199 };
200
201 static struct specialix_port sx_port[SX_NBOARD * SX_NPORT];
202
203
204 #ifdef SPECIALIX_TIMER
205 static struct timer_list missed_irq_timer;
206 static irqreturn_t sx_interrupt(int irq, void * dev_id, struct pt_regs * regs);
207 #endif
208
209
210
211 static inline int sx_paranoia_check(struct specialix_port const * port,
212                                     char *name, const char *routine)
213 {
214 #ifdef SPECIALIX_PARANOIA_CHECK
215         static const char *badmagic =
216                 KERN_ERR "sx: Warning: bad specialix port magic number for device %s in %s\n";
217         static const char *badinfo =
218                 KERN_ERR "sx: Warning: null specialix port for device %s in %s\n";
219  
220         if (!port) {
221                 printk(badinfo, name, routine);
222                 return 1;
223         }
224         if (port->magic != SPECIALIX_MAGIC) {
225                 printk(badmagic, name, routine);
226                 return 1;
227         }
228 #endif
229         return 0;
230 }
231
232
233 /*
234  * 
235  *  Service functions for specialix IO8+ driver.
236  * 
237  */
238
239 /* Get board number from pointer */
240 static inline int board_No (struct specialix_board * bp)
241 {
242         return bp - sx_board;
243 }
244
245
246 /* Get port number from pointer */
247 static inline int port_No (struct specialix_port const * port)
248 {
249         return SX_PORT(port - sx_port); 
250 }
251
252
253 /* Get pointer to board from pointer to port */
254 static inline struct specialix_board * port_Board(struct specialix_port const * port)
255 {
256         return &sx_board[SX_BOARD(port - sx_port)];
257 }
258
259
260 /* Input Byte from CL CD186x register */
261 static inline unsigned char sx_in(struct specialix_board  * bp, unsigned short reg)
262 {
263         bp->reg = reg | 0x80;
264         outb (reg | 0x80, bp->base + SX_ADDR_REG);
265         return inb  (bp->base + SX_DATA_REG);
266 }
267
268
269 /* Output Byte to CL CD186x register */
270 static inline void sx_out(struct specialix_board  * bp, unsigned short reg,
271                           unsigned char val)
272 {
273         bp->reg = reg | 0x80;
274         outb (reg | 0x80, bp->base + SX_ADDR_REG);
275         outb (val, bp->base + SX_DATA_REG);
276 }
277
278
279 /* Input Byte from CL CD186x register */
280 static inline unsigned char sx_in_off(struct specialix_board  * bp, unsigned short reg)
281 {
282         bp->reg = reg;
283         outb (reg, bp->base + SX_ADDR_REG);
284         return inb  (bp->base + SX_DATA_REG);
285 }
286
287
288 /* Output Byte to CL CD186x register */
289 static inline void sx_out_off(struct specialix_board  * bp, unsigned short reg,
290                           unsigned char val)
291 {
292         bp->reg = reg;
293         outb (reg, bp->base + SX_ADDR_REG);
294         outb (val, bp->base + SX_DATA_REG);
295 }
296
297
298 /* Wait for Channel Command Register ready */
299 static inline void sx_wait_CCR(struct specialix_board  * bp)
300 {
301         unsigned long delay, flags;
302         unsigned char ccr;
303
304         for (delay = SX_CCR_TIMEOUT; delay; delay--) {
305                 spin_lock_irqsave(&bp->lock, flags);
306                 ccr = sx_in(bp, CD186x_CCR);
307                 spin_unlock_irqrestore(&bp->lock, flags);
308                 if (!ccr)
309                         return;
310                 udelay (1);
311         }
312         
313         printk(KERN_ERR "sx%d: Timeout waiting for CCR.\n", board_No(bp));
314 }
315
316
317 /* Wait for Channel Command Register ready */
318 static inline void sx_wait_CCR_off(struct specialix_board  * bp)
319 {
320         unsigned long delay;
321         unsigned char crr;
322         unsigned long flags;
323
324         for (delay = SX_CCR_TIMEOUT; delay; delay--) {
325                 spin_lock_irqsave(&bp->lock, flags);
326                 crr = sx_in_off(bp, CD186x_CCR);
327                 spin_unlock_irqrestore(&bp->lock, flags);
328                 if (!crr)
329                         return;
330                 udelay (1);
331         }
332         
333         printk(KERN_ERR "sx%d: Timeout waiting for CCR.\n", board_No(bp));
334 }
335
336
337 /*
338  *  specialix IO8+ IO range functions.
339  */
340
341 static inline int sx_check_io_range(struct specialix_board * bp)
342 {
343         return check_region (bp->base, SX_IO_SPACE);
344 }
345
346
347 static inline void sx_request_io_range(struct specialix_board * bp)
348 {
349         request_region(bp->base, 
350                        bp->flags&SX_BOARD_IS_PCI?SX_PCI_IO_SPACE:SX_IO_SPACE,
351                        "specialix IO8+" );
352 }
353
354
355 static inline void sx_release_io_range(struct specialix_board * bp)
356 {
357         release_region(bp->base, 
358                        bp->flags&SX_BOARD_IS_PCI?SX_PCI_IO_SPACE:SX_IO_SPACE);
359 }
360
361         
362 /* Must be called with enabled interrupts */
363 /* Ugly. Very ugly. Don't use this for anything else than initialization 
364    code */
365 static inline void sx_long_delay(unsigned long delay)
366 {
367         unsigned long i;
368         
369         for (i = jiffies + delay; time_after(i, jiffies); ) ;
370 }
371
372
373
374 /* Set the IRQ using the RTS lines that run to the PAL on the board.... */
375 static int sx_set_irq ( struct specialix_board *bp)
376 {
377         int virq;
378         int i;
379         unsigned long flags;
380
381         if (bp->flags & SX_BOARD_IS_PCI) 
382                 return 1;
383         switch (bp->irq) {
384         /* In the same order as in the docs... */
385         case 15: virq = 0;break;
386         case 12: virq = 1;break;
387         case 11: virq = 2;break;
388         case 9:  virq = 3;break;
389         default: printk (KERN_ERR "Speclialix: cannot set irq to %d.\n", bp->irq);
390                  return 0;
391         }
392         spin_lock_irqsave(&bp->lock, flags);
393         for (i=0;i<2;i++) {
394                 sx_out(bp, CD186x_CAR, i);
395                 sx_out(bp, CD186x_MSVRTS, ((virq >> i) & 0x1)? MSVR_RTS:0);
396         }
397         spin_unlock_irqrestore(&bp->lock, flags);
398         return 1;
399 }
400
401
402 /* Reset and setup CD186x chip */
403 static int sx_init_CD186x(struct specialix_board  * bp)
404 {
405         unsigned long flags;
406         int scaler;
407         int rv = 1;
408
409         func_enter();
410         sx_wait_CCR_off(bp);                       /* Wait for CCR ready        */
411         spin_lock_irqsave(&bp->lock, flags);
412         sx_out_off(bp, CD186x_CCR, CCR_HARDRESET);      /* Reset CD186x chip          */
413         spin_unlock_irqrestore(&bp->lock, flags);
414         sx_long_delay(HZ/20);                      /* Delay 0.05 sec            */
415         spin_lock_irqsave(&bp->lock, flags);
416         sx_out_off(bp, CD186x_GIVR, SX_ID);             /* Set ID for this chip      */
417         sx_out_off(bp, CD186x_GICR, 0);                 /* Clear all bits            */
418         sx_out_off(bp, CD186x_PILR1, SX_ACK_MINT);      /* Prio for modem intr       */
419         sx_out_off(bp, CD186x_PILR2, SX_ACK_TINT);      /* Prio for transmitter intr */
420         sx_out_off(bp, CD186x_PILR3, SX_ACK_RINT);      /* Prio for receiver intr    */
421         /* Set RegAckEn */
422         sx_out_off(bp, CD186x_SRCR, sx_in (bp, CD186x_SRCR) | SRCR_REGACKEN);
423         
424         /* Setting up prescaler. We need 4 ticks per 1 ms */
425         scaler =  SX_OSCFREQ/SPECIALIX_TPS;
426
427         sx_out_off(bp, CD186x_PPRH, scaler >> 8);
428         sx_out_off(bp, CD186x_PPRL, scaler & 0xff);
429         spin_unlock_irqrestore(&bp->lock, flags);
430
431         if (!sx_set_irq (bp)) {
432                 /* Figure out how to pass this along... */
433                 printk (KERN_ERR "Cannot set irq to %d.\n", bp->irq);
434                 rv = 0;
435         }
436
437         func_exit();
438         return rv;
439 }
440
441
442 static int read_cross_byte (struct specialix_board *bp, int reg, int bit)
443 {
444         int i;
445         int t;
446         unsigned long flags;
447
448         spin_lock_irqsave(&bp->lock, flags);
449         for (i=0, t=0;i<8;i++) {
450                 sx_out_off (bp, CD186x_CAR, i);
451                 if (sx_in_off (bp, reg) & bit) 
452                         t |= 1 << i;
453         }
454         spin_unlock_irqrestore(&bp->lock, flags);
455
456         return t;
457 }
458
459
460 #ifdef SPECIALIX_TIMER
461 void missed_irq (unsigned long data)
462 {
463         unsigned char irq;
464         unsigned long flags;
465         struct specialix_board  *bp = (struct specialix_board *)data;
466
467         spin_lock_irqsave(&bp->lock, flags);
468         irq = sx_in ((struct specialix_board *)data, CD186x_SRSR) &
469                                                     (SRSR_RREQint |
470                                                      SRSR_TREQint |
471                                                      SRSR_MREQint);
472         spin_unlock_irqrestore(&bp->lock, flags);
473         if (irq) {
474                 printk (KERN_INFO "Missed interrupt... Calling int from timer. \n");
475                 sx_interrupt (((struct specialix_board *)data)->irq, 
476                               (void*)data, NULL);
477         }
478         missed_irq_timer.expires = jiffies + sx_poll;
479         add_timer (&missed_irq_timer);
480 }
481 #endif
482
483
484
485 /* Main probing routine, also sets irq. */
486 static int sx_probe(struct specialix_board *bp)
487 {
488         unsigned char val1, val2;
489 #if 0
490         int irqs = 0;
491         int retries;
492 #endif
493         int rev;
494         int chip;
495
496         func_enter();
497
498         if (sx_check_io_range(bp)) {
499                 func_exit();
500                 return 1;
501         }
502
503         /* Are the I/O ports here ? */
504         sx_out_off(bp, CD186x_PPRL, 0x5a);
505         short_pause ();
506         val1 = sx_in_off(bp, CD186x_PPRL);
507
508         sx_out_off(bp, CD186x_PPRL, 0xa5);
509         short_pause ();
510         val2 = sx_in_off(bp, CD186x_PPRL);
511
512         
513         if ((val1 != 0x5a) || (val2 != 0xa5)) {
514                 printk(KERN_INFO "sx%d: specialix IO8+ Board at 0x%03x not found.\n",
515                        board_No(bp), bp->base);
516                 func_exit();
517                 return 1;
518         }
519
520         /* Check the DSR lines that Specialix uses as board 
521            identification */
522         val1 = read_cross_byte (bp, CD186x_MSVR, MSVR_DSR);
523         val2 = read_cross_byte (bp, CD186x_MSVR, MSVR_RTS);
524         dprintk (SX_DEBUG_INIT, "sx%d: DSR lines are: %02x, rts lines are: %02x\n",
525                 board_No(bp),  val1, val2);
526
527         /* They managed to switch the bit order between the docs and
528            the IO8+ card. The new PCI card now conforms to old docs.
529            They changed the PCI docs to reflect the situation on the
530            old card. */
531         val2 = (bp->flags & SX_BOARD_IS_PCI)?0x4d : 0xb2;
532         if (val1 != val2) {
533                 printk(KERN_INFO "sx%d: specialix IO8+ ID %02x at 0x%03x not found (%02x).\n",
534                        board_No(bp), val2, bp->base, val1);
535                 func_exit();
536                 return 1;
537         }
538
539
540 #if 0
541         /* It's time to find IRQ for this board */
542         for (retries = 0; retries < 5 && irqs <= 0; retries++) {
543                 irqs = probe_irq_on();
544                 sx_init_CD186x(bp);                     /* Reset CD186x chip       */
545                 sx_out(bp, CD186x_CAR, 2);               /* Select port 2          */
546                 sx_wait_CCR(bp);
547                 sx_out(bp, CD186x_CCR, CCR_TXEN);        /* Enable transmitter     */
548                 sx_out(bp, CD186x_IER, IER_TXRDY);       /* Enable tx empty intr   */
549                 sx_long_delay(HZ/20);                   
550                 irqs = probe_irq_off(irqs);
551
552                 dprintk (SX_DEBUG_INIT, "SRSR = %02x, ", sx_in(bp, CD186x_SRSR));
553                 dprintk (SX_DEBUG_INIT, "TRAR = %02x, ", sx_in(bp, CD186x_TRAR));
554                 dprintk (SX_DEBUG_INIT, "GIVR = %02x, ", sx_in(bp, CD186x_GIVR));
555                 dprintk (SX_DEBUG_INIT, "GICR = %02x, ", sx_in(bp, CD186x_GICR));
556                 dprintk (SX_DEBUG_INIT, "\n");
557
558                 /* Reset CD186x again      */
559                 if (!sx_init_CD186x(bp)) {
560                         /* Hmmm. This is dead code anyway. */
561                 }
562
563                 dprintk (SX_DEBUG_INIT "val1 = %02x, val2 = %02x, val3 = %02x.\n",
564                         val1, val2, val3); 
565         
566         }
567         
568 #if 0
569         if (irqs <= 0) {
570                 printk(KERN_ERR "sx%d: Can't find IRQ for specialix IO8+ board at 0x%03x.\n",
571                        board_No(bp), bp->base);
572                 func_exit();
573                 return 1;
574         }
575 #endif
576         printk (KERN_INFO "Started with irq=%d, but now have irq=%d.\n", bp->irq, irqs);
577         if (irqs > 0)
578                 bp->irq = irqs;
579 #endif
580         /* Reset CD186x again  */
581         if (!sx_init_CD186x(bp)) {
582                 func_exit();
583                 return -EIO;
584         }
585
586         sx_request_io_range(bp);
587         bp->flags |= SX_BOARD_PRESENT;
588         
589         /* Chip           revcode   pkgtype
590                           GFRCR     SRCR bit 7
591            CD180 rev B    0x81      0
592            CD180 rev C    0x82      0
593            CD1864 rev A   0x82      1
594            CD1865 rev A   0x83      1  -- Do not use!!! Does not work. 
595            CD1865 rev B   0x84      1
596          -- Thanks to Gwen Wang, Cirrus Logic.
597          */
598
599         switch (sx_in_off(bp, CD186x_GFRCR)) {
600         case 0x82:chip = 1864;rev='A';break;
601         case 0x83:chip = 1865;rev='A';break;
602         case 0x84:chip = 1865;rev='B';break;
603         case 0x85:chip = 1865;rev='C';break; /* Does not exist at this time */
604         default:chip=-1;rev='x';
605         }
606
607         dprintk (SX_DEBUG_INIT, " GFCR = 0x%02x\n", sx_in_off(bp, CD186x_GFRCR) );
608
609 #ifdef SPECIALIX_TIMER
610         init_timer (&missed_irq_timer);
611         missed_irq_timer.function = missed_irq;
612         missed_irq_timer.data = (unsigned long) bp;
613         missed_irq_timer.expires = jiffies + sx_poll;
614         add_timer (&missed_irq_timer);
615 #endif
616
617         printk(KERN_INFO"sx%d: specialix IO8+ board detected at 0x%03x, IRQ %d, CD%d Rev. %c.\n",
618                board_No(bp),
619                bp->base, bp->irq,
620                chip, rev);
621
622         func_exit();
623         return 0;
624 }
625
626 /* 
627  * 
628  *  Interrupt processing routines.
629  * */
630
631 static inline void sx_mark_event(struct specialix_port * port, int event)
632 {
633         func_enter();
634
635         set_bit(event, &port->event);
636         schedule_work(&port->tqueue);
637
638         func_exit();
639 }
640
641
642 static inline struct specialix_port * sx_get_port(struct specialix_board * bp,
643                                                unsigned char const * what)
644 {
645         unsigned char channel;
646         struct specialix_port * port = NULL;
647
648         channel = sx_in(bp, CD186x_GICR) >> GICR_CHAN_OFF;
649         dprintk (SX_DEBUG_CHAN, "channel: %d\n", channel);
650         if (channel < CD186x_NCH) {
651                 port = &sx_port[board_No(bp) * SX_NPORT + channel];
652                 dprintk (SX_DEBUG_CHAN, "port: %d %p flags: 0x%x\n",board_No(bp) * SX_NPORT + channel,  port, port->flags & ASYNC_INITIALIZED);
653
654                 if (port->flags & ASYNC_INITIALIZED) {
655                         dprintk (SX_DEBUG_CHAN, "port: %d %p\n", channel, port);
656                         func_exit();
657                         return port;
658                 }
659         }
660         printk(KERN_INFO "sx%d: %s interrupt from invalid port %d\n", 
661                board_No(bp), what, channel);
662         return NULL;
663 }
664
665
666 static inline void sx_receive_exc(struct specialix_board * bp)
667 {
668         struct specialix_port *port;
669         struct tty_struct *tty;
670         unsigned char status;
671         unsigned char ch;
672
673         func_enter();
674
675         port = sx_get_port(bp, "Receive");
676         if (!port) {
677                 dprintk (SX_DEBUG_RX, "Hmm, couldn't find port.\n");
678                 func_exit();
679                 return;
680         }
681         tty = port->tty;
682         dprintk (SX_DEBUG_RX, "port: %p count: %d BUFF_SIZE: %d\n",
683                  port,  tty->flip.count, TTY_FLIPBUF_SIZE);
684         
685         status = sx_in(bp, CD186x_RCSR);
686
687         dprintk (SX_DEBUG_RX, "status: 0x%x\n", status);
688         if (status & RCSR_OE) {
689                 port->overrun++;
690                 dprintk(SX_DEBUG_FIFO, "sx%d: port %d: Overrun. Total %ld overruns.\n",
691                        board_No(bp), port_No(port), port->overrun);
692         }
693         status &= port->mark_mask;
694
695         /* This flip buffer check needs to be below the reading of the
696            status register to reset the chip's IRQ.... */
697         if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
698                 dprintk(SX_DEBUG_FIFO, "sx%d: port %d: Working around flip buffer overflow.\n",
699                        board_No(bp), port_No(port));
700                 func_exit();
701                 return;
702         }
703
704         ch = sx_in(bp, CD186x_RDR);
705         if (!status) {
706                 func_exit();
707                 return;
708         }
709         if (status & RCSR_TOUT) {
710                 printk(KERN_INFO "sx%d: port %d: Receiver timeout. Hardware problems ?\n", 
711                        board_No(bp), port_No(port));
712                 func_exit();
713                 return;
714                 
715         } else if (status & RCSR_BREAK) {
716                 dprintk(SX_DEBUG_RX, "sx%d: port %d: Handling break...\n",
717                        board_No(bp), port_No(port));
718                 *tty->flip.flag_buf_ptr++ = TTY_BREAK;
719                 if (port->flags & ASYNC_SAK)
720                         do_SAK(tty);
721                 
722         } else if (status & RCSR_PE) 
723                 *tty->flip.flag_buf_ptr++ = TTY_PARITY;
724         
725         else if (status & RCSR_FE) 
726                 *tty->flip.flag_buf_ptr++ = TTY_FRAME;
727         
728         else if (status & RCSR_OE)
729                 *tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
730         
731         else
732                 *tty->flip.flag_buf_ptr++ = 0;
733         
734         *tty->flip.char_buf_ptr++ = ch;
735         tty->flip.count++;
736         schedule_delayed_work(&tty->flip.work, 1);
737
738         func_exit();
739 }
740
741
742 static inline void sx_receive(struct specialix_board * bp)
743 {
744         struct specialix_port *port;
745         struct tty_struct *tty;
746         unsigned char count;
747
748         func_enter();
749         
750         if (!(port = sx_get_port(bp, "Receive"))) {
751                 dprintk (SX_DEBUG_RX, "Hmm, couldn't find port.\n");
752                 func_exit();
753                 return;
754         }
755         tty = port->tty;
756         
757         count = sx_in(bp, CD186x_RDCR);
758         dprintk (SX_DEBUG_RX, "port: %p: count: %d\n", port, count);
759         port->hits[count > 8 ? 9 : count]++;
760         
761         while (count--) {
762                 if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
763                         printk(KERN_INFO "sx%d: port %d: Working around flip buffer overflow.\n",
764                                board_No(bp), port_No(port));
765                         break;
766                 }
767                 *tty->flip.char_buf_ptr++ = sx_in(bp, CD186x_RDR);
768                 *tty->flip.flag_buf_ptr++ = 0;
769                 tty->flip.count++;
770         }
771         schedule_delayed_work(&tty->flip.work, 1);
772
773         func_exit();
774 }
775
776
777 static inline void sx_transmit(struct specialix_board * bp)
778 {
779         struct specialix_port *port;
780         struct tty_struct *tty;
781         unsigned char count;
782
783         func_enter();
784         if (!(port = sx_get_port(bp, "Transmit"))) {
785                 func_exit();
786                 return;
787         }
788         dprintk (SX_DEBUG_TX, "port: %p\n", port);
789         tty = port->tty;
790         
791         if (port->IER & IER_TXEMPTY) {
792                 /* FIFO drained */
793                 sx_out(bp, CD186x_CAR, port_No(port));
794                 port->IER &= ~IER_TXEMPTY;
795                 sx_out(bp, CD186x_IER, port->IER);
796                 func_exit();
797                 return;
798         }
799         
800         if ((port->xmit_cnt <= 0 && !port->break_length)
801             || tty->stopped || tty->hw_stopped) {
802                 sx_out(bp, CD186x_CAR, port_No(port));
803                 port->IER &= ~IER_TXRDY;
804                 sx_out(bp, CD186x_IER, port->IER);
805                 func_exit();
806                 return;
807         }
808         
809         if (port->break_length) {
810                 if (port->break_length > 0) {
811                         if (port->COR2 & COR2_ETC) {
812                                 sx_out(bp, CD186x_TDR, CD186x_C_ESC);
813                                 sx_out(bp, CD186x_TDR, CD186x_C_SBRK);
814                                 port->COR2 &= ~COR2_ETC;
815                         }
816                         count = min_t(int, port->break_length, 0xff);
817                         sx_out(bp, CD186x_TDR, CD186x_C_ESC);
818                         sx_out(bp, CD186x_TDR, CD186x_C_DELAY);
819                         sx_out(bp, CD186x_TDR, count);
820                         if (!(port->break_length -= count))
821                                 port->break_length--;
822                 } else {
823                         sx_out(bp, CD186x_TDR, CD186x_C_ESC);
824                         sx_out(bp, CD186x_TDR, CD186x_C_EBRK);
825                         sx_out(bp, CD186x_COR2, port->COR2);
826                         sx_wait_CCR(bp);
827                         sx_out(bp, CD186x_CCR, CCR_CORCHG2);
828                         port->break_length = 0;
829                 }
830
831                 func_exit();
832                 return;
833         }
834         
835         count = CD186x_NFIFO;
836         do {
837                 sx_out(bp, CD186x_TDR, port->xmit_buf[port->xmit_tail++]);
838                 port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE-1);
839                 if (--port->xmit_cnt <= 0)
840                         break;
841         } while (--count > 0);
842         
843         if (port->xmit_cnt <= 0) {
844                 sx_out(bp, CD186x_CAR, port_No(port));
845                 port->IER &= ~IER_TXRDY;
846                 sx_out(bp, CD186x_IER, port->IER);
847         }
848         if (port->xmit_cnt <= port->wakeup_chars)
849                 sx_mark_event(port, RS_EVENT_WRITE_WAKEUP);
850
851         func_exit();
852 }
853
854
855 static inline void sx_check_modem(struct specialix_board * bp)
856 {
857         struct specialix_port *port;
858         struct tty_struct *tty;
859         unsigned char mcr;
860         int msvr_cd;
861
862         dprintk (SX_DEBUG_SIGNALS, "Modem intr. ");
863         if (!(port = sx_get_port(bp, "Modem")))
864                 return;
865         
866         tty = port->tty;
867         
868         mcr = sx_in(bp, CD186x_MCR);
869         printk ("mcr = %02x.\n", mcr);
870
871         if ((mcr & MCR_CDCHG)) {
872                 dprintk (SX_DEBUG_SIGNALS, "CD just changed... ");
873                 msvr_cd = sx_in(bp, CD186x_MSVR) & MSVR_CD;
874                 if (msvr_cd) {
875                         dprintk (SX_DEBUG_SIGNALS, "Waking up guys in open.\n");
876                         wake_up_interruptible(&port->open_wait);
877                 } else {
878                         dprintk (SX_DEBUG_SIGNALS, "Sending HUP.\n");
879                         schedule_work(&port->tqueue_hangup);
880                 }
881         }
882         
883 #ifdef SPECIALIX_BRAIN_DAMAGED_CTS
884         if (mcr & MCR_CTSCHG) {
885                 if (sx_in(bp, CD186x_MSVR) & MSVR_CTS) {
886                         tty->hw_stopped = 0;
887                         port->IER |= IER_TXRDY;
888                         if (port->xmit_cnt <= port->wakeup_chars)
889                                 sx_mark_event(port, RS_EVENT_WRITE_WAKEUP);
890                 } else {
891                         tty->hw_stopped = 1;
892                         port->IER &= ~IER_TXRDY;
893                 }
894                 sx_out(bp, CD186x_IER, port->IER);
895         }
896         if (mcr & MCR_DSSXHG) {
897                 if (sx_in(bp, CD186x_MSVR) & MSVR_DSR) {
898                         tty->hw_stopped = 0;
899                         port->IER |= IER_TXRDY;
900                         if (port->xmit_cnt <= port->wakeup_chars)
901                                 sx_mark_event(port, RS_EVENT_WRITE_WAKEUP);
902                 } else {
903                         tty->hw_stopped = 1;
904                         port->IER &= ~IER_TXRDY;
905                 }
906                 sx_out(bp, CD186x_IER, port->IER);
907         }
908 #endif /* SPECIALIX_BRAIN_DAMAGED_CTS */
909         
910         /* Clear change bits */
911         sx_out(bp, CD186x_MCR, 0);
912 }
913
914
915 /* The main interrupt processing routine */
916 static irqreturn_t sx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
917 {
918         unsigned char status;
919         unsigned char ack;
920         struct specialix_board *bp;
921         unsigned long loop = 0;
922         int saved_reg;
923         unsigned long flags;
924
925         func_enter();
926
927         bp = dev_id;
928         spin_lock_irqsave(&bp->lock, flags);
929
930         dprintk (SX_DEBUG_FLOW, "enter %s port %d room: %ld\n", __FUNCTION__, port_No(sx_get_port(bp, "INT")), SERIAL_XMIT_SIZE - sx_get_port(bp, "ITN")->xmit_cnt - 1);
931         if (!bp || !(bp->flags & SX_BOARD_ACTIVE)) {
932                 dprintk (SX_DEBUG_IRQ, "sx: False interrupt. irq %d.\n", irq);
933                 spin_unlock_irqrestore(&bp->lock, flags);
934                 func_exit();
935                 return IRQ_NONE;
936         }
937
938         saved_reg = bp->reg;
939
940         while ((++loop < 16) && (status = (sx_in(bp, CD186x_SRSR) &
941                                            (SRSR_RREQint |
942                                             SRSR_TREQint |
943                                             SRSR_MREQint)))) {  
944                 if (status & SRSR_RREQint) {
945                         ack = sx_in(bp, CD186x_RRAR);
946
947                         if (ack == (SX_ID | GIVR_IT_RCV))
948                                 sx_receive(bp);
949                         else if (ack == (SX_ID | GIVR_IT_REXC))
950                                 sx_receive_exc(bp);
951                         else
952                                 printk(KERN_ERR "sx%d: status: 0x%x Bad receive ack 0x%02x.\n",
953                                        board_No(bp), status, ack);
954                 
955                 } else if (status & SRSR_TREQint) {
956                         ack = sx_in(bp, CD186x_TRAR);
957
958                         if (ack == (SX_ID | GIVR_IT_TX))
959                                 sx_transmit(bp);
960                         else
961                                 printk(KERN_ERR "sx%d: status: 0x%x Bad transmit ack 0x%02x. port: %d\n",
962                                        board_No(bp), status, ack, port_No (sx_get_port (bp, "Int")));
963                 } else if (status & SRSR_MREQint) {
964                         ack = sx_in(bp, CD186x_MRAR);
965
966                         if (ack == (SX_ID | GIVR_IT_MODEM)) 
967                                 sx_check_modem(bp);
968                         else
969                                 printk(KERN_ERR "sx%d: status: 0x%x Bad modem ack 0x%02x.\n",
970                                        board_No(bp), status, ack);
971                 
972                 } 
973
974                 sx_out(bp, CD186x_EOIR, 0);   /* Mark end of interrupt */
975         }
976         bp->reg = saved_reg;
977         outb (bp->reg, bp->base + SX_ADDR_REG);
978         spin_unlock_irqrestore(&bp->lock, flags);
979         func_exit();
980         return IRQ_HANDLED;
981 }
982
983
984 /*
985  *  Routines for open & close processing.
986  */
987
988 static void turn_ints_off (struct specialix_board *bp)
989 {
990         unsigned long flags;
991
992         func_enter();
993         if (bp->flags & SX_BOARD_IS_PCI) {
994                 /* This was intended for enabeling the interrupt on the
995                  * PCI card. However it seems that it's already enabled
996                  * and as PCI interrupts can be shared, there is no real
997                  * reason to have to turn it off. */
998         }
999
1000         spin_lock_irqsave(&bp->lock, flags);
1001         (void) sx_in_off (bp, 0); /* Turn off interrupts. */
1002         spin_unlock_irqrestore(&bp->lock, flags);
1003
1004         func_exit();
1005 }
1006
1007 static void turn_ints_on (struct specialix_board *bp)
1008 {
1009         unsigned long flags;
1010
1011         func_enter();
1012
1013         if (bp->flags & SX_BOARD_IS_PCI) {
1014                 /* play with the PCI chip. See comment above. */
1015         }
1016         spin_lock_irqsave(&bp->lock, flags);
1017         (void) sx_in (bp, 0); /* Turn ON interrupts. */
1018         spin_unlock_irqrestore(&bp->lock, flags);
1019
1020         func_exit();
1021 }
1022
1023
1024 /* Called with disabled interrupts */
1025 static inline int sx_setup_board(struct specialix_board * bp)
1026 {
1027         int error;
1028
1029         if (bp->flags & SX_BOARD_ACTIVE) 
1030                 return 0;
1031
1032         if (bp->flags & SX_BOARD_IS_PCI)
1033                 error = request_irq(bp->irq, sx_interrupt, SA_INTERRUPT | SA_SHIRQ, "specialix IO8+", bp);
1034         else
1035                 error = request_irq(bp->irq, sx_interrupt, SA_INTERRUPT, "specialix IO8+", bp);
1036
1037         if (error) 
1038                 return error;
1039
1040         turn_ints_on (bp);
1041         bp->flags |= SX_BOARD_ACTIVE;
1042
1043         return 0;
1044 }
1045
1046
1047 /* Called with disabled interrupts */
1048 static inline void sx_shutdown_board(struct specialix_board *bp)
1049 {
1050         func_enter();
1051
1052         if (!(bp->flags & SX_BOARD_ACTIVE)) {
1053                 func_exit();
1054                 return;
1055         }
1056
1057         bp->flags &= ~SX_BOARD_ACTIVE;
1058         
1059         dprintk (SX_DEBUG_IRQ, "Freeing IRQ%d for board %d.\n",
1060                  bp->irq, board_No (bp));
1061         free_irq(bp->irq, bp);
1062
1063         turn_ints_off (bp);
1064
1065
1066         func_exit();
1067 }
1068
1069
1070 /*
1071  * Setting up port characteristics. 
1072  * Must be called with disabled interrupts
1073  */
1074 static void sx_change_speed(struct specialix_board *bp, struct specialix_port *port)
1075 {
1076         struct tty_struct *tty;
1077         unsigned long baud;
1078         long tmp;
1079         unsigned char cor1 = 0, cor3 = 0;
1080         unsigned char mcor1 = 0, mcor2 = 0;
1081         static unsigned long again;
1082         unsigned long flags;
1083
1084         func_enter();
1085
1086         if (!(tty = port->tty) || !tty->termios) {
1087                 func_exit();
1088                 return;
1089         }
1090
1091         port->IER  = 0;
1092         port->COR2 = 0;
1093         /* Select port on the board */
1094         spin_lock_irqsave(&bp->lock, flags);
1095         sx_out(bp, CD186x_CAR, port_No(port));
1096
1097         /* The Specialix board doens't implement the RTS lines.
1098            They are used to set the IRQ level. Don't touch them. */
1099         if (SX_CRTSCTS(tty))
1100                 port->MSVR = MSVR_DTR | (sx_in(bp, CD186x_MSVR) & MSVR_RTS);
1101         else
1102                 port->MSVR =  (sx_in(bp, CD186x_MSVR) & MSVR_RTS);
1103         spin_unlock_irqrestore(&bp->lock, flags);
1104         dprintk (SX_DEBUG_TERMIOS, "sx: got MSVR=%02x.\n", port->MSVR);
1105         baud = C_BAUD(tty);
1106         
1107         if (baud & CBAUDEX) {
1108                 baud &= ~CBAUDEX;
1109                 if (baud < 1 || baud > 2) 
1110                         port->tty->termios->c_cflag &= ~CBAUDEX;
1111                 else
1112                         baud += 15;
1113         }
1114         if (baud == 15) {
1115                 if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
1116                         baud ++;
1117                 if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
1118                         baud += 2;
1119         }
1120         
1121         
1122         if (!baud_table[baud]) {
1123                 /* Drop DTR & exit */
1124                 dprintk (SX_DEBUG_TERMIOS, "Dropping DTR...  Hmm....\n");
1125                 if (!SX_CRTSCTS (tty)) {
1126                         port -> MSVR &= ~ MSVR_DTR;
1127                         spin_lock_irqsave(&bp->lock, flags);
1128                         sx_out(bp, CD186x_MSVR, port->MSVR );
1129                         spin_unlock_irqrestore(&bp->lock, flags);
1130                 } 
1131                 else
1132                         dprintk (SX_DEBUG_TERMIOS, "Can't drop DTR: no DTR.\n");
1133                 return;
1134         } else {
1135                 /* Set DTR on */
1136                 if (!SX_CRTSCTS (tty)) {
1137                         port ->MSVR |= MSVR_DTR;
1138                 }
1139         }
1140         
1141         /*
1142          * Now we must calculate some speed depended things 
1143          */
1144
1145         /* Set baud rate for port */
1146         tmp = port->custom_divisor ;
1147         if ( tmp )
1148                 printk (KERN_INFO "sx%d: Using custom baud rate divisor %ld. \n"
1149                                   "This is an untested option, please be carefull.\n",
1150                                   port_No (port), tmp);
1151         else
1152                 tmp = (((SX_OSCFREQ + baud_table[baud]/2) / baud_table[baud] +
1153                          CD186x_TPC/2) / CD186x_TPC);
1154
1155         if ((tmp < 0x10) && time_before(again, jiffies)) { 
1156                 again = jiffies + HZ * 60;
1157                 /* Page 48 of version 2.0 of the CL-CD1865 databook */
1158                 if (tmp >= 12) {
1159                         printk (KERN_INFO "sx%d: Baud rate divisor is %ld. \n"
1160                                 "Performance degradation is possible.\n"
1161                                 "Read specialix.txt for more info.\n",
1162                                 port_No (port), tmp);
1163                 } else {
1164                         printk (KERN_INFO "sx%d: Baud rate divisor is %ld. \n"
1165                                 "Warning: overstressing Cirrus chip. "
1166                                 "This might not work.\n"
1167                                 "Read specialix.txt for more info.\n", 
1168                                 port_No (port), tmp);
1169                 }
1170         }
1171         spin_lock_irqsave(&bp->lock, flags);
1172         sx_out(bp, CD186x_RBPRH, (tmp >> 8) & 0xff); 
1173         sx_out(bp, CD186x_TBPRH, (tmp >> 8) & 0xff); 
1174         sx_out(bp, CD186x_RBPRL, tmp & 0xff); 
1175         sx_out(bp, CD186x_TBPRL, tmp & 0xff);
1176         spin_unlock_irqrestore(&bp->lock, flags);
1177         if (port->custom_divisor) {
1178                 baud = (SX_OSCFREQ + port->custom_divisor/2) / port->custom_divisor;
1179                 baud = ( baud + 5 ) / 10;
1180         } else 
1181                 baud = (baud_table[baud] + 5) / 10;   /* Estimated CPS */
1182
1183         /* Two timer ticks seems enough to wakeup something like SLIP driver */
1184         tmp = ((baud + HZ/2) / HZ) * 2 - CD186x_NFIFO;          
1185         port->wakeup_chars = (tmp < 0) ? 0 : ((tmp >= SERIAL_XMIT_SIZE) ?
1186                                               SERIAL_XMIT_SIZE - 1 : tmp);
1187         
1188         /* Receiver timeout will be transmission time for 1.5 chars */
1189         tmp = (SPECIALIX_TPS + SPECIALIX_TPS/2 + baud/2) / baud;
1190         tmp = (tmp > 0xff) ? 0xff : tmp;
1191         spin_lock_irqsave(&bp->lock, flags);
1192         sx_out(bp, CD186x_RTPR, tmp);
1193         spin_unlock_irqrestore(&bp->lock, flags);
1194         switch (C_CSIZE(tty)) {
1195          case CS5:
1196                 cor1 |= COR1_5BITS;
1197                 break;
1198          case CS6:
1199                 cor1 |= COR1_6BITS;
1200                 break;
1201          case CS7:
1202                 cor1 |= COR1_7BITS;
1203                 break;
1204          case CS8:
1205                 cor1 |= COR1_8BITS;
1206                 break;
1207         }
1208         
1209         if (C_CSTOPB(tty)) 
1210                 cor1 |= COR1_2SB;
1211         
1212         cor1 |= COR1_IGNORE;
1213         if (C_PARENB(tty)) {
1214                 cor1 |= COR1_NORMPAR;
1215                 if (C_PARODD(tty)) 
1216                         cor1 |= COR1_ODDP;
1217                 if (I_INPCK(tty)) 
1218                         cor1 &= ~COR1_IGNORE;
1219         }
1220         /* Set marking of some errors */
1221         port->mark_mask = RCSR_OE | RCSR_TOUT;
1222         if (I_INPCK(tty)) 
1223                 port->mark_mask |= RCSR_FE | RCSR_PE;
1224         if (I_BRKINT(tty) || I_PARMRK(tty)) 
1225                 port->mark_mask |= RCSR_BREAK;
1226         if (I_IGNPAR(tty)) 
1227                 port->mark_mask &= ~(RCSR_FE | RCSR_PE);
1228         if (I_IGNBRK(tty)) {
1229                 port->mark_mask &= ~RCSR_BREAK;
1230                 if (I_IGNPAR(tty)) 
1231                         /* Real raw mode. Ignore all */
1232                         port->mark_mask &= ~RCSR_OE;
1233         }
1234         /* Enable Hardware Flow Control */
1235         if (C_CRTSCTS(tty)) {
1236 #ifdef SPECIALIX_BRAIN_DAMAGED_CTS
1237                 port->IER |= IER_DSR | IER_CTS;
1238                 mcor1 |= MCOR1_DSRZD | MCOR1_CTSZD;
1239                 mcor2 |= MCOR2_DSROD | MCOR2_CTSOD;
1240                 spin_lock_irqsave(&bp->lock, flags);
1241                 tty->hw_stopped = !(sx_in(bp, CD186x_MSVR) & (MSVR_CTS|MSVR_DSR));
1242                 spin_unlock_irqrestore(&bp->lock, flags);
1243 #else
1244                 port->COR2 |= COR2_CTSAE; 
1245 #endif
1246         }
1247         /* Enable Software Flow Control. FIXME: I'm not sure about this */
1248         /* Some people reported that it works, but I still doubt it */
1249         if (I_IXON(tty)) {
1250                 port->COR2 |= COR2_TXIBE;
1251                 cor3 |= (COR3_FCT | COR3_SCDE);
1252                 if (I_IXANY(tty))
1253                         port->COR2 |= COR2_IXM;
1254                 spin_lock_irqsave(&bp->lock, flags);
1255                 sx_out(bp, CD186x_SCHR1, START_CHAR(tty));
1256                 sx_out(bp, CD186x_SCHR2, STOP_CHAR(tty));
1257                 sx_out(bp, CD186x_SCHR3, START_CHAR(tty));
1258                 sx_out(bp, CD186x_SCHR4, STOP_CHAR(tty));
1259                 spin_unlock_irqrestore(&bp->lock, flags);
1260         }
1261         if (!C_CLOCAL(tty)) {
1262                 /* Enable CD check */
1263                 port->IER |= IER_CD;
1264                 mcor1 |= MCOR1_CDZD;
1265                 mcor2 |= MCOR2_CDOD;
1266         }
1267         
1268         if (C_CREAD(tty)) 
1269                 /* Enable receiver */
1270                 port->IER |= IER_RXD;
1271         
1272         /* Set input FIFO size (1-8 bytes) */
1273         cor3 |= sx_rxfifo;
1274         /* Setting up CD186x channel registers */
1275         spin_lock_irqsave(&bp->lock, flags);
1276         sx_out(bp, CD186x_COR1, cor1);
1277         sx_out(bp, CD186x_COR2, port->COR2);
1278         sx_out(bp, CD186x_COR3, cor3);
1279         spin_unlock_irqrestore(&bp->lock, flags);
1280         /* Make CD186x know about registers change */
1281         sx_wait_CCR(bp);
1282         spin_lock_irqsave(&bp->lock, flags);
1283         sx_out(bp, CD186x_CCR, CCR_CORCHG1 | CCR_CORCHG2 | CCR_CORCHG3);
1284         /* Setting up modem option registers */
1285         dprintk (SX_DEBUG_TERMIOS, "Mcor1 = %02x, mcor2 = %02x.\n", mcor1, mcor2);
1286         sx_out(bp, CD186x_MCOR1, mcor1);
1287         sx_out(bp, CD186x_MCOR2, mcor2);
1288         spin_unlock_irqrestore(&bp->lock, flags);
1289         /* Enable CD186x transmitter & receiver */
1290         sx_wait_CCR(bp);
1291         spin_lock_irqsave(&bp->lock, flags);
1292         sx_out(bp, CD186x_CCR, CCR_TXEN | CCR_RXEN);
1293         /* Enable interrupts */
1294         sx_out(bp, CD186x_IER, port->IER);
1295         /* And finally set the modem lines... */
1296         sx_out(bp, CD186x_MSVR, port->MSVR);
1297         spin_unlock_irqrestore(&bp->lock, flags);
1298
1299         func_exit();
1300 }
1301
1302
1303 /* Must be called with interrupts enabled */
1304 static int sx_setup_port(struct specialix_board *bp, struct specialix_port *port)
1305 {
1306         unsigned long flags;
1307
1308         func_enter();
1309
1310         if (port->flags & ASYNC_INITIALIZED) {
1311                 func_exit();
1312                 return 0;
1313         }
1314         
1315         if (!port->xmit_buf) {
1316                 /* We may sleep in get_zeroed_page() */
1317                 unsigned long tmp;
1318                 
1319                 if (!(tmp = get_zeroed_page(GFP_KERNEL))) {
1320                         func_exit();
1321                         return -ENOMEM;
1322                 }
1323
1324                 if (port->xmit_buf) {
1325                         free_page(tmp);
1326                         func_exit();
1327                         return -ERESTARTSYS;
1328                 }
1329                 port->xmit_buf = (unsigned char *) tmp;
1330         }
1331                 
1332         spin_lock_irqsave(&port->lock, flags);
1333
1334         if (port->tty) 
1335                 clear_bit(TTY_IO_ERROR, &port->tty->flags);
1336
1337         port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
1338         sx_change_speed(bp, port);
1339         port->flags |= ASYNC_INITIALIZED;
1340
1341         spin_unlock_irqrestore(&port->lock, flags);
1342
1343                 
1344         func_exit();
1345         return 0;
1346 }
1347
1348
1349 /* Must be called with interrupts disabled */
1350 static void sx_shutdown_port(struct specialix_board *bp, struct specialix_port *port)
1351 {
1352         struct tty_struct *tty;
1353         int i;
1354         unsigned long flags;
1355         
1356         func_enter();
1357
1358         if (!(port->flags & ASYNC_INITIALIZED)) {
1359                 func_exit();
1360                 return;
1361         }
1362         
1363         if (sx_debug & SX_DEBUG_FIFO) {
1364                 dprintk(SX_DEBUG_FIFO, "sx%d: port %d: %ld overruns, FIFO hits [ ",
1365                         board_No(bp), port_No(port), port->overrun);
1366                 for (i = 0; i < 10; i++) {
1367                         dprintk(SX_DEBUG_FIFO, "%ld ", port->hits[i]);
1368                 }
1369                 dprintk(SX_DEBUG_FIFO, "].\n");
1370         }
1371
1372         if (port->xmit_buf) {
1373                 free_page((unsigned long) port->xmit_buf);
1374                 port->xmit_buf = NULL;
1375         }
1376
1377         /* Select port */
1378         spin_lock_irqsave(&bp->lock, flags);
1379         sx_out(bp, CD186x_CAR, port_No(port));
1380
1381         if (!(tty = port->tty) || C_HUPCL(tty)) {
1382                 /* Drop DTR */
1383                 sx_out(bp, CD186x_MSVDTR, 0);
1384         }
1385         spin_unlock_irqrestore(&bp->lock, flags);
1386         /* Reset port */
1387         sx_wait_CCR(bp);
1388         spin_lock_irqsave(&bp->lock, flags);
1389         sx_out(bp, CD186x_CCR, CCR_SOFTRESET);
1390         /* Disable all interrupts from this port */
1391         port->IER = 0;
1392         sx_out(bp, CD186x_IER, port->IER);
1393         spin_unlock_irqrestore(&bp->lock, flags);
1394         if (tty)
1395                 set_bit(TTY_IO_ERROR, &tty->flags);
1396         port->flags &= ~ASYNC_INITIALIZED;
1397         
1398         if (!bp->count) 
1399                 sx_shutdown_board(bp);
1400         func_exit();
1401 }
1402
1403         
1404 static int block_til_ready(struct tty_struct *tty, struct file * filp,
1405                            struct specialix_port *port)
1406 {
1407         DECLARE_WAITQUEUE(wait,  current);
1408         struct specialix_board *bp = port_Board(port);
1409         int    retval;
1410         int    do_clocal = 0;
1411         int    CD;
1412         unsigned long flags;
1413
1414         func_enter();
1415
1416         /*
1417          * If the device is in the middle of being closed, then block
1418          * until it's done, and then try again.
1419          */
1420         if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
1421                 interruptible_sleep_on(&port->close_wait);
1422                 if (port->flags & ASYNC_HUP_NOTIFY) {
1423                         func_exit();
1424                         return -EAGAIN;
1425                 } else {
1426                         func_exit();
1427                         return -ERESTARTSYS;
1428                 }
1429         }
1430         
1431         /*
1432          * If non-blocking mode is set, or the port is not enabled,
1433          * then make the check up front and then exit.
1434          */
1435         if ((filp->f_flags & O_NONBLOCK) ||
1436             (tty->flags & (1 << TTY_IO_ERROR))) {
1437                 port->flags |= ASYNC_NORMAL_ACTIVE;
1438                 func_exit();
1439                 return 0;
1440         }
1441
1442         if (C_CLOCAL(tty))
1443                 do_clocal = 1;
1444
1445         /*
1446          * Block waiting for the carrier detect and the line to become
1447          * free (i.e., not in use by the callout).  While we are in
1448          * this loop, info->count is dropped by one, so that
1449          * rs_close() knows when to free things.  We restore it upon
1450          * exit, either normal or abnormal.
1451          */
1452         retval = 0;
1453         add_wait_queue(&port->open_wait, &wait);
1454         spin_lock_irqsave(&port->lock, flags);
1455         if (!tty_hung_up_p(filp)) {
1456                 port->count--;
1457         }
1458         spin_unlock_irqrestore(&port->lock, flags);
1459         port->blocked_open++;
1460         while (1) {
1461                 spin_lock_irqsave(&bp->lock, flags);
1462                 sx_out(bp, CD186x_CAR, port_No(port));
1463                 CD = sx_in(bp, CD186x_MSVR) & MSVR_CD;
1464                 if (SX_CRTSCTS (tty)) {
1465                         /* Activate RTS */
1466                         port->MSVR |= MSVR_DTR;         /* WTF? */
1467                         sx_out (bp, CD186x_MSVR, port->MSVR);
1468                 } else {
1469                         /* Activate DTR */
1470                         port->MSVR |= MSVR_DTR;
1471                         sx_out (bp, CD186x_MSVR, port->MSVR);
1472                 }
1473                 spin_unlock_irqrestore(&bp->lock, flags);
1474                 set_current_state(TASK_INTERRUPTIBLE);
1475                 if (tty_hung_up_p(filp) ||
1476                     !(port->flags & ASYNC_INITIALIZED)) {
1477                         if (port->flags & ASYNC_HUP_NOTIFY)
1478                                 retval = -EAGAIN;
1479                         else
1480                                 retval = -ERESTARTSYS;  
1481                         break;
1482                 }
1483                 if (!(port->flags & ASYNC_CLOSING) &&
1484                     (do_clocal || CD))
1485                         break;
1486                 if (signal_pending(current)) {
1487                         retval = -ERESTARTSYS;
1488                         break;
1489                 }
1490                 schedule();
1491         }
1492
1493         set_current_state(TASK_RUNNING);
1494         remove_wait_queue(&port->open_wait, &wait);
1495         spin_lock_irqsave(&port->lock, flags);
1496         if (!tty_hung_up_p(filp)) {
1497                 port->count++;
1498         }
1499         port->blocked_open--;
1500         spin_unlock_irqrestore(&port->lock, flags);
1501         if (retval) {
1502                 func_exit();
1503                 return retval;
1504         }
1505
1506         port->flags |= ASYNC_NORMAL_ACTIVE;
1507         func_exit();
1508         return 0;
1509 }       
1510
1511
1512 static int sx_open(struct tty_struct * tty, struct file * filp)
1513 {
1514         int board;
1515         int error;
1516         struct specialix_port * port;
1517         struct specialix_board * bp;
1518         int i;
1519         unsigned long flags;
1520
1521         func_enter();
1522
1523         board = SX_BOARD(tty->index);
1524
1525         if (board >= SX_NBOARD || !(sx_board[board].flags & SX_BOARD_PRESENT)) {
1526                 func_exit();
1527                 return -ENODEV;
1528         }
1529         
1530         bp = &sx_board[board];
1531         port = sx_port + board * SX_NPORT + SX_PORT(tty->index);
1532         port->overrun = 0;
1533         for (i = 0; i < 10; i++)
1534                 port->hits[i]=0;
1535
1536         dprintk (SX_DEBUG_OPEN, "Board = %d, bp = %p, port = %p, portno = %d.\n",
1537                 board, bp, port, SX_PORT(tty->index));
1538
1539         if (sx_paranoia_check(port, tty->name, "sx_open")) {
1540                 func_enter();
1541                 return -ENODEV;
1542         }
1543
1544         if ((error = sx_setup_board(bp))) {
1545                 func_exit();
1546                 return error;
1547         }
1548
1549         spin_lock_irqsave(&bp->lock, flags);
1550         port->count++;
1551         bp->count++;
1552         tty->driver_data = port;
1553         port->tty = tty;
1554         spin_unlock_irqrestore(&bp->lock, flags);
1555
1556         if ((error = sx_setup_port(bp, port))) {
1557                 func_enter();
1558                 return error;
1559         }
1560         
1561         if ((error = block_til_ready(tty, filp, port))) {
1562                 func_enter();
1563                 return error;
1564         }
1565
1566         func_exit();
1567         return 0;
1568 }
1569
1570
1571 static void sx_close(struct tty_struct * tty, struct file * filp)
1572 {
1573         struct specialix_port *port = (struct specialix_port *) tty->driver_data;
1574         struct specialix_board *bp;
1575         unsigned long flags;
1576         unsigned long timeout;
1577         
1578         func_enter();
1579         if (!port || sx_paranoia_check(port, tty->name, "close")) {
1580                 func_exit();
1581                 return;
1582         }
1583         spin_lock_irqsave(&port->lock, flags);
1584
1585         if (tty_hung_up_p(filp)) {
1586                 spin_unlock_irqrestore(&port->lock, flags);
1587                 func_exit();
1588                 return;
1589         }
1590         
1591         bp = port_Board(port);
1592         if ((tty->count == 1) && (port->count != 1)) {
1593                 printk(KERN_ERR "sx%d: sx_close: bad port count;"
1594                        " tty->count is 1, port count is %d\n",
1595                        board_No(bp), port->count);
1596                 port->count = 1;
1597         }
1598
1599         if (port->count > 1) {
1600                 port->count--;
1601                 bp->count--;
1602
1603                 spin_unlock_irqrestore(&port->lock, flags);
1604
1605                 func_exit();
1606                 return;
1607         }
1608         port->flags |= ASYNC_CLOSING;
1609         /*
1610          * Now we wait for the transmit buffer to clear; and we notify 
1611          * the line discipline to only process XON/XOFF characters.
1612          */
1613         tty->closing = 1;
1614         spin_unlock_irqrestore(&port->lock, flags);
1615         dprintk (SX_DEBUG_OPEN, "Closing\n");
1616         if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) {
1617                 tty_wait_until_sent(tty, port->closing_wait);
1618         }
1619         /*
1620          * At this point we stop accepting input.  To do this, we
1621          * disable the receive line status interrupts, and tell the
1622          * interrupt driver to stop checking the data ready bit in the
1623          * line status register.
1624          */
1625         dprintk (SX_DEBUG_OPEN, "Closed\n");
1626         port->IER &= ~IER_RXD;
1627         if (port->flags & ASYNC_INITIALIZED) {
1628                 port->IER &= ~IER_TXRDY;
1629                 port->IER |= IER_TXEMPTY;
1630                 spin_lock_irqsave(&bp->lock, flags);
1631                 sx_out(bp, CD186x_CAR, port_No(port));
1632                 sx_out(bp, CD186x_IER, port->IER);
1633                 spin_unlock_irqrestore(&bp->lock, flags);
1634                 /*
1635                  * Before we drop DTR, make sure the UART transmitter
1636                  * has completely drained; this is especially
1637                  * important if there is a transmit FIFO!
1638                  */
1639                 timeout = jiffies+HZ;
1640                 while(port->IER & IER_TXEMPTY) {
1641                         set_current_state (TASK_INTERRUPTIBLE);
1642                         msleep_interruptible(jiffies_to_msecs(port->timeout));
1643                         if (time_after(jiffies, timeout)) {
1644                                 printk (KERN_INFO "Timeout waiting for close\n");
1645                                 break;
1646                         }
1647                 }
1648
1649         }
1650
1651         if (--bp->count < 0) {
1652                 printk(KERN_ERR "sx%d: sx_shutdown_port: bad board count: %d port: %d\n",
1653                        board_No(bp), bp->count, tty->index);
1654                 bp->count = 0;
1655         }
1656         if (--port->count < 0) {
1657                 printk(KERN_ERR "sx%d: sx_close: bad port count for tty%d: %d\n",
1658                        board_No(bp), port_No(port), port->count);
1659                 port->count = 0;
1660         }
1661
1662         sx_shutdown_port(bp, port);
1663         if (tty->driver->flush_buffer)
1664                 tty->driver->flush_buffer(tty);
1665         tty_ldisc_flush(tty);
1666         spin_lock_irqsave(&port->lock, flags);
1667         tty->closing = 0;
1668         port->event = 0;
1669         port->tty = NULL;
1670         spin_unlock_irqrestore(&port->lock, flags);
1671         if (port->blocked_open) {
1672                 if (port->close_delay) {
1673                         msleep_interruptible(jiffies_to_msecs(port->close_delay));
1674                 }
1675                 wake_up_interruptible(&port->open_wait);
1676         }
1677         port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
1678         wake_up_interruptible(&port->close_wait);
1679
1680         func_exit();
1681 }
1682
1683
1684 static int sx_write(struct tty_struct * tty, 
1685                     const unsigned char *buf, int count)
1686 {
1687         struct specialix_port *port = (struct specialix_port *)tty->driver_data;
1688         struct specialix_board *bp;
1689         int c, total = 0;
1690         unsigned long flags;
1691
1692         func_enter();
1693         if (sx_paranoia_check(port, tty->name, "sx_write")) {
1694                 func_exit();
1695                 return 0;
1696         }
1697         
1698         bp = port_Board(port);
1699
1700         if (!tty || !port->xmit_buf || !tmp_buf) {
1701                 func_exit();
1702                 return 0;
1703         }
1704
1705         while (1) {
1706                 spin_lock_irqsave(&port->lock, flags);
1707                 c = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
1708                                    SERIAL_XMIT_SIZE - port->xmit_head));
1709                 if (c <= 0) {
1710                         spin_unlock_irqrestore(&port->lock, flags);
1711                         break;
1712                 }
1713                 memcpy(port->xmit_buf + port->xmit_head, buf, c);
1714                 port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
1715                 port->xmit_cnt += c;
1716                 spin_unlock_irqrestore(&port->lock, flags);
1717
1718                 buf += c;
1719                 count -= c;
1720                 total += c;
1721         }
1722
1723         spin_lock_irqsave(&bp->lock, flags);
1724         if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
1725             !(port->IER & IER_TXRDY)) {
1726                 port->IER |= IER_TXRDY;
1727                 sx_out(bp, CD186x_CAR, port_No(port));
1728                 sx_out(bp, CD186x_IER, port->IER);
1729         }
1730         spin_unlock_irqrestore(&bp->lock, flags);
1731         func_exit();
1732
1733         return total;
1734 }
1735
1736
1737 static void sx_put_char(struct tty_struct * tty, unsigned char ch)
1738 {
1739         struct specialix_port *port = (struct specialix_port *)tty->driver_data;
1740         unsigned long flags;
1741         struct specialix_board  * bp;
1742
1743         func_enter();
1744
1745         if (sx_paranoia_check(port, tty->name, "sx_put_char")) {
1746                 func_exit();
1747                 return;
1748         }
1749         dprintk (SX_DEBUG_TX, "check tty: %p %p\n", tty, port->xmit_buf);
1750         if (!tty || !port->xmit_buf) {
1751                 func_exit();
1752                 return;
1753         }
1754         bp = port_Board(port);
1755         spin_lock_irqsave(&port->lock, flags);
1756
1757         dprintk (SX_DEBUG_TX, "xmit_cnt: %d xmit_buf: %p\n", port->xmit_cnt, port->xmit_buf);
1758         if ((port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) || (!port->xmit_buf)) {
1759                 spin_unlock_irqrestore(&port->lock, flags);
1760                 dprintk (SX_DEBUG_TX, "Exit size\n");
1761                 func_exit();
1762                 return;
1763         }
1764         dprintk (SX_DEBUG_TX, "Handle xmit: %p %p\n", port, port->xmit_buf);
1765         port->xmit_buf[port->xmit_head++] = ch;
1766         port->xmit_head &= SERIAL_XMIT_SIZE - 1;
1767         port->xmit_cnt++;
1768         spin_unlock_irqrestore(&port->lock, flags);
1769
1770         func_exit();
1771 }
1772
1773
1774 static void sx_flush_chars(struct tty_struct * tty)
1775 {
1776         struct specialix_port *port = (struct specialix_port *)tty->driver_data;
1777         unsigned long flags;
1778         struct specialix_board  * bp = port_Board(port);
1779
1780         func_enter();
1781
1782         if (sx_paranoia_check(port, tty->name, "sx_flush_chars")) {
1783                 func_exit();
1784                 return;
1785         }
1786         if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
1787             !port->xmit_buf) {
1788                 func_exit();
1789                 return;
1790         }
1791         spin_lock_irqsave(&bp->lock, flags);
1792         port->IER |= IER_TXRDY;
1793         sx_out(port_Board(port), CD186x_CAR, port_No(port));
1794         sx_out(port_Board(port), CD186x_IER, port->IER);
1795         spin_unlock_irqrestore(&bp->lock, flags);
1796
1797         func_exit();
1798 }
1799
1800
1801 static int sx_write_room(struct tty_struct * tty)
1802 {
1803         struct specialix_port *port = (struct specialix_port *)tty->driver_data;
1804         int     ret;
1805
1806         func_enter();
1807
1808         if (sx_paranoia_check(port, tty->name, "sx_write_room")) {
1809                 func_exit();
1810                 return 0;
1811         }
1812
1813         ret = SERIAL_XMIT_SIZE - port->xmit_cnt - 1;
1814         if (ret < 0)
1815                 ret = 0;
1816
1817         func_exit();
1818         return ret;
1819 }
1820
1821
1822 static int sx_chars_in_buffer(struct tty_struct *tty)
1823 {
1824         struct specialix_port *port = (struct specialix_port *)tty->driver_data;
1825
1826         func_enter();
1827         
1828         if (sx_paranoia_check(port, tty->name, "sx_chars_in_buffer")) {
1829                 func_exit();
1830                 return 0;
1831         }
1832         func_exit();
1833         return port->xmit_cnt;
1834 }
1835
1836
1837 static void sx_flush_buffer(struct tty_struct *tty)
1838 {
1839         struct specialix_port *port = (struct specialix_port *)tty->driver_data;
1840         unsigned long flags;
1841         struct specialix_board  * bp;
1842
1843         func_enter();
1844
1845         if (sx_paranoia_check(port, tty->name, "sx_flush_buffer")) {
1846                 func_exit();
1847                 return;
1848         }
1849
1850         bp = port_Board(port);
1851         spin_lock_irqsave(&port->lock, flags);
1852         port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
1853         spin_unlock_irqrestore(&port->lock, flags);
1854         tty_wakeup(tty);
1855
1856         func_exit();
1857 }
1858
1859
1860 static int sx_tiocmget(struct tty_struct *tty, struct file *file)
1861 {
1862         struct specialix_port *port = (struct specialix_port *)tty->driver_data;
1863         struct specialix_board * bp;
1864         unsigned char status;
1865         unsigned int result;
1866         unsigned long flags;
1867
1868         func_enter();
1869
1870         if (sx_paranoia_check(port, tty->name, __FUNCTION__)) {
1871                 func_exit();
1872                 return -ENODEV;
1873         }
1874
1875         bp = port_Board(port);
1876         spin_lock_irqsave (&bp->lock, flags);
1877         sx_out(bp, CD186x_CAR, port_No(port));
1878         status = sx_in(bp, CD186x_MSVR);
1879         spin_unlock_irqrestore(&bp->lock, flags);
1880         dprintk (SX_DEBUG_INIT, "Got msvr[%d] = %02x, car = %d.\n",
1881                 port_No(port), status, sx_in (bp, CD186x_CAR));
1882         dprintk (SX_DEBUG_INIT, "sx_port = %p, port = %p\n", sx_port, port);
1883         if (SX_CRTSCTS(port->tty)) {
1884                 result  = /*   (status & MSVR_RTS) ? */ TIOCM_DTR /* : 0) */ 
1885                           |   ((status & MSVR_DTR) ? TIOCM_RTS : 0)
1886                           |   ((status & MSVR_CD)  ? TIOCM_CAR : 0)
1887                           |/* ((status & MSVR_DSR) ? */ TIOCM_DSR /* : 0) */
1888                           |   ((status & MSVR_CTS) ? TIOCM_CTS : 0);
1889         } else {
1890                 result  = /*   (status & MSVR_RTS) ? */ TIOCM_RTS /* : 0) */ 
1891                           |   ((status & MSVR_DTR) ? TIOCM_DTR : 0)
1892                           |   ((status & MSVR_CD)  ? TIOCM_CAR : 0)
1893                           |/* ((status & MSVR_DSR) ? */ TIOCM_DSR /* : 0) */
1894                           |   ((status & MSVR_CTS) ? TIOCM_CTS : 0);
1895         }
1896
1897         func_exit();
1898
1899         return result;
1900 }
1901
1902
1903 static int sx_tiocmset(struct tty_struct *tty, struct file *file,
1904                        unsigned int set, unsigned int clear)
1905 {
1906         struct specialix_port *port = (struct specialix_port *)tty->driver_data;
1907         unsigned long flags;
1908         struct specialix_board *bp;
1909
1910         func_enter();
1911
1912         if (sx_paranoia_check(port, tty->name, __FUNCTION__)) {
1913                 func_exit();
1914                 return -ENODEV;
1915         }
1916
1917         bp = port_Board(port);
1918
1919         spin_lock_irqsave(&port->lock, flags);
1920    /*   if (set & TIOCM_RTS)
1921                 port->MSVR |= MSVR_RTS; */
1922    /*   if (set & TIOCM_DTR)
1923                 port->MSVR |= MSVR_DTR; */
1924
1925         if (SX_CRTSCTS(port->tty)) {
1926                 if (set & TIOCM_RTS)
1927                         port->MSVR |= MSVR_DTR;
1928         } else {
1929                 if (set & TIOCM_DTR)
1930                         port->MSVR |= MSVR_DTR;
1931         }
1932
1933   /*    if (clear & TIOCM_RTS)
1934                 port->MSVR &= ~MSVR_RTS; */
1935   /*    if (clear & TIOCM_DTR)
1936                 port->MSVR &= ~MSVR_DTR; */
1937         if (SX_CRTSCTS(port->tty)) {
1938                 if (clear & TIOCM_RTS)
1939                         port->MSVR &= ~MSVR_DTR;
1940         } else {
1941                 if (clear & TIOCM_DTR)
1942                         port->MSVR &= ~MSVR_DTR;
1943         }
1944         spin_lock_irqsave(&bp->lock, flags);
1945         sx_out(bp, CD186x_CAR, port_No(port));
1946         sx_out(bp, CD186x_MSVR, port->MSVR);
1947         spin_unlock_irqrestore(&bp->lock, flags);
1948         spin_unlock_irqrestore(&port->lock, flags);
1949         func_exit();
1950         return 0;
1951 }
1952
1953
1954 static inline void sx_send_break(struct specialix_port * port, unsigned long length)
1955 {
1956         struct specialix_board *bp = port_Board(port);
1957         unsigned long flags;
1958         
1959         func_enter();
1960
1961         spin_lock_irqsave (&port->lock, flags);
1962         port->break_length = SPECIALIX_TPS / HZ * length;
1963         port->COR2 |= COR2_ETC;
1964         port->IER  |= IER_TXRDY;
1965         spin_lock_irqsave(&bp->lock, flags);
1966         sx_out(bp, CD186x_CAR, port_No(port));
1967         sx_out(bp, CD186x_COR2, port->COR2);
1968         sx_out(bp, CD186x_IER, port->IER);
1969         spin_unlock_irqrestore(&bp->lock, flags);
1970         spin_unlock_irqrestore (&port->lock, flags);
1971         sx_wait_CCR(bp);
1972         spin_lock_irqsave(&bp->lock, flags);
1973         sx_out(bp, CD186x_CCR, CCR_CORCHG2);
1974         spin_unlock_irqrestore(&bp->lock, flags);
1975         sx_wait_CCR(bp);
1976
1977         func_exit();
1978 }
1979
1980
1981 static inline int sx_set_serial_info(struct specialix_port * port,
1982                                      struct serial_struct __user * newinfo)
1983 {
1984         struct serial_struct tmp;
1985         struct specialix_board *bp = port_Board(port);
1986         int change_speed;
1987
1988         func_enter();
1989         /*
1990         if (!access_ok(VERIFY_READ, (void *) newinfo, sizeof(tmp))) {
1991                 func_exit();
1992                 return -EFAULT;
1993         }
1994         */
1995         if (copy_from_user(&tmp, newinfo, sizeof(tmp))) {
1996                 func_enter();
1997                 return -EFAULT;
1998         }
1999         
2000 #if 0   
2001         if ((tmp.irq != bp->irq) ||
2002             (tmp.port != bp->base) ||
2003             (tmp.type != PORT_CIRRUS) ||
2004             (tmp.baud_base != (SX_OSCFREQ + CD186x_TPC/2) / CD186x_TPC) ||
2005             (tmp.custom_divisor != 0) ||
2006             (tmp.xmit_fifo_size != CD186x_NFIFO) ||
2007             (tmp.flags & ~SPECIALIX_LEGAL_FLAGS)) {
2008                 func_exit();
2009                 return -EINVAL;
2010         }
2011 #endif  
2012
2013         change_speed = ((port->flags & ASYNC_SPD_MASK) !=
2014                         (tmp.flags & ASYNC_SPD_MASK));
2015         change_speed |= (tmp.custom_divisor != port->custom_divisor);
2016         
2017         if (!capable(CAP_SYS_ADMIN)) {
2018                 if ((tmp.close_delay != port->close_delay) ||
2019                     (tmp.closing_wait != port->closing_wait) ||
2020                     ((tmp.flags & ~ASYNC_USR_MASK) !=
2021                      (port->flags & ~ASYNC_USR_MASK))) {
2022                         func_exit();
2023                         return -EPERM;
2024                 }
2025                 port->flags = ((port->flags & ~ASYNC_USR_MASK) |
2026                                   (tmp.flags & ASYNC_USR_MASK));
2027                 port->custom_divisor = tmp.custom_divisor;
2028         } else {
2029                 port->flags = ((port->flags & ~ASYNC_FLAGS) |
2030                                   (tmp.flags & ASYNC_FLAGS));
2031                 port->close_delay = tmp.close_delay;
2032                 port->closing_wait = tmp.closing_wait;
2033                 port->custom_divisor = tmp.custom_divisor;
2034         }
2035         if (change_speed) {
2036                 sx_change_speed(bp, port);
2037         }
2038         func_exit();
2039         return 0;
2040 }
2041
2042
2043 static inline int sx_get_serial_info(struct specialix_port * port,
2044                                      struct serial_struct __user *retinfo)
2045 {
2046         struct serial_struct tmp;
2047         struct specialix_board *bp = port_Board(port);
2048         
2049         func_enter();
2050
2051         /*
2052         if (!access_ok(VERIFY_WRITE, (void *) retinfo, sizeof(tmp)))
2053                 return -EFAULT;
2054         */
2055
2056         memset(&tmp, 0, sizeof(tmp));
2057         tmp.type = PORT_CIRRUS;
2058         tmp.line = port - sx_port;
2059         tmp.port = bp->base;
2060         tmp.irq  = bp->irq;
2061         tmp.flags = port->flags;
2062         tmp.baud_base = (SX_OSCFREQ + CD186x_TPC/2) / CD186x_TPC;
2063         tmp.close_delay = port->close_delay * HZ/100;
2064         tmp.closing_wait = port->closing_wait * HZ/100;
2065         tmp.custom_divisor =  port->custom_divisor;
2066         tmp.xmit_fifo_size = CD186x_NFIFO;
2067         if (copy_to_user(retinfo, &tmp, sizeof(tmp))) {
2068                 func_exit();
2069                 return -EFAULT;
2070         }
2071
2072         func_exit();
2073         return 0;
2074 }
2075
2076
2077 static int sx_ioctl(struct tty_struct * tty, struct file * filp, 
2078                     unsigned int cmd, unsigned long arg)
2079 {
2080         struct specialix_port *port = (struct specialix_port *)tty->driver_data;
2081         int retval;
2082         void __user *argp = (void __user *)arg;
2083
2084         func_enter();
2085
2086         if (sx_paranoia_check(port, tty->name, "sx_ioctl")) {
2087                 func_exit();
2088                 return -ENODEV;
2089         }
2090         
2091         switch (cmd) {
2092          case TCSBRK:   /* SVID version: non-zero arg --> no break */
2093                 retval = tty_check_change(tty);
2094                 if (retval) {
2095                         func_exit();
2096                         return retval;
2097                 }
2098                 tty_wait_until_sent(tty, 0);
2099                 if (!arg)
2100                         sx_send_break(port, HZ/4);      /* 1/4 second */
2101                 return 0;
2102          case TCSBRKP:  /* support for POSIX tcsendbreak() */
2103                 retval = tty_check_change(tty);
2104                 if (retval) {
2105                         func_exit();
2106                         return retval;
2107                 }
2108                 tty_wait_until_sent(tty, 0);
2109                 sx_send_break(port, arg ? arg*(HZ/10) : HZ/4);
2110                 func_exit();
2111                 return 0;
2112          case TIOCGSOFTCAR:
2113                  if (put_user(C_CLOCAL(tty)?1:0, (unsigned long __user *)argp)) {
2114                          func_exit();
2115                          return -EFAULT;
2116                  }
2117                  func_exit();
2118                 return 0;
2119          case TIOCSSOFTCAR:
2120                  if (get_user(arg, (unsigned long __user *) argp)) {
2121                          func_exit();
2122                          return -EFAULT;
2123                  }
2124                 tty->termios->c_cflag =
2125                         ((tty->termios->c_cflag & ~CLOCAL) |
2126                         (arg ? CLOCAL : 0));
2127                 func_exit();
2128                 return 0;
2129          case TIOCGSERIAL:
2130                  func_exit();
2131                 return sx_get_serial_info(port, argp);
2132          case TIOCSSERIAL:      
2133                  func_exit();
2134                 return sx_set_serial_info(port, argp);
2135          default:
2136                  func_exit();
2137                 return -ENOIOCTLCMD;
2138         }
2139         func_exit();
2140         return 0;
2141 }
2142
2143
2144 static void sx_throttle(struct tty_struct * tty)
2145 {
2146         struct specialix_port *port = (struct specialix_port *)tty->driver_data;
2147         struct specialix_board *bp;
2148         unsigned long flags;
2149
2150         func_enter();
2151
2152         if (sx_paranoia_check(port, tty->name, "sx_throttle")) {
2153                 func_exit();
2154                 return;
2155         }
2156         
2157         bp = port_Board(port);
2158         
2159         /* Use DTR instead of RTS ! */
2160         if (SX_CRTSCTS (tty)) 
2161                 port->MSVR &= ~MSVR_DTR;
2162         else {
2163                 /* Auch!!! I think the system shouldn't call this then. */
2164                 /* Or maybe we're supposed (allowed?) to do our side of hw
2165                    handshake anyway, even when hardware handshake is off. 
2166                    When you see this in your logs, please report.... */
2167                 printk (KERN_ERR "sx%d: Need to throttle, but can't (hardware hs is off)\n",
2168                          port_No (port));
2169         }
2170         spin_lock_irqsave(&bp->lock, flags);
2171         sx_out(bp, CD186x_CAR, port_No(port));
2172         spin_unlock_irqrestore(&bp->lock, flags);
2173         if (I_IXOFF(tty)) {
2174                 spin_unlock_irqrestore(&bp->lock, flags);
2175                 sx_wait_CCR(bp);
2176                 spin_lock_irqsave(&bp->lock, flags);
2177                 sx_out(bp, CD186x_CCR, CCR_SSCH2);
2178                 spin_unlock_irqrestore(&bp->lock, flags);
2179                 sx_wait_CCR(bp);
2180         }
2181         spin_lock_irqsave(&bp->lock, flags);
2182         sx_out(bp, CD186x_MSVR, port->MSVR);
2183         spin_unlock_irqrestore(&bp->lock, flags);
2184
2185         func_exit();
2186 }
2187
2188
2189 static void sx_unthrottle(struct tty_struct * tty)
2190 {
2191         struct specialix_port *port = (struct specialix_port *)tty->driver_data;
2192         struct specialix_board *bp;
2193         unsigned long flags;
2194
2195         func_enter();
2196                                 
2197         if (sx_paranoia_check(port, tty->name, "sx_unthrottle")) {
2198                 func_exit();
2199                 return;
2200         }
2201         
2202         bp = port_Board(port);
2203         
2204         spin_lock_irqsave(&port->lock, flags);
2205         /* XXXX Use DTR INSTEAD???? */
2206         if (SX_CRTSCTS(tty)) {
2207                 port->MSVR |= MSVR_DTR;
2208         } /* Else clause: see remark in "sx_throttle"... */
2209         spin_lock_irqsave(&bp->lock, flags);
2210         sx_out(bp, CD186x_CAR, port_No(port));
2211         spin_unlock_irqrestore(&bp->lock, flags);
2212         if (I_IXOFF(tty)) {
2213                 spin_unlock_irqrestore(&port->lock, flags);
2214                 sx_wait_CCR(bp);
2215                 spin_lock_irqsave(&bp->lock, flags);
2216                 sx_out(bp, CD186x_CCR, CCR_SSCH1);
2217                 spin_unlock_irqrestore(&bp->lock, flags);
2218                 sx_wait_CCR(bp);
2219                 spin_lock_irqsave(&port->lock, flags);
2220         }
2221         spin_lock_irqsave(&bp->lock, flags);
2222         sx_out(bp, CD186x_MSVR, port->MSVR);
2223         spin_unlock_irqrestore(&bp->lock, flags);
2224         spin_unlock_irqrestore(&port->lock, flags);
2225
2226         func_exit();
2227 }
2228
2229
2230 static void sx_stop(struct tty_struct * tty)
2231 {
2232         struct specialix_port *port = (struct specialix_port *)tty->driver_data;
2233         struct specialix_board *bp;
2234         unsigned long flags;
2235
2236         func_enter();
2237         
2238         if (sx_paranoia_check(port, tty->name, "sx_stop")) {
2239                 func_exit();
2240                 return;
2241         }
2242
2243         bp = port_Board(port);
2244         
2245         spin_lock_irqsave(&port->lock, flags);
2246         port->IER &= ~IER_TXRDY;
2247         spin_lock_irqsave(&bp->lock, flags);
2248         sx_out(bp, CD186x_CAR, port_No(port));
2249         sx_out(bp, CD186x_IER, port->IER);
2250         spin_unlock_irqrestore(&bp->lock, flags);
2251         spin_unlock_irqrestore(&port->lock, flags);
2252
2253         func_exit();
2254 }
2255
2256
2257 static void sx_start(struct tty_struct * tty)
2258 {
2259         struct specialix_port *port = (struct specialix_port *)tty->driver_data;
2260         struct specialix_board *bp;
2261         unsigned long flags;
2262
2263         func_enter();
2264                                 
2265         if (sx_paranoia_check(port, tty->name, "sx_start")) {
2266                 func_exit();
2267                 return;
2268         }
2269         
2270         bp = port_Board(port);
2271         
2272         spin_lock_irqsave(&port->lock, flags);
2273         if (port->xmit_cnt && port->xmit_buf && !(port->IER & IER_TXRDY)) {
2274                 port->IER |= IER_TXRDY;
2275                 spin_lock_irqsave(&bp->lock, flags);
2276                 sx_out(bp, CD186x_CAR, port_No(port));
2277                 sx_out(bp, CD186x_IER, port->IER);
2278                 spin_unlock_irqrestore(&bp->lock, flags);
2279         }
2280         spin_unlock_irqrestore(&port->lock, flags);
2281
2282         func_exit();
2283 }
2284
2285
2286 /*
2287  * This routine is called from the work-queue when the interrupt
2288  * routine has signalled that a hangup has occurred.  The path of
2289  * hangup processing is:
2290  *
2291  *      serial interrupt routine -> (workqueue) ->
2292  *      do_sx_hangup() -> tty->hangup() -> sx_hangup()
2293  * 
2294  */
2295 static void do_sx_hangup(void *private_)
2296 {
2297         struct specialix_port   *port = (struct specialix_port *) private_;
2298         struct tty_struct       *tty;
2299         
2300         func_enter();
2301
2302         tty = port->tty;
2303         if (tty)
2304                 tty_hangup(tty);        /* FIXME: module removal race here */
2305
2306         func_exit();
2307 }
2308
2309
2310 static void sx_hangup(struct tty_struct * tty)
2311 {
2312         struct specialix_port *port = (struct specialix_port *)tty->driver_data;
2313         struct specialix_board *bp;
2314         unsigned long flags;
2315
2316         func_enter();
2317
2318         if (sx_paranoia_check(port, tty->name, "sx_hangup")) {
2319                 func_exit();
2320                 return;
2321         }
2322         
2323         bp = port_Board(port);
2324         
2325         sx_shutdown_port(bp, port);
2326         spin_lock_irqsave(&port->lock, flags);
2327         port->event = 0;
2328         bp->count -= port->count;
2329         if (bp->count < 0) {
2330                 printk(KERN_ERR "sx%d: sx_hangup: bad board count: %d port: %d\n",
2331                         board_No(bp), bp->count, tty->index);
2332                 bp->count = 0;
2333         }
2334         port->count = 0;
2335         port->flags &= ~ASYNC_NORMAL_ACTIVE;
2336         port->tty = NULL;
2337         spin_unlock_irqrestore(&port->lock, flags);
2338         wake_up_interruptible(&port->open_wait);
2339
2340         func_exit();
2341 }
2342
2343
2344 static void sx_set_termios(struct tty_struct * tty, struct termios * old_termios)
2345 {
2346         struct specialix_port *port = (struct specialix_port *)tty->driver_data;
2347         unsigned long flags;
2348         struct specialix_board  * bp;
2349                                 
2350         if (sx_paranoia_check(port, tty->name, "sx_set_termios"))
2351                 return;
2352         
2353         if (tty->termios->c_cflag == old_termios->c_cflag &&
2354             tty->termios->c_iflag == old_termios->c_iflag)
2355                 return;
2356
2357         bp = port_Board(port);
2358         spin_lock_irqsave(&port->lock, flags);
2359         sx_change_speed(port_Board(port), port);
2360         spin_unlock_irqrestore(&port->lock, flags);
2361
2362         if ((old_termios->c_cflag & CRTSCTS) &&
2363             !(tty->termios->c_cflag & CRTSCTS)) {
2364                 tty->hw_stopped = 0;
2365                 sx_start(tty);
2366         }
2367 }
2368
2369
2370 static void do_softint(void *private_)
2371 {
2372         struct specialix_port   *port = (struct specialix_port *) private_;
2373         struct tty_struct       *tty;
2374
2375         func_enter();
2376
2377         if(!(tty = port->tty)) {
2378                 func_exit();
2379                 return;
2380         }
2381
2382         if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) {
2383                 tty_wakeup(tty);
2384                 //wake_up_interruptible(&tty->write_wait);
2385         }
2386
2387         func_exit();
2388 }
2389
2390 static struct tty_operations sx_ops = {
2391         .open  = sx_open,
2392         .close = sx_close,
2393         .write = sx_write,
2394         .put_char = sx_put_char,
2395         .flush_chars = sx_flush_chars,
2396         .write_room = sx_write_room,
2397         .chars_in_buffer = sx_chars_in_buffer,
2398         .flush_buffer = sx_flush_buffer,
2399         .ioctl = sx_ioctl,
2400         .throttle = sx_throttle,
2401         .unthrottle = sx_unthrottle,
2402         .set_termios = sx_set_termios,
2403         .stop = sx_stop,
2404         .start = sx_start,
2405         .hangup = sx_hangup,
2406         .tiocmget = sx_tiocmget,
2407         .tiocmset = sx_tiocmset,
2408 };
2409
2410 static int sx_init_drivers(void)
2411 {
2412         int error;
2413         int i;
2414
2415         func_enter();
2416
2417         specialix_driver = alloc_tty_driver(SX_NBOARD * SX_NPORT);
2418         if (!specialix_driver) {
2419                 printk(KERN_ERR "sx: Couldn't allocate tty_driver.\n");
2420                 func_exit();
2421                 return 1;
2422         }
2423         
2424         if (!(tmp_buf = (unsigned char *) get_zeroed_page(GFP_KERNEL))) {
2425                 printk(KERN_ERR "sx: Couldn't get free page.\n");
2426                 put_tty_driver(specialix_driver);
2427                 func_exit();
2428                 return 1;
2429         }
2430         specialix_driver->owner = THIS_MODULE;
2431         specialix_driver->name = "ttyW";
2432         specialix_driver->major = SPECIALIX_NORMAL_MAJOR;
2433         specialix_driver->type = TTY_DRIVER_TYPE_SERIAL;
2434         specialix_driver->subtype = SERIAL_TYPE_NORMAL;
2435         specialix_driver->init_termios = tty_std_termios;
2436         specialix_driver->init_termios.c_cflag =
2437                 B9600 | CS8 | CREAD | HUPCL | CLOCAL;
2438         specialix_driver->flags = TTY_DRIVER_REAL_RAW;
2439         tty_set_operations(specialix_driver, &sx_ops);
2440
2441         if ((error = tty_register_driver(specialix_driver))) {
2442                 put_tty_driver(specialix_driver);
2443                 free_page((unsigned long)tmp_buf);
2444                 printk(KERN_ERR "sx: Couldn't register specialix IO8+ driver, error = %d\n",
2445                        error);
2446                 func_exit();
2447                 return 1;
2448         }
2449         memset(sx_port, 0, sizeof(sx_port));
2450         for (i = 0; i < SX_NPORT * SX_NBOARD; i++) {
2451                 sx_port[i].magic = SPECIALIX_MAGIC;
2452                 INIT_WORK(&sx_port[i].tqueue, do_softint, &sx_port[i]);
2453                 INIT_WORK(&sx_port[i].tqueue_hangup, do_sx_hangup, &sx_port[i]);
2454                 sx_port[i].close_delay = 50 * HZ/100;
2455                 sx_port[i].closing_wait = 3000 * HZ/100;
2456                 init_waitqueue_head(&sx_port[i].open_wait);
2457                 init_waitqueue_head(&sx_port[i].close_wait);
2458                 spin_lock_init(&sx_port[i].lock);
2459         }
2460         
2461         func_exit();
2462         return 0;
2463 }
2464
2465 static void sx_release_drivers(void)
2466 {
2467         func_enter();
2468
2469         free_page((unsigned long)tmp_buf);
2470         tty_unregister_driver(specialix_driver);
2471         put_tty_driver(specialix_driver);
2472         func_exit();
2473 }
2474
2475 /* 
2476  * This routine must be called by kernel at boot time 
2477  */
2478 static int __init specialix_init(void)
2479 {
2480         int i;
2481         int found = 0;
2482
2483         func_enter();
2484
2485         printk(KERN_INFO "sx: Specialix IO8+ driver v" VERSION ", (c) R.E.Wolff 1997/1998.\n");
2486         printk(KERN_INFO "sx: derived from work (c) D.Gorodchanin 1994-1996.\n");
2487 #ifdef CONFIG_SPECIALIX_RTSCTS
2488         printk (KERN_INFO "sx: DTR/RTS pin is always RTS.\n");
2489 #else
2490         printk (KERN_INFO "sx: DTR/RTS pin is RTS when CRTSCTS is on.\n");
2491 #endif
2492         
2493         for (i = 0; i < SX_NBOARD; i++)
2494                 sx_board[i].lock = SPIN_LOCK_UNLOCKED;
2495
2496         if (sx_init_drivers()) {
2497                 func_exit();
2498                 return -EIO;
2499         }
2500
2501         for (i = 0; i < SX_NBOARD; i++) 
2502                 if (sx_board[i].base && !sx_probe(&sx_board[i]))
2503                         found++;
2504
2505 #ifdef CONFIG_PCI
2506         {
2507                 struct pci_dev *pdev = NULL;
2508
2509                 i=0;
2510                 while (i < SX_NBOARD) {
2511                         if (sx_board[i].flags & SX_BOARD_PRESENT) {
2512                                 i++;
2513                                 continue;
2514                         }
2515                         pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX, 
2516                                                 PCI_DEVICE_ID_SPECIALIX_IO8, 
2517                                                 pdev);
2518                         if (!pdev) break;
2519
2520                         if (pci_enable_device(pdev))
2521                                 continue;
2522
2523                         sx_board[i].irq = pdev->irq;
2524
2525                         sx_board[i].base = pci_resource_start (pdev, 2);
2526
2527                         sx_board[i].flags |= SX_BOARD_IS_PCI;
2528                         if (!sx_probe(&sx_board[i]))
2529                                 found ++;
2530                 }
2531         }
2532 #endif
2533
2534         if (!found) {
2535                 sx_release_drivers();
2536                 printk(KERN_INFO "sx: No specialix IO8+ boards detected.\n");
2537                 func_exit();
2538                 return -EIO;
2539         }
2540
2541         func_exit();
2542         return 0;
2543 }
2544
2545 static int iobase[SX_NBOARD]  = {0,};
2546
2547 static int irq [SX_NBOARD] = {0,};
2548
2549 module_param_array(iobase, int, NULL, 0);
2550 module_param_array(irq, int, NULL, 0);
2551 module_param(sx_debug, int, 0);
2552 module_param(sx_rxfifo, int, 0);
2553 #ifdef SPECIALIX_TIMER
2554 module_param(sx_poll, int, 0);
2555 #endif
2556
2557 /*
2558  * You can setup up to 4 boards.
2559  * by specifying "iobase=0xXXX,0xXXX ..." as insmod parameter.
2560  * You should specify the IRQs too in that case "irq=....,...". 
2561  * 
2562  * More than 4 boards in one computer is not possible, as the card can
2563  * only use 4 different interrupts. 
2564  *
2565  */
2566 static int __init specialix_init_module(void)
2567 {
2568         int i;
2569
2570         func_enter();
2571
2572         init_MUTEX(&tmp_buf_sem); /* Init de the semaphore - pvdl */
2573
2574         if (iobase[0] || iobase[1] || iobase[2] || iobase[3]) {
2575                 for(i = 0; i < SX_NBOARD; i++) {
2576                         sx_board[i].base = iobase[i];
2577                         sx_board[i].irq = irq[i];
2578                         sx_board[i].count= 0;
2579                 }
2580         }
2581
2582         func_exit();
2583
2584         return specialix_init();
2585 }
2586         
2587 static void __exit specialix_exit_module(void)
2588 {
2589         int i;
2590         
2591         func_enter();
2592
2593         sx_release_drivers();
2594         for (i = 0; i < SX_NBOARD; i++)
2595                 if (sx_board[i].flags & SX_BOARD_PRESENT) 
2596                         sx_release_io_range(&sx_board[i]);
2597 #ifdef SPECIALIX_TIMER
2598         del_timer (&missed_irq_timer);
2599 #endif
2600
2601         func_exit();
2602 }
2603
2604 module_init(specialix_init_module);
2605 module_exit(specialix_exit_module);
2606
2607 MODULE_LICENSE("GPL");