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

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [char/] [vme_scc.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * drivers/char/vme_scc.c: MVME147, MVME162, BVME6000 SCC serial ports
3
 * implementation.
4
 * Copyright 1999 Richard Hirst <richard@sleepie.demon.co.uk>
5
 *
6
 * Based on atari_SCC.c which was
7
 *   Copyright 1994-95 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
8
 *   Partially based on PC-Linux serial.c by Linus Torvalds and Theodore Ts'o
9
 *
10
 * This file is subject to the terms and conditions of the GNU General Public
11
 * License.  See the file COPYING in the main directory of this archive
12
 * for more details.
13
 *
14
 */
15
 
16
#include <linux/module.h>
17
#include <linux/kdev_t.h>
18
#include <asm/io.h>
19
#include <linux/kernel.h>
20
#include <linux/ioport.h>
21
#include <linux/interrupt.h>
22
#include <linux/errno.h>
23
#include <linux/tty.h>
24
#include <linux/tty_flip.h>
25
#include <linux/mm.h>
26
#include <linux/serial.h>
27
#include <linux/fcntl.h>
28
#include <linux/major.h>
29
#include <linux/delay.h>
30
#include <linux/slab.h>
31
#include <linux/miscdevice.h>
32
#include <linux/console.h>
33
#include <linux/init.h>
34
#include <asm/setup.h>
35
#include <asm/bootinfo.h>
36
 
37
#ifdef CONFIG_MVME147_SCC
38
#include <asm/mvme147hw.h>
39
#endif
40
#ifdef CONFIG_MVME162_SCC
41
#include <asm/mvme16xhw.h>
42
#endif
43
#ifdef CONFIG_BVME6000_SCC
44
#include <asm/bvme6000hw.h>
45
#endif
46
 
47
#include <linux/generic_serial.h>
48
#include "scc.h"
49
 
50
 
51
#define CHANNEL_A       0
52
#define CHANNEL_B       1
53
 
54
#define SCC_MINOR_BASE  64
55
 
56
/* Shadows for all SCC write registers */
57
static unsigned char scc_shadow[2][16];
58
 
59
/* Location to access for SCC register access delay */
60
static volatile unsigned char *scc_del = NULL;
61
 
62
/* To keep track of STATUS_REG state for detection of Ext/Status int source */
63
static unsigned char scc_last_status_reg[2];
64
 
65
/***************************** Prototypes *****************************/
66
 
67
/* Function prototypes */
68
static void scc_disable_tx_interrupts(void * ptr);
69
static void scc_enable_tx_interrupts(void * ptr);
70
static void scc_disable_rx_interrupts(void * ptr);
71
static void scc_enable_rx_interrupts(void * ptr);
72
static int  scc_get_CD(void * ptr);
73
static void scc_shutdown_port(void * ptr);
74
static int scc_set_real_termios(void  *ptr);
75
static void scc_hungup(void  *ptr);
76
static void scc_close(void  *ptr);
77
static int scc_chars_in_buffer(void * ptr);
78
static int scc_open(struct tty_struct * tty, struct file * filp);
79
static int scc_ioctl(struct tty_struct * tty, struct file * filp,
80
                     unsigned int cmd, unsigned long arg);
81
static void scc_throttle(struct tty_struct *tty);
82
static void scc_unthrottle(struct tty_struct *tty);
83
static irqreturn_t scc_tx_int(int irq, void *data);
84
static irqreturn_t scc_rx_int(int irq, void *data);
85
static irqreturn_t scc_stat_int(int irq, void *data);
86
static irqreturn_t scc_spcond_int(int irq, void *data);
87
static void scc_setsignals(struct scc_port *port, int dtr, int rts);
88
static void scc_break_ctl(struct tty_struct *tty, int break_state);
89
 
90
static struct tty_driver *scc_driver;
91
 
92
struct scc_port scc_ports[2];
93
 
94
int scc_initialized = 0;
95
 
96
/*---------------------------------------------------------------------------
97
 * Interface from generic_serial.c back here
98
 *--------------------------------------------------------------------------*/
99
 
100
static struct real_driver scc_real_driver = {
101
        scc_disable_tx_interrupts,
102
        scc_enable_tx_interrupts,
103
        scc_disable_rx_interrupts,
104
        scc_enable_rx_interrupts,
105
        scc_get_CD,
106
        scc_shutdown_port,
107
        scc_set_real_termios,
108
        scc_chars_in_buffer,
109
        scc_close,
110
        scc_hungup,
111
        NULL
112
};
113
 
114
 
115
static const struct tty_operations scc_ops = {
116
        .open   = scc_open,
117
        .close = gs_close,
118
        .write = gs_write,
119
        .put_char = gs_put_char,
120
        .flush_chars = gs_flush_chars,
121
        .write_room = gs_write_room,
122
        .chars_in_buffer = gs_chars_in_buffer,
123
        .flush_buffer = gs_flush_buffer,
124
        .ioctl = scc_ioctl,
125
        .throttle = scc_throttle,
126
        .unthrottle = scc_unthrottle,
127
        .set_termios = gs_set_termios,
128
        .stop = gs_stop,
129
        .start = gs_start,
130
        .hangup = gs_hangup,
131
        .break_ctl = scc_break_ctl,
132
};
133
 
134
/*----------------------------------------------------------------------------
135
 * vme_scc_init() and support functions
136
 *---------------------------------------------------------------------------*/
137
 
138
static int scc_init_drivers(void)
139
{
140
        int error;
141
 
142
        scc_driver = alloc_tty_driver(2);
143
        if (!scc_driver)
144
                return -ENOMEM;
145
        scc_driver->owner = THIS_MODULE;
146
        scc_driver->driver_name = "scc";
147
        scc_driver->name = "ttyS";
148
        scc_driver->major = TTY_MAJOR;
149
        scc_driver->minor_start = SCC_MINOR_BASE;
150
        scc_driver->type = TTY_DRIVER_TYPE_SERIAL;
151
        scc_driver->subtype = SERIAL_TYPE_NORMAL;
152
        scc_driver->init_termios = tty_std_termios;
153
        scc_driver->init_termios.c_cflag =
154
          B9600 | CS8 | CREAD | HUPCL | CLOCAL;
155
        scc_driver->init_termios.c_ispeed = 9600;
156
        scc_driver->init_termios.c_ospeed = 9600;
157
        scc_driver->flags = TTY_DRIVER_REAL_RAW;
158
        tty_set_operations(scc_driver, &scc_ops);
159
 
160
        if ((error = tty_register_driver(scc_driver))) {
161
                printk(KERN_ERR "scc: Couldn't register scc driver, error = %d\n",
162
                       error);
163
                put_tty_driver(scc_driver);
164
                return 1;
165
        }
166
 
167
        return 0;
168
}
169
 
170
 
171
/* ports[] array is indexed by line no (i.e. [0] for ttyS0, [1] for ttyS1).
172
 */
173
 
174
static void scc_init_portstructs(void)
175
{
176
        struct scc_port *port;
177
        int i;
178
 
179
        for (i = 0; i < 2; i++) {
180
                port = scc_ports + i;
181
                port->gs.magic = SCC_MAGIC;
182
                port->gs.close_delay = HZ/2;
183
                port->gs.closing_wait = 30 * HZ;
184
                port->gs.rd = &scc_real_driver;
185
#ifdef NEW_WRITE_LOCKING
186
                port->gs.port_write_mutex = MUTEX;
187
#endif
188
                init_waitqueue_head(&port->gs.open_wait);
189
                init_waitqueue_head(&port->gs.close_wait);
190
        }
191
}
192
 
193
 
194
#ifdef CONFIG_MVME147_SCC
195
static int mvme147_scc_init(void)
196
{
197
        struct scc_port *port;
198
 
199
        printk(KERN_INFO "SCC: MVME147 Serial Driver\n");
200
        /* Init channel A */
201
        port = &scc_ports[0];
202
        port->channel = CHANNEL_A;
203
        port->ctrlp = (volatile unsigned char *)M147_SCC_A_ADDR;
204
        port->datap = port->ctrlp + 1;
205
        port->port_a = &scc_ports[0];
206
        port->port_b = &scc_ports[1];
207
        request_irq(MVME147_IRQ_SCCA_TX, scc_tx_int, IRQF_DISABLED,
208
                            "SCC-A TX", port);
209
        request_irq(MVME147_IRQ_SCCA_STAT, scc_stat_int, IRQF_DISABLED,
210
                            "SCC-A status", port);
211
        request_irq(MVME147_IRQ_SCCA_RX, scc_rx_int, IRQF_DISABLED,
212
                            "SCC-A RX", port);
213
        request_irq(MVME147_IRQ_SCCA_SPCOND, scc_spcond_int, IRQF_DISABLED,
214
                            "SCC-A special cond", port);
215
        {
216
                SCC_ACCESS_INIT(port);
217
 
218
                /* disable interrupts for this channel */
219
                SCCwrite(INT_AND_DMA_REG, 0);
220
                /* Set the interrupt vector */
221
                SCCwrite(INT_VECTOR_REG, MVME147_IRQ_SCC_BASE);
222
                /* Interrupt parameters: vector includes status, status low */
223
                SCCwrite(MASTER_INT_CTRL, MIC_VEC_INCL_STAT);
224
                SCCmod(MASTER_INT_CTRL, 0xff, MIC_MASTER_INT_ENAB);
225
        }
226
 
227
        /* Init channel B */
228
        port = &scc_ports[1];
229
        port->channel = CHANNEL_B;
230
        port->ctrlp = (volatile unsigned char *)M147_SCC_B_ADDR;
231
        port->datap = port->ctrlp + 1;
232
        port->port_a = &scc_ports[0];
233
        port->port_b = &scc_ports[1];
234
        request_irq(MVME147_IRQ_SCCB_TX, scc_tx_int, IRQF_DISABLED,
235
                            "SCC-B TX", port);
236
        request_irq(MVME147_IRQ_SCCB_STAT, scc_stat_int, IRQF_DISABLED,
237
                            "SCC-B status", port);
238
        request_irq(MVME147_IRQ_SCCB_RX, scc_rx_int, IRQF_DISABLED,
239
                            "SCC-B RX", port);
240
        request_irq(MVME147_IRQ_SCCB_SPCOND, scc_spcond_int, IRQF_DISABLED,
241
                            "SCC-B special cond", port);
242
        {
243
                SCC_ACCESS_INIT(port);
244
 
245
                /* disable interrupts for this channel */
246
                SCCwrite(INT_AND_DMA_REG, 0);
247
        }
248
 
249
        /* Ensure interrupts are enabled in the PCC chip */
250
        m147_pcc->serial_cntrl=PCC_LEVEL_SERIAL|PCC_INT_ENAB;
251
 
252
        /* Initialise the tty driver structures and register */
253
        scc_init_portstructs();
254
        scc_init_drivers();
255
 
256
        return 0;
257
}
258
#endif
259
 
260
 
261
#ifdef CONFIG_MVME162_SCC
262
static int mvme162_scc_init(void)
263
{
264
        struct scc_port *port;
265
 
266
        if (!(mvme16x_config & MVME16x_CONFIG_GOT_SCCA))
267
                return (-ENODEV);
268
 
269
        printk(KERN_INFO "SCC: MVME162 Serial Driver\n");
270
        /* Init channel A */
271
        port = &scc_ports[0];
272
        port->channel = CHANNEL_A;
273
        port->ctrlp = (volatile unsigned char *)MVME_SCC_A_ADDR;
274
        port->datap = port->ctrlp + 2;
275
        port->port_a = &scc_ports[0];
276
        port->port_b = &scc_ports[1];
277
        request_irq(MVME162_IRQ_SCCA_TX, scc_tx_int, IRQF_DISABLED,
278
                            "SCC-A TX", port);
279
        request_irq(MVME162_IRQ_SCCA_STAT, scc_stat_int, IRQF_DISABLED,
280
                            "SCC-A status", port);
281
        request_irq(MVME162_IRQ_SCCA_RX, scc_rx_int, IRQF_DISABLED,
282
                            "SCC-A RX", port);
283
        request_irq(MVME162_IRQ_SCCA_SPCOND, scc_spcond_int, IRQF_DISABLED,
284
                            "SCC-A special cond", port);
285
        {
286
                SCC_ACCESS_INIT(port);
287
 
288
                /* disable interrupts for this channel */
289
                SCCwrite(INT_AND_DMA_REG, 0);
290
                /* Set the interrupt vector */
291
                SCCwrite(INT_VECTOR_REG, MVME162_IRQ_SCC_BASE);
292
                /* Interrupt parameters: vector includes status, status low */
293
                SCCwrite(MASTER_INT_CTRL, MIC_VEC_INCL_STAT);
294
                SCCmod(MASTER_INT_CTRL, 0xff, MIC_MASTER_INT_ENAB);
295
        }
296
 
297
        /* Init channel B */
298
        port = &scc_ports[1];
299
        port->channel = CHANNEL_B;
300
        port->ctrlp = (volatile unsigned char *)MVME_SCC_B_ADDR;
301
        port->datap = port->ctrlp + 2;
302
        port->port_a = &scc_ports[0];
303
        port->port_b = &scc_ports[1];
304
        request_irq(MVME162_IRQ_SCCB_TX, scc_tx_int, IRQF_DISABLED,
305
                            "SCC-B TX", port);
306
        request_irq(MVME162_IRQ_SCCB_STAT, scc_stat_int, IRQF_DISABLED,
307
                            "SCC-B status", port);
308
        request_irq(MVME162_IRQ_SCCB_RX, scc_rx_int, IRQF_DISABLED,
309
                            "SCC-B RX", port);
310
        request_irq(MVME162_IRQ_SCCB_SPCOND, scc_spcond_int, IRQF_DISABLED,
311
                            "SCC-B special cond", port);
312
 
313
        {
314
                SCC_ACCESS_INIT(port);  /* Either channel will do */
315
 
316
                /* disable interrupts for this channel */
317
                SCCwrite(INT_AND_DMA_REG, 0);
318
        }
319
 
320
        /* Ensure interrupts are enabled in the MC2 chip */
321
        *(volatile char *)0xfff4201d = 0x14;
322
 
323
        /* Initialise the tty driver structures and register */
324
        scc_init_portstructs();
325
        scc_init_drivers();
326
 
327
        return 0;
328
}
329
#endif
330
 
331
 
332
#ifdef CONFIG_BVME6000_SCC
333
static int bvme6000_scc_init(void)
334
{
335
        struct scc_port *port;
336
 
337
        printk(KERN_INFO "SCC: BVME6000 Serial Driver\n");
338
        /* Init channel A */
339
        port = &scc_ports[0];
340
        port->channel = CHANNEL_A;
341
        port->ctrlp = (volatile unsigned char *)BVME_SCC_A_ADDR;
342
        port->datap = port->ctrlp + 4;
343
        port->port_a = &scc_ports[0];
344
        port->port_b = &scc_ports[1];
345
        request_irq(BVME_IRQ_SCCA_TX, scc_tx_int, IRQF_DISABLED,
346
                            "SCC-A TX", port);
347
        request_irq(BVME_IRQ_SCCA_STAT, scc_stat_int, IRQF_DISABLED,
348
                            "SCC-A status", port);
349
        request_irq(BVME_IRQ_SCCA_RX, scc_rx_int, IRQF_DISABLED,
350
                            "SCC-A RX", port);
351
        request_irq(BVME_IRQ_SCCA_SPCOND, scc_spcond_int, IRQF_DISABLED,
352
                            "SCC-A special cond", port);
353
        {
354
                SCC_ACCESS_INIT(port);
355
 
356
                /* disable interrupts for this channel */
357
                SCCwrite(INT_AND_DMA_REG, 0);
358
                /* Set the interrupt vector */
359
                SCCwrite(INT_VECTOR_REG, BVME_IRQ_SCC_BASE);
360
                /* Interrupt parameters: vector includes status, status low */
361
                SCCwrite(MASTER_INT_CTRL, MIC_VEC_INCL_STAT);
362
                SCCmod(MASTER_INT_CTRL, 0xff, MIC_MASTER_INT_ENAB);
363
        }
364
 
365
        /* Init channel B */
366
        port = &scc_ports[1];
367
        port->channel = CHANNEL_B;
368
        port->ctrlp = (volatile unsigned char *)BVME_SCC_B_ADDR;
369
        port->datap = port->ctrlp + 4;
370
        port->port_a = &scc_ports[0];
371
        port->port_b = &scc_ports[1];
372
        request_irq(BVME_IRQ_SCCB_TX, scc_tx_int, IRQF_DISABLED,
373
                            "SCC-B TX", port);
374
        request_irq(BVME_IRQ_SCCB_STAT, scc_stat_int, IRQF_DISABLED,
375
                            "SCC-B status", port);
376
        request_irq(BVME_IRQ_SCCB_RX, scc_rx_int, IRQF_DISABLED,
377
                            "SCC-B RX", port);
378
        request_irq(BVME_IRQ_SCCB_SPCOND, scc_spcond_int, IRQF_DISABLED,
379
                            "SCC-B special cond", port);
380
 
381
        {
382
                SCC_ACCESS_INIT(port);  /* Either channel will do */
383
 
384
                /* disable interrupts for this channel */
385
                SCCwrite(INT_AND_DMA_REG, 0);
386
        }
387
 
388
        /* Initialise the tty driver structures and register */
389
        scc_init_portstructs();
390
        scc_init_drivers();
391
 
392
        return 0;
393
}
394
#endif
395
 
396
 
397
static int vme_scc_init(void)
398
{
399
        int res = -ENODEV;
400
 
401
#ifdef CONFIG_MVME147_SCC
402
        if (MACH_IS_MVME147)
403
                res = mvme147_scc_init();
404
#endif
405
#ifdef CONFIG_MVME162_SCC
406
        if (MACH_IS_MVME16x)
407
                res = mvme162_scc_init();
408
#endif
409
#ifdef CONFIG_BVME6000_SCC
410
        if (MACH_IS_BVME6000)
411
                res = bvme6000_scc_init();
412
#endif
413
        return res;
414
}
415
 
416
module_init(vme_scc_init);
417
 
418
 
419
/*---------------------------------------------------------------------------
420
 * Interrupt handlers
421
 *--------------------------------------------------------------------------*/
422
 
423
static irqreturn_t scc_rx_int(int irq, void *data)
424
{
425
        unsigned char   ch;
426
        struct scc_port *port = data;
427
        struct tty_struct *tty = port->gs.tty;
428
        SCC_ACCESS_INIT(port);
429
 
430
        ch = SCCread_NB(RX_DATA_REG);
431
        if (!tty) {
432
                printk(KERN_WARNING "scc_rx_int with NULL tty!\n");
433
                SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
434
                return IRQ_HANDLED;
435
        }
436
        tty_insert_flip_char(tty, ch, 0);
437
 
438
        /* Check if another character is already ready; in that case, the
439
         * spcond_int() function must be used, because this character may have an
440
         * error condition that isn't signalled by the interrupt vector used!
441
         */
442
        if (SCCread(INT_PENDING_REG) &
443
            (port->channel == CHANNEL_A ? IPR_A_RX : IPR_B_RX)) {
444
                scc_spcond_int (irq, data);
445
                return IRQ_HANDLED;
446
        }
447
 
448
        SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
449
 
450
        tty_flip_buffer_push(tty);
451
        return IRQ_HANDLED;
452
}
453
 
454
 
455
static irqreturn_t scc_spcond_int(int irq, void *data)
456
{
457
        struct scc_port *port = data;
458
        struct tty_struct *tty = port->gs.tty;
459
        unsigned char   stat, ch, err;
460
        int             int_pending_mask = port->channel == CHANNEL_A ?
461
                                           IPR_A_RX : IPR_B_RX;
462
        SCC_ACCESS_INIT(port);
463
 
464
        if (!tty) {
465
                printk(KERN_WARNING "scc_spcond_int with NULL tty!\n");
466
                SCCwrite(COMMAND_REG, CR_ERROR_RESET);
467
                SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
468
                return IRQ_HANDLED;
469
        }
470
        do {
471
                stat = SCCread(SPCOND_STATUS_REG);
472
                ch = SCCread_NB(RX_DATA_REG);
473
 
474
                if (stat & SCSR_RX_OVERRUN)
475
                        err = TTY_OVERRUN;
476
                else if (stat & SCSR_PARITY_ERR)
477
                        err = TTY_PARITY;
478
                else if (stat & SCSR_CRC_FRAME_ERR)
479
                        err = TTY_FRAME;
480
                else
481
                        err = 0;
482
 
483
                tty_insert_flip_char(tty, ch, err);
484
 
485
                /* ++TeSche: *All* errors have to be cleared manually,
486
                 * else the condition persists for the next chars
487
                 */
488
                if (err)
489
                  SCCwrite(COMMAND_REG, CR_ERROR_RESET);
490
 
491
        } while(SCCread(INT_PENDING_REG) & int_pending_mask);
492
 
493
        SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
494
 
495
        tty_flip_buffer_push(tty);
496
        return IRQ_HANDLED;
497
}
498
 
499
 
500
static irqreturn_t scc_tx_int(int irq, void *data)
501
{
502
        struct scc_port *port = data;
503
        SCC_ACCESS_INIT(port);
504
 
505
        if (!port->gs.tty) {
506
                printk(KERN_WARNING "scc_tx_int with NULL tty!\n");
507
                SCCmod (INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0);
508
                SCCwrite(COMMAND_REG, CR_TX_PENDING_RESET);
509
                SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
510
                return IRQ_HANDLED;
511
        }
512
        while ((SCCread_NB(STATUS_REG) & SR_TX_BUF_EMPTY)) {
513
                if (port->x_char) {
514
                        SCCwrite(TX_DATA_REG, port->x_char);
515
                        port->x_char = 0;
516
                }
517
                else if ((port->gs.xmit_cnt <= 0) || port->gs.tty->stopped ||
518
                                port->gs.tty->hw_stopped)
519
                        break;
520
                else {
521
                        SCCwrite(TX_DATA_REG, port->gs.xmit_buf[port->gs.xmit_tail++]);
522
                        port->gs.xmit_tail = port->gs.xmit_tail & (SERIAL_XMIT_SIZE-1);
523
                        if (--port->gs.xmit_cnt <= 0)
524
                                break;
525
                }
526
        }
527
        if ((port->gs.xmit_cnt <= 0) || port->gs.tty->stopped ||
528
                        port->gs.tty->hw_stopped) {
529
                /* disable tx interrupts */
530
                SCCmod (INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0);
531
                SCCwrite(COMMAND_REG, CR_TX_PENDING_RESET);   /* disable tx_int on next tx underrun? */
532
                port->gs.flags &= ~GS_TX_INTEN;
533
        }
534
        if (port->gs.tty && port->gs.xmit_cnt <= port->gs.wakeup_chars)
535
                tty_wakeup(port->gs.tty);
536
 
537
        SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
538
        return IRQ_HANDLED;
539
}
540
 
541
 
542
static irqreturn_t scc_stat_int(int irq, void *data)
543
{
544
        struct scc_port *port = data;
545
        unsigned channel = port->channel;
546
        unsigned char   last_sr, sr, changed;
547
        SCC_ACCESS_INIT(port);
548
 
549
        last_sr = scc_last_status_reg[channel];
550
        sr = scc_last_status_reg[channel] = SCCread_NB(STATUS_REG);
551
        changed = last_sr ^ sr;
552
 
553
        if (changed & SR_DCD) {
554
                port->c_dcd = !!(sr & SR_DCD);
555
                if (!(port->gs.flags & ASYNC_CHECK_CD))
556
                        ;       /* Don't report DCD changes */
557
                else if (port->c_dcd) {
558
                        wake_up_interruptible(&port->gs.open_wait);
559
                }
560
                else {
561
                        if (port->gs.tty)
562
                                tty_hangup (port->gs.tty);
563
                }
564
        }
565
        SCCwrite(COMMAND_REG, CR_EXTSTAT_RESET);
566
        SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
567
        return IRQ_HANDLED;
568
}
569
 
570
 
571
/*---------------------------------------------------------------------------
572
 * generic_serial.c callback funtions
573
 *--------------------------------------------------------------------------*/
574
 
575
static void scc_disable_tx_interrupts(void *ptr)
576
{
577
        struct scc_port *port = ptr;
578
        unsigned long   flags;
579
        SCC_ACCESS_INIT(port);
580
 
581
        local_irq_save(flags);
582
        SCCmod(INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0);
583
        port->gs.flags &= ~GS_TX_INTEN;
584
        local_irq_restore(flags);
585
}
586
 
587
 
588
static void scc_enable_tx_interrupts(void *ptr)
589
{
590
        struct scc_port *port = ptr;
591
        unsigned long   flags;
592
        SCC_ACCESS_INIT(port);
593
 
594
        local_irq_save(flags);
595
        SCCmod(INT_AND_DMA_REG, 0xff, IDR_TX_INT_ENAB);
596
        /* restart the transmitter */
597
        scc_tx_int (0, port);
598
        local_irq_restore(flags);
599
}
600
 
601
 
602
static void scc_disable_rx_interrupts(void *ptr)
603
{
604
        struct scc_port *port = ptr;
605
        unsigned long   flags;
606
        SCC_ACCESS_INIT(port);
607
 
608
        local_irq_save(flags);
609
        SCCmod(INT_AND_DMA_REG,
610
            ~(IDR_RX_INT_MASK|IDR_PARERR_AS_SPCOND|IDR_EXTSTAT_INT_ENAB), 0);
611
        local_irq_restore(flags);
612
}
613
 
614
 
615
static void scc_enable_rx_interrupts(void *ptr)
616
{
617
        struct scc_port *port = ptr;
618
        unsigned long   flags;
619
        SCC_ACCESS_INIT(port);
620
 
621
        local_irq_save(flags);
622
        SCCmod(INT_AND_DMA_REG, 0xff,
623
                IDR_EXTSTAT_INT_ENAB|IDR_PARERR_AS_SPCOND|IDR_RX_INT_ALL);
624
        local_irq_restore(flags);
625
}
626
 
627
 
628
static int scc_get_CD(void *ptr)
629
{
630
        struct scc_port *port = ptr;
631
        unsigned channel = port->channel;
632
 
633
        return !!(scc_last_status_reg[channel] & SR_DCD);
634
}
635
 
636
 
637
static void scc_shutdown_port(void *ptr)
638
{
639
        struct scc_port *port = ptr;
640
 
641
        port->gs.flags &= ~ GS_ACTIVE;
642
        if (port->gs.tty && port->gs.tty->termios->c_cflag & HUPCL) {
643
                scc_setsignals (port, 0, 0);
644
        }
645
}
646
 
647
 
648
static int scc_set_real_termios (void *ptr)
649
{
650
        /* the SCC has char sizes 5,7,6,8 in that order! */
651
        static int chsize_map[4] = { 0, 2, 1, 3 };
652
        unsigned cflag, baud, chsize, channel, brgval = 0;
653
        unsigned long flags;
654
        struct scc_port *port = ptr;
655
        SCC_ACCESS_INIT(port);
656
 
657
        if (!port->gs.tty || !port->gs.tty->termios) return 0;
658
 
659
        channel = port->channel;
660
 
661
        if (channel == CHANNEL_A)
662
                return 0;                /* Settings controlled by boot PROM */
663
 
664
        cflag  = port->gs.tty->termios->c_cflag;
665
        baud = port->gs.baud;
666
        chsize = (cflag & CSIZE) >> 4;
667
 
668
        if (baud == 0) {
669
                /* speed == 0 -> drop DTR */
670
                local_irq_save(flags);
671
                SCCmod(TX_CTRL_REG, ~TCR_DTR, 0);
672
                local_irq_restore(flags);
673
                return 0;
674
        }
675
        else if ((MACH_IS_MVME16x && (baud < 50 || baud > 38400)) ||
676
                 (MACH_IS_MVME147 && (baud < 50 || baud > 19200)) ||
677
                 (MACH_IS_BVME6000 &&(baud < 50 || baud > 76800))) {
678
                printk(KERN_NOTICE "SCC: Bad speed requested, %d\n", baud);
679
                return 0;
680
        }
681
 
682
        if (cflag & CLOCAL)
683
                port->gs.flags &= ~ASYNC_CHECK_CD;
684
        else
685
                port->gs.flags |= ASYNC_CHECK_CD;
686
 
687
#ifdef CONFIG_MVME147_SCC
688
        if (MACH_IS_MVME147)
689
                brgval = (M147_SCC_PCLK + baud/2) / (16 * 2 * baud) - 2;
690
#endif
691
#ifdef CONFIG_MVME162_SCC
692
        if (MACH_IS_MVME16x)
693
                brgval = (MVME_SCC_PCLK + baud/2) / (16 * 2 * baud) - 2;
694
#endif
695
#ifdef CONFIG_BVME6000_SCC
696
        if (MACH_IS_BVME6000)
697
                brgval = (BVME_SCC_RTxC + baud/2) / (16 * 2 * baud) - 2;
698
#endif
699
        /* Now we have all parameters and can go to set them: */
700
        local_irq_save(flags);
701
 
702
        /* receiver's character size and auto-enables */
703
        SCCmod(RX_CTRL_REG, ~(RCR_CHSIZE_MASK|RCR_AUTO_ENAB_MODE),
704
                        (chsize_map[chsize] << 6) |
705
                        ((cflag & CRTSCTS) ? RCR_AUTO_ENAB_MODE : 0));
706
        /* parity and stop bits (both, Tx and Rx), clock mode never changes */
707
        SCCmod (AUX1_CTRL_REG,
708
                ~(A1CR_PARITY_MASK | A1CR_MODE_MASK),
709
                ((cflag & PARENB
710
                  ? (cflag & PARODD ? A1CR_PARITY_ODD : A1CR_PARITY_EVEN)
711
                  : A1CR_PARITY_NONE)
712
                 | (cflag & CSTOPB ? A1CR_MODE_ASYNC_2 : A1CR_MODE_ASYNC_1)));
713
        /* sender's character size, set DTR for valid baud rate */
714
        SCCmod(TX_CTRL_REG, ~TCR_CHSIZE_MASK, chsize_map[chsize] << 5 | TCR_DTR);
715
        /* clock sources never change */
716
        /* disable BRG before changing the value */
717
        SCCmod(DPLL_CTRL_REG, ~DCR_BRG_ENAB, 0);
718
        /* BRG value */
719
        SCCwrite(TIMER_LOW_REG, brgval & 0xff);
720
        SCCwrite(TIMER_HIGH_REG, (brgval >> 8) & 0xff);
721
        /* BRG enable, and clock source never changes */
722
        SCCmod(DPLL_CTRL_REG, 0xff, DCR_BRG_ENAB);
723
 
724
        local_irq_restore(flags);
725
 
726
        return 0;
727
}
728
 
729
 
730
static int scc_chars_in_buffer (void *ptr)
731
{
732
        struct scc_port *port = ptr;
733
        SCC_ACCESS_INIT(port);
734
 
735
        return (SCCread (SPCOND_STATUS_REG) & SCSR_ALL_SENT) ? 0  : 1;
736
}
737
 
738
 
739
/* Comment taken from sx.c (2.4.0):
740
   I haven't the foggiest why the decrement use count has to happen
741
   here. The whole linux serial drivers stuff needs to be redesigned.
742
   My guess is that this is a hack to minimize the impact of a bug
743
   elsewhere. Thinking about it some more. (try it sometime) Try
744
   running minicom on a serial port that is driven by a modularized
745
   driver. Have the modem hangup. Then remove the driver module. Then
746
   exit minicom.  I expect an "oops".  -- REW */
747
 
748
static void scc_hungup(void *ptr)
749
{
750
        scc_disable_tx_interrupts(ptr);
751
        scc_disable_rx_interrupts(ptr);
752
}
753
 
754
 
755
static void scc_close(void *ptr)
756
{
757
        scc_disable_tx_interrupts(ptr);
758
        scc_disable_rx_interrupts(ptr);
759
}
760
 
761
 
762
/*---------------------------------------------------------------------------
763
 * Internal support functions
764
 *--------------------------------------------------------------------------*/
765
 
766
static void scc_setsignals(struct scc_port *port, int dtr, int rts)
767
{
768
        unsigned long flags;
769
        unsigned char t;
770
        SCC_ACCESS_INIT(port);
771
 
772
        local_irq_save(flags);
773
        t = SCCread(TX_CTRL_REG);
774
        if (dtr >= 0) t = dtr? (t | TCR_DTR): (t & ~TCR_DTR);
775
        if (rts >= 0) t = rts? (t | TCR_RTS): (t & ~TCR_RTS);
776
        SCCwrite(TX_CTRL_REG, t);
777
        local_irq_restore(flags);
778
}
779
 
780
 
781
static void scc_send_xchar(struct tty_struct *tty, char ch)
782
{
783
        struct scc_port *port = (struct scc_port *)tty->driver_data;
784
 
785
        port->x_char = ch;
786
        if (ch)
787
                scc_enable_tx_interrupts(port);
788
}
789
 
790
 
791
/*---------------------------------------------------------------------------
792
 * Driver entrypoints referenced from above
793
 *--------------------------------------------------------------------------*/
794
 
795
static int scc_open (struct tty_struct * tty, struct file * filp)
796
{
797
        int line = tty->index;
798
        int retval;
799
        struct scc_port *port = &scc_ports[line];
800
        int i, channel = port->channel;
801
        unsigned long   flags;
802
        SCC_ACCESS_INIT(port);
803
#if defined(CONFIG_MVME162_SCC) || defined(CONFIG_MVME147_SCC)
804
        static const struct {
805
                unsigned reg, val;
806
        } mvme_init_tab[] = {
807
                /* Values for MVME162 and MVME147 */
808
                /* no parity, 1 stop bit, async, 1:16 */
809
                { AUX1_CTRL_REG, A1CR_PARITY_NONE|A1CR_MODE_ASYNC_1|A1CR_CLKMODE_x16 },
810
                /* parity error is special cond, ints disabled, no DMA */
811
                { INT_AND_DMA_REG, IDR_PARERR_AS_SPCOND | IDR_RX_INT_DISAB },
812
                /* Rx 8 bits/char, no auto enable, Rx off */
813
                { RX_CTRL_REG, RCR_CHSIZE_8 },
814
                /* DTR off, Tx 8 bits/char, RTS off, Tx off */
815
                { TX_CTRL_REG, TCR_CHSIZE_8 },
816
                /* special features off */
817
                { AUX2_CTRL_REG, 0 },
818
                { CLK_CTRL_REG, CCR_RXCLK_BRG | CCR_TXCLK_BRG },
819
                { DPLL_CTRL_REG, DCR_BRG_ENAB | DCR_BRG_USE_PCLK },
820
                /* Start Rx */
821
                { RX_CTRL_REG, RCR_RX_ENAB | RCR_CHSIZE_8 },
822
                /* Start Tx */
823
                { TX_CTRL_REG, TCR_TX_ENAB | TCR_RTS | TCR_DTR | TCR_CHSIZE_8 },
824
                /* Ext/Stat ints: DCD only */
825
                { INT_CTRL_REG, ICR_ENAB_DCD_INT },
826
                /* Reset Ext/Stat ints */
827
                { COMMAND_REG, CR_EXTSTAT_RESET },
828
                /* ...again */
829
                { COMMAND_REG, CR_EXTSTAT_RESET },
830
        };
831
#endif
832
#if defined(CONFIG_BVME6000_SCC)
833
        static const struct {
834
                unsigned reg, val;
835
        } bvme_init_tab[] = {
836
                /* Values for BVME6000 */
837
                /* no parity, 1 stop bit, async, 1:16 */
838
                { AUX1_CTRL_REG, A1CR_PARITY_NONE|A1CR_MODE_ASYNC_1|A1CR_CLKMODE_x16 },
839
                /* parity error is special cond, ints disabled, no DMA */
840
                { INT_AND_DMA_REG, IDR_PARERR_AS_SPCOND | IDR_RX_INT_DISAB },
841
                /* Rx 8 bits/char, no auto enable, Rx off */
842
                { RX_CTRL_REG, RCR_CHSIZE_8 },
843
                /* DTR off, Tx 8 bits/char, RTS off, Tx off */
844
                { TX_CTRL_REG, TCR_CHSIZE_8 },
845
                /* special features off */
846
                { AUX2_CTRL_REG, 0 },
847
                { CLK_CTRL_REG, CCR_RTxC_XTAL | CCR_RXCLK_BRG | CCR_TXCLK_BRG },
848
                { DPLL_CTRL_REG, DCR_BRG_ENAB },
849
                /* Start Rx */
850
                { RX_CTRL_REG, RCR_RX_ENAB | RCR_CHSIZE_8 },
851
                /* Start Tx */
852
                { TX_CTRL_REG, TCR_TX_ENAB | TCR_RTS | TCR_DTR | TCR_CHSIZE_8 },
853
                /* Ext/Stat ints: DCD only */
854
                { INT_CTRL_REG, ICR_ENAB_DCD_INT },
855
                /* Reset Ext/Stat ints */
856
                { COMMAND_REG, CR_EXTSTAT_RESET },
857
                /* ...again */
858
                { COMMAND_REG, CR_EXTSTAT_RESET },
859
        };
860
#endif
861
        if (!(port->gs.flags & ASYNC_INITIALIZED)) {
862
                local_irq_save(flags);
863
#if defined(CONFIG_MVME147_SCC) || defined(CONFIG_MVME162_SCC)
864
                if (MACH_IS_MVME147 || MACH_IS_MVME16x) {
865
                        for (i = 0; i < ARRAY_SIZE(mvme_init_tab); ++i)
866
                                SCCwrite(mvme_init_tab[i].reg, mvme_init_tab[i].val);
867
                }
868
#endif
869
#if defined(CONFIG_BVME6000_SCC)
870
                if (MACH_IS_BVME6000) {
871
                        for (i = 0; i < ARRAY_SIZE(bvme_init_tab); ++i)
872
                                SCCwrite(bvme_init_tab[i].reg, bvme_init_tab[i].val);
873
                }
874
#endif
875
 
876
                /* remember status register for detection of DCD and CTS changes */
877
                scc_last_status_reg[channel] = SCCread(STATUS_REG);
878
 
879
                port->c_dcd = 0; /* Prevent initial 1->0 interrupt */
880
                scc_setsignals (port, 1,1);
881
                local_irq_restore(flags);
882
        }
883
 
884
        tty->driver_data = port;
885
        port->gs.tty = tty;
886
        port->gs.count++;
887
        retval = gs_init_port(&port->gs);
888
        if (retval) {
889
                port->gs.count--;
890
                return retval;
891
        }
892
        port->gs.flags |= GS_ACTIVE;
893
        retval = gs_block_til_ready(port, filp);
894
 
895
        if (retval) {
896
                port->gs.count--;
897
                return retval;
898
        }
899
 
900
        port->c_dcd = scc_get_CD (port);
901
 
902
        scc_enable_rx_interrupts(port);
903
 
904
        return 0;
905
}
906
 
907
 
908
static void scc_throttle (struct tty_struct * tty)
909
{
910
        struct scc_port *port = (struct scc_port *)tty->driver_data;
911
        unsigned long   flags;
912
        SCC_ACCESS_INIT(port);
913
 
914
        if (tty->termios->c_cflag & CRTSCTS) {
915
                local_irq_save(flags);
916
                SCCmod(TX_CTRL_REG, ~TCR_RTS, 0);
917
                local_irq_restore(flags);
918
        }
919
        if (I_IXOFF(tty))
920
                scc_send_xchar(tty, STOP_CHAR(tty));
921
}
922
 
923
 
924
static void scc_unthrottle (struct tty_struct * tty)
925
{
926
        struct scc_port *port = (struct scc_port *)tty->driver_data;
927
        unsigned long   flags;
928
        SCC_ACCESS_INIT(port);
929
 
930
        if (tty->termios->c_cflag & CRTSCTS) {
931
                local_irq_save(flags);
932
                SCCmod(TX_CTRL_REG, 0xff, TCR_RTS);
933
                local_irq_restore(flags);
934
        }
935
        if (I_IXOFF(tty))
936
                scc_send_xchar(tty, START_CHAR(tty));
937
}
938
 
939
 
940
static int scc_ioctl(struct tty_struct *tty, struct file *file,
941
                     unsigned int cmd, unsigned long arg)
942
{
943
        return -ENOIOCTLCMD;
944
}
945
 
946
 
947
static void scc_break_ctl(struct tty_struct *tty, int break_state)
948
{
949
        struct scc_port *port = (struct scc_port *)tty->driver_data;
950
        unsigned long   flags;
951
        SCC_ACCESS_INIT(port);
952
 
953
        local_irq_save(flags);
954
        SCCmod(TX_CTRL_REG, ~TCR_SEND_BREAK,
955
                        break_state ? TCR_SEND_BREAK : 0);
956
        local_irq_restore(flags);
957
}
958
 
959
 
960
/*---------------------------------------------------------------------------
961
 * Serial console stuff...
962
 *--------------------------------------------------------------------------*/
963
 
964
#define scc_delay() do { __asm__ __volatile__ (" nop; nop"); } while (0)
965
 
966
static void scc_ch_write (char ch)
967
{
968
        volatile char *p = NULL;
969
 
970
#ifdef CONFIG_MVME147_SCC
971
        if (MACH_IS_MVME147)
972
                p = (volatile char *)M147_SCC_A_ADDR;
973
#endif
974
#ifdef CONFIG_MVME162_SCC
975
        if (MACH_IS_MVME16x)
976
                p = (volatile char *)MVME_SCC_A_ADDR;
977
#endif
978
#ifdef CONFIG_BVME6000_SCC
979
        if (MACH_IS_BVME6000)
980
                p = (volatile char *)BVME_SCC_A_ADDR;
981
#endif
982
 
983
        do {
984
                scc_delay();
985
        }
986
        while (!(*p & 4));
987
        scc_delay();
988
        *p = 8;
989
        scc_delay();
990
        *p = ch;
991
}
992
 
993
/* The console must be locked when we get here. */
994
 
995
static void scc_console_write (struct console *co, const char *str, unsigned count)
996
{
997
        unsigned long   flags;
998
 
999
        local_irq_save(flags);
1000
 
1001
        while (count--)
1002
        {
1003
                if (*str == '\n')
1004
                        scc_ch_write ('\r');
1005
                scc_ch_write (*str++);
1006
        }
1007
        local_irq_restore(flags);
1008
}
1009
 
1010
static struct tty_driver *scc_console_device(struct console *c, int *index)
1011
{
1012
        *index = c->index;
1013
        return scc_driver;
1014
}
1015
 
1016
static struct console sercons = {
1017
        .name           = "ttyS",
1018
        .write          = scc_console_write,
1019
        .device         = scc_console_device,
1020
        .flags          = CON_PRINTBUFFER,
1021
        .index          = -1,
1022
};
1023
 
1024
 
1025
static int __init vme_scc_console_init(void)
1026
{
1027
        if (vme_brdtype == VME_TYPE_MVME147 ||
1028
                        vme_brdtype == VME_TYPE_MVME162 ||
1029
                        vme_brdtype == VME_TYPE_MVME172 ||
1030
                        vme_brdtype == VME_TYPE_BVME4000 ||
1031
                        vme_brdtype == VME_TYPE_BVME6000)
1032
                register_console(&sercons);
1033
        return 0;
1034
}
1035
console_initcall(vme_scc_console_init);

powered by: WebSVN 2.1.0

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