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

5
Last change on this file since 0a05c6a was c28f503, checked in by Joel Sherrill <joel.sherrill@…>, on 10/14/14 at 14:34:52

m68k/gen68340: Fix warnings

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