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

4.104.115
Last change on this file since feb6a01d was feb6a01d, checked in by Ralf Corsepius <ralf.corsepius@…>, on 09/30/09 at 04:06:15

2009-09-30 Ralf Corsépius <ralf.corsepius@…>

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