2008-02-08 15:19:31 +03:00
/* MN10300 On-chip serial port UART driver
*
* Copyright ( C ) 2007 Red Hat , Inc . All Rights Reserved .
* Written by David Howells ( dhowells @ redhat . com )
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation ; either version
* 2 of the Licence , or ( at your option ) any later version .
*/
static const char serial_name [ ] = " MN10300 Serial driver " ;
static const char serial_version [ ] = " mn10300_serial-1.0 " ;
static const char serial_revdate [ ] = " 2007-11-06 " ;
# if defined(CONFIG_MN10300_TTYSM_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
# define SUPPORT_SYSRQ
# endif
# include <linux/module.h>
# include <linux/serial.h>
# include <linux/circ_buf.h>
# include <linux/errno.h>
# include <linux/signal.h>
# include <linux/sched.h>
# include <linux/timer.h>
# include <linux/interrupt.h>
# include <linux/tty.h>
# include <linux/tty_flip.h>
# include <linux/major.h>
# include <linux/string.h>
# include <linux/ioport.h>
# include <linux/mm.h>
# include <linux/slab.h>
# include <linux/init.h>
# include <linux/console.h>
# include <linux/sysrq.h>
# include <asm/system.h>
# include <asm/io.h>
# include <asm/irq.h>
# include <asm/bitops.h>
# include <asm/serial-regs.h>
2009-04-10 17:33:48 +04:00
# include <unit/timex.h>
2008-02-08 15:19:31 +03:00
# include "mn10300-serial.h"
static inline __attribute__ ( ( format ( printf , 1 , 2 ) ) )
void no_printk ( const char * fmt , . . . )
{
}
# define kenter(FMT, ...) \
printk ( KERN_DEBUG " -->%s( " FMT " ) \n " , __func__ , # # __VA_ARGS__ )
# define _enter(FMT, ...) \
no_printk ( KERN_DEBUG " -->%s( " FMT " ) \n " , __func__ , # # __VA_ARGS__ )
# define kdebug(FMT, ...) \
printk ( KERN_DEBUG " --- " FMT " \n " , # # __VA_ARGS__ )
# define _debug(FMT, ...) \
no_printk ( KERN_DEBUG " --- " FMT " \n " , # # __VA_ARGS__ )
# define kproto(FMT, ...) \
printk ( KERN_DEBUG " ### MNSERIAL " FMT " ### \n " , # # __VA_ARGS__ )
# define _proto(FMT, ...) \
no_printk ( KERN_DEBUG " ### MNSERIAL " FMT " ### \n " , # # __VA_ARGS__ )
# define NR_UARTS 3
# ifdef CONFIG_MN10300_TTYSM_CONSOLE
static void mn10300_serial_console_write ( struct console * co ,
const char * s , unsigned count ) ;
static int __init mn10300_serial_console_setup ( struct console * co ,
char * options ) ;
static struct uart_driver mn10300_serial_driver ;
static struct console mn10300_serial_console = {
. name = " ttySM " ,
. write = mn10300_serial_console_write ,
. device = uart_console_device ,
. setup = mn10300_serial_console_setup ,
. flags = CON_PRINTBUFFER ,
. index = - 1 ,
. data = & mn10300_serial_driver ,
} ;
# endif
static struct uart_driver mn10300_serial_driver = {
. owner = NULL ,
. driver_name = " mn10300-serial " ,
. dev_name = " ttySM " ,
. major = TTY_MAJOR ,
. minor = 128 ,
. nr = NR_UARTS ,
# ifdef CONFIG_MN10300_TTYSM_CONSOLE
. cons = & mn10300_serial_console ,
# endif
} ;
static unsigned int mn10300_serial_tx_empty ( struct uart_port * ) ;
static void mn10300_serial_set_mctrl ( struct uart_port * , unsigned int mctrl ) ;
static unsigned int mn10300_serial_get_mctrl ( struct uart_port * ) ;
static void mn10300_serial_stop_tx ( struct uart_port * ) ;
static void mn10300_serial_start_tx ( struct uart_port * ) ;
static void mn10300_serial_send_xchar ( struct uart_port * , char ch ) ;
static void mn10300_serial_stop_rx ( struct uart_port * ) ;
static void mn10300_serial_enable_ms ( struct uart_port * ) ;
static void mn10300_serial_break_ctl ( struct uart_port * , int ctl ) ;
static int mn10300_serial_startup ( struct uart_port * ) ;
static void mn10300_serial_shutdown ( struct uart_port * ) ;
static void mn10300_serial_set_termios ( struct uart_port * ,
struct ktermios * new ,
struct ktermios * old ) ;
static const char * mn10300_serial_type ( struct uart_port * ) ;
static void mn10300_serial_release_port ( struct uart_port * ) ;
static int mn10300_serial_request_port ( struct uart_port * ) ;
static void mn10300_serial_config_port ( struct uart_port * , int ) ;
static int mn10300_serial_verify_port ( struct uart_port * ,
struct serial_struct * ) ;
static const struct uart_ops mn10300_serial_ops = {
. tx_empty = mn10300_serial_tx_empty ,
. set_mctrl = mn10300_serial_set_mctrl ,
. get_mctrl = mn10300_serial_get_mctrl ,
. stop_tx = mn10300_serial_stop_tx ,
. start_tx = mn10300_serial_start_tx ,
. send_xchar = mn10300_serial_send_xchar ,
. stop_rx = mn10300_serial_stop_rx ,
. enable_ms = mn10300_serial_enable_ms ,
. break_ctl = mn10300_serial_break_ctl ,
. startup = mn10300_serial_startup ,
. shutdown = mn10300_serial_shutdown ,
. set_termios = mn10300_serial_set_termios ,
. type = mn10300_serial_type ,
. release_port = mn10300_serial_release_port ,
. request_port = mn10300_serial_request_port ,
. config_port = mn10300_serial_config_port ,
. verify_port = mn10300_serial_verify_port ,
} ;
static irqreturn_t mn10300_serial_interrupt ( int irq , void * dev_id ) ;
/*
* the first on - chip serial port : ttySM0 ( aka SIF0 )
*/
# ifdef CONFIG_MN10300_TTYSM0
struct mn10300_serial_port mn10300_serial_port_sif0 = {
. uart . ops = & mn10300_serial_ops ,
. uart . membase = ( void __iomem * ) & SC0CTR ,
. uart . mapbase = ( unsigned long ) & SC0CTR ,
. uart . iotype = UPIO_MEM ,
. uart . irq = 0 ,
. uart . uartclk = 0 , /* MN10300_IOCLK, */
. uart . fifosize = 1 ,
. uart . flags = UPF_BOOT_AUTOCONF ,
. uart . line = 0 ,
. uart . type = PORT_MN10300 ,
. uart . lock =
__SPIN_LOCK_UNLOCKED ( mn10300_serial_port_sif0 . uart . lock ) ,
. name = " ttySM0 " ,
. _iobase = & SC0CTR ,
. _control = & SC0CTR ,
. _status = ( volatile u8 * ) & SC0STR ,
. _intr = & SC0ICR ,
. _rxb = & SC0RXB ,
. _txb = & SC0TXB ,
. rx_name = " ttySM0/Rx " ,
. tx_name = " ttySM0/Tx " ,
# ifdef CONFIG_MN10300_TTYSM0_TIMER8
. tm_name = " ttySM0/Timer8 " ,
. _tmxmd = & TM8MD ,
. _tmxbr = & TM8BR ,
. _tmicr = & TM8ICR ,
. tm_irq = TM8IRQ ,
. div_timer = MNSCx_DIV_TIMER_16BIT ,
# else /* CONFIG_MN10300_TTYSM0_TIMER2 */
. tm_name = " ttySM0/Timer2 " ,
. _tmxmd = & TM2MD ,
. _tmxbr = ( volatile u16 * ) & TM2BR ,
. _tmicr = & TM2ICR ,
. tm_irq = TM2IRQ ,
. div_timer = MNSCx_DIV_TIMER_8BIT ,
# endif
. rx_irq = SC0RXIRQ ,
. tx_irq = SC0TXIRQ ,
. rx_icr = & GxICR ( SC0RXIRQ ) ,
. tx_icr = & GxICR ( SC0TXIRQ ) ,
. clock_src = MNSCx_CLOCK_SRC_IOCLK ,
. options = 0 ,
# ifdef CONFIG_GDBSTUB_ON_TTYSM0
. gdbstub = 1 ,
# endif
} ;
# endif /* CONFIG_MN10300_TTYSM0 */
/*
* the second on - chip serial port : ttySM1 ( aka SIF1 )
*/
# ifdef CONFIG_MN10300_TTYSM1
struct mn10300_serial_port mn10300_serial_port_sif1 = {
. uart . ops = & mn10300_serial_ops ,
. uart . membase = ( void __iomem * ) & SC1CTR ,
. uart . mapbase = ( unsigned long ) & SC1CTR ,
. uart . iotype = UPIO_MEM ,
. uart . irq = 0 ,
. uart . uartclk = 0 , /* MN10300_IOCLK, */
. uart . fifosize = 1 ,
. uart . flags = UPF_BOOT_AUTOCONF ,
. uart . line = 1 ,
. uart . type = PORT_MN10300 ,
. uart . lock =
__SPIN_LOCK_UNLOCKED ( mn10300_serial_port_sif1 . uart . lock ) ,
. name = " ttySM1 " ,
. _iobase = & SC1CTR ,
. _control = & SC1CTR ,
. _status = ( volatile u8 * ) & SC1STR ,
. _intr = & SC1ICR ,
. _rxb = & SC1RXB ,
. _txb = & SC1TXB ,
. rx_name = " ttySM1/Rx " ,
. tx_name = " ttySM1/Tx " ,
# ifdef CONFIG_MN10300_TTYSM1_TIMER9
. tm_name = " ttySM1/Timer9 " ,
. _tmxmd = & TM9MD ,
. _tmxbr = & TM9BR ,
. _tmicr = & TM9ICR ,
. tm_irq = TM9IRQ ,
. div_timer = MNSCx_DIV_TIMER_16BIT ,
# else /* CONFIG_MN10300_TTYSM1_TIMER3 */
. tm_name = " ttySM1/Timer3 " ,
. _tmxmd = & TM3MD ,
. _tmxbr = ( volatile u16 * ) & TM3BR ,
. _tmicr = & TM3ICR ,
. tm_irq = TM3IRQ ,
. div_timer = MNSCx_DIV_TIMER_8BIT ,
# endif
. rx_irq = SC1RXIRQ ,
. tx_irq = SC1TXIRQ ,
. rx_icr = & GxICR ( SC1RXIRQ ) ,
. tx_icr = & GxICR ( SC1TXIRQ ) ,
. clock_src = MNSCx_CLOCK_SRC_IOCLK ,
. options = 0 ,
# ifdef CONFIG_GDBSTUB_ON_TTYSM1
. gdbstub = 1 ,
# endif
} ;
# endif /* CONFIG_MN10300_TTYSM1 */
/*
* the third on - chip serial port : ttySM2 ( aka SIF2 )
*/
# ifdef CONFIG_MN10300_TTYSM2
struct mn10300_serial_port mn10300_serial_port_sif2 = {
. uart . ops = & mn10300_serial_ops ,
. uart . membase = ( void __iomem * ) & SC2CTR ,
. uart . mapbase = ( unsigned long ) & SC2CTR ,
. uart . iotype = UPIO_MEM ,
. uart . irq = 0 ,
. uart . uartclk = 0 , /* MN10300_IOCLK, */
. uart . fifosize = 1 ,
. uart . flags = UPF_BOOT_AUTOCONF ,
. uart . line = 2 ,
# ifdef CONFIG_MN10300_TTYSM2_CTS
. uart . type = PORT_MN10300_CTS ,
# else
. uart . type = PORT_MN10300 ,
# endif
. uart . lock =
__SPIN_LOCK_UNLOCKED ( mn10300_serial_port_sif2 . uart . lock ) ,
. name = " ttySM2 " ,
. rx_name = " ttySM2/Rx " ,
. tx_name = " ttySM2/Tx " ,
. tm_name = " ttySM2/Timer10 " ,
. _iobase = & SC2CTR ,
. _control = & SC2CTR ,
. _status = & SC2STR ,
. _intr = & SC2ICR ,
. _rxb = & SC2RXB ,
. _txb = & SC2TXB ,
. _tmxmd = & TM10MD ,
. _tmxbr = & TM10BR ,
. _tmicr = & TM10ICR ,
. tm_irq = TM10IRQ ,
. div_timer = MNSCx_DIV_TIMER_16BIT ,
. rx_irq = SC2RXIRQ ,
. tx_irq = SC2TXIRQ ,
. rx_icr = & GxICR ( SC2RXIRQ ) ,
. tx_icr = & GxICR ( SC2TXIRQ ) ,
. clock_src = MNSCx_CLOCK_SRC_IOCLK ,
# ifdef CONFIG_MN10300_TTYSM2_CTS
. options = MNSCx_OPT_CTS ,
# else
. options = 0 ,
# endif
# ifdef CONFIG_GDBSTUB_ON_TTYSM2
. gdbstub = 1 ,
# endif
} ;
# endif /* CONFIG_MN10300_TTYSM2 */
/*
* list of available serial ports
*/
struct mn10300_serial_port * mn10300_serial_ports [ NR_UARTS + 1 ] = {
# ifdef CONFIG_MN10300_TTYSM0
[ 0 ] = & mn10300_serial_port_sif0 ,
# endif
# ifdef CONFIG_MN10300_TTYSM1
[ 1 ] = & mn10300_serial_port_sif1 ,
# endif
# ifdef CONFIG_MN10300_TTYSM2
[ 2 ] = & mn10300_serial_port_sif2 ,
# endif
[ NR_UARTS ] = NULL ,
} ;
/*
* we abuse the serial ports ' baud timers ' interrupt lines to get the ability
* to deliver interrupts to userspace as we use the ports ' interrupt lines to
* do virtual DMA on account of the ports having no hardware FIFOs
*
* we can generate an interrupt manually in the assembly stubs by writing to
* the enable and detect bits in the interrupt control register , so all we need
* to do here is disable the interrupt line
*
* note that we can ' t just leave the line enabled as the baud rate timer * also *
* generates interrupts
*/
static void mn10300_serial_mask_ack ( unsigned int irq )
{
u16 tmp ;
GxICR ( irq ) = GxICR_LEVEL_6 ;
tmp = GxICR ( irq ) ; /* flush write buffer */
}
static void mn10300_serial_nop ( unsigned int irq )
{
}
static struct irq_chip mn10300_serial_pic = {
. name = " mnserial " ,
. ack = mn10300_serial_mask_ack ,
. mask = mn10300_serial_mask_ack ,
. mask_ack = mn10300_serial_mask_ack ,
. unmask = mn10300_serial_nop ,
. end = mn10300_serial_nop ,
} ;
/*
* serial virtual DMA interrupt jump table
*/
struct mn10300_serial_int mn10300_serial_int_tbl [ NR_IRQS ] ;
static void mn10300_serial_dis_tx_intr ( struct mn10300_serial_port * port )
{
u16 x ;
* port - > tx_icr = GxICR_LEVEL_1 | GxICR_DETECT ;
x = * port - > tx_icr ;
}
static void mn10300_serial_en_tx_intr ( struct mn10300_serial_port * port )
{
u16 x ;
* port - > tx_icr = GxICR_LEVEL_1 | GxICR_ENABLE ;
x = * port - > tx_icr ;
}
static void mn10300_serial_dis_rx_intr ( struct mn10300_serial_port * port )
{
u16 x ;
* port - > rx_icr = GxICR_LEVEL_1 | GxICR_DETECT ;
x = * port - > rx_icr ;
}
/*
* multi - bit equivalent of test_and_clear_bit ( )
*/
static int mask_test_and_clear ( volatile u8 * ptr , u8 mask )
{
u32 epsw ;
asm volatile ( " bclr %1,(%2) \n "
" mov epsw,%0 \n "
: " =d " ( epsw ) : " d " ( mask ) , " a " ( ptr ) ) ;
return ! ( epsw & EPSW_FLAG_Z ) ;
}
/*
* receive chars from the ring buffer for this serial port
* - must do break detection here ( not done in the UART )
*/
static void mn10300_serial_receive_interrupt ( struct mn10300_serial_port * port )
{
struct uart_icount * icount = & port - > uart . icount ;
2008-07-17 00:54:01 +04:00
struct tty_struct * tty = port - > uart . info - > port . tty ;
2008-02-08 15:19:31 +03:00
unsigned ix ;
int count ;
u8 st , ch , push , status , overrun ;
_enter ( " %s " , port - > name ) ;
push = 0 ;
count = CIRC_CNT ( port - > rx_inp , port - > rx_outp , MNSC_BUFFER_SIZE ) ;
count = tty_buffer_request_room ( tty , count ) ;
if ( count = = 0 ) {
if ( ! tty - > low_latency )
tty_flip_buffer_push ( tty ) ;
return ;
}
try_again :
/* pull chars out of the hat */
ix = port - > rx_outp ;
if ( ix = = port - > rx_inp ) {
if ( push & & ! tty - > low_latency )
tty_flip_buffer_push ( tty ) ;
return ;
}
ch = port - > rx_buffer [ ix + + ] ;
st = port - > rx_buffer [ ix + + ] ;
smp_rmb ( ) ;
port - > rx_outp = ix & ( MNSC_BUFFER_SIZE - 1 ) ;
port - > uart . icount . rx + + ;
st & = SC01STR_FEF | SC01STR_PEF | SC01STR_OEF ;
status = 0 ;
overrun = 0 ;
/* the UART doesn't detect BREAK, so we have to do that ourselves
* - it starts as a framing error on a NUL character
* - then we count another two NUL characters before issuing TTY_BREAK
* - then we end on a normal char or one that has all the bottom bits
* zero and the top bits set
*/
switch ( port - > rx_brk ) {
case 0 :
/* not breaking at the moment */
break ;
case 1 :
if ( st & SC01STR_FEF & & ch = = 0 ) {
port - > rx_brk = 2 ;
goto try_again ;
}
goto not_break ;
case 2 :
if ( st & SC01STR_FEF & & ch = = 0 ) {
port - > rx_brk = 3 ;
_proto ( " Rx Break Detected " ) ;
icount - > brk + + ;
if ( uart_handle_break ( & port - > uart ) )
goto ignore_char ;
status | = 1 < < TTY_BREAK ;
goto insert ;
}
goto not_break ;
default :
if ( st & ( SC01STR_FEF | SC01STR_PEF | SC01STR_OEF ) )
goto try_again ; /* still breaking */
port - > rx_brk = 0 ; /* end of the break */
switch ( ch ) {
case 0xFF :
case 0xFE :
case 0xFC :
case 0xF8 :
case 0xF0 :
case 0xE0 :
case 0xC0 :
case 0x80 :
case 0x00 :
/* discard char at probable break end */
goto try_again ;
}
break ;
}
process_errors :
/* handle framing error */
if ( st & SC01STR_FEF ) {
if ( ch = = 0 ) {
/* framing error with NUL char is probably a BREAK */
port - > rx_brk = 1 ;
goto try_again ;
}
_proto ( " Rx Framing Error " ) ;
icount - > frame + + ;
status | = 1 < < TTY_FRAME ;
}
/* handle parity error */
if ( st & SC01STR_PEF ) {
_proto ( " Rx Parity Error " ) ;
icount - > parity + + ;
status = TTY_PARITY ;
}
/* handle normal char */
if ( status = = 0 ) {
if ( uart_handle_sysrq_char ( & port - > uart , ch ) )
goto ignore_char ;
status = ( 1 < < TTY_NORMAL ) ;
}
/* handle overrun error */
if ( st & SC01STR_OEF ) {
if ( port - > rx_brk )
goto try_again ;
_proto ( " Rx Overrun Error " ) ;
icount - > overrun + + ;
overrun = 1 ;
}
insert :
status & = port - > uart . read_status_mask ;
if ( ! overrun & & ! ( status & port - > uart . ignore_status_mask ) ) {
int flag ;
if ( status & ( 1 < < TTY_BREAK ) )
flag = TTY_BREAK ;
else if ( status & ( 1 < < TTY_PARITY ) )
flag = TTY_PARITY ;
else if ( status & ( 1 < < TTY_FRAME ) )
flag = TTY_FRAME ;
else
flag = TTY_NORMAL ;
tty_insert_flip_char ( tty , ch , flag ) ;
}
/* overrun is special, since it's reported immediately, and doesn't
* affect the current character
*/
if ( overrun )
tty_insert_flip_char ( tty , 0 , TTY_OVERRUN ) ;
count - - ;
if ( count < = 0 ) {
if ( ! tty - > low_latency )
tty_flip_buffer_push ( tty ) ;
return ;
}
ignore_char :
push = 1 ;
goto try_again ;
not_break :
port - > rx_brk = 0 ;
goto process_errors ;
}
/*
* handle an interrupt from the serial transmission " virtual DMA " driver
* - note : the interrupt routine will disable its own interrupts when the Tx
* buffer is empty
*/
static void mn10300_serial_transmit_interrupt ( struct mn10300_serial_port * port )
{
_enter ( " %s " , port - > name ) ;
2008-12-10 15:43:24 +03:00
if ( ! port - > uart . info | | ! port - > uart . info - > port . tty ) {
mn10300_serial_dis_tx_intr ( port ) ;
return ;
}
2008-02-08 15:19:31 +03:00
if ( uart_tx_stopped ( & port - > uart ) | |
uart_circ_empty ( & port - > uart . info - > xmit ) )
mn10300_serial_dis_tx_intr ( port ) ;
if ( uart_circ_chars_pending ( & port - > uart . info - > xmit ) < WAKEUP_CHARS )
uart_write_wakeup ( & port - > uart ) ;
}
/*
* deal with a change in the status of the CTS line
*/
static void mn10300_serial_cts_changed ( struct mn10300_serial_port * port , u8 st )
{
u16 ctr ;
port - > tx_cts = st ;
port - > uart . icount . cts + + ;
/* flip the CTS state selector flag to interrupt when it changes
* back */
ctr = * port - > _control ;
ctr ^ = SC2CTR_TWS ;
* port - > _control = ctr ;
uart_handle_cts_change ( & port - > uart , st & SC2STR_CTS ) ;
wake_up_interruptible ( & port - > uart . info - > delta_msr_wait ) ;
}
/*
* handle a virtual interrupt generated by the lower level " virtual DMA "
* routines ( irq is the baud timer interrupt )
*/
static irqreturn_t mn10300_serial_interrupt ( int irq , void * dev_id )
{
struct mn10300_serial_port * port = dev_id ;
u8 st ;
spin_lock ( & port - > uart . lock ) ;
if ( port - > intr_flags ) {
_debug ( " INT %s: %x " , port - > name , port - > intr_flags ) ;
if ( mask_test_and_clear ( & port - > intr_flags , MNSCx_RX_AVAIL ) )
mn10300_serial_receive_interrupt ( port ) ;
if ( mask_test_and_clear ( & port - > intr_flags ,
MNSCx_TX_SPACE | MNSCx_TX_EMPTY ) )
mn10300_serial_transmit_interrupt ( port ) ;
}
/* the only modem control line amongst the whole lot is CTS on
* serial port 2 */
if ( port - > type = = PORT_MN10300_CTS ) {
st = * port - > _status ;
if ( ( port - > tx_cts ^ st ) & SC2STR_CTS )
mn10300_serial_cts_changed ( port , st ) ;
}
spin_unlock ( & port - > uart . lock ) ;
return IRQ_HANDLED ;
}
/*
* return indication of whether the hardware transmit buffer is empty
*/
static unsigned int mn10300_serial_tx_empty ( struct uart_port * _port )
{
struct mn10300_serial_port * port =
container_of ( _port , struct mn10300_serial_port , uart ) ;
_enter ( " %s " , port - > name ) ;
return ( * port - > _status & ( SC01STR_TXF | SC01STR_TBF ) ) ?
0 : TIOCSER_TEMT ;
}
/*
* set the modem control lines ( we don ' t have any )
*/
static void mn10300_serial_set_mctrl ( struct uart_port * _port ,
unsigned int mctrl )
{
struct mn10300_serial_port * port =
container_of ( _port , struct mn10300_serial_port , uart ) ;
_enter ( " %s,%x " , port - > name , mctrl ) ;
}
/*
* get the modem control line statuses
*/
static unsigned int mn10300_serial_get_mctrl ( struct uart_port * _port )
{
struct mn10300_serial_port * port =
container_of ( _port , struct mn10300_serial_port , uart ) ;
_enter ( " %s " , port - > name ) ;
if ( port - > type = = PORT_MN10300_CTS & & ! ( * port - > _status & SC2STR_CTS ) )
return TIOCM_CAR | TIOCM_DSR ;
return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR ;
}
/*
* stop transmitting characters
*/
static void mn10300_serial_stop_tx ( struct uart_port * _port )
{
struct mn10300_serial_port * port =
container_of ( _port , struct mn10300_serial_port , uart ) ;
_enter ( " %s " , port - > name ) ;
/* disable the virtual DMA */
mn10300_serial_dis_tx_intr ( port ) ;
}
/*
* start transmitting characters
* - jump - start transmission if it has stalled
* - enable the serial Tx interrupt ( used by the virtual DMA controller )
* - force an interrupt to happen if necessary
*/
static void mn10300_serial_start_tx ( struct uart_port * _port )
{
struct mn10300_serial_port * port =
container_of ( _port , struct mn10300_serial_port , uart ) ;
u16 x ;
_enter ( " %s{%lu} " ,
port - > name ,
CIRC_CNT ( & port - > uart . info - > xmit . head ,
& port - > uart . info - > xmit . tail ,
UART_XMIT_SIZE ) ) ;
/* kick the virtual DMA controller */
x = * port - > tx_icr ;
x | = GxICR_ENABLE ;
if ( * port - > _status & SC01STR_TBF )
x & = ~ ( GxICR_REQUEST | GxICR_DETECT ) ;
else
x | = GxICR_REQUEST | GxICR_DETECT ;
_debug ( " CTR=%04hx ICR=%02hx STR=%04x TMD=%02hx TBR=%04hx ICR=%04hx " ,
* port - > _control , * port - > _intr , * port - > _status ,
* port - > _tmxmd , * port - > _tmxbr , * port - > tx_icr ) ;
* port - > tx_icr = x ;
x = * port - > tx_icr ;
}
/*
* transmit a high - priority XON / XOFF character
*/
static void mn10300_serial_send_xchar ( struct uart_port * _port , char ch )
{
struct mn10300_serial_port * port =
container_of ( _port , struct mn10300_serial_port , uart ) ;
_enter ( " %s,%02x " , port - > name , ch ) ;
if ( likely ( port - > gdbstub ) ) {
port - > tx_xchar = ch ;
if ( ch )
mn10300_serial_en_tx_intr ( port ) ;
}
}
/*
* stop receiving characters
* - called whilst the port is being closed
*/
static void mn10300_serial_stop_rx ( struct uart_port * _port )
{
struct mn10300_serial_port * port =
container_of ( _port , struct mn10300_serial_port , uart ) ;
u16 ctr ;
_enter ( " %s " , port - > name ) ;
ctr = * port - > _control ;
ctr & = ~ SC01CTR_RXE ;
* port - > _control = ctr ;
mn10300_serial_dis_rx_intr ( port ) ;
}
/*
* enable modem status interrupts
*/
static void mn10300_serial_enable_ms ( struct uart_port * _port )
{
struct mn10300_serial_port * port =
container_of ( _port , struct mn10300_serial_port , uart ) ;
u16 ctr , cts ;
_enter ( " %s " , port - > name ) ;
if ( port - > type = = PORT_MN10300_CTS ) {
/* want to interrupt when CTS goes low if CTS is now high and
* vice versa
*/
port - > tx_cts = * port - > _status ;
cts = ( port - > tx_cts & SC2STR_CTS ) ?
SC2CTR_TWE : SC2CTR_TWE | SC2CTR_TWS ;
ctr = * port - > _control ;
ctr & = ~ SC2CTR_TWS ;
ctr | = cts ;
* port - > _control = ctr ;
mn10300_serial_en_tx_intr ( port ) ;
}
}
/*
* transmit or cease transmitting a break signal
*/
static void mn10300_serial_break_ctl ( struct uart_port * _port , int ctl )
{
struct mn10300_serial_port * port =
container_of ( _port , struct mn10300_serial_port , uart ) ;
_enter ( " %s,%d " , port - > name , ctl ) ;
if ( ctl ) {
/* tell the virtual DMA handler to assert BREAK */
port - > tx_break = 1 ;
mn10300_serial_en_tx_intr ( port ) ;
} else {
port - > tx_break = 0 ;
* port - > _control & = ~ SC01CTR_BKE ;
mn10300_serial_en_tx_intr ( port ) ;
}
}
/*
* grab the interrupts and enable the port for reception
*/
static int mn10300_serial_startup ( struct uart_port * _port )
{
struct mn10300_serial_port * port =
container_of ( _port , struct mn10300_serial_port , uart ) ;
struct mn10300_serial_int * pint ;
_enter ( " %s{%d} " , port - > name , port - > gdbstub ) ;
if ( unlikely ( port - > gdbstub ) )
return - EBUSY ;
/* allocate an Rx buffer for the virtual DMA handler */
port - > rx_buffer = kmalloc ( MNSC_BUFFER_SIZE , GFP_KERNEL ) ;
if ( ! port - > rx_buffer )
return - ENOMEM ;
port - > rx_inp = port - > rx_outp = 0 ;
/* finally, enable the device */
* port - > _intr = SC01ICR_TI ;
* port - > _control | = SC01CTR_TXE | SC01CTR_RXE ;
pint = & mn10300_serial_int_tbl [ port - > rx_irq ] ;
pint - > port = port ;
pint - > vdma = mn10300_serial_vdma_rx_handler ;
pint = & mn10300_serial_int_tbl [ port - > tx_irq ] ;
pint - > port = port ;
pint - > vdma = mn10300_serial_vdma_tx_handler ;
set_intr_level ( port - > rx_irq , GxICR_LEVEL_1 ) ;
set_intr_level ( port - > tx_irq , GxICR_LEVEL_1 ) ;
set_irq_chip ( port - > tm_irq , & mn10300_serial_pic ) ;
if ( request_irq ( port - > rx_irq , mn10300_serial_interrupt ,
IRQF_DISABLED , port - > rx_name , port ) < 0 )
goto error ;
if ( request_irq ( port - > tx_irq , mn10300_serial_interrupt ,
IRQF_DISABLED , port - > tx_name , port ) < 0 )
goto error2 ;
if ( request_irq ( port - > tm_irq , mn10300_serial_interrupt ,
IRQF_DISABLED , port - > tm_name , port ) < 0 )
goto error3 ;
mn10300_serial_mask_ack ( port - > tm_irq ) ;
return 0 ;
error3 :
free_irq ( port - > tx_irq , port ) ;
error2 :
free_irq ( port - > rx_irq , port ) ;
error :
kfree ( port - > rx_buffer ) ;
port - > rx_buffer = NULL ;
return - EBUSY ;
}
/*
* shutdown the port and release interrupts
*/
static void mn10300_serial_shutdown ( struct uart_port * _port )
{
struct mn10300_serial_port * port =
container_of ( _port , struct mn10300_serial_port , uart ) ;
_enter ( " %s " , port - > name ) ;
/* disable the serial port and its baud rate timer */
port - > tx_break = 0 ;
* port - > _control & = ~ ( SC01CTR_TXE | SC01CTR_RXE | SC01CTR_BKE ) ;
* port - > _tmxmd = 0 ;
if ( port - > rx_buffer ) {
void * buf = port - > rx_buffer ;
port - > rx_buffer = NULL ;
kfree ( buf ) ;
}
/* disable all intrs */
free_irq ( port - > tm_irq , port ) ;
free_irq ( port - > rx_irq , port ) ;
free_irq ( port - > tx_irq , port ) ;
* port - > rx_icr = GxICR_LEVEL_1 ;
* port - > tx_icr = GxICR_LEVEL_1 ;
}
/*
* this routine is called to set the UART divisor registers to match the
* specified baud rate for a serial port .
*/
static void mn10300_serial_change_speed ( struct mn10300_serial_port * port ,
struct ktermios * new ,
struct ktermios * old )
{
unsigned long flags ;
unsigned long ioclk = port - > ioclk ;
unsigned cflag ;
int baud , bits , xdiv , tmp ;
u16 tmxbr , scxctr ;
u8 tmxmd , battempt ;
u8 div_timer = port - > div_timer ;
_enter ( " %s{%lu} " , port - > name , ioclk ) ;
/* byte size and parity */
cflag = new - > c_cflag ;
switch ( cflag & CSIZE ) {
case CS7 : scxctr = SC01CTR_CLN_7BIT ; bits = 9 ; break ;
case CS8 : scxctr = SC01CTR_CLN_8BIT ; bits = 10 ; break ;
default : scxctr = SC01CTR_CLN_8BIT ; bits = 10 ; break ;
}
if ( cflag & CSTOPB ) {
scxctr | = SC01CTR_STB_2BIT ;
bits + + ;
}
if ( cflag & PARENB ) {
bits + + ;
if ( cflag & PARODD )
scxctr | = SC01CTR_PB_ODD ;
# ifdef CMSPAR
else if ( cflag & CMSPAR )
scxctr | = SC01CTR_PB_FIXED0 ;
# endif
else
scxctr | = SC01CTR_PB_EVEN ;
}
/* Determine divisor based on baud rate */
battempt = 0 ;
if ( div_timer = = MNSCx_DIV_TIMER_16BIT )
scxctr | = SC0CTR_CK_TM8UFLOW_8 ; /* ( == SC1CTR_CK_TM9UFLOW_8
* = = SC2CTR_CK_TM10UFLOW ) */
else if ( div_timer = = MNSCx_DIV_TIMER_8BIT )
scxctr | = SC0CTR_CK_TM2UFLOW_8 ;
try_alternative :
baud = uart_get_baud_rate ( & port - > uart , new , old , 0 ,
port - > ioclk / 8 ) ;
_debug ( " ALT %d [baud %d] " , battempt , baud ) ;
if ( ! baud )
baud = 9600 ; /* B0 transition handled in rs_set_termios */
xdiv = 1 ;
if ( baud = = 134 ) {
baud = 269 ; /* 134 is really 134.5 */
xdiv = 2 ;
}
if ( baud = = 38400 & &
( port - > uart . flags & UPF_SPD_MASK ) = = UPF_SPD_CUST
) {
_debug ( " CUSTOM %u " , port - > uart . custom_divisor ) ;
if ( div_timer = = MNSCx_DIV_TIMER_16BIT ) {
if ( port - > uart . custom_divisor < = 65535 ) {
tmxmd = TM8MD_SRC_IOCLK ;
tmxbr = port - > uart . custom_divisor ;
port - > uart . uartclk = ioclk ;
goto timer_okay ;
}
if ( port - > uart . custom_divisor / 8 < = 65535 ) {
tmxmd = TM8MD_SRC_IOCLK_8 ;
tmxbr = port - > uart . custom_divisor / 8 ;
port - > uart . custom_divisor = tmxbr * 8 ;
port - > uart . uartclk = ioclk / 8 ;
goto timer_okay ;
}
if ( port - > uart . custom_divisor / 32 < = 65535 ) {
tmxmd = TM8MD_SRC_IOCLK_32 ;
tmxbr = port - > uart . custom_divisor / 32 ;
port - > uart . custom_divisor = tmxbr * 32 ;
port - > uart . uartclk = ioclk / 32 ;
goto timer_okay ;
}
} else if ( div_timer = = MNSCx_DIV_TIMER_8BIT ) {
if ( port - > uart . custom_divisor < = 255 ) {
tmxmd = TM2MD_SRC_IOCLK ;
tmxbr = port - > uart . custom_divisor ;
port - > uart . uartclk = ioclk ;
goto timer_okay ;
}
if ( port - > uart . custom_divisor / 8 < = 255 ) {
tmxmd = TM2MD_SRC_IOCLK_8 ;
tmxbr = port - > uart . custom_divisor / 8 ;
port - > uart . custom_divisor = tmxbr * 8 ;
port - > uart . uartclk = ioclk / 8 ;
goto timer_okay ;
}
if ( port - > uart . custom_divisor / 32 < = 255 ) {
tmxmd = TM2MD_SRC_IOCLK_32 ;
tmxbr = port - > uart . custom_divisor / 32 ;
port - > uart . custom_divisor = tmxbr * 32 ;
port - > uart . uartclk = ioclk / 32 ;
goto timer_okay ;
}
}
}
switch ( div_timer ) {
case MNSCx_DIV_TIMER_16BIT :
port - > uart . uartclk = ioclk ;
tmxmd = TM8MD_SRC_IOCLK ;
tmxbr = tmp = ( ioclk / ( baud * xdiv ) + 4 ) / 8 - 1 ;
if ( tmp > 0 & & tmp < = 65535 )
goto timer_okay ;
port - > uart . uartclk = ioclk / 8 ;
tmxmd = TM8MD_SRC_IOCLK_8 ;
tmxbr = tmp = ( ioclk / ( baud * 8 * xdiv ) + 4 ) / 8 - 1 ;
if ( tmp > 0 & & tmp < = 65535 )
goto timer_okay ;
port - > uart . uartclk = ioclk / 32 ;
tmxmd = TM8MD_SRC_IOCLK_32 ;
tmxbr = tmp = ( ioclk / ( baud * 32 * xdiv ) + 4 ) / 8 - 1 ;
if ( tmp > 0 & & tmp < = 65535 )
goto timer_okay ;
break ;
case MNSCx_DIV_TIMER_8BIT :
port - > uart . uartclk = ioclk ;
tmxmd = TM2MD_SRC_IOCLK ;
tmxbr = tmp = ( ioclk / ( baud * xdiv ) + 4 ) / 8 - 1 ;
if ( tmp > 0 & & tmp < = 255 )
goto timer_okay ;
port - > uart . uartclk = ioclk / 8 ;
tmxmd = TM2MD_SRC_IOCLK_8 ;
tmxbr = tmp = ( ioclk / ( baud * 8 * xdiv ) + 4 ) / 8 - 1 ;
if ( tmp > 0 & & tmp < = 255 )
goto timer_okay ;
port - > uart . uartclk = ioclk / 32 ;
tmxmd = TM2MD_SRC_IOCLK_32 ;
tmxbr = tmp = ( ioclk / ( baud * 32 * xdiv ) + 4 ) / 8 - 1 ;
if ( tmp > 0 & & tmp < = 255 )
goto timer_okay ;
break ;
default :
BUG ( ) ;
return ;
}
/* refuse to change to a baud rate we can't support */
_debug ( " CAN'T SUPPORT " ) ;
switch ( battempt ) {
case 0 :
if ( old ) {
new - > c_cflag & = ~ CBAUD ;
new - > c_cflag | = ( old - > c_cflag & CBAUD ) ;
battempt = 1 ;
goto try_alternative ;
}
case 1 :
/* as a last resort, if the quotient is zero, default to 9600
* bps */
new - > c_cflag & = ~ CBAUD ;
new - > c_cflag | = B9600 ;
battempt = 2 ;
goto try_alternative ;
default :
/* hmmm... can't seem to support 9600 either
* - we could try iterating through the speeds we know about to
* find the lowest
*/
new - > c_cflag & = ~ CBAUD ;
new - > c_cflag | = B0 ;
if ( div_timer = = MNSCx_DIV_TIMER_16BIT )
tmxmd = TM8MD_SRC_IOCLK_32 ;
else if ( div_timer = = MNSCx_DIV_TIMER_8BIT )
tmxmd = TM2MD_SRC_IOCLK_32 ;
tmxbr = 1 ;
port - > uart . uartclk = ioclk / 32 ;
break ;
}
timer_okay :
_debug ( " UARTCLK: %u / %hu " , port - > uart . uartclk , tmxbr ) ;
/* make the changes */
spin_lock_irqsave ( & port - > uart . lock , flags ) ;
uart_update_timeout ( & port - > uart , new - > c_cflag , baud ) ;
/* set the timer to produce the required baud rate */
switch ( div_timer ) {
case MNSCx_DIV_TIMER_16BIT :
* port - > _tmxmd = 0 ;
* port - > _tmxbr = tmxbr ;
* port - > _tmxmd = TM8MD_INIT_COUNTER ;
* port - > _tmxmd = tmxmd | TM8MD_COUNT_ENABLE ;
break ;
case MNSCx_DIV_TIMER_8BIT :
* port - > _tmxmd = 0 ;
* ( volatile u8 * ) port - > _tmxbr = ( u8 ) tmxbr ;
* port - > _tmxmd = TM2MD_INIT_COUNTER ;
* port - > _tmxmd = tmxmd | TM2MD_COUNT_ENABLE ;
break ;
}
/* CTS flow control flag and modem status interrupts */
scxctr & = ~ ( SC2CTR_TWE | SC2CTR_TWS ) ;
if ( port - > type = = PORT_MN10300_CTS & & cflag & CRTSCTS ) {
/* want to interrupt when CTS goes low if CTS is now
* high and vice versa
*/
port - > tx_cts = * port - > _status ;
if ( port - > tx_cts & SC2STR_CTS )
scxctr | = SC2CTR_TWE ;
else
scxctr | = SC2CTR_TWE | SC2CTR_TWS ;
}
/* set up parity check flag */
port - > uart . read_status_mask = ( 1 < < TTY_NORMAL ) | ( 1 < < TTY_OVERRUN ) ;
if ( new - > c_iflag & INPCK )
port - > uart . read_status_mask | =
( 1 < < TTY_PARITY ) | ( 1 < < TTY_FRAME ) ;
if ( new - > c_iflag & ( BRKINT | PARMRK ) )
port - > uart . read_status_mask | = ( 1 < < TTY_BREAK ) ;
/* characters to ignore */
port - > uart . ignore_status_mask = 0 ;
if ( new - > c_iflag & IGNPAR )
port - > uart . ignore_status_mask | =
( 1 < < TTY_PARITY ) | ( 1 < < TTY_FRAME ) ;
if ( new - > c_iflag & IGNBRK ) {
port - > uart . ignore_status_mask | = ( 1 < < TTY_BREAK ) ;
/*
* If we ' re ignoring parity and break indicators ,
* ignore overruns to ( for real raw support ) .
*/
if ( new - > c_iflag & IGNPAR )
port - > uart . ignore_status_mask | = ( 1 < < TTY_OVERRUN ) ;
}
/* Ignore all characters if CREAD is not set */
if ( ( new - > c_cflag & CREAD ) = = 0 )
port - > uart . ignore_status_mask | = ( 1 < < TTY_NORMAL ) ;
scxctr | = * port - > _control & ( SC01CTR_TXE | SC01CTR_RXE | SC01CTR_BKE ) ;
* port - > _control = scxctr ;
spin_unlock_irqrestore ( & port - > uart . lock , flags ) ;
}
/*
* set the terminal I / O parameters
*/
static void mn10300_serial_set_termios ( struct uart_port * _port ,
struct ktermios * new ,
struct ktermios * old )
{
struct mn10300_serial_port * port =
container_of ( _port , struct mn10300_serial_port , uart ) ;
_enter ( " %s,%p,%p " , port - > name , new , old ) ;
mn10300_serial_change_speed ( port , new , old ) ;
/* handle turning off CRTSCTS */
if ( ! ( new - > c_cflag & CRTSCTS ) ) {
u16 ctr = * port - > _control ;
ctr & = ~ SC2CTR_TWE ;
* port - > _control = ctr ;
}
}
/*
* return description of port type
*/
static const char * mn10300_serial_type ( struct uart_port * _port )
{
struct mn10300_serial_port * port =
container_of ( _port , struct mn10300_serial_port , uart ) ;
if ( port - > uart . type = = PORT_MN10300_CTS )
return " MN10300 SIF_CTS " ;
return " MN10300 SIF " ;
}
/*
* release I / O and memory regions in use by port
*/
static void mn10300_serial_release_port ( struct uart_port * _port )
{
struct mn10300_serial_port * port =
container_of ( _port , struct mn10300_serial_port , uart ) ;
_enter ( " %s " , port - > name ) ;
release_mem_region ( ( unsigned long ) port - > _iobase , 16 ) ;
}
/*
* request I / O and memory regions for port
*/
static int mn10300_serial_request_port ( struct uart_port * _port )
{
struct mn10300_serial_port * port =
container_of ( _port , struct mn10300_serial_port , uart ) ;
_enter ( " %s " , port - > name ) ;
request_mem_region ( ( unsigned long ) port - > _iobase , 16 , port - > name ) ;
return 0 ;
}
/*
* configure the type and reserve the ports
*/
static void mn10300_serial_config_port ( struct uart_port * _port , int type )
{
struct mn10300_serial_port * port =
container_of ( _port , struct mn10300_serial_port , uart ) ;
_enter ( " %s " , port - > name ) ;
port - > uart . type = PORT_MN10300 ;
if ( port - > options & MNSCx_OPT_CTS )
port - > uart . type = PORT_MN10300_CTS ;
mn10300_serial_request_port ( _port ) ;
}
/*
* verify serial parameters are suitable for this port type
*/
static int mn10300_serial_verify_port ( struct uart_port * _port ,
struct serial_struct * ss )
{
struct mn10300_serial_port * port =
container_of ( _port , struct mn10300_serial_port , uart ) ;
void * mapbase = ( void * ) ( unsigned long ) port - > uart . mapbase ;
_enter ( " %s " , port - > name ) ;
/* these things may not be changed */
if ( ss - > irq ! = port - > uart . irq | |
ss - > port ! = port - > uart . iobase | |
ss - > io_type ! = port - > uart . iotype | |
ss - > iomem_base ! = mapbase | |
ss - > iomem_reg_shift ! = port - > uart . regshift | |
ss - > hub6 ! = port - > uart . hub6 | |
ss - > xmit_fifo_size ! = port - > uart . fifosize )
return - EINVAL ;
/* type may be changed on a port that supports CTS */
if ( ss - > type ! = port - > uart . type ) {
if ( ! ( port - > options & MNSCx_OPT_CTS ) )
return - EINVAL ;
if ( ss - > type ! = PORT_MN10300 & &
ss - > type ! = PORT_MN10300_CTS )
return - EINVAL ;
}
return 0 ;
}
/*
* initialise the MN10300 on - chip UARTs
*/
static int __init mn10300_serial_init ( void )
{
struct mn10300_serial_port * port ;
int ret , i ;
printk ( KERN_INFO " %s version %s (%s) \n " ,
serial_name , serial_version , serial_revdate ) ;
# ifdef CONFIG_MN10300_TTYSM2
SC2TIM = 8 ; /* make the baud base of timer 2 IOCLK/8 */
# endif
set_intr_stub ( EXCEP_IRQ_LEVEL1 , mn10300_serial_vdma_interrupt ) ;
ret = uart_register_driver ( & mn10300_serial_driver ) ;
if ( ! ret ) {
for ( i = 0 ; i < NR_PORTS ; i + + ) {
port = mn10300_serial_ports [ i ] ;
if ( ! port | | port - > gdbstub )
continue ;
switch ( port - > clock_src ) {
case MNSCx_CLOCK_SRC_IOCLK :
port - > ioclk = MN10300_IOCLK ;
break ;
# ifdef MN10300_IOBCLK
case MNSCx_CLOCK_SRC_IOBCLK :
port - > ioclk = MN10300_IOBCLK ;
break ;
# endif
default :
BUG ( ) ;
}
ret = uart_add_one_port ( & mn10300_serial_driver ,
& port - > uart ) ;
if ( ret < 0 ) {
_debug ( " ERROR %d " , - ret ) ;
break ;
}
}
if ( ret )
uart_unregister_driver ( & mn10300_serial_driver ) ;
}
return ret ;
}
__initcall ( mn10300_serial_init ) ;
# ifdef CONFIG_MN10300_TTYSM_CONSOLE
/*
* print a string to the serial port without disturbing the real user of the
* port too much
* - the console must be locked by the caller
*/
static void mn10300_serial_console_write ( struct console * co ,
const char * s , unsigned count )
{
struct mn10300_serial_port * port ;
unsigned i ;
u16 scxctr , txicr , tmp ;
u8 tmxmd ;
port = mn10300_serial_ports [ co - > index ] ;
/* firstly hijack the serial port from the "virtual DMA" controller */
txicr = * port - > tx_icr ;
* port - > tx_icr = GxICR_LEVEL_1 ;
tmp = * port - > tx_icr ;
/* the transmitter may be disabled */
scxctr = * port - > _control ;
if ( ! ( scxctr & SC01CTR_TXE ) ) {
/* restart the UART clock */
tmxmd = * port - > _tmxmd ;
switch ( port - > div_timer ) {
case MNSCx_DIV_TIMER_16BIT :
* port - > _tmxmd = 0 ;
* port - > _tmxmd = TM8MD_INIT_COUNTER ;
* port - > _tmxmd = tmxmd | TM8MD_COUNT_ENABLE ;
break ;
case MNSCx_DIV_TIMER_8BIT :
* port - > _tmxmd = 0 ;
* port - > _tmxmd = TM2MD_INIT_COUNTER ;
* port - > _tmxmd = tmxmd | TM2MD_COUNT_ENABLE ;
break ;
}
/* enable the transmitter */
* port - > _control = ( scxctr & ~ SC01CTR_BKE ) | SC01CTR_TXE ;
} else if ( scxctr & SC01CTR_BKE ) {
/* stop transmitting BREAK */
* port - > _control = ( scxctr & ~ SC01CTR_BKE ) ;
}
/* send the chars into the serial port (with LF -> LFCR conversion) */
for ( i = 0 ; i < count ; i + + ) {
char ch = * s + + ;
while ( * port - > _status & SC01STR_TBF )
continue ;
* ( u8 * ) port - > _txb = ch ;
if ( ch = = 0x0a ) {
while ( * port - > _status & SC01STR_TBF )
continue ;
* ( u8 * ) port - > _txb = 0xd ;
}
}
/* can't let the transmitter be turned off if it's actually
* transmitting */
while ( * port - > _status & ( SC01STR_TXF | SC01STR_TBF ) )
continue ;
/* disable the transmitter if we re-enabled it */
if ( ! ( scxctr & SC01CTR_TXE ) )
* port - > _control = scxctr ;
* port - > tx_icr = txicr ;
tmp = * port - > tx_icr ;
}
/*
* set up a serial port as a console
* - construct a cflag setting for the first rs_open ( )
* - initialize the serial port
* - return non - zero if we didn ' t find a serial port .
*/
static int __init mn10300_serial_console_setup ( struct console * co ,
char * options )
{
struct mn10300_serial_port * port ;
int i , parity = ' n ' , baud = 9600 , bits = 8 , flow = 0 ;
for ( i = 0 ; i < NR_PORTS ; i + + ) {
port = mn10300_serial_ports [ i ] ;
if ( port & & ! port - > gdbstub & & port - > uart . line = = co - > index )
goto found_device ;
}
return - ENODEV ;
found_device :
switch ( port - > clock_src ) {
case MNSCx_CLOCK_SRC_IOCLK :
port - > ioclk = MN10300_IOCLK ;
break ;
# ifdef MN10300_IOBCLK
case MNSCx_CLOCK_SRC_IOBCLK :
port - > ioclk = MN10300_IOBCLK ;
break ;
# endif
default :
BUG ( ) ;
}
if ( options )
uart_parse_options ( options , & baud , & parity , & bits , & flow ) ;
return uart_set_options ( & port - > uart , co , baud , parity , bits , flow ) ;
}
/*
* register console
*/
static int __init mn10300_serial_console_init ( void )
{
register_console ( & mn10300_serial_console ) ;
return 0 ;
}
console_initcall ( mn10300_serial_console_init ) ;
# endif