source: rtems/bsps/m68k/gen68340/console/console.c @ d7d66d7

Last change on this file since d7d66d7 was d7d66d7, checked in by Sebastian Huber <sebastian.huber@…>, on Apr 19, 2018 at 4:28:01 AM

bsps: Move console drivers to bsps

This patch is a part of the BSP source reorganization.

Update #3285.

  • Property mode set to 100644
File size: 19.1 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
478 /* convert it */
479 ispeed = rtems_termios_baud_to_number(t->c_ispeed);
480 ospeed = rtems_termios_baud_to_number(t->c_ospeed);
481
482 if (ispeed || ospeed) {
483       /* update config table */
484       m340_uart_config[UART_CHANNEL_A].rx_baudrate = ((minor==UART_CHANNEL_A)&&(ispeed!=0)) ? ispeed  : m340_uart_config[UART_CHANNEL_A].rx_baudrate;
485       m340_uart_config[UART_CHANNEL_A].tx_baudrate = ((minor==UART_CHANNEL_A)&&(ospeed!=0)) ? ospeed  : m340_uart_config[UART_CHANNEL_A].tx_baudrate;
486       m340_uart_config[UART_CHANNEL_B].rx_baudrate = ((minor==UART_CHANNEL_B)&&(ispeed!=0)) ? ispeed  : m340_uart_config[UART_CHANNEL_B].rx_baudrate;
487       m340_uart_config[UART_CHANNEL_B].tx_baudrate = ((minor==UART_CHANNEL_B)&&(ospeed!=0)) ? ospeed  : m340_uart_config[UART_CHANNEL_B].tx_baudrate;
488 }
489
490 /* change parity */
491 if (t->c_cflag & PARENB) {
492    if (t->c_cflag & PARODD) m340_uart_config[minor].parity_mode = m340_Odd_Parity;
493    else m340_uart_config[minor].parity_mode = m340_Even_Parity;
494 }
495
496 /* change bits per character */
497 if (t->c_cflag & CSIZE) {
498    switch (t->c_cflag & CSIZE) {
499        default:        break;
500        case CS5:       m340_uart_config[minor].bits_per_char = m340_5bpc;      break;
501        case CS6:       m340_uart_config[minor].bits_per_char = m340_6bpc;      break;
502        case CS7:       m340_uart_config[minor].bits_per_char = m340_7bpc;      break;
503        case CS8:       m340_uart_config[minor].bits_per_char = m340_8bpc;      break;
504    }
505 }
506
507 /* if serial module configuration has been changed */
508 if (t->c_cflag & (CSIZE | PARENB)) {
509    rtems_interrupt_disable(level);
510    /* reinit the UART */
511    dbugInitialise();
512    rtems_interrupt_enable (level);
513 }
514
515 return 0;
516}
517
518/******************************************************
519  Name: console_initialize
520  Input parameters: MAJOR # of console_driver,
521                    minor is always 0,
522                    args are always NULL
523  Output parameters: -
524  Description: Reserve resources consumed by this driver
525  TODO: We should pass m340_uart_config table in arg
526 *****************************************************/
527rtems_device_driver console_initialize(
528  rtems_device_major_number  major,
529  rtems_device_minor_number  minor,
530  void                      *arg
531)
532{
533        rtems_status_code status;
534        int i;
535
536        /*
537         * Set up TERMIOS
538         */
539        rtems_termios_initialize ();
540
541        /*
542         * Do device-specific initialization
543         */
544        Init_UART_Table();
545        dbugInitialise ();
546        Fifo_Full_benchmark_timer_initialize();
547
548        /*
549         * Register the devices
550         */
551        for (i=0; i<UART_NUMBER_OF_CHANNELS; i++) {
552            if (m340_uart_config[i].enable) {
553                status = rtems_io_register_name (m340_uart_config[i].name, major, i);
554                if (status != RTEMS_SUCCESSFUL)
555                        rtems_fatal_error_occurred (status);
556            }
557        }
558
559        return RTEMS_SUCCESSFUL;
560}
561
562/******************************************************
563  Name: console_open
564  Input parameters: channel #, arg
565  Output parameters: -
566  Description: open the device
567 *****************************************************/
568rtems_device_driver console_open(
569  rtems_device_major_number major,
570  rtems_device_minor_number minor,
571  void                    * arg
572)
573{
574 rtems_status_code sc = 0;
575
576 static const rtems_termios_callbacks intrCallbacks = {
577                NULL,                   /* firstOpen */
578                NULL,                   /* lastClose */
579                NULL,                   /* pollRead */
580                InterruptWrite,         /* write */
581                SetAttributes,          /* setAttributes */
582                NULL,                   /* stopRemoteTx */
583                NULL,                   /* startRemoteTx */
584                1                       /* outputUsesInterrupts */
585 };
586
587 static const rtems_termios_callbacks pollCallbacks = {
588                NULL,                   /* firstOpen */
589                NULL,                   /* lastClose */
590                dbugRead,               /* pollRead */
591                dbugWrite,              /* write */
592                SetAttributes,          /* setAttributes */
593                NULL,                   /* stopRemoteTx */
594                NULL,                   /* startRemoteTx */
595                0                       /* outputUsesInterrupts */
596 };
597
598 if (minor==UART_CHANNEL_A) {
599        if (USE_INTERRUPTS_A) {
600                rtems_libio_open_close_args_t *args = arg;
601
602                sc |= rtems_termios_open (major, minor, arg, &intrCallbacks);
603                ttypA = args->iop->data1;
604        }
605        else {
606                sc |= rtems_termios_open (major, minor, arg, &pollCallbacks);
607        }
608 }
609
610 else if (minor==UART_CHANNEL_B) {
611        if (USE_INTERRUPTS_B) {
612                rtems_libio_open_close_args_t *args = arg;
613
614                sc |= rtems_termios_open (major, minor, arg, &intrCallbacks);
615                ttypB = args->iop->data1;
616        }
617        else {
618                sc |= rtems_termios_open (major, minor, arg, &pollCallbacks);
619        }
620 }
621
622 else return RTEMS_INVALID_NUMBER;
623
624 return sc;
625}
626
627/******************************************************
628  Name: console_close
629  Input parameters: channel #, termios args
630  Output parameters: -
631  Description: close the device
632 *****************************************************/
633rtems_device_driver console_close(
634  rtems_device_major_number major,
635  rtems_device_minor_number minor,
636  void                    * arg
637)
638{
639        return rtems_termios_close (arg);
640}
641
642/******************************************************
643  Name: console_read
644  Input parameters: channel #, termios args
645  Output parameters: -
646  Description: read the device
647 *****************************************************/
648rtems_device_driver console_read(
649  rtems_device_major_number major,
650  rtems_device_minor_number minor,
651  void                    * arg
652)
653{
654        return rtems_termios_read (arg);
655}
656
657/******************************************************
658  Name: console_write
659  Input parameters: channel #, termios args
660  Output parameters: -
661  Description: write to the device
662 *****************************************************/
663rtems_device_driver console_write(
664  rtems_device_major_number major,
665  rtems_device_minor_number minor,
666  void                    * arg
667)
668{
669        return rtems_termios_write (arg);
670}
671
672/******************************************************
673  Name: console_control
674  Input parameters: channel #, termios args
675  Output parameters: -
676  Description: Handle ioctl request
677 *****************************************************/
678rtems_device_driver console_control(
679  rtems_device_major_number major,
680  rtems_device_minor_number minor,
681  void                    * arg
682)
683{
684        rtems_libio_ioctl_args_t *args = arg;
685
686  if (args->command == TIOCSETA)
687                SetAttributes (minor, (struct termios *)args->buffer);
688
689        return rtems_termios_ioctl (arg);
690}
Note: See TracBrowser for help on using the repository browser.