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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [uclinux/] [uClinux-2.0.x/] [drivers/] [char/] [specialix.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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