summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/m68k/gen68340/console
diff options
context:
space:
mode:
Diffstat (limited to 'c/src/lib/libbsp/m68k/gen68340/console')
-rw-r--r--c/src/lib/libbsp/m68k/gen68340/console/Makefile.in59
-rw-r--r--c/src/lib/libbsp/m68k/gen68340/console/Modif_cpu_asm.s184
-rw-r--r--c/src/lib/libbsp/m68k/gen68340/console/console.c740
-rw-r--r--c/src/lib/libbsp/m68k/gen68340/console/m340uart.c409
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++ );
+}
+
+