OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [char/] [specialix.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.