diff options
Diffstat (limited to 'c/src/lib/libbsp/m68k/gen68340/console')
-rw-r--r-- | c/src/lib/libbsp/m68k/gen68340/console/Makefile.in | 59 | ||||
-rw-r--r-- | c/src/lib/libbsp/m68k/gen68340/console/Modif_cpu_asm.s | 184 | ||||
-rw-r--r-- | c/src/lib/libbsp/m68k/gen68340/console/console.c | 740 | ||||
-rw-r--r-- | c/src/lib/libbsp/m68k/gen68340/console/m340uart.c | 409 |
4 files changed, 1392 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/m68k/gen68340/console/Makefile.in b/c/src/lib/libbsp/m68k/gen68340/console/Makefile.in new file mode 100644 index 0000000000..62a52b15e6 --- /dev/null +++ b/c/src/lib/libbsp/m68k/gen68340/console/Makefile.in @@ -0,0 +1,59 @@ +# +# $Id$ +# + +@SET_MAKE@ +srcdir = @srcdir@ +VPATH = @srcdir@ +RTEMS_ROOT = @top_srcdir@ +PROJECT_ROOT = @PROJECT_ROOT@ + +PGM=${ARCH}/console.rel + +# C source names, if any, go here -- minus the .c +C_PIECES=console m340uart +C_FILES=$(C_PIECES:%=%.c) +C_O_FILES=$(C_PIECES:%=${ARCH}/%.o) + +H_FILES= + +# Assembly source names, if any, go here -- minus the .s +S_PIECES=Modif_cpu_asm +S_FILES=$(S_PIECES:%=%.s) +S_O_FILES=$(S_FILES:%.s=${ARCH}/%.o) + +SRCS=$(C_FILES) $(H_FILES) $(S_FILES) +OBJS=$(C_O_FILES) $(S_O_FILES) + +include $(RTEMS_ROOT)/make/custom/$(RTEMS_BSP).cfg +include $(RTEMS_ROOT)/make/leaf.cfg + +# +# (OPTIONAL) Add local stuff here using += +# + +DEFINES += +CPPFLAGS += +CFLAGS += + +LD_PATHS += +LD_LIBS += +LDFLAGS += + +# +# Add your list of files to delete here. The config files +# already know how to delete some stuff, so you may want +# to just run 'make clean' first to see what gets missed. +# 'make clobber' already includes 'make clean' +# + +CLEAN_ADDITIONS += +CLOBBER_ADDITIONS += + +${PGM}: ${SRCS} ${OBJS} + $(make-rel) + +all: ${ARCH} $(SRCS) $(PGM) + +# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile +install: all diff --git a/c/src/lib/libbsp/m68k/gen68340/console/Modif_cpu_asm.s b/c/src/lib/libbsp/m68k/gen68340/console/Modif_cpu_asm.s new file mode 100644 index 0000000000..0da5865fb3 --- /dev/null +++ b/c/src/lib/libbsp/m68k/gen68340/console/Modif_cpu_asm.s @@ -0,0 +1,184 @@ +/* cpu_asm.s + * + * This file contains all assembly code for the MC68020 implementation + * of RTEMS. + * + * ATTENTION: Modified for benchmarks + * + * COPYRIGHT (c) 1989-1998. + * On-Line Applications Research Corporation (OAR). + * Copyright assigned to U.S. Government, 1994. + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.OARcorp.com/rtems/license.html. + * + * $Id$ + */ + + +#include <asm.h> + + .text + +/*PAGE + * void _Debug_ISR_Handler_Console() + * + * This routine provides the RTEMS interrupt management. + * + * NOTE: + * Upon entry, the master stack will contain an interrupt stack frame + * back to the interrupted thread and the interrupt stack will contain + * a throwaway interrupt stack frame. If dispatching is enabled, this + * is the outer most interrupt, and (a context switch is necessary or + * the current thread has signals), then set up the master stack to + * transfer control to the interrupt dispatcher. + * NOTE: + * USED TO MESURE THE TIME SPENT IN THE INTERRUPT SUBROUTINE + * CS5 - CS8 are linked to an oscilloscope so that you can mesure + * RTEMS overhead (BTW it's very short :) ) + */ + +/* + * With this approach, lower priority interrupts may + * execute twice if a higher priority interrupt is + * acknowledged before _Thread_Dispatch_disable is + * increamented and the higher priority interrupt + * preforms a context switch after executing. The lower + * priority intterrupt will execute (1) at the end of the + * higher priority interrupt in the new context if + * permitted by the new interrupt level mask, and (2) when + * the original context regains the cpu. + */ + +#if ( M68K_HAS_VBR == 1) +.set SR_OFFSET, 0 | Status register offset +.set PC_OFFSET, 2 | Program Counter offset +.set FVO_OFFSET, 6 | Format/vector offset +#else +.set SR_OFFSET, 2 | Status register offset +.set PC_OFFSET, 4 | Program Counter offset +.set FVO_OFFSET, 0 | Format/vector offset placed in the stack +#endif /* M68K_HAS_VBR */ + +.set SAVED, 16 | space for saved registers + + .align 4 + .global SYM (_Debug_ISR_Handler_Console) + +SYM (_Debug_ISR_Handler_Console): + + | + tst.w 0x14000000 | ALLUME CS5 + | + + addql #1,SYM (_Thread_Dispatch_disable_level) | disable multitasking + moveml d0-d1/a0-a1,a7@- | save d0-d1,a0-a1 + movew a7@(SAVED+FVO_OFFSET),d0 | d0 = F/VO + andl #0x0fff,d0 | d0 = vector offset in vbr + + +#if ( CPU_HAS_SOFTWARE_INTERRUPT_STACK == 1 ) + movew sr,d1 | Save status register + oriw #0x700,sr | Disable interrupts + tstl SYM (_ISR_Nest_level) | Interrupting an interrupt handler? + bne 1f | Yes, just skip over stack switch code + movel SYM(_CPU_Interrupt_stack_high),a0 | End of interrupt stack + movel a7,a0@- | Save task stack pointer + movel a0,a7 | Switch to interrupt stack +1: + addql #1,SYM(_ISR_Nest_level) | one nest level deeper + movew d1,sr | Restore status register +#else + addql #1,SYM (_ISR_Nest_level) | one nest level deeper +#endif /* CPU_HAS_SOFTWARE_INTERRUPT_STACK == 1 */ + +#if ( M68K_HAS_PREINDEXING == 1 ) + movel @( SYM (_ISR_Vector_table),d0:w:1),a0| fetch the ISR +#else + movel # SYM (_ISR_Vector_table),a0 | a0 = base of RTEMS table + addal d0,a0 | a0 = address of vector + movel (a0),a0 | a0 = address of user routine +#endif + + lsrl #2,d0 | d0 = vector number + movel d0,a7@- | push vector number + + | + tst.w 0x18000000 | ALLUME CS6 + | + + jbsr a0@ | invoke the user ISR + + | + tst.w 0x18000000 | ALLUME CS6 + | + + addql #4,a7 | remove vector number + +#if ( CPU_HAS_SOFTWARE_INTERRUPT_STACK == 1 ) + movew sr,d0 | Save status register + oriw #0x700,sr | Disable interrupts + subql #1,SYM(_ISR_Nest_level) | Reduce interrupt-nesting count + bne 1f | Skip if return to interrupt + movel (a7),a7 | Restore task stack pointer +1: + movew d0,sr | Restore status register +#else + subql #1,SYM (_ISR_Nest_level) | one less nest level +#endif /* CPU_HAS_SOFTWARE_INTERRUPT_STACK == 1 */ + + subql #1,SYM (_Thread_Dispatch_disable_level) + | unnest multitasking + bne Debug_exit | If dispatch disabled, Debug_exit + +#if ( M68K_HAS_SEPARATE_STACKS == 1 ) + movew #0xf000,d0 | isolate format nibble + andw a7@(SAVED+FVO_OFFSET),d0 | get F/VO + cmpiw #0x1000,d0 | is it a throwaway isf? + bne Debug_exit | NOT outer level, so branch +#endif + + tstl SYM (_Context_Switch_necessary) + | Is thread switch necessary? + bne bframe | Yes, invoke dispatcher + + tstl SYM (_ISR_Signals_to_thread_executing) + | signals sent to Run_thread + | while in interrupt handler? + beq Debug_exit | No, then Debug_exit + + +bframe: clrl SYM (_ISR_Signals_to_thread_executing) + | If sent, will be processed +#if ( M68K_HAS_SEPARATE_STACKS == 1 ) + movec msp,a0 | a0 = master stack pointer + movew #0,a0@- | push format word + movel # SYM (_ISR_Dispatch),a0@- | push return addr + | filter out the trace bit to stop single step debugging breaking + movew a0@(6+SR_OFFSET),d0 + andw #0x7FFF,d0 + movew d0,a0@- | push thread sr + movec a0,msp | set master stack pointer +#else + + | filter out the trace bit to stop single step debugging breaking + movew a7@(16+SR_OFFSET),d0 + andw #0x7FFF,d0 + movew d0,sr + jsr SYM (_Thread_Dispatch) +#endif + +Debug_exit: moveml a7@+,d0-d1/a0-a1 | restore d0-d1,a0-a1 +#if ( M68K_HAS_VBR == 0 ) + addql #2,a7 | pop format/id +#endif /* M68K_HAS_VBR */ + + | + tst.w 0x1C000000 | ALLUME CS7 + | + + rte | return to thread + | OR _Isr_dispatch + + diff --git a/c/src/lib/libbsp/m68k/gen68340/console/console.c b/c/src/lib/libbsp/m68k/gen68340/console/console.c new file mode 100644 index 0000000000..adeff172ed --- /dev/null +++ b/c/src/lib/libbsp/m68k/gen68340/console/console.c @@ -0,0 +1,740 @@ +/* + * 68340/68349 console serial I/O. + * + * Author: + * Geoffroy Montel + * France Telecom - CNET/DSM/TAM/CAT + * 4, rue du Clos Courtel + * 35512 CESSON-SEVIGNE + * FRANCE + * + * e-mail: g_montel@yahoo.com + * + * COPYRIGHT (c) 1989-1998. + * On-Line Applications Research Corporation (OAR). + * Copyright assigned to U.S. Government, 1994. + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * + * http://www.OARcorp.com/rtems/license.html. + * + * $Id$ + */ + +#include <termios.h> +#include <bsp.h> +#include <rtems/libio.h> +#include <m68340.h> +#include <m340uart.h> +#include <m340timer.h> + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> + +#define CONSOLE_VECTOR 121 +#define CONSOLE_IRQ_LEVEL 3 +#define CONSOLE_INTERRUPT_ARBITRATION 2 + +static void *ttypA; /* to remember which tty has been opened on channel A + used when interrupts are enabled */ + +static void *ttypB; /* to remember which tty has been opened on channel B + used when interrupts are enabled */ + +unsigned char DUIER_mirror = 0 ; /* reflects the state of IER register, which is Write Only */ +unsigned char Error_Status_A = 0; /* error status on Channel A */ +unsigned char Error_Status_B = 0; /* error status on Channel A */ + +/* + * Device-specific routines + */ + +#define USE_INTERRUPTS_A (m340_uart_config[UART_CHANNEL_A].mode==UART_INTERRUPTS) +#define USE_INTERRUPTS_B (m340_uart_config[UART_CHANNEL_B].mode==UART_INTERRUPTS) +#define CHANNEL_ENABLED_A m340_uart_config[UART_CHANNEL_A].enable +#define CHANNEL_ENABLED_B m340_uart_config[UART_CHANNEL_B].enable + +#define set_DUIER(a) DUIER_mirror |= (a); DUIER = DUIER_mirror +#define unset_DUIER(a) DUIER_mirror &= ~(a); DUIER = DUIER_mirror + +#define Enable_Interrupts_Tx_A if (USE_INTERRUPTS_A) set_DUIER(m340_TxRDYA) +#define Disable_Interrupts_Tx_A if (USE_INTERRUPTS_A) unset_DUIER(m340_TxRDYA) + +#define Enable_Interrupts_Tx_B if (USE_INTERRUPTS_B) set_DUIER(m340_TxRDYB) +#define Disable_Interrupts_Tx_B if (USE_INTERRUPTS_B) unset_DUIER(m340_TxRDYB) + +/****************************************************** + Name: erreur + Input parameters: string + Output parameters: - + Description: small error routine :) + *****************************************************/ +static void erreur (char * string) +{ + fprintf(stderr, string); +} + +/****************************************************** + Name: InterruptHandler + Input parameters: vector number + Output parameters: - + Description: UART ISR Routine, called by _RTEMS_ISR + *****************************************************/ +rtems_isr +InterruptHandler (rtems_vector_number v) +{ + char ch; + + /***************************************************************************** + ** CHANNEL A ** + *****************************************************************************/ + + /* check Received Break*/ + if (DUSRA & m340_RB) { + Error_Status_A |= m340_RB; + /* reset error status */ + DUCRA = m340_Reset_Error_Status; + } + + /* buffer received ? */ + if (DUSRA & m340_Rx_RDY) { + do { + /* error encountered? */ + if (DUSRA & (m340_OE | m340_PE | m340_FE | m340_RB)) { + Error_Status_A |= DUSRA; + /* reset error status */ + DUCRA = m340_Reset_Error_Status; + /* all the characters in the queue may not be good */ + while (DUSRA & m340_Rx_RDY) + /* push them in a trash */ + ch = DURBA; + } + else { + /* this is necessary, otherwise it blocks when FIFO is full */ + ch = DURBA; + rtems_termios_enqueue_raw_characters(ttypA,&ch,1); + } + } while (DUSRA & m340_Rx_RDY); + Restart_Fifo_Full_A_Timer(); /* only if necessary (pointer to a fake function if + not in FIFO full mode) */ + } + + else /* if no character has been received */ + Restart_Check_A_Timer(); /* same remark */ + + /* ready to accept a character ? */ + if (DUISR & DUIER_mirror & m340_TxRDYA) { + Disable_Interrupts_Tx_A; + /* one character has been transmitted */ + rtems_termios_dequeue_characters(ttypA,1); + } + + /***************************************************************************** + ** CHANNEL B ** + *****************************************************************************/ + + /* check Received Break*/ + if (DUSRB & m340_RB) { + Error_Status_B |= m340_RB; + /* reset error status */ + DUCRB = m340_Reset_Error_Status; + } + + /* buffer received ? */ + if (DUSRB & m340_Rx_RDY) { + do { + if (DUSRB & (m340_OE | m340_PE | m340_FE | m340_RB)) { + Error_Status_B |= DUSRB; + /* reset error status */ + DUCRB = m340_Reset_Error_Status; + /* all the characters in the queue may not be good */ + while (DUSRB & m340_Rx_RDY) + /* push them in a trash */ + ch = DURBB; + } + else { + ch = DURBB; + rtems_termios_enqueue_raw_characters(ttypB,&ch,1); + } + + } while (DUSRB & m340_Rx_RDY); + Restart_Fifo_Full_B_Timer(); + } + else /* if no character has been received */ + Restart_Check_B_Timer(); + + /* ready to accept a character ? */ + if (DUISR & DUIER_mirror & m340_TxRDYB) { + Disable_Interrupts_Tx_B; + /* one character has been transmitted */ + rtems_termios_dequeue_characters(ttypB,1); + } +} + +/****************************************************** + Name: InterruptWrite + Input parameters: minor = channel, pointer to buffer, + and length of buffer to transmit + Output parameters: - + Description: write the first character of buf only + may be called by either console_write + or rtems_termios_enqueue_raw_characters + *****************************************************/ +static int +InterruptWrite (int minor, const char *buf, int len) +{ + if (minor==UART_CHANNEL_A) { + if (len>0) (char)DUTBA=*buf; + Enable_Interrupts_Tx_A; + } + else if (minor==UART_CHANNEL_B) { + if (len>0) (char)DUTBB=*buf; + Enable_Interrupts_Tx_B; + } + return 0; +} + +/****************************************************** + Name: dbug_out_char + Input parameters: channel, character to emit + Output parameters: - + Description: wait for the UART to be ready to emit + a character and send it + *****************************************************/ +void dbug_out_char( int minor, int ch ) +{ + if (minor==UART_CHANNEL_A) { + while (!(DUSRA & m340_Tx_RDY)) continue; + DUTBA=ch; + } + else if (minor==UART_CHANNEL_B) { + while (!(DUSRB & m340_Tx_RDY)) continue; + DUTBB=ch; + } +} + +/****************************************************** + Name: dbug_in_char + Input parameters: - + Output parameters: received character + Description: return the character in the UART + *****************************************************/ +int dbug_in_char( int minor ) +{ + if (minor==UART_CHANNEL_A) { + return DURBA; + } + else if (minor==UART_CHANNEL_B) { + return DURBB; + } + return 0; +} + +/****************************************************** + Name: dbug_char_present + Input parameters: channel # + Output parameters: TRUE or FALSE + Description: return whether there's a character + in the receive buffer + *****************************************************/ +int dbug_char_present( int minor ) +{ + if (minor==UART_CHANNEL_A) { + return (DUSRA & m340_Rx_RDY); + } + else if (minor==UART_CHANNEL_B) { + return (DUSRB & m340_Rx_RDY); + } + return 0; +} + +/****************************************************** + Name: dbugInitialise + Input parameters: - + Output parameters: - + Description: Init the UART + *****************************************************/ +static void +dbugInitialise () +{ + t_baud_speed_table uart_config; /* configuration of UARTS */ + + /* + * Reset Receiver + */ + DUCRA = m340_Reset_Receiver; + DUCRB = m340_Reset_Receiver; + + /* + * Reset Transmitter + */ + DUCRA = m340_Reset_Transmitter; + DUCRB = m340_Reset_Transmitter; + + /* + * Enable serial module for normal operation, ignore FREEZE, select the crystal clock, + * supervisor/user serial registers unrestricted + * interrupt arbitration at priority CONSOLE_INTERRUPT_ARBITRATION + * WARNING : 8 bits access only on this UART! + */ + DUMCRH = 0x00; + DUMCRL = CONSOLE_INTERRUPT_ARBITRATION; + + /* + * Interrupt level register + */ + DUILR = CONSOLE_IRQ_LEVEL; + + /* sets the IVR */ + DUIVR = CONSOLE_VECTOR; + + /* search for a correct m340 uart configuration */ + uart_config = Find_Right_m340_UART_Config(m340_uart_config[UART_CHANNEL_A].rx_baudrate, + m340_uart_config[UART_CHANNEL_A].tx_baudrate, + CHANNEL_ENABLED_A, + m340_uart_config[UART_CHANNEL_B].rx_baudrate, + m340_uart_config[UART_CHANNEL_B].tx_baudrate, + CHANNEL_ENABLED_B); + + /***************************************************************************** + ** CHANNEL A ** + *****************************************************************************/ + if (CHANNEL_ENABLED_A) { + + if (USE_INTERRUPTS_A) { + rtems_isr_entry old_handler; + rtems_status_code sc; + + proc_ptr ignored; + extern void _Debug_ISR_Handler_Console(void); + + sc = rtems_interrupt_catch (InterruptHandler, + CONSOLE_VECTOR, + &old_handler); + + /* uncomment this if you want to pass control to your own ISR handler + it may be usefull to do so to check for performances with an oscilloscope */ + /* + _CPU_ISR_install_raw_handler( CONSOLE_VECTOR, _Debug_ISR_Handler_Console, &ignored ); + */ + + /* + * Interrupt Enable Register + * Enable Interrupts on Channel A Receiver Ready + */ + set_DUIER(m340_RxRDYA); + } + else { + /* + * Disable Interrupts on channel A + */ + unset_DUIER(m340_RxRDYA&m340_TxRDYA); + } + + /* + * Change set of baud speeds + * disable input control + */ + /* no good uart configuration ? */ + if (uart_config.nb<1) rtems_fatal_error_occurred (-1); + + if (uart_config.baud_speed_table[UART_CHANNEL_A].set==1) + DUACR = m340_BRG_Set1; + else + DUACR = m340_BRG_Set2; + + /* + * make OPCR an auxiliary function serving the communication channels + */ + DUOPCR = m340_OPCR_Aux; + + /* poll the XTAL_RDY bit until it is cleared to ensure that an unstable crystal + input is not applied to the baud rate generator */ + while (DUISR & m340_XTAL_RDY) continue; + + /* + * Serial Channel Baud Speed + */ + DUCSRA = (uart_config.baud_speed_table[UART_CHANNEL_A].rcs << 4) + | (uart_config.baud_speed_table[UART_CHANNEL_A].tcs); + + /* + * Serial Channel Configuration + */ + DUMR1A = m340_uart_config[UART_CHANNEL_A].parity_mode + | m340_uart_config[UART_CHANNEL_A].bits_per_char + | m340_RxRTS; + + if (m340_uart_config[UART_CHANNEL_A].rx_mode==UART_FIFO_FULL) DUMR1A |= m340_R_F | m340_ERR; + + /* + * Serial Channel Configuration 2 + */ + DUMR2A |= m340_normal; + + /* + * Enable Channel A: transmitter and receiver + */ + DUCRA = m340_Transmitter_Enable | m340_Receiver_Enable; + } /* channel A enabled */ + + /***************************************************************************** + ** CHANNEL B ** + *****************************************************************************/ + if (CHANNEL_ENABLED_B) { + + /* we mustn't set the console vector twice! */ + if ((USE_INTERRUPTS_B && !(CHANNEL_ENABLED_A)) + || (USE_INTERRUPTS_B && CHANNEL_ENABLED_A && !USE_INTERRUPTS_A)) { + rtems_isr_entry old_handler; + rtems_status_code sc; + + proc_ptr ignored; + extern void _Debug_ISR_Handler_Console(void); + + sc = rtems_interrupt_catch (InterruptHandler, + CONSOLE_VECTOR, + &old_handler); + + /* uncomment this if you want to pass control to your own ISR handler + it may be usefull to do so to check for performances with an oscilloscope */ + /* + _CPU_ISR_install_raw_handler( CONSOLE_VECTOR, _Debug_ISR_Handler_Console, &ignored ); + */ + + /* + * Interrupt Enable Register + * Enable Interrupts on Channel A Receiver Ready + */ + set_DUIER(m340_RxRDYB); + } + else { + /* + * Disable Interrupts on channel B + */ + unset_DUIER(m340_RxRDYB&m340_TxRDYB); + } + + /* + * Change set of baud speeds + * disable input control + */ + + /* no good uart configuration ? */ + if (uart_config.nb<2) rtems_fatal_error_occurred (-1); + + /* don't set DUACR twice! */ + if (!CHANNEL_ENABLED_A) + if (uart_config.baud_speed_table[UART_CHANNEL_B].set==1) DUACR = m340_BRG_Set1; + else DUACR = m340_BRG_Set2; + + /* + * make OPCR an auxiliary function serving the communication channels + */ + if (!CHANNEL_ENABLED_A) DUOPCR = m340_OPCR_Aux; + + /* poll the XTAL_RDY bit until it is cleared to ensure that an unstable crystal + input is not applied to the baud rate generator */ + while (DUISR & m340_XTAL_RDY) continue; + + /* + * Serial Channel Baud Speed + */ + DUCSRB = (uart_config.baud_speed_table[UART_CHANNEL_B].rcs << 4) + | (uart_config.baud_speed_table[UART_CHANNEL_B].tcs); + + /* + * Serial Channel Configuration + */ + DUMR1B = m340_uart_config[UART_CHANNEL_B].parity_mode + | m340_uart_config[UART_CHANNEL_B].bits_per_char + | m340_RxRTS; + + if (m340_uart_config[UART_CHANNEL_B].rx_mode==UART_FIFO_FULL) DUMR1B |= m340_R_F | m340_ERR; + + /* + * Serial Channel Configuration 2 + */ + DUMR2B |= m340_normal; + + /* + * Enable Channel A: transmitter and receiver + */ + DUCRB = m340_Transmitter_Enable | m340_Receiver_Enable; + } /* channel B enabled */ +} + +/****************************************************** + Name: SetAttributes + Input parameters: termios structure, channel + Output parameters: - + Description: return whether there's a character + in the receive buffer + TO DO: add the channel # to check for!! + *****************************************************/ +static void +SetAttributes (struct termios *t, int minor) +{ + rtems_interrupt_level level; + float ispeed, ospeed; + int isp, osp; + + /* output speed */ + if (t->c_cflag & CBAUDEX) + osp = (t->c_cflag & CBAUD) + CBAUD + 1; + else + osp = t->c_cflag & CBAUD; + + /* input speed */ + isp = (t->c_cflag / (CIBAUD / CBAUD)) & CBAUD; + + /* convert it */ + ispeed = termios_baud_rates_equivalence(isp); + ospeed = termios_baud_rates_equivalence(osp); + + if (ispeed || ospeed) { + /* update config table */ + m340_uart_config[UART_CHANNEL_A].rx_baudrate = ((minor==UART_CHANNEL_A)&&(ispeed!=0)) ? ispeed : m340_uart_config[UART_CHANNEL_A].rx_baudrate; + m340_uart_config[UART_CHANNEL_A].tx_baudrate = ((minor==UART_CHANNEL_A)&&(ospeed!=0)) ? ospeed : m340_uart_config[UART_CHANNEL_A].tx_baudrate; + m340_uart_config[UART_CHANNEL_B].rx_baudrate = ((minor==UART_CHANNEL_B)&&(ispeed!=0)) ? ispeed : m340_uart_config[UART_CHANNEL_B].rx_baudrate; + m340_uart_config[UART_CHANNEL_B].tx_baudrate = ((minor==UART_CHANNEL_B)&&(ospeed!=0)) ? ospeed : m340_uart_config[UART_CHANNEL_B].tx_baudrate; + } + + /* change parity */ + if (t->c_cflag & PARENB) { + if (t->c_cflag & PARODD) m340_uart_config[minor].parity_mode = m340_Odd_Parity; + else m340_uart_config[minor].parity_mode = m340_Even_Parity; + } + + /* change bits per character */ + if (t->c_cflag & CSIZE) { + switch (t->c_cflag & CSIZE) { + default: break; + case CS5: m340_uart_config[minor].bits_per_char = m340_5bpc; break; + case CS6: m340_uart_config[minor].bits_per_char = m340_6bpc; break; + case CS7: m340_uart_config[minor].bits_per_char = m340_7bpc; break; + case CS8: m340_uart_config[minor].bits_per_char = m340_8bpc; break; + } + } + + /* if serial module configuration has been changed */ + if (t->c_cflag & (CBAUD | CIBAUD | CSIZE | PARENB)) { + rtems_interrupt_disable(level); + /* reinit the UART */ + dbugInitialise(); + rtems_interrupt_enable (level); + } +} + +/****************************************************** + Name: console_atexit + Input parameters: - + Output parameters: - + Description: called at program termination. + TO DO: add a TERMIOS routine to wait for all the + characters to be transmitted + *****************************************************/ +void console_atexit(void) +{ + if ((CHANNEL_ENABLED_A && USE_INTERRUPTS_A) || (CHANNEL_ENABLED_B && USE_INTERRUPTS_B)) + { + /* should do a drain output but the function is static + and we do not have a table holding all the file descriptors */ + /* just loop, I don't mind not to shutdown the executive */ + while (1) continue; + } +} + +/****************************************************** + Name: console_reserve_resources + Input parameters: - + Output parameters: - + Description: Reserve resources consumed by this driver + *****************************************************/ +void console_reserve_resources( + rtems_configuration_table *configuration +) +{ + rtems_termios_reserve_resources (configuration, 1); +} + +/****************************************************** + Name: console_initialize + Input parameters: MAJOR # of console_driver, + minor is always 0, + args are always NULL + Output parameters: - + Description: Reserve resources consumed by this driver + TODO: We should pass m340_uart_config table in arg + *****************************************************/ +rtems_device_driver console_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + rtems_status_code status; + int i; + + /* + * Set up console driver needs for program termination + */ + atexit(console_atexit); + + /* + * Set up TERMIOS + */ + rtems_termios_initialize (); + + /* + * Do device-specific initialization + */ + Init_UART_Table(); + dbugInitialise (); + Fifo_Full_Timer_initialize(); + + /* + * Register the devices + */ + for (i=0; i<UART_NUMBER_OF_CHANNELS; i++) { + if (m340_uart_config[i].enable) { + status = rtems_io_register_name (m340_uart_config[i].name, major, i); + if (status != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred (status); + } + } + + return RTEMS_SUCCESSFUL; +} + +/****************************************************** + Name: console_open + Input parameters: channel #, arg + Output parameters: - + Description: open the device + *****************************************************/ +rtems_device_driver console_open( + rtems_device_major_number major, + rtems_device_minor_number minor, + void * arg +) +{ + rtems_status_code sc = 0; + + static const rtems_termios_callbacks intrCallbacks = { + NULL, /* firstOpen */ + NULL, /* lastClose */ + NULL, /* pollRead */ + InterruptWrite, /* write */ + SetAttributes, /* setAttributes */ + NULL, /* stopRemoteTx */ + NULL, /* startRemoteTx */ + 1 /* outputUsesInterrupts */ + }; + + static const rtems_termios_callbacks pollCallbacks = { + NULL, /* firstOpen */ + NULL, /* lastClose */ + dbugRead, /* pollRead */ + dbugWrite, /* write */ + SetAttributes, /* setAttributes */ + NULL, /* stopRemoteTx */ + NULL, /* startRemoteTx */ + 0 /* outputUsesInterrupts */ + }; + + if (minor==UART_CHANNEL_A) { + if (USE_INTERRUPTS_A) { + rtems_libio_open_close_args_t *args = arg; + + sc |= rtems_termios_open (major, minor, arg, &intrCallbacks); + ttypA = args->iop->data1; + } + else { + sc |= rtems_termios_open (major, minor, arg, &pollCallbacks); + } + } + + else if (minor==UART_CHANNEL_B) { + if (USE_INTERRUPTS_B) { + rtems_libio_open_close_args_t *args = arg; + + sc |= rtems_termios_open (major, minor, arg, &intrCallbacks); + ttypB = args->iop->data1; + } + else { + sc |= rtems_termios_open (major, minor, arg, &pollCallbacks); + } + } + + else return RTEMS_INVALID_NUMBER; + + return sc; +} + +/****************************************************** + Name: console_close + Input parameters: channel #, termios args + Output parameters: - + Description: close the device + *****************************************************/ +rtems_device_driver console_close( + rtems_device_major_number major, + rtems_device_minor_number minor, + void * arg +) +{ + return rtems_termios_close (arg); +} + +/****************************************************** + Name: console_read + Input parameters: channel #, termios args + Output parameters: - + Description: read the device + *****************************************************/ +rtems_device_driver console_read( + rtems_device_major_number major, + rtems_device_minor_number minor, + void * arg +) +{ + return rtems_termios_read (arg); +} + +/****************************************************** + Name: console_write + Input parameters: channel #, termios args + Output parameters: - + Description: write to the device + *****************************************************/ +rtems_device_driver console_write( + rtems_device_major_number major, + rtems_device_minor_number minor, + void * arg +) +{ + return rtems_termios_write (arg); +} + +/****************************************************** + Name: console_control + Input parameters: channel #, termios args + Output parameters: - + Description: Handle ioctl request + *****************************************************/ +rtems_device_driver console_control( + rtems_device_major_number major, + rtems_device_minor_number minor, + void * arg +) +{ + rtems_libio_ioctl_args_t *args = arg; + + if (args->command == RTEMS_IO_SET_ATTRIBUTES) + SetAttributes ((struct termios *)args->buffer, minor); + + return rtems_termios_ioctl (arg); +} diff --git a/c/src/lib/libbsp/m68k/gen68340/console/m340uart.c b/c/src/lib/libbsp/m68k/gen68340/console/m340uart.c new file mode 100644 index 0000000000..a293f6c83c --- /dev/null +++ b/c/src/lib/libbsp/m68k/gen68340/console/m340uart.c @@ -0,0 +1,409 @@ +/* + * M68340/349 uart management tools + * + * Author: + * Geoffroy Montel + * France Telecom - CNET/DSM/TAM/CAT + * 4, rue du Clos Courtel + * 35512 CESSON-SEVIGNE + * FRANCE + * + * e-mail: g_montel@yahoo.com + * + * COPYRIGHT (c) 1989-1998. + * On-Line Applications Research Corporation (OAR). + * Copyright assigned to U.S. Government, 1994. + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * + * http://www.OARcorp.com/rtems/license.html. + * + * $Id$ + */ + +#include <termios.h> +#include <bsp.h> +#include <rtems/libio.h> +#include <m68340.h> +#include <m340uart.h> +#include <stdarg.h> + +/* this table shows compatible speed configurations for the MC68340: + the first row shows baud rates for baud speed set 1 + the second row shows baud rates for baud speed set 2 + look at Motorola's MC68340 Integrated Processor User's Manual + page 7-30 for more infos */ + +float m340_Baud_Rates_Table[16][2] = {\ + { 50, 75 }, \ + { 110, 110 }, \ + { 134.5, 134.5 }, \ + { 200, 150 }, \ + { 300, 300 }, \ + { 600, 600 }, \ + { 1200, 1200 }, \ + { 1050, 2000 }, \ + { 2400, 2400 }, \ + { 4800, 4800 }, \ + { 7200, 1800 }, \ + { 9600, 9600 }, \ + { 38400, 19200 }, \ + { 76800, 38400 }, \ + { SCLK/16, SCLK/16}, \ + { SCLK, SCLK }, \ +}; + +/* config on both 340 channels */ +uart_channel_config m340_uart_config[UART_NUMBER_OF_CHANNELS]; + +/* + * Init UART table + */ + +#define NOT_IMPLEMENTED_YET 0 + +/****************************************************** + Name: Init_UART_Table + Input parameters: - + Output parameters: - + Description: Init the m340_uart_config + THIS SHOULD NOT BE HERE! + Its aim was to let the user configure + UARTs for each application. + As we can't pass args to the console + driver initialisation routine at the + moment, this was not done. + ATTENTION: TERMIOS init presupposes that the channel + baud rates is 9600/9600. + -> risks when using IOCTL + *****************************************************/ +void Init_UART_Table(void) +{ + m340_uart_config[UART_CHANNEL_A].enable = TRUE; + strcpy(m340_uart_config[UART_CHANNEL_A].name, UART_CONSOLE_NAME); + m340_uart_config[UART_CHANNEL_A].parity_mode = m340_No_Parity; + m340_uart_config[UART_CHANNEL_A].bits_per_char = m340_8bpc; + m340_uart_config[UART_CHANNEL_A].rx_baudrate = 9600; + m340_uart_config[UART_CHANNEL_A].tx_baudrate = 9600; + m340_uart_config[UART_CHANNEL_A].rx_mode = UART_CRR; + m340_uart_config[UART_CHANNEL_A].mode = UART_POLLING; + + m340_uart_config[UART_CHANNEL_A].termios.enable = TRUE; + m340_uart_config[UART_CHANNEL_A].termios.rx_buffer_size = NOT_IMPLEMENTED_YET; + m340_uart_config[UART_CHANNEL_A].termios.tx_buffer_size = NOT_IMPLEMENTED_YET; + + m340_uart_config[UART_CHANNEL_B].enable = FALSE; + strcpy(m340_uart_config[UART_CHANNEL_B].name, UART_RAW_IO_NAME); + m340_uart_config[UART_CHANNEL_B].parity_mode = m340_No_Parity; + m340_uart_config[UART_CHANNEL_B].bits_per_char = m340_8bpc; + m340_uart_config[UART_CHANNEL_B].rx_baudrate = 38400; + m340_uart_config[UART_CHANNEL_B].tx_baudrate = 38400; + m340_uart_config[UART_CHANNEL_B].rx_mode = UART_CRR; + m340_uart_config[UART_CHANNEL_B].mode = UART_INTERRUPTS; + + m340_uart_config[UART_CHANNEL_B].termios.enable = TRUE; + m340_uart_config[UART_CHANNEL_B].termios.rx_buffer_size = NOT_IMPLEMENTED_YET; + m340_uart_config[UART_CHANNEL_B].termios.tx_buffer_size = NOT_IMPLEMENTED_YET; +} + +/****************************************************** + Name: Find_Right_m340_UART_Channel_Config + Input parameters: Send/Receive baud rates for a + given channel + Output parameters: UART compatible configs for this + channel + Description: returns which uart configurations fit + Receiver Baud Rate and Transmitter Baud + Rate for a given channel + For instance, according to the + m340_Baud_Rates_Table: + - Output Speed = 50, Input Speed = 75 + is not a correct config, because + 50 bauds implies set 1 and 75 bauds + implies set 2 + - Output Speed = 9600, Input Speed = 9600 + two correct configs for this: + RCS=11, TCS=11, Set=1 or 2 + *****************************************************/ +t_baud_speed_table +Find_Right_m340_UART_Channel_Config(float ReceiverBaudRate, float TransmitterBaudRate) +{ + t_baud_speed_table return_value; + + struct { + int cs; + int set; + } Receiver[2], Transmitter[2]; + + int Receiver_nb_of_config = 0; + int Transmitter_nb_of_config = 0; + + int i,j; + + /* Receiver and Transmitter baud rates must be compatible, ie in the same set */ + + /* search for configurations for ReceiverBaudRate - there can't be more than two (only two sets) */ + for (i=0;i<16;i++) + for (j=0;j<2;j++) + if (m340_Baud_Rates_Table[i][j]==ReceiverBaudRate) { + Receiver[Receiver_nb_of_config].cs=i; + Receiver[Receiver_nb_of_config].set=j; + Receiver_nb_of_config++; + } + + /* search for configurations for TransmitterBaudRate - there can't be more than two (only two sets) */ + for (i=0;i<16;i++) + for (j=0;j<2;j++) + if (m340_Baud_Rates_Table[i][j]==TransmitterBaudRate) { + Transmitter[Transmitter_nb_of_config].cs=i; + Transmitter[Transmitter_nb_of_config].set=j; + Transmitter_nb_of_config++; + } + + /* now check if there's a compatible config */ + return_value.nb=0; + + for (i=0; i<Receiver_nb_of_config; i++) + for (j=0;j<Transmitter_nb_of_config;j++) + if (Receiver[i].set == Transmitter[j].set) { + return_value.baud_speed_table[return_value.nb].set = Receiver[i].set + 1; /* we want set 1 or set 2, not 0 or 1 */ + return_value.baud_speed_table[return_value.nb].rcs = Receiver[i].cs; + return_value.baud_speed_table[return_value.nb].tcs = Transmitter[j].cs; + return_value.nb++; + } + + return return_value; +} + +/****************************************************** + Name: Find_Right_m340_UART_Config + Input parameters: Send/Receive baud rates for both + channels + Output parameters: UART compatible configs for + BOTH channels + Description: returns which uart configurations fit + Receiver Baud Rate and Transmitter Baud + Rate for both channels + For instance, if we want 9600/38400 on + channel A and 9600/19200 on channel B, + this is not a good m340 uart config + (channel A needs set 1 and channel B + needs set 2) + *****************************************************/ +t_baud_speed_table +Find_Right_m340_UART_Config(float ChannelA_ReceiverBaudRate, float ChannelA_TransmitterBaudRate, rtems_unsigned8 enableA, + float ChannelB_ReceiverBaudRate, float ChannelB_TransmitterBaudRate, rtems_unsigned8 enableB) +{ + t_baud_speed_table tableA, tableB; + t_baud_speed_table return_value, tmp; + int i,j; + + return_value.nb=0; + + if (enableA && enableB) { + tableA = Find_Right_m340_UART_Channel_Config(ChannelA_ReceiverBaudRate, ChannelA_TransmitterBaudRate); + tableB = Find_Right_m340_UART_Channel_Config(ChannelB_ReceiverBaudRate, ChannelB_TransmitterBaudRate); + + for (i=0;i<tableA.nb;i++) + for (j=0;j<tableB.nb;j++) + if (tableA.baud_speed_table[i].set==tableB.baud_speed_table[j].set) { + return_value.baud_speed_table[UART_CHANNEL_A].set=tableA.baud_speed_table[i].set; + return_value.baud_speed_table[UART_CHANNEL_A].rcs=tableA.baud_speed_table[i].rcs; + return_value.baud_speed_table[UART_CHANNEL_A].tcs=tableA.baud_speed_table[i].tcs; + return_value.baud_speed_table[UART_CHANNEL_B].set=tableB.baud_speed_table[j].set; + return_value.baud_speed_table[UART_CHANNEL_B].rcs=tableB.baud_speed_table[j].rcs; + return_value.baud_speed_table[UART_CHANNEL_B].tcs=tableB.baud_speed_table[j].tcs; + return_value.nb=2; + break; + } + return return_value; + } + + if (enableA) { + return_value = Find_Right_m340_UART_Channel_Config(ChannelA_ReceiverBaudRate, ChannelA_TransmitterBaudRate); + return return_value; + } + + if (enableB) { + tmp = Find_Right_m340_UART_Channel_Config(ChannelB_ReceiverBaudRate, ChannelB_TransmitterBaudRate); + if (tmp.nb!=0) { + return_value.nb = 2; + return_value.baud_speed_table[1].set = tmp.baud_speed_table[0].set; + return_value.baud_speed_table[1].rcs = tmp.baud_speed_table[0].rcs; + return_value.baud_speed_table[1].tcs = tmp.baud_speed_table[0].tcs; + } + } + return return_value; +} + +/****************************************************** + Name: termios_baud_rates_equivalence + Input parameters: Termios coded speed + Output parameters: explicit speed + Description: ioctl calls return termios coded speed + we need to know real speed in order + to use the functions above + *****************************************************/ +float termios_baud_rates_equivalence ( int speed ) +{ + switch (speed) { + default: return 0; break; + case B50: return 50; break; + case B75: return 75; break; + case B110: return 110; break; + case B134: return 134; break; + case B150: return 150; break; + case B200: return 200; break; + case B300: return 300; break; + case B600: return 600; break; + case B1200: return 1200; break; + case B1800: return 1800; break; + case B2400: return 2400; break; + case B4800: return 4800; break; + case B9600: return 9600; break; + case B19200: return 19200; break; + case B38400: return 38400; break; + case B57600: return 57600; break; + case B115200: return 115200; break; + case B230400: return 230400; break; + case B460800: return 460800; break; + } + return 0; +} + +/****************************************************************************************************/ + +/* + * very low level fmted output + */ + +extern void dbug_out_char( int minor, int ch ); +extern int dbug_in_char( int minor ); +extern int dbug_char_present( int minor ); + +/****************************************************** + Name: dbugRead + Input parameters: channel + Output parameters: char read + Description: polled read + *****************************************************/ +int dbugRead (int minor) +{ + if (dbug_char_present(minor) == 0) + return -1; + return dbug_in_char(minor); +} + +/****************************************************** + Name: dbugWrite + Input parameters: channel, buffer and its length + Output parameters: always successfull + Description: polled write + *****************************************************/ +int dbugWrite (int minor, const char *buf, int len) +{ + static char txBuf; + + while (len--) { + txBuf = *buf++; + dbug_out_char( minor, (int)txBuf ); + } + return 0; +} + +static void fmt_num( int minor, unsigned long, unsigned ); +static void fmt_str( int minor, const char* ); + +/****************************************************** + Name: RAW_GETC + Input parameters: channel, buffer and its length + Output parameters: + Description: a light blocking "getc" + *****************************************************/ +char RAW_GETC(int minor) +{ + while (!dbug_char_present(minor)) continue; + return dbug_in_char(minor); +} + +/****************************************************** + Name: RAW_FMT + Input parameters: channel, buffer and its length + Output parameters: always successfull + Description: a light polled "printf" + useful when there's a serious pb and + there are no more interrupts + *****************************************************/ +void RAW_FMT( int minor, const char* fmt, ... ) +{ + int ch; + va_list va; + + va_start( va, fmt ); + + while( (ch = *fmt++) ) + if( ch != '%' || (ch = *fmt++) == '%' ) + { + if( ch == '\n' ) + dbug_out_char( minor, '\r' ); + dbug_out_char( minor, ch ); + } + else switch( ch ) + { + case 'c': + dbug_out_char( minor, va_arg( va, int ) ); + continue; + case 's': + fmt_str( minor, va_arg( va, char* ) ); + continue; + case 'd': + ch = va_arg( va, int ); + if( ch >= 0 ) + fmt_num( minor, ch, 10 ); + else + { + dbug_out_char( minor, '-' ); + fmt_num( minor, -ch, 10 ); + } + continue; + case 'u': + fmt_num( minor, va_arg( va, unsigned ), 10 ); + continue; + case 'o': + fmt_num( minor, va_arg( va, unsigned ), 8 ); + continue; + case 'x': + case 'p': + fmt_num( minor, va_arg( va, unsigned ), 16 ); + continue; + default: continue; + return; + } + va_end( va ); +} + +static void fmt_num( int minor, unsigned long num, unsigned base ) +{ + char buf[33]; + int ib = sizeof(buf); + + buf[--ib] = 0; + do + { + buf[--ib] = "0123456789ABCDEF"[num%base]; + num /= base; + } + while( num != 0 ); + + fmt_str( minor, buf+ib ); +} + +static void fmt_str( int minor, const char* str ) +{ + if( str ) + while( *str ) + dbug_out_char( minor, *str++ ); +} + + |