2005-04-17 02:20:36 +04:00
/*
* Driver for 8250 / 16550 - type serial ports
*
* Based on drivers / char / serial . c , by Linus Torvalds , Theodore Ts ' o .
*
* Copyright ( C ) 2001 Russell King .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* A note about mapbase / membase
*
* mapbase is the physical address of the IO port . Currently , we don ' t
* support this very well , and it may well be dropped from this driver
* in future . As such , mapbase should be NULL .
*
* membase is an ' ioremapped ' cookie . This is compatible with the old
* serial . c driver , and is currently the preferred form .
*/
# include <linux/config.h>
# include <linux/module.h>
# include <linux/tty.h>
# include <linux/ioport.h>
# include <linux/init.h>
# include <linux/console.h>
# include <linux/sysrq.h>
# include <linux/serial.h>
# include <linux/serialP.h>
# include <linux/delay.h>
# include <asm/serial.h>
# include <asm/io.h>
# include <asm/irq.h>
# include <asm/mach-au1x00/au1000.h>
# if defined(CONFIG_SERIAL_AU1X00_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
# define SUPPORT_SYSRQ
# endif
# include <linux/serial_core.h>
# include "8250.h"
/*
* Debugging .
*/
#if 0
# define DEBUG_AUTOCONF(fmt...) printk(fmt)
# else
# define DEBUG_AUTOCONF(fmt...) do { } while (0)
# endif
#if 0
# define DEBUG_INTR(fmt...) printk(fmt)
# else
# define DEBUG_INTR(fmt...) do { } while (0)
# endif
# define PASS_LIMIT 256
/*
* We default to IRQ0 for the " no irq " hack . Some
* machine types want others as well - they ' re free
* to redefine this in their header file .
*/
# define is_real_interrupt(irq) ((irq) != 0)
static struct old_serial_port old_serial_port [ ] = {
{ . baud_base = 0 ,
. iomem_base = ( u8 * ) UART0_ADDR ,
. irq = AU1000_UART0_INT ,
. flags = STD_COM_FLAGS ,
. iomem_reg_shift = 2 ,
} , {
. baud_base = 0 ,
. iomem_base = ( u8 * ) UART1_ADDR ,
. irq = AU1000_UART1_INT ,
. flags = STD_COM_FLAGS ,
. iomem_reg_shift = 2
} , {
. baud_base = 0 ,
. iomem_base = ( u8 * ) UART2_ADDR ,
. irq = AU1000_UART2_INT ,
. flags = STD_COM_FLAGS ,
. iomem_reg_shift = 2
} , {
. baud_base = 0 ,
. iomem_base = ( u8 * ) UART3_ADDR ,
. irq = AU1000_UART3_INT ,
. flags = STD_COM_FLAGS ,
. iomem_reg_shift = 2
}
} ;
# define UART_NR ARRAY_SIZE(old_serial_port)
struct uart_8250_port {
struct uart_port port ;
struct timer_list timer ; /* "no irq" timer */
struct list_head list ; /* ports on this IRQ */
unsigned short rev ;
unsigned char acr ;
unsigned char ier ;
unsigned char lcr ;
unsigned char mcr_mask ; /* mask of user bits */
unsigned char mcr_force ; /* mask of forced bits */
unsigned char lsr_break_flag ;
/*
* We provide a per - port pm hook .
*/
void ( * pm ) ( struct uart_port * port ,
unsigned int state , unsigned int old ) ;
} ;
struct irq_info {
spinlock_t lock ;
struct list_head * head ;
} ;
static struct irq_info irq_lists [ NR_IRQS ] ;
/*
* Here we define the default xmit fifo size used for each type of UART .
*/
static const struct serial_uart_config uart_config [ PORT_MAX_8250 + 1 ] = {
{ " unknown " , 1 , 0 } ,
{ " 8250 " , 1 , 0 } ,
{ " 16450 " , 1 , 0 } ,
{ " 16550 " , 1 , 0 } ,
/* PORT_16550A */
{ " AU1X00_UART " , 16 , UART_CLEAR_FIFO | UART_USE_FIFO } ,
} ;
static _INLINE_ unsigned int serial_in ( struct uart_8250_port * up , int offset )
{
return au_readl ( ( unsigned long ) up - > port . membase + offset ) ;
}
static _INLINE_ void
serial_out ( struct uart_8250_port * up , int offset , int value )
{
au_writel ( value , ( unsigned long ) up - > port . membase + offset ) ;
}
# define serial_inp(up, offset) serial_in(up, offset)
# define serial_outp(up, offset, value) serial_out(up, offset, value)
/*
* This routine is called by rs_init ( ) to initialize a specific serial
* port . It determines what type of UART chip this serial port is
* using : 8250 , 16450 , 16550 , 16550 A . The important question is
* whether or not this UART is a 16550 A or not , since this will
* determine whether or not we can use its FIFO features or not .
*/
static void autoconfig ( struct uart_8250_port * up , unsigned int probeflags )
{
unsigned char save_lcr , save_mcr ;
unsigned long flags ;
if ( ! up - > port . iobase & & ! up - > port . mapbase & & ! up - > port . membase )
return ;
DEBUG_AUTOCONF ( " ttyS%d: autoconf (0x%04x, 0x%08lx): " ,
up - > port . line , up - > port . iobase , up - > port . membase ) ;
/*
* We really do need global IRQs disabled here - we ' re going to
* be frobbing the chips IRQ enable register to see if it exists .
*/
spin_lock_irqsave ( & up - > port . lock , flags ) ;
// save_flags(flags); cli();
save_mcr = serial_in ( up , UART_MCR ) ;
save_lcr = serial_in ( up , UART_LCR ) ;
up - > port . type = PORT_16550A ;
serial_outp ( up , UART_LCR , save_lcr ) ;
up - > port . fifosize = uart_config [ up - > port . type ] . dfl_xmit_fifo_size ;
if ( up - > port . type = = PORT_UNKNOWN )
goto out ;
/*
* Reset the UART .
*/
serial_outp ( up , UART_MCR , save_mcr ) ;
serial_outp ( up , UART_FCR , ( UART_FCR_ENABLE_FIFO |
UART_FCR_CLEAR_RCVR |
UART_FCR_CLEAR_XMIT ) ) ;
serial_outp ( up , UART_FCR , 0 ) ;
( void ) serial_in ( up , UART_RX ) ;
serial_outp ( up , UART_IER , 0 ) ;
out :
spin_unlock_irqrestore ( & up - > port . lock , flags ) ;
// restore_flags(flags);
DEBUG_AUTOCONF ( " type=%s \n " , uart_config [ up - > port . type ] . name ) ;
}
2005-08-31 13:12:14 +04:00
static void serial8250_stop_tx ( struct uart_port * port )
2005-04-17 02:20:36 +04:00
{
struct uart_8250_port * up = ( struct uart_8250_port * ) port ;
if ( up - > ier & UART_IER_THRI ) {
up - > ier & = ~ UART_IER_THRI ;
serial_out ( up , UART_IER , up - > ier ) ;
}
}
2005-08-31 13:12:14 +04:00
static void serial8250_start_tx ( struct uart_port * port )
2005-04-17 02:20:36 +04:00
{
struct uart_8250_port * up = ( struct uart_8250_port * ) port ;
if ( ! ( up - > ier & UART_IER_THRI ) ) {
up - > ier | = UART_IER_THRI ;
serial_out ( up , UART_IER , up - > ier ) ;
}
}
static void serial8250_stop_rx ( struct uart_port * port )
{
struct uart_8250_port * up = ( struct uart_8250_port * ) port ;
up - > ier & = ~ UART_IER_RLSI ;
up - > port . read_status_mask & = ~ UART_LSR_DR ;
serial_out ( up , UART_IER , up - > ier ) ;
}
static void serial8250_enable_ms ( struct uart_port * port )
{
struct uart_8250_port * up = ( struct uart_8250_port * ) port ;
up - > ier | = UART_IER_MSI ;
serial_out ( up , UART_IER , up - > ier ) ;
}
static _INLINE_ void
receive_chars ( struct uart_8250_port * up , int * status , struct pt_regs * regs )
{
struct tty_struct * tty = up - > port . info - > tty ;
unsigned char ch ;
int max_count = 256 ;
do {
if ( unlikely ( tty - > flip . count > = TTY_FLIPBUF_SIZE ) ) {
tty - > flip . work . func ( ( void * ) tty ) ;
if ( tty - > flip . count > = TTY_FLIPBUF_SIZE )
return ; // if TTY_DONT_FLIP is set
}
ch = serial_inp ( up , UART_RX ) ;
* tty - > flip . char_buf_ptr = ch ;
* tty - > flip . flag_buf_ptr = TTY_NORMAL ;
up - > port . icount . rx + + ;
if ( unlikely ( * status & ( UART_LSR_BI | UART_LSR_PE |
UART_LSR_FE | UART_LSR_OE ) ) ) {
/*
* For statistics only
*/
if ( * status & UART_LSR_BI ) {
* status & = ~ ( UART_LSR_FE | UART_LSR_PE ) ;
up - > port . icount . brk + + ;
/*
* We do the SysRQ and SAK checking
* here because otherwise the break
* may get masked by ignore_status_mask
* or read_status_mask .
*/
if ( uart_handle_break ( & up - > port ) )
goto ignore_char ;
} else if ( * status & UART_LSR_PE )
up - > port . icount . parity + + ;
else if ( * status & UART_LSR_FE )
up - > port . icount . frame + + ;
if ( * status & UART_LSR_OE )
up - > port . icount . overrun + + ;
/*
* Mask off conditions which should be ingored .
*/
* status & = up - > port . read_status_mask ;
# ifdef CONFIG_SERIAL_AU1X00_CONSOLE
if ( up - > port . line = = up - > port . cons - > index ) {
/* Recover the break flag from console xmit */
* status | = up - > lsr_break_flag ;
up - > lsr_break_flag = 0 ;
}
# endif
if ( * status & UART_LSR_BI ) {
DEBUG_INTR ( " handling break.... " ) ;
* tty - > flip . flag_buf_ptr = TTY_BREAK ;
} else if ( * status & UART_LSR_PE )
* tty - > flip . flag_buf_ptr = TTY_PARITY ;
else if ( * status & UART_LSR_FE )
* tty - > flip . flag_buf_ptr = TTY_FRAME ;
}
if ( uart_handle_sysrq_char ( & up - > port , ch , regs ) )
goto ignore_char ;
if ( ( * status & up - > port . ignore_status_mask ) = = 0 ) {
tty - > flip . flag_buf_ptr + + ;
tty - > flip . char_buf_ptr + + ;
tty - > flip . count + + ;
}
if ( ( * status & UART_LSR_OE ) & &
tty - > flip . count < TTY_FLIPBUF_SIZE ) {
/*
* Overrun is special , since it ' s reported
* immediately , and doesn ' t affect the current
* character .
*/
* tty - > flip . flag_buf_ptr = TTY_OVERRUN ;
tty - > flip . flag_buf_ptr + + ;
tty - > flip . char_buf_ptr + + ;
tty - > flip . count + + ;
}
ignore_char :
* status = serial_inp ( up , UART_LSR ) ;
} while ( ( * status & UART_LSR_DR ) & & ( max_count - - > 0 ) ) ;
spin_unlock ( & up - > port . lock ) ;
tty_flip_buffer_push ( tty ) ;
spin_lock ( & up - > port . lock ) ;
}
static _INLINE_ void transmit_chars ( struct uart_8250_port * up )
{
struct circ_buf * xmit = & up - > port . info - > xmit ;
int count ;
if ( up - > port . x_char ) {
serial_outp ( up , UART_TX , up - > port . x_char ) ;
up - > port . icount . tx + + ;
up - > port . x_char = 0 ;
return ;
}
if ( uart_circ_empty ( xmit ) | | uart_tx_stopped ( & up - > port ) ) {
2005-08-31 13:12:14 +04:00
serial8250_stop_tx ( & up - > port ) ;
2005-04-17 02:20:36 +04:00
return ;
}
count = up - > port . fifosize ;
do {
serial_out ( up , UART_TX , xmit - > buf [ xmit - > tail ] ) ;
xmit - > tail = ( xmit - > tail + 1 ) & ( UART_XMIT_SIZE - 1 ) ;
up - > port . icount . tx + + ;
if ( uart_circ_empty ( xmit ) )
break ;
} while ( - - count > 0 ) ;
if ( uart_circ_chars_pending ( xmit ) < WAKEUP_CHARS )
uart_write_wakeup ( & up - > port ) ;
DEBUG_INTR ( " THRE... " ) ;
if ( uart_circ_empty ( xmit ) )
2005-08-31 13:12:14 +04:00
serial8250_stop_tx ( & up - > port ) ;
2005-04-17 02:20:36 +04:00
}
static _INLINE_ void check_modem_status ( struct uart_8250_port * up )
{
int status ;
status = serial_in ( up , UART_MSR ) ;
if ( ( status & UART_MSR_ANY_DELTA ) = = 0 )
return ;
if ( status & UART_MSR_TERI )
up - > port . icount . rng + + ;
if ( status & UART_MSR_DDSR )
up - > port . icount . dsr + + ;
if ( status & UART_MSR_DDCD )
uart_handle_dcd_change ( & up - > port , status & UART_MSR_DCD ) ;
if ( status & UART_MSR_DCTS )
uart_handle_cts_change ( & up - > port , status & UART_MSR_CTS ) ;
wake_up_interruptible ( & up - > port . info - > delta_msr_wait ) ;
}
/*
* This handles the interrupt from one port .
*/
static inline void
serial8250_handle_port ( struct uart_8250_port * up , struct pt_regs * regs )
{
unsigned int status = serial_inp ( up , UART_LSR ) ;
DEBUG_INTR ( " status = %x... " , status ) ;
if ( status & UART_LSR_DR )
receive_chars ( up , & status , regs ) ;
check_modem_status ( up ) ;
if ( status & UART_LSR_THRE )
transmit_chars ( up ) ;
}
/*
* This is the serial driver ' s interrupt routine .
*
* Arjan thinks the old way was overly complex , so it got simplified .
* Alan disagrees , saying that need the complexity to handle the weird
* nature of ISA shared interrupts . ( This is a special exception . )
*
* In order to handle ISA shared interrupts properly , we need to check
* that all ports have been serviced , and therefore the ISA interrupt
* line has been de - asserted .
*
* This means we need to loop through all ports . checking that they
* don ' t have an interrupt pending .
*/
static irqreturn_t serial8250_interrupt ( int irq , void * dev_id , struct pt_regs * regs )
{
struct irq_info * i = dev_id ;
struct list_head * l , * end = NULL ;
int pass_counter = 0 ;
DEBUG_INTR ( " serial8250_interrupt(%d)... " , irq ) ;
spin_lock ( & i - > lock ) ;
l = i - > head ;
do {
struct uart_8250_port * up ;
unsigned int iir ;
up = list_entry ( l , struct uart_8250_port , list ) ;
iir = serial_in ( up , UART_IIR ) ;
if ( ! ( iir & UART_IIR_NO_INT ) ) {
spin_lock ( & up - > port . lock ) ;
serial8250_handle_port ( up , regs ) ;
spin_unlock ( & up - > port . lock ) ;
end = NULL ;
} else if ( end = = NULL )
end = l ;
l = l - > next ;
if ( l = = i - > head & & pass_counter + + > PASS_LIMIT ) {
/* If we hit this, we're dead. */
printk ( KERN_ERR " serial8250: too much work for "
" irq%d \n " , irq ) ;
break ;
}
} while ( l ! = end ) ;
spin_unlock ( & i - > lock ) ;
DEBUG_INTR ( " end. \n " ) ;
/* FIXME! Was it really ours? */
return IRQ_HANDLED ;
}
/*
* To support ISA shared interrupts , we need to have one interrupt
* handler that ensures that the IRQ line has been deasserted
* before returning . Failing to do this will result in the IRQ
* line being stuck active , and , since ISA irqs are edge triggered ,
* no more IRQs will be seen .
*/
static void serial_do_unlink ( struct irq_info * i , struct uart_8250_port * up )
{
spin_lock_irq ( & i - > lock ) ;
if ( ! list_empty ( i - > head ) ) {
if ( i - > head = = & up - > list )
i - > head = i - > head - > next ;
list_del ( & up - > list ) ;
} else {
BUG_ON ( i - > head ! = & up - > list ) ;
i - > head = NULL ;
}
spin_unlock_irq ( & i - > lock ) ;
}
static int serial_link_irq_chain ( struct uart_8250_port * up )
{
struct irq_info * i = irq_lists + up - > port . irq ;
int ret , irq_flags = up - > port . flags & UPF_SHARE_IRQ ? SA_SHIRQ : 0 ;
spin_lock_irq ( & i - > lock ) ;
if ( i - > head ) {
list_add ( & up - > list , i - > head ) ;
spin_unlock_irq ( & i - > lock ) ;
ret = 0 ;
} else {
INIT_LIST_HEAD ( & up - > list ) ;
i - > head = & up - > list ;
spin_unlock_irq ( & i - > lock ) ;
ret = request_irq ( up - > port . irq , serial8250_interrupt ,
irq_flags , " serial " , i ) ;
if ( ret < 0 )
serial_do_unlink ( i , up ) ;
}
return ret ;
}
static void serial_unlink_irq_chain ( struct uart_8250_port * up )
{
struct irq_info * i = irq_lists + up - > port . irq ;
BUG_ON ( i - > head = = NULL ) ;
if ( list_empty ( i - > head ) )
free_irq ( up - > port . irq , i ) ;
serial_do_unlink ( i , up ) ;
}
/*
* This function is used to handle ports that do not have an
* interrupt . This doesn ' t work very well for 16450 ' s , but gives
* barely passable results for a 16550 A . ( Although at the expense
* of much CPU overhead ) .
*/
static void serial8250_timeout ( unsigned long data )
{
struct uart_8250_port * up = ( struct uart_8250_port * ) data ;
unsigned int timeout ;
unsigned int iir ;
iir = serial_in ( up , UART_IIR ) ;
if ( ! ( iir & UART_IIR_NO_INT ) ) {
spin_lock ( & up - > port . lock ) ;
serial8250_handle_port ( up , NULL ) ;
spin_unlock ( & up - > port . lock ) ;
}
timeout = up - > port . timeout ;
timeout = timeout > 6 ? ( timeout / 2 - 2 ) : 1 ;
mod_timer ( & up - > timer , jiffies + timeout ) ;
}
static unsigned int serial8250_tx_empty ( struct uart_port * port )
{
struct uart_8250_port * up = ( struct uart_8250_port * ) port ;
unsigned long flags ;
unsigned int ret ;
spin_lock_irqsave ( & up - > port . lock , flags ) ;
ret = serial_in ( up , UART_LSR ) & UART_LSR_TEMT ? TIOCSER_TEMT : 0 ;
spin_unlock_irqrestore ( & up - > port . lock , flags ) ;
return ret ;
}
static unsigned int serial8250_get_mctrl ( struct uart_port * port )
{
struct uart_8250_port * up = ( struct uart_8250_port * ) port ;
unsigned char status ;
unsigned int ret ;
status = serial_in ( up , UART_MSR ) ;
ret = 0 ;
if ( status & UART_MSR_DCD )
ret | = TIOCM_CAR ;
if ( status & UART_MSR_RI )
ret | = TIOCM_RNG ;
if ( status & UART_MSR_DSR )
ret | = TIOCM_DSR ;
if ( status & UART_MSR_CTS )
ret | = TIOCM_CTS ;
return ret ;
}
static void serial8250_set_mctrl ( struct uart_port * port , unsigned int mctrl )
{
struct uart_8250_port * up = ( struct uart_8250_port * ) port ;
unsigned char mcr = 0 ;
if ( mctrl & TIOCM_RTS )
mcr | = UART_MCR_RTS ;
if ( mctrl & TIOCM_DTR )
mcr | = UART_MCR_DTR ;
if ( mctrl & TIOCM_OUT1 )
mcr | = UART_MCR_OUT1 ;
if ( mctrl & TIOCM_OUT2 )
mcr | = UART_MCR_OUT2 ;
if ( mctrl & TIOCM_LOOP )
mcr | = UART_MCR_LOOP ;
mcr = ( mcr & up - > mcr_mask ) | up - > mcr_force ;
serial_out ( up , UART_MCR , mcr ) ;
}
static void serial8250_break_ctl ( struct uart_port * port , int break_state )
{
struct uart_8250_port * up = ( struct uart_8250_port * ) port ;
unsigned long flags ;
spin_lock_irqsave ( & up - > port . lock , flags ) ;
if ( break_state = = - 1 )
up - > lcr | = UART_LCR_SBC ;
else
up - > lcr & = ~ UART_LCR_SBC ;
serial_out ( up , UART_LCR , up - > lcr ) ;
spin_unlock_irqrestore ( & up - > port . lock , flags ) ;
}
static int serial8250_startup ( struct uart_port * port )
{
struct uart_8250_port * up = ( struct uart_8250_port * ) port ;
unsigned long flags ;
int retval ;
/*
* Clear the FIFO buffers and disable them .
* ( they will be reeanbled in set_termios ( ) )
*/
if ( uart_config [ up - > port . type ] . flags & UART_CLEAR_FIFO ) {
serial_outp ( up , UART_FCR , UART_FCR_ENABLE_FIFO ) ;
serial_outp ( up , UART_FCR , UART_FCR_ENABLE_FIFO |
UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT ) ;
serial_outp ( up , UART_FCR , 0 ) ;
}
/*
* Clear the interrupt registers .
*/
( void ) serial_inp ( up , UART_LSR ) ;
( void ) serial_inp ( up , UART_RX ) ;
( void ) serial_inp ( up , UART_IIR ) ;
( void ) serial_inp ( up , UART_MSR ) ;
/*
* At this point , there ' s no way the LSR could still be 0xff ;
* if it is , then bail out , because there ' s likely no UART
* here .
*/
if ( ! ( up - > port . flags & UPF_BUGGY_UART ) & &
( serial_inp ( up , UART_LSR ) = = 0xff ) ) {
printk ( " ttyS%d: LSR safety check engaged! \n " , up - > port . line ) ;
return - ENODEV ;
}
retval = serial_link_irq_chain ( up ) ;
if ( retval )
return retval ;
/*
* Now , initialize the UART
*/
serial_outp ( up , UART_LCR , UART_LCR_WLEN8 ) ;
spin_lock_irqsave ( & up - > port . lock , flags ) ;
if ( up - > port . flags & UPF_FOURPORT ) {
if ( ! is_real_interrupt ( up - > port . irq ) )
up - > port . mctrl | = TIOCM_OUT1 ;
} else
/*
* Most PC uarts need OUT2 raised to enable interrupts .
*/
if ( is_real_interrupt ( up - > port . irq ) )
up - > port . mctrl | = TIOCM_OUT2 ;
serial8250_set_mctrl ( & up - > port , up - > port . mctrl ) ;
spin_unlock_irqrestore ( & up - > port . lock , flags ) ;
/*
* Finally , enable interrupts . Note : Modem status interrupts
* are set via set_termios ( ) , which will be occurring imminently
* anyway , so we don ' t enable them here .
*/
up - > ier = UART_IER_RLSI | UART_IER_RDI ;
serial_outp ( up , UART_IER , up - > ier ) ;
if ( up - > port . flags & UPF_FOURPORT ) {
unsigned int icp ;
/*
* Enable interrupts on the AST Fourport board
*/
icp = ( up - > port . iobase & 0xfe0 ) | 0x01f ;
outb_p ( 0x80 , icp ) ;
( void ) inb_p ( icp ) ;
}
/*
* And clear the interrupt registers again for luck .
*/
( void ) serial_inp ( up , UART_LSR ) ;
( void ) serial_inp ( up , UART_RX ) ;
( void ) serial_inp ( up , UART_IIR ) ;
( void ) serial_inp ( up , UART_MSR ) ;
return 0 ;
}
static void serial8250_shutdown ( struct uart_port * port )
{
struct uart_8250_port * up = ( struct uart_8250_port * ) port ;
unsigned long flags ;
/*
* Disable interrupts from this port
*/
up - > ier = 0 ;
serial_outp ( up , UART_IER , 0 ) ;
spin_lock_irqsave ( & up - > port . lock , flags ) ;
if ( up - > port . flags & UPF_FOURPORT ) {
/* reset interrupts on the AST Fourport board */
inb ( ( up - > port . iobase & 0xfe0 ) | 0x1f ) ;
up - > port . mctrl | = TIOCM_OUT1 ;
} else
up - > port . mctrl & = ~ TIOCM_OUT2 ;
serial8250_set_mctrl ( & up - > port , up - > port . mctrl ) ;
spin_unlock_irqrestore ( & up - > port . lock , flags ) ;
/*
* Disable break condition and FIFOs
*/
serial_out ( up , UART_LCR , serial_inp ( up , UART_LCR ) & ~ UART_LCR_SBC ) ;
serial_outp ( up , UART_FCR , UART_FCR_ENABLE_FIFO |
UART_FCR_CLEAR_RCVR |
UART_FCR_CLEAR_XMIT ) ;
serial_outp ( up , UART_FCR , 0 ) ;
/*
* Read data port to reset things , and then unlink from
* the IRQ chain .
*/
( void ) serial_in ( up , UART_RX ) ;
if ( ! is_real_interrupt ( up - > port . irq ) )
del_timer_sync ( & up - > timer ) ;
else
serial_unlink_irq_chain ( up ) ;
}
static unsigned int serial8250_get_divisor ( struct uart_port * port , unsigned int baud )
{
unsigned int quot ;
/*
* Handle magic divisors for baud rates above baud_base on
* SMSC SuperIO chips .
*/
if ( ( port - > flags & UPF_MAGIC_MULTIPLIER ) & &
baud = = ( port - > uartclk / 4 ) )
quot = 0x8001 ;
else if ( ( port - > flags & UPF_MAGIC_MULTIPLIER ) & &
baud = = ( port - > uartclk / 8 ) )
quot = 0x8002 ;
else
quot = uart_get_divisor ( port , baud ) ;
return quot ;
}
static void
serial8250_set_termios ( struct uart_port * port , struct termios * termios ,
struct termios * old )
{
struct uart_8250_port * up = ( struct uart_8250_port * ) port ;
unsigned char cval , fcr = 0 ;
unsigned long flags ;
unsigned int baud , quot ;
switch ( termios - > c_cflag & CSIZE ) {
case CS5 :
2005-06-24 22:48:22 +04:00
cval = UART_LCR_WLEN5 ;
2005-04-17 02:20:36 +04:00
break ;
case CS6 :
2005-06-24 22:48:22 +04:00
cval = UART_LCR_WLEN6 ;
2005-04-17 02:20:36 +04:00
break ;
case CS7 :
2005-06-24 22:48:22 +04:00
cval = UART_LCR_WLEN7 ;
2005-04-17 02:20:36 +04:00
break ;
default :
case CS8 :
2005-06-24 22:48:22 +04:00
cval = UART_LCR_WLEN8 ;
2005-04-17 02:20:36 +04:00
break ;
}
if ( termios - > c_cflag & CSTOPB )
2005-06-24 22:48:22 +04:00
cval | = UART_LCR_STOP ;
2005-04-17 02:20:36 +04:00
if ( termios - > c_cflag & PARENB )
cval | = UART_LCR_PARITY ;
if ( ! ( termios - > c_cflag & PARODD ) )
cval | = UART_LCR_EPAR ;
# ifdef CMSPAR
if ( termios - > c_cflag & CMSPAR )
cval | = UART_LCR_SPAR ;
# endif
/*
* Ask the core to calculate the divisor for us .
*/
baud = uart_get_baud_rate ( port , termios , old , 0 , port - > uartclk / 16 ) ;
quot = serial8250_get_divisor ( port , baud ) ;
quot = 0x35 ; /* FIXME */
/*
* Work around a bug in the Oxford Semiconductor 952 rev B
* chip which causes it to seriously miscalculate baud rates
* when DLL is 0.
*/
if ( ( quot & 0xff ) = = 0 & & up - > port . type = = PORT_16C950 & &
up - > rev = = 0x5201 )
quot + + ;
if ( uart_config [ up - > port . type ] . flags & UART_USE_FIFO ) {
if ( baud < 2400 )
fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIGGER_1 ;
else
fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIGGER_8 ;
}
/*
* Ok , we ' re now changing the port state . Do it with
* interrupts disabled .
*/
spin_lock_irqsave ( & up - > port . lock , flags ) ;
/*
* Update the per - port timeout .
*/
uart_update_timeout ( port , termios - > c_cflag , baud ) ;
up - > port . read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR ;
if ( termios - > c_iflag & INPCK )
up - > port . read_status_mask | = UART_LSR_FE | UART_LSR_PE ;
if ( termios - > c_iflag & ( BRKINT | PARMRK ) )
up - > port . read_status_mask | = UART_LSR_BI ;
/*
* Characteres to ignore
*/
up - > port . ignore_status_mask = 0 ;
if ( termios - > c_iflag & IGNPAR )
up - > port . ignore_status_mask | = UART_LSR_PE | UART_LSR_FE ;
if ( termios - > c_iflag & IGNBRK ) {
up - > port . ignore_status_mask | = UART_LSR_BI ;
/*
* If we ' re ignoring parity and break indicators ,
* ignore overruns too ( for real raw support ) .
*/
if ( termios - > c_iflag & IGNPAR )
up - > port . ignore_status_mask | = UART_LSR_OE ;
}
/*
* ignore all characters if CREAD is not set
*/
if ( ( termios - > c_cflag & CREAD ) = = 0 )
up - > port . ignore_status_mask | = UART_LSR_DR ;
/*
* CTS flow control flag and modem status interrupts
*/
up - > ier & = ~ UART_IER_MSI ;
if ( UART_ENABLE_MS ( & up - > port , termios - > c_cflag ) )
up - > ier | = UART_IER_MSI ;
serial_out ( up , UART_IER , up - > ier ) ;
serial_outp ( up , 0x28 , quot & 0xffff ) ;
up - > lcr = cval ; /* Save LCR */
if ( up - > port . type ! = PORT_16750 ) {
if ( fcr & UART_FCR_ENABLE_FIFO ) {
/* emulated UARTs (Lucent Venus 167x) need two steps */
serial_outp ( up , UART_FCR , UART_FCR_ENABLE_FIFO ) ;
}
serial_outp ( up , UART_FCR , fcr ) ; /* set fcr */
}
spin_unlock_irqrestore ( & up - > port . lock , flags ) ;
}
static void
serial8250_pm ( struct uart_port * port , unsigned int state ,
unsigned int oldstate )
{
struct uart_8250_port * up = ( struct uart_8250_port * ) port ;
if ( state ) {
/* sleep */
if ( up - > pm )
up - > pm ( port , state , oldstate ) ;
} else {
/* wake */
if ( up - > pm )
up - > pm ( port , state , oldstate ) ;
}
}
/*
* Resource handling . This is complicated by the fact that resources
* depend on the port type . Maybe we should be claiming the standard
* 8250 ports , and then trying to get other resources as necessary ?
*/
static int
serial8250_request_std_resource ( struct uart_8250_port * up , struct resource * * res )
{
unsigned int size = 8 < < up - > port . regshift ;
int ret = 0 ;
switch ( up - > port . iotype ) {
case SERIAL_IO_MEM :
if ( up - > port . mapbase ) {
* res = request_mem_region ( up - > port . mapbase , size , " serial " ) ;
if ( ! * res )
ret = - EBUSY ;
}
break ;
case SERIAL_IO_HUB6 :
case SERIAL_IO_PORT :
* res = request_region ( up - > port . iobase , size , " serial " ) ;
if ( ! * res )
ret = - EBUSY ;
break ;
}
return ret ;
}
static void serial8250_release_port ( struct uart_port * port )
{
struct uart_8250_port * up = ( struct uart_8250_port * ) port ;
unsigned long start , offset = 0 , size = 0 ;
size < < = up - > port . regshift ;
switch ( up - > port . iotype ) {
case SERIAL_IO_MEM :
if ( up - > port . mapbase ) {
/*
* Unmap the area .
*/
iounmap ( up - > port . membase ) ;
up - > port . membase = NULL ;
start = up - > port . mapbase ;
if ( size )
release_mem_region ( start + offset , size ) ;
release_mem_region ( start , 8 < < up - > port . regshift ) ;
}
break ;
case SERIAL_IO_HUB6 :
case SERIAL_IO_PORT :
start = up - > port . iobase ;
if ( size )
release_region ( start + offset , size ) ;
release_region ( start + offset , 8 < < up - > port . regshift ) ;
break ;
default :
break ;
}
}
static int serial8250_request_port ( struct uart_port * port )
{
struct uart_8250_port * up = ( struct uart_8250_port * ) port ;
struct resource * res = NULL , * res_rsa = NULL ;
int ret = 0 ;
ret = serial8250_request_std_resource ( up , & res ) ;
/*
* If we have a mapbase , then request that as well .
*/
if ( ret = = 0 & & up - > port . flags & UPF_IOREMAP ) {
int size = res - > end - res - > start + 1 ;
up - > port . membase = ioremap ( up - > port . mapbase , size ) ;
if ( ! up - > port . membase )
ret = - ENOMEM ;
}
if ( ret < 0 ) {
if ( res_rsa )
release_resource ( res_rsa ) ;
if ( res )
release_resource ( res ) ;
}
return ret ;
}
static void serial8250_config_port ( struct uart_port * port , int flags )
{
struct uart_8250_port * up = ( struct uart_8250_port * ) port ;
struct resource * res_std = NULL , * res_rsa = NULL ;
int probeflags = PROBE_ANY ;
probeflags & = ~ PROBE_RSA ;
if ( flags & UART_CONFIG_TYPE )
autoconfig ( up , probeflags ) ;
/*
* If the port wasn ' t an RSA port , release the resource .
*/
if ( up - > port . type ! = PORT_RSA & & res_rsa )
release_resource ( res_rsa ) ;
if ( up - > port . type = = PORT_UNKNOWN & & res_std )
release_resource ( res_std ) ;
}
static int
serial8250_verify_port ( struct uart_port * port , struct serial_struct * ser )
{
if ( ser - > irq > = NR_IRQS | | ser - > irq < 0 | |
ser - > baud_base < 9600 | | ser - > type < PORT_UNKNOWN | |
ser - > type > PORT_MAX_8250 | | ser - > type = = PORT_CIRRUS | |
ser - > type = = PORT_STARTECH )
return - EINVAL ;
return 0 ;
}
static const char *
serial8250_type ( struct uart_port * port )
{
int type = port - > type ;
if ( type > = ARRAY_SIZE ( uart_config ) )
type = 0 ;
return uart_config [ type ] . name ;
}
static struct uart_ops serial8250_pops = {
. tx_empty = serial8250_tx_empty ,
. set_mctrl = serial8250_set_mctrl ,
. get_mctrl = serial8250_get_mctrl ,
. stop_tx = serial8250_stop_tx ,
. start_tx = serial8250_start_tx ,
. stop_rx = serial8250_stop_rx ,
. enable_ms = serial8250_enable_ms ,
. break_ctl = serial8250_break_ctl ,
. startup = serial8250_startup ,
. shutdown = serial8250_shutdown ,
. set_termios = serial8250_set_termios ,
. pm = serial8250_pm ,
. type = serial8250_type ,
. release_port = serial8250_release_port ,
. request_port = serial8250_request_port ,
. config_port = serial8250_config_port ,
. verify_port = serial8250_verify_port ,
} ;
static struct uart_8250_port serial8250_ports [ UART_NR ] ;
static void __init serial8250_isa_init_ports ( void )
{
struct uart_8250_port * up ;
static int first = 1 ;
int i ;
if ( ! first )
return ;
first = 0 ;
for ( i = 0 , up = serial8250_ports ; i < ARRAY_SIZE ( old_serial_port ) ;
i + + , up + + ) {
up - > port . iobase = old_serial_port [ i ] . port ;
up - > port . irq = old_serial_port [ i ] . irq ;
up - > port . uartclk = get_au1x00_uart_baud_base ( ) ;
up - > port . flags = old_serial_port [ i ] . flags ;
up - > port . hub6 = old_serial_port [ i ] . hub6 ;
up - > port . membase = old_serial_port [ i ] . iomem_base ;
up - > port . iotype = old_serial_port [ i ] . io_type ;
up - > port . regshift = old_serial_port [ i ] . iomem_reg_shift ;
up - > port . ops = & serial8250_pops ;
}
}
static void __init serial8250_register_ports ( struct uart_driver * drv )
{
int i ;
serial8250_isa_init_ports ( ) ;
for ( i = 0 ; i < UART_NR ; i + + ) {
struct uart_8250_port * up = & serial8250_ports [ i ] ;
up - > port . line = i ;
up - > port . ops = & serial8250_pops ;
init_timer ( & up - > timer ) ;
up - > timer . function = serial8250_timeout ;
/*
* ALPHA_KLUDGE_MCR needs to be killed .
*/
up - > mcr_mask = ~ ALPHA_KLUDGE_MCR ;
up - > mcr_force = ALPHA_KLUDGE_MCR ;
uart_add_one_port ( drv , & up - > port ) ;
}
}
# ifdef CONFIG_SERIAL_AU1X00_CONSOLE
# define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
/*
* Wait for transmitter & holding register to empty
*/
static inline void wait_for_xmitr ( struct uart_8250_port * up )
{
unsigned int status , tmout = 10000 ;
/* Wait up to 10ms for the character(s) to be sent. */
do {
status = serial_in ( up , UART_LSR ) ;
if ( status & UART_LSR_BI )
up - > lsr_break_flag = UART_LSR_BI ;
if ( - - tmout = = 0 )
break ;
udelay ( 1 ) ;
} while ( ( status & BOTH_EMPTY ) ! = BOTH_EMPTY ) ;
/* Wait up to 1s for flow control if necessary */
if ( up - > port . flags & UPF_CONS_FLOW ) {
tmout = 1000000 ;
while ( - - tmout & &
( ( serial_in ( up , UART_MSR ) & UART_MSR_CTS ) = = 0 ) )
udelay ( 1 ) ;
}
}
/*
* Print a string to the serial port trying not to disturb
* any possible real use of the port . . .
*
* The console_lock must be held when we get here .
*/
static void
serial8250_console_write ( struct console * co , const char * s , unsigned int count )
{
struct uart_8250_port * up = & serial8250_ports [ co - > index ] ;
unsigned int ier ;
int i ;
/*
* First save the UER then disable the interrupts
*/
ier = serial_in ( up , UART_IER ) ;
serial_out ( up , UART_IER , 0 ) ;
/*
* Now , do each character
*/
for ( i = 0 ; i < count ; i + + , s + + ) {
wait_for_xmitr ( up ) ;
/*
* Send the character out .
* If a LF , also do CR . . .
*/
serial_out ( up , UART_TX , * s ) ;
if ( * s = = 10 ) {
wait_for_xmitr ( up ) ;
serial_out ( up , UART_TX , 13 ) ;
}
}
/*
* Finally , wait for transmitter to become empty
* and restore the IER
*/
wait_for_xmitr ( up ) ;
serial_out ( up , UART_IER , ier ) ;
}
static int __init serial8250_console_setup ( struct console * co , char * options )
{
struct uart_port * port ;
int baud = 9600 ;
int bits = 8 ;
int parity = ' n ' ;
int flow = ' n ' ;
/*
* Check whether an invalid uart number has been specified , and
* if so , search for the first available port that does have
* console support .
*/
if ( co - > index > = UART_NR )
co - > index = 0 ;
port = & serial8250_ports [ co - > index ] . port ;
/*
* Temporary fix .
*/
spin_lock_init ( & port - > lock ) ;
if ( options )
uart_parse_options ( options , & baud , & parity , & bits , & flow ) ;
return uart_set_options ( port , co , baud , parity , bits , flow ) ;
}
extern struct uart_driver serial8250_reg ;
static struct console serial8250_console = {
. name = " ttyS " ,
. write = serial8250_console_write ,
. device = uart_console_device ,
. setup = serial8250_console_setup ,
. flags = CON_PRINTBUFFER ,
. index = - 1 ,
. data = & serial8250_reg ,
} ;
static int __init serial8250_console_init ( void )
{
serial8250_isa_init_ports ( ) ;
register_console ( & serial8250_console ) ;
return 0 ;
}
console_initcall ( serial8250_console_init ) ;
# define SERIAL8250_CONSOLE &serial8250_console
# else
# define SERIAL8250_CONSOLE NULL
# endif
static struct uart_driver serial8250_reg = {
. owner = THIS_MODULE ,
. driver_name = " serial " ,
. devfs_name = " tts/ " ,
. dev_name = " ttyS " ,
. major = TTY_MAJOR ,
. minor = 64 ,
. nr = UART_NR ,
. cons = SERIAL8250_CONSOLE ,
} ;
int __init early_serial_setup ( struct uart_port * port )
{
serial8250_isa_init_ports ( ) ;
serial8250_ports [ port - > line ] . port = * port ;
serial8250_ports [ port - > line ] . port . ops = & serial8250_pops ;
return 0 ;
}
/**
* serial8250_suspend_port - suspend one serial port
* @ line : serial line number
* @ level : the level of port suspension , as per uart_suspend_port
*
* Suspend one serial port .
*/
void serial8250_suspend_port ( int line )
{
uart_suspend_port ( & serial8250_reg , & serial8250_ports [ line ] . port ) ;
}
/**
* serial8250_resume_port - resume one serial port
* @ line : serial line number
* @ level : the level of port resumption , as per uart_resume_port
*
* Resume one serial port .
*/
void serial8250_resume_port ( int line )
{
uart_resume_port ( & serial8250_reg , & serial8250_ports [ line ] . port ) ;
}
static int __init serial8250_init ( void )
{
int ret , i ;
printk ( KERN_INFO " Serial: Au1x00 driver \n " ) ;
for ( i = 0 ; i < NR_IRQS ; i + + )
spin_lock_init ( & irq_lists [ i ] . lock ) ;
ret = uart_register_driver ( & serial8250_reg ) ;
if ( ret > = 0 )
serial8250_register_ports ( & serial8250_reg ) ;
return ret ;
}
static void __exit serial8250_exit ( void )
{
int i ;
for ( i = 0 ; i < UART_NR ; i + + )
uart_remove_one_port ( & serial8250_reg , & serial8250_ports [ i ] . port ) ;
uart_unregister_driver ( & serial8250_reg ) ;
}
module_init ( serial8250_init ) ;
module_exit ( serial8250_exit ) ;
EXPORT_SYMBOL ( serial8250_suspend_port ) ;
EXPORT_SYMBOL ( serial8250_resume_port ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_DESCRIPTION ( " Au1x00 serial driver \n " ) ;