source: rtems/c/src/lib/libbsp/m68k/gen68340/console/console.c @ d7aecdc

4.104.114.84.95
Last change on this file since d7aecdc was df49c60, checked in by Joel Sherrill <joel.sherrill@…>, on 06/12/00 at 15:00:15

Merged from 4.5.0-beta3a

  • Property mode set to 100644
File size: 19.4 KB
Line 
1/*
2 *  68340/68349 console serial I/O.
3 *
4 *  Author:
5 *  Geoffroy Montel
6 *  France Telecom - CNET/DSM/TAM/CAT
7 *  4, rue du Clos Courtel
8 *  35512 CESSON-SEVIGNE
9 *  FRANCE
10 *
11 *  e-mail: g_montel@yahoo.com
12 *
13 *  COPYRIGHT (c) 1989-1999.
14 *  On-Line Applications Research Corporation (OAR).
15 *
16 *  The license and distribution terms for this file may be
17 *  found in the file LICENSE in this distribution or at
18 *
19 *  http://www.OARcorp.com/rtems/license.html.
20 *
21 *  $Id$
22 */
23
24#include <termios.h>
25#include <bsp.h>
26#include <rtems/libio.h>
27#include <m68340.h>
28#include <m340uart.h>
29#include <m340timer.h>
30
31#include <stdarg.h>
32#include <stdio.h>
33#include <stdlib.h>
34
35#define CONSOLE_VECTOR 121
36#define CONSOLE_IRQ_LEVEL 3
37#define CONSOLE_INTERRUPT_ARBITRATION 2
38
39static void *ttypA;             /* to remember which tty has been opened on channel A
40                                   used when interrupts are enabled */
41
42static void *ttypB;             /* to remember which tty has been opened on channel B
43                                   used when interrupts are enabled */
44
45unsigned char DUIER_mirror = 0 ;  /* reflects the state of IER register, which is Write Only */
46unsigned char Error_Status_A = 0; /* error status on Channel A */
47unsigned char Error_Status_B = 0; /* error status on Channel A */
48
49/*
50 * Device-specific routines
51 */
52
53#define USE_INTERRUPTS_A (m340_uart_config[UART_CHANNEL_A].mode==UART_INTERRUPTS)
54#define USE_INTERRUPTS_B (m340_uart_config[UART_CHANNEL_B].mode==UART_INTERRUPTS)
55#define CHANNEL_ENABLED_A m340_uart_config[UART_CHANNEL_A].enable
56#define CHANNEL_ENABLED_B m340_uart_config[UART_CHANNEL_B].enable
57
58#define set_DUIER(a) DUIER_mirror |= (a); DUIER = DUIER_mirror
59#define unset_DUIER(a) DUIER_mirror &= ~(a); DUIER = DUIER_mirror
60
61#define Enable_Interrupts_Tx_A if (USE_INTERRUPTS_A) set_DUIER(m340_TxRDYA)
62#define Disable_Interrupts_Tx_A if (USE_INTERRUPTS_A) unset_DUIER(m340_TxRDYA)
63
64#define Enable_Interrupts_Tx_B if (USE_INTERRUPTS_B) set_DUIER(m340_TxRDYB)
65#define Disable_Interrupts_Tx_B if (USE_INTERRUPTS_B) unset_DUIER(m340_TxRDYB)
66
67/******************************************************
68  Name: InterruptHandler
69  Input parameters: vector number
70  Output parameters: -
71  Description: UART ISR Routine, called by _RTEMS_ISR
72 *****************************************************/
73rtems_isr
74InterruptHandler (rtems_vector_number v)
75{
76 char ch;
77
78 /*****************************************************************************
79 **                             CHANNEL A                                    **
80 *****************************************************************************/
81
82    /* check Received Break*/
83    if (DUSRA & m340_RB) {
84       Error_Status_A |= m340_RB;
85       /* reset error status */
86       DUCRA = m340_Reset_Error_Status;
87    }
88
89    /* buffer received ? */
90    if (DUSRA & m340_Rx_RDY) {
91       do {
92           /* error encountered? */
93           if (DUSRA & (m340_OE | m340_PE | m340_FE | m340_RB)) {
94              Error_Status_A |= DUSRA;
95              /* reset error status */
96              DUCRA = m340_Reset_Error_Status;
97              /* all the characters in the queue may not be good */
98              while (DUSRA & m340_Rx_RDY)
99                    /* push them in a trash */
100                    ch = DURBA;
101           }
102           else {
103                 /* this is necessary, otherwise it blocks when FIFO is full */
104                 ch = DURBA;
105                 rtems_termios_enqueue_raw_characters(ttypA,&ch,1);
106           }
107       } while (DUSRA & m340_Rx_RDY);
108       Restart_Fifo_Full_A_Timer();     /* only if necessary (pointer to a fake function if
109                                           not in FIFO full mode) */
110    }
111
112    else /* if no character has been received */
113       Restart_Check_A_Timer();         /* same remark */
114
115    /* ready to accept a character ? */
116    if (DUISR & DUIER_mirror & m340_TxRDYA) {
117        Disable_Interrupts_Tx_A;
118        /* one character has been transmitted */
119        rtems_termios_dequeue_characters(ttypA,1);
120    }
121
122 /*****************************************************************************
123 **                             CHANNEL B                                    **
124 *****************************************************************************/
125
126    /* check Received Break*/
127    if (DUSRB & m340_RB) {
128       Error_Status_B |= m340_RB;
129       /* reset error status */
130       DUCRB = m340_Reset_Error_Status;
131    }
132
133    /* buffer received ? */
134    if (DUSRB & m340_Rx_RDY) {
135       do {
136           if (DUSRB & (m340_OE | m340_PE | m340_FE | m340_RB)) {
137              Error_Status_B |= DUSRB;
138              /* reset error status */
139              DUCRB = m340_Reset_Error_Status;
140              /* all the characters in the queue may not be good */
141              while (DUSRB & m340_Rx_RDY)
142                    /* push them in a trash */
143                    ch = DURBB;
144           }
145           else {
146                 ch = DURBB;
147                 rtems_termios_enqueue_raw_characters(ttypB,&ch,1);
148           }
149
150       } while (DUSRB & m340_Rx_RDY);
151       Restart_Fifo_Full_B_Timer();
152    }
153    else /* if no character has been received */
154       Restart_Check_B_Timer();
155
156    /* ready to accept a character ? */
157    if (DUISR & DUIER_mirror & m340_TxRDYB) {
158        Disable_Interrupts_Tx_B;
159        /* one character has been transmitted */
160        rtems_termios_dequeue_characters(ttypB,1);
161    }
162}
163
164/******************************************************
165  Name: InterruptWrite
166  Input parameters: minor = channel, pointer to buffer,
167                    and length of buffer to transmit
168  Output parameters: -
169  Description: write the first character of buf only
170               may be called by either console_write
171               or rtems_termios_enqueue_raw_characters
172 *****************************************************/
173static int
174InterruptWrite (int minor, const char *buf, int len)
175{
176 if (minor==UART_CHANNEL_A) {
177    if (len>0) (char)DUTBA=*buf;
178    Enable_Interrupts_Tx_A;
179 }
180 else if (minor==UART_CHANNEL_B) {
181    if (len>0) (char)DUTBB=*buf;
182    Enable_Interrupts_Tx_B;
183 }
184 return 0;
185}
186
187/******************************************************
188  Name: dbug_out_char
189  Input parameters: channel, character to emit
190  Output parameters: -
191  Description: wait for the UART to be ready to emit
192               a character and send it
193 *****************************************************/
194void dbug_out_char( int minor, int ch )
195{
196 if (minor==UART_CHANNEL_A) {
197    while (!(DUSRA & m340_Tx_RDY)) continue;
198    DUTBA=ch;
199 }
200 else if (minor==UART_CHANNEL_B) {
201    while (!(DUSRB & m340_Tx_RDY)) continue;
202    DUTBB=ch;
203 }
204}
205
206/******************************************************
207  Name: dbug_in_char
208  Input parameters: -
209  Output parameters: received character
210  Description: return the character in the UART
211 *****************************************************/
212int dbug_in_char( int minor )
213{
214 if (minor==UART_CHANNEL_A) {
215    return DURBA;
216 }
217 else if (minor==UART_CHANNEL_B) {
218    return DURBB;
219 }
220 return 0;
221}
222
223/******************************************************
224  Name: dbug_char_present
225  Input parameters: channel #
226  Output parameters: TRUE or FALSE
227  Description: return whether there's a character
228               in the receive buffer
229 *****************************************************/
230int dbug_char_present( int minor )
231{
232 if (minor==UART_CHANNEL_A) {
233    return (DUSRA & m340_Rx_RDY);
234 }
235 else if (minor==UART_CHANNEL_B) {
236    return (DUSRB & m340_Rx_RDY);
237 }
238 return 0;
239}
240
241/******************************************************
242  Name: dbugInitialise
243  Input parameters: -
244  Output parameters: -
245  Description: Init the UART
246 *****************************************************/
247static void
248dbugInitialise ()
249{
250     t_baud_speed_table uart_config;            /* configuration of UARTS */
251
252     /*
253      * Reset Receiver
254      */
255     DUCRA = m340_Reset_Receiver;
256     DUCRB = m340_Reset_Receiver;
257
258     /*
259      * Reset Transmitter
260      */
261     DUCRA = m340_Reset_Transmitter;
262     DUCRB = m340_Reset_Transmitter;
263
264     /*
265      * Enable serial module for normal operation, ignore FREEZE, select the crystal clock,
266      * supervisor/user serial registers unrestricted
267      * interrupt arbitration at priority CONSOLE_INTERRUPT_ARBITRATION
268      * WARNING : 8 bits access only on this UART!
269      */
270     DUMCRH = 0x00;
271     DUMCRL = CONSOLE_INTERRUPT_ARBITRATION;
272
273     /*
274      * Interrupt level register
275      */
276     DUILR = CONSOLE_IRQ_LEVEL;
277
278     /* sets the IVR */
279     DUIVR = CONSOLE_VECTOR;
280
281     /* search for a correct m340 uart configuration */
282     uart_config = Find_Right_m340_UART_Config(m340_uart_config[UART_CHANNEL_A].rx_baudrate,
283                                               m340_uart_config[UART_CHANNEL_A].tx_baudrate,
284                                               CHANNEL_ENABLED_A,
285                                               m340_uart_config[UART_CHANNEL_B].rx_baudrate,
286                                               m340_uart_config[UART_CHANNEL_B].tx_baudrate,
287                                               CHANNEL_ENABLED_B);
288
289     /*****************************************************************************
290     **                         CHANNEL A                                        **
291     *****************************************************************************/
292     if (CHANNEL_ENABLED_A) {
293
294        if (USE_INTERRUPTS_A) {
295           rtems_isr_entry old_handler;
296           rtems_status_code sc;
297
298           extern void _Debug_ISR_Handler_Console(void);
299
300           sc = rtems_interrupt_catch (InterruptHandler,
301                                       CONSOLE_VECTOR,
302                                       &old_handler);
303
304           /* uncomment this if you want to pass control to your own ISR handler
305              it may be usefull to do so to check for performances with an oscilloscope */
306           /*
307           {
308            proc_ptr ignored;
309            _CPU_ISR_install_raw_handler( CONSOLE_VECTOR, _Debug_ISR_Handler_Console, &ignored );
310           }
311           */
312
313           /*
314            * Interrupt Enable Register
315            * Enable Interrupts on Channel A Receiver Ready
316            */
317           set_DUIER(m340_RxRDYA);
318        }
319        else {
320                /*
321                 * Disable Interrupts on channel A
322                 */
323                unset_DUIER(m340_RxRDYA&m340_TxRDYA);
324        }
325       
326        /*
327         * Change set of baud speeds
328         * disable input control
329         */
330        /* no good uart configuration ? */
331        if (uart_config.nb<1) rtems_fatal_error_occurred (-1);
332       
333        if (uart_config.baud_speed_table[UART_CHANNEL_A].set==1)
334           DUACR = m340_BRG_Set1;
335        else
336           DUACR = m340_BRG_Set2;
337
338        /*
339         * make OPCR an auxiliary function serving the communication channels
340         */
341        DUOPCR = m340_OPCR_Aux;
342
343        /* poll the XTAL_RDY bit until it is cleared to ensure that an unstable crystal
344           input is not applied to the baud rate generator */
345        while (DUISR & m340_XTAL_RDY) continue;
346
347        /*
348         * Serial Channel Baud Speed
349         */
350        DUCSRA = (uart_config.baud_speed_table[UART_CHANNEL_A].rcs << 4)
351               | (uart_config.baud_speed_table[UART_CHANNEL_A].tcs);
352
353        /*
354         * Serial Channel Configuration
355         */
356        DUMR1A = m340_uart_config[UART_CHANNEL_A].parity_mode
357               | m340_uart_config[UART_CHANNEL_A].bits_per_char
358               | m340_RxRTS;
359
360        if (m340_uart_config[UART_CHANNEL_A].rx_mode==UART_FIFO_FULL) DUMR1A |= m340_R_F | m340_ERR;
361
362        /*
363         * Serial Channel Configuration 2
364         */
365        DUMR2A |= m340_normal;
366
367        /*
368         * Enable Channel A: transmitter and receiver
369         */
370        DUCRA = m340_Transmitter_Enable | m340_Receiver_Enable;
371     } /* channel A enabled */
372
373     /*****************************************************************************
374     **                         CHANNEL B                                        **
375     *****************************************************************************/
376     if (CHANNEL_ENABLED_B) {
377
378        /* we mustn't set the console vector twice! */
379        if ((USE_INTERRUPTS_B && !(CHANNEL_ENABLED_A))
380           || (USE_INTERRUPTS_B && CHANNEL_ENABLED_A && !USE_INTERRUPTS_A)) {
381           rtems_isr_entry old_handler;
382           rtems_status_code sc;
383
384           extern void _Debug_ISR_Handler_Console(void);
385
386           sc = rtems_interrupt_catch (InterruptHandler,
387                                       CONSOLE_VECTOR,
388                                       &old_handler);
389
390           /* uncomment this if you want to pass control to your own ISR handler
391              it may be usefull to do so to check for performances with an oscilloscope */
392           /*
393           {
394            proc_ptr ignored;
395            _CPU_ISR_install_raw_handler( CONSOLE_VECTOR, _Debug_ISR_Handler_Console, &ignored );
396           }
397           */
398
399           /*
400            * Interrupt Enable Register
401            * Enable Interrupts on Channel A Receiver Ready
402            */
403           set_DUIER(m340_RxRDYB);
404        }
405        else {
406                /*
407                 * Disable Interrupts on channel B
408                 */
409                unset_DUIER(m340_RxRDYB&m340_TxRDYB);
410        }
411       
412        /*
413         * Change set of baud speeds
414         * disable input control
415         */
416
417        /* no good uart configuration ? */
418        if (uart_config.nb<2) rtems_fatal_error_occurred (-1);
419       
420        /* don't set DUACR twice! */
421        if (!CHANNEL_ENABLED_A)
422           if (uart_config.baud_speed_table[UART_CHANNEL_B].set==1) DUACR = m340_BRG_Set1;
423           else DUACR = m340_BRG_Set2;
424
425        /*
426         * make OPCR an auxiliary function serving the communication channels
427         */
428        if (!CHANNEL_ENABLED_A) DUOPCR = m340_OPCR_Aux;
429
430        /* poll the XTAL_RDY bit until it is cleared to ensure that an unstable crystal
431           input is not applied to the baud rate generator */
432        while (DUISR & m340_XTAL_RDY) continue;
433
434        /*
435         * Serial Channel Baud Speed
436         */
437        DUCSRB = (uart_config.baud_speed_table[UART_CHANNEL_B].rcs << 4)
438               | (uart_config.baud_speed_table[UART_CHANNEL_B].tcs);
439
440        /*
441         * Serial Channel Configuration
442         */
443        DUMR1B = m340_uart_config[UART_CHANNEL_B].parity_mode
444               | m340_uart_config[UART_CHANNEL_B].bits_per_char
445               | m340_RxRTS;
446
447        if (m340_uart_config[UART_CHANNEL_B].rx_mode==UART_FIFO_FULL) DUMR1B |= m340_R_F | m340_ERR;
448
449        /*
450         * Serial Channel Configuration 2
451         */
452        DUMR2B |= m340_normal;
453
454        /*
455         * Enable Channel A: transmitter and receiver
456         */
457        DUCRB = m340_Transmitter_Enable | m340_Receiver_Enable;
458     } /* channel B enabled */
459}
460
461/******************************************************
462  Name: SetAttributes
463  Input parameters: termios structure, channel
464  Output parameters: -
465  Description: return whether there's a character
466               in the receive buffer
467  TO DO: add the channel # to check for!!
468 *****************************************************/
469static int
470SetAttributes (int minor, const struct termios *t)
471{
472 rtems_interrupt_level level;
473 float ispeed, ospeed;
474 int isp, osp;
475
476 /* output speed */
477 if (t->c_cflag & CBAUDEX)
478    osp = (t->c_cflag & CBAUD) + CBAUD + 1;
479 else
480    osp = t->c_cflag & CBAUD;
481
482 /* input speed */
483 isp = (t->c_cflag / (CIBAUD / CBAUD)) &  CBAUD;
484
485 /* convert it */
486 ispeed = termios_baud_rates_equivalence(isp);
487 ospeed = termios_baud_rates_equivalence(osp);
488
489 if (ispeed || ospeed) {
490       /* update config table */
491       m340_uart_config[UART_CHANNEL_A].rx_baudrate = ((minor==UART_CHANNEL_A)&&(ispeed!=0)) ? ispeed  : m340_uart_config[UART_CHANNEL_A].rx_baudrate;
492       m340_uart_config[UART_CHANNEL_A].tx_baudrate = ((minor==UART_CHANNEL_A)&&(ospeed!=0)) ? ospeed  : m340_uart_config[UART_CHANNEL_A].tx_baudrate;
493       m340_uart_config[UART_CHANNEL_B].rx_baudrate = ((minor==UART_CHANNEL_B)&&(ispeed!=0)) ? ispeed  : m340_uart_config[UART_CHANNEL_B].rx_baudrate;
494       m340_uart_config[UART_CHANNEL_B].tx_baudrate = ((minor==UART_CHANNEL_B)&&(ospeed!=0)) ? ospeed  : m340_uart_config[UART_CHANNEL_B].tx_baudrate;
495 }
496
497 /* change parity */
498 if (t->c_cflag & PARENB) {
499    if (t->c_cflag & PARODD) m340_uart_config[minor].parity_mode = m340_Odd_Parity;
500    else m340_uart_config[minor].parity_mode = m340_Even_Parity;
501 }
502
503 /* change bits per character */
504 if (t->c_cflag & CSIZE) {
505    switch (t->c_cflag & CSIZE) {
506        default:        break;
507        case CS5:       m340_uart_config[minor].bits_per_char = m340_5bpc;      break;
508        case CS6:       m340_uart_config[minor].bits_per_char = m340_6bpc;      break;
509        case CS7:       m340_uart_config[minor].bits_per_char = m340_7bpc;      break;
510        case CS8:       m340_uart_config[minor].bits_per_char = m340_8bpc;      break;
511    }
512 }
513
514 /* if serial module configuration has been changed */
515 if (t->c_cflag & (CBAUD | CIBAUD | CSIZE | PARENB)) {
516    rtems_interrupt_disable(level);
517    /* reinit the UART */
518    dbugInitialise();
519    rtems_interrupt_enable (level);
520 }
521
522 return 0;
523}
524
525/******************************************************
526  Name: console_initialize
527  Input parameters: MAJOR # of console_driver,
528                    minor is always 0,
529                    args are always NULL
530  Output parameters: -
531  Description: Reserve resources consumed by this driver
532  TODO: We should pass m340_uart_config table in arg
533 *****************************************************/
534rtems_device_driver console_initialize(
535  rtems_device_major_number  major,
536  rtems_device_minor_number  minor,
537  void                      *arg
538)
539{
540        rtems_status_code status;
541        int i;
542
543        /*
544         * Set up TERMIOS
545         */
546        rtems_termios_initialize ();
547
548        /*
549         * Do device-specific initialization
550         */
551        Init_UART_Table();
552        dbugInitialise ();
553        Fifo_Full_Timer_initialize();
554
555        /*
556         * Register the devices
557         */
558        for (i=0; i<UART_NUMBER_OF_CHANNELS; i++) {
559            if (m340_uart_config[i].enable) {
560                status = rtems_io_register_name (m340_uart_config[i].name, major, i);
561                if (status != RTEMS_SUCCESSFUL)
562                        rtems_fatal_error_occurred (status);
563            }
564        }
565
566        return RTEMS_SUCCESSFUL;
567}
568
569/******************************************************
570  Name: console_open
571  Input parameters: channel #, arg
572  Output parameters: -
573  Description: open the device
574 *****************************************************/
575rtems_device_driver console_open(
576  rtems_device_major_number major,
577  rtems_device_minor_number minor,
578  void                    * arg
579)
580{
581 rtems_status_code sc = 0;
582
583 static const rtems_termios_callbacks intrCallbacks = {
584                NULL,                   /* firstOpen */
585                NULL,                   /* lastClose */
586                NULL,                   /* pollRead */
587                InterruptWrite,         /* write */
588                SetAttributes,          /* setAttributes */
589                NULL,                   /* stopRemoteTx */
590                NULL,                   /* startRemoteTx */
591                1                       /* outputUsesInterrupts */
592 };
593
594 static const rtems_termios_callbacks pollCallbacks = {
595                NULL,                   /* firstOpen */
596                NULL,                   /* lastClose */
597                dbugRead,               /* pollRead */
598                dbugWrite,              /* write */
599                SetAttributes,          /* setAttributes */
600                NULL,                   /* stopRemoteTx */
601                NULL,                   /* startRemoteTx */
602                0                       /* outputUsesInterrupts */
603 };
604
605 if (minor==UART_CHANNEL_A) {
606        if (USE_INTERRUPTS_A) {
607                rtems_libio_open_close_args_t *args = arg;
608
609                sc |= rtems_termios_open (major, minor, arg, &intrCallbacks);
610                ttypA = args->iop->data1;
611        }
612        else {
613                sc |= rtems_termios_open (major, minor, arg, &pollCallbacks);
614        }
615 }
616
617 else if (minor==UART_CHANNEL_B) {
618        if (USE_INTERRUPTS_B) {
619                rtems_libio_open_close_args_t *args = arg;
620
621                sc |= rtems_termios_open (major, minor, arg, &intrCallbacks);
622                ttypB = args->iop->data1;
623        }
624        else {
625                sc |= rtems_termios_open (major, minor, arg, &pollCallbacks);
626        }
627 }
628
629 else return RTEMS_INVALID_NUMBER;
630
631 return sc;
632}
633 
634/******************************************************
635  Name: console_close
636  Input parameters: channel #, termios args
637  Output parameters: -
638  Description: close the device
639 *****************************************************/
640rtems_device_driver console_close(
641  rtems_device_major_number major,
642  rtems_device_minor_number minor,
643  void                    * arg
644)
645{
646        return rtems_termios_close (arg);
647}
648
649/******************************************************
650  Name: console_read
651  Input parameters: channel #, termios args
652  Output parameters: -
653  Description: read the device
654 *****************************************************/
655rtems_device_driver console_read(
656  rtems_device_major_number major,
657  rtems_device_minor_number minor,
658  void                    * arg
659)
660{
661        return rtems_termios_read (arg);
662}
663
664/******************************************************
665  Name: console_write
666  Input parameters: channel #, termios args
667  Output parameters: -
668  Description: write to the device
669 *****************************************************/
670rtems_device_driver console_write(
671  rtems_device_major_number major,
672  rtems_device_minor_number minor,
673  void                    * arg
674)
675{
676        return rtems_termios_write (arg);
677}
678
679/******************************************************
680  Name: console_control
681  Input parameters: channel #, termios args
682  Output parameters: -
683  Description: Handle ioctl request
684 *****************************************************/
685rtems_device_driver console_control(
686  rtems_device_major_number major,
687  rtems_device_minor_number minor,
688  void                    * arg
689)
690{
691        rtems_libio_ioctl_args_t *args = arg;
692 
693        if (args->command == RTEMS_IO_SET_ATTRIBUTES)
694                SetAttributes (minor, (struct termios *)args->buffer);
695 
696        return rtems_termios_ioctl (arg);
697}
Note: See TracBrowser for help on using the repository browser.