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

5
Last change on this file since eefad309 was eefad309, checked in by Joel Sherrill <joel@…>, on 03/29/16 at 18:10:51

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