2005-04-17 02:20:36 +04:00
/*
* linux / drivers / char / 8250. c
*
* 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 .
*
* $ Id : 8250. c , v 1.90 2002 / 07 / 28 10 : 03 : 27 rmk Exp $
*
* A note about mapbase / membase
*
* mapbase is the physical address of the IO port .
* membase is an ' ioremapped ' cookie .
*/
# include <linux/config.h>
# if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
# define SUPPORT_SYSRQ
# endif
# include <linux/module.h>
# include <linux/moduleparam.h>
# include <linux/ioport.h>
# include <linux/init.h>
# include <linux/console.h>
# include <linux/sysrq.h>
# include <linux/mca.h>
# include <linux/delay.h>
# include <linux/device.h>
# include <linux/tty.h>
# include <linux/tty_flip.h>
# include <linux/serial_reg.h>
# include <linux/serial_core.h>
# include <linux/serial.h>
# include <linux/serial_8250.h>
# include <asm/io.h>
# include <asm/irq.h>
# include "8250.h"
/*
* Configuration :
* share_irqs - whether we pass SA_SHIRQ to request_irq ( ) . This option
* is unsafe when used on edge - triggered interrupts .
*/
2005-05-01 19:59:29 +04:00
static unsigned int share_irqs = SERIAL8250_SHARE_IRQS ;
2005-04-17 02:20:36 +04:00
/*
* 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)
# ifdef CONFIG_SERIAL_8250_DETECT_IRQ
# define CONFIG_SERIAL_DETECT_IRQ 1
# endif
# ifdef CONFIG_SERIAL_8250_MANY_PORTS
# define CONFIG_SERIAL_MANY_PORTS 1
# endif
/*
* HUB6 is always on . This will be removed once the header
* files have been cleaned .
*/
# define CONFIG_HUB6 1
# include <asm/serial.h>
/*
* SERIAL_PORT_DFNS tells us about built - in ports that have no
* standard enumeration mechanism . Platforms that can find all
* serial ports via mechanisms like ACPI or PCI need not supply it .
*/
# ifndef SERIAL_PORT_DFNS
# define SERIAL_PORT_DFNS
# endif
static struct old_serial_port old_serial_port [ ] = {
SERIAL_PORT_DFNS /* defined in asm/serial.h */
} ;
2005-06-29 21:45:19 +04:00
# define UART_NR CONFIG_SERIAL_8250_NR_UARTS
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_SERIAL_8250_RSA
# define PORT_RSA_MAX 4
static unsigned long probe_rsa [ PORT_RSA_MAX ] ;
static unsigned int probe_rsa_count ;
# endif /* CONFIG_SERIAL_8250_RSA */
struct uart_8250_port {
struct uart_port port ;
struct timer_list timer ; /* "no irq" timer */
struct list_head list ; /* ports on this IRQ */
2005-06-23 13:43:04 +04:00
unsigned short capabilities ; /* port capabilities */
unsigned short bugs ; /* port bugs */
2005-04-17 02:20:36 +04:00
unsigned int tx_loadsz ; /* transmit fifo load size */
unsigned char acr ;
unsigned char ier ;
unsigned char lcr ;
unsigned char mcr ;
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 serial8250_config uart_config [ ] = {
[ PORT_UNKNOWN ] = {
. name = " unknown " ,
. fifo_size = 1 ,
. tx_loadsz = 1 ,
} ,
[ PORT_8250 ] = {
. name = " 8250 " ,
. fifo_size = 1 ,
. tx_loadsz = 1 ,
} ,
[ PORT_16450 ] = {
. name = " 16450 " ,
. fifo_size = 1 ,
. tx_loadsz = 1 ,
} ,
[ PORT_16550 ] = {
. name = " 16550 " ,
. fifo_size = 1 ,
. tx_loadsz = 1 ,
} ,
[ PORT_16550A ] = {
. name = " 16550A " ,
. fifo_size = 16 ,
. tx_loadsz = 16 ,
. fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 ,
. flags = UART_CAP_FIFO ,
} ,
[ PORT_CIRRUS ] = {
. name = " Cirrus " ,
. fifo_size = 1 ,
. tx_loadsz = 1 ,
} ,
[ PORT_16650 ] = {
. name = " ST16650 " ,
. fifo_size = 1 ,
. tx_loadsz = 1 ,
. flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP ,
} ,
[ PORT_16650V2 ] = {
. name = " ST16650V2 " ,
. fifo_size = 32 ,
. tx_loadsz = 16 ,
. fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 |
UART_FCR_T_TRIG_00 ,
. flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP ,
} ,
[ PORT_16750 ] = {
. name = " TI16750 " ,
. fifo_size = 64 ,
. tx_loadsz = 64 ,
. fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 |
UART_FCR7_64BYTE ,
. flags = UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_AFE ,
} ,
[ PORT_STARTECH ] = {
. name = " Startech " ,
. fifo_size = 1 ,
. tx_loadsz = 1 ,
} ,
[ PORT_16C950 ] = {
. name = " 16C950/954 " ,
. fifo_size = 128 ,
. tx_loadsz = 128 ,
. fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 ,
. flags = UART_CAP_FIFO ,
} ,
[ PORT_16654 ] = {
. name = " ST16654 " ,
. fifo_size = 64 ,
. tx_loadsz = 32 ,
. fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 |
UART_FCR_T_TRIG_10 ,
. flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP ,
} ,
[ PORT_16850 ] = {
. name = " XR16850 " ,
. fifo_size = 128 ,
. tx_loadsz = 128 ,
. fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 ,
. flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP ,
} ,
[ PORT_RSA ] = {
. name = " RSA " ,
. fifo_size = 2048 ,
. tx_loadsz = 2048 ,
. fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_11 ,
. flags = UART_CAP_FIFO ,
} ,
[ PORT_NS16550A ] = {
. name = " NS16550A " ,
. fifo_size = 16 ,
. tx_loadsz = 16 ,
. fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 ,
. flags = UART_CAP_FIFO | UART_NATSEMI ,
} ,
[ PORT_XSCALE ] = {
. name = " XScale " ,
. fifo_size = 32 ,
. tx_loadsz = 32 ,
. fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 ,
. flags = UART_CAP_FIFO | UART_CAP_UUE ,
} ,
} ;
static _INLINE_ unsigned int serial_in ( struct uart_8250_port * up , int offset )
{
offset < < = up - > port . regshift ;
switch ( up - > port . iotype ) {
case UPIO_HUB6 :
outb ( up - > port . hub6 - 1 + offset , up - > port . iobase ) ;
return inb ( up - > port . iobase + 1 ) ;
case UPIO_MEM :
return readb ( up - > port . membase + offset ) ;
case UPIO_MEM32 :
return readl ( up - > port . membase + offset ) ;
default :
return inb ( up - > port . iobase + offset ) ;
}
}
static _INLINE_ void
serial_out ( struct uart_8250_port * up , int offset , int value )
{
offset < < = up - > port . regshift ;
switch ( up - > port . iotype ) {
case UPIO_HUB6 :
outb ( up - > port . hub6 - 1 + offset , up - > port . iobase ) ;
outb ( value , up - > port . iobase + 1 ) ;
break ;
case UPIO_MEM :
writeb ( value , up - > port . membase + offset ) ;
break ;
case UPIO_MEM32 :
writel ( value , up - > port . membase + offset ) ;
break ;
default :
outb ( value , up - > port . iobase + offset ) ;
}
}
/*
* We used to support using pause I / O for certain machines . We
* haven ' t supported this for a while , but just in case it ' s badly
* needed for certain old 386 machines , I ' ve left these # define ' s
* in . . . .
*/
# define serial_inp(up, offset) serial_in(up, offset)
# define serial_outp(up, offset, value) serial_out(up, offset, value)
/*
* For the 16 C950
*/
static void serial_icr_write ( struct uart_8250_port * up , int offset , int value )
{
serial_out ( up , UART_SCR , offset ) ;
serial_out ( up , UART_ICR , value ) ;
}
static unsigned int serial_icr_read ( struct uart_8250_port * up , int offset )
{
unsigned int value ;
serial_icr_write ( up , UART_ACR , up - > acr | UART_ACR_ICRRD ) ;
serial_out ( up , UART_SCR , offset ) ;
value = serial_in ( up , UART_ICR ) ;
serial_icr_write ( up , UART_ACR , up - > acr ) ;
return value ;
}
/*
* FIFO support .
*/
static inline void serial8250_clear_fifos ( struct uart_8250_port * p )
{
if ( p - > capabilities & UART_CAP_FIFO ) {
serial_outp ( p , UART_FCR , UART_FCR_ENABLE_FIFO ) ;
serial_outp ( p , UART_FCR , UART_FCR_ENABLE_FIFO |
UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT ) ;
serial_outp ( p , UART_FCR , 0 ) ;
}
}
/*
* IER sleep support . UARTs which have EFRs need the " extended
* capability " bit enabled. Note that on XR16C850s, we need to
* reset LCR to write to IER .
*/
static inline void serial8250_set_sleep ( struct uart_8250_port * p , int sleep )
{
if ( p - > capabilities & UART_CAP_SLEEP ) {
if ( p - > capabilities & UART_CAP_EFR ) {
serial_outp ( p , UART_LCR , 0xBF ) ;
serial_outp ( p , UART_EFR , UART_EFR_ECB ) ;
serial_outp ( p , UART_LCR , 0 ) ;
}
serial_outp ( p , UART_IER , sleep ? UART_IERX_SLEEP : 0 ) ;
if ( p - > capabilities & UART_CAP_EFR ) {
serial_outp ( p , UART_LCR , 0xBF ) ;
serial_outp ( p , UART_EFR , 0 ) ;
serial_outp ( p , UART_LCR , 0 ) ;
}
}
}
# ifdef CONFIG_SERIAL_8250_RSA
/*
* Attempts to turn on the RSA FIFO . Returns zero on failure .
* We set the port uart clock rate if we succeed .
*/
static int __enable_rsa ( struct uart_8250_port * up )
{
unsigned char mode ;
int result ;
mode = serial_inp ( up , UART_RSA_MSR ) ;
result = mode & UART_RSA_MSR_FIFO ;
if ( ! result ) {
serial_outp ( up , UART_RSA_MSR , mode | UART_RSA_MSR_FIFO ) ;
mode = serial_inp ( up , UART_RSA_MSR ) ;
result = mode & UART_RSA_MSR_FIFO ;
}
if ( result )
up - > port . uartclk = SERIAL_RSA_BAUD_BASE * 16 ;
return result ;
}
static void enable_rsa ( struct uart_8250_port * up )
{
if ( up - > port . type = = PORT_RSA ) {
if ( up - > port . uartclk ! = SERIAL_RSA_BAUD_BASE * 16 ) {
spin_lock_irq ( & up - > port . lock ) ;
__enable_rsa ( up ) ;
spin_unlock_irq ( & up - > port . lock ) ;
}
if ( up - > port . uartclk = = SERIAL_RSA_BAUD_BASE * 16 )
serial_outp ( up , UART_RSA_FRR , 0 ) ;
}
}
/*
* Attempts to turn off the RSA FIFO . Returns zero on failure .
* It is unknown why interrupts were disabled in here . However ,
* the caller is expected to preserve this behaviour by grabbing
* the spinlock before calling this function .
*/
static void disable_rsa ( struct uart_8250_port * up )
{
unsigned char mode ;
int result ;
if ( up - > port . type = = PORT_RSA & &
up - > port . uartclk = = SERIAL_RSA_BAUD_BASE * 16 ) {
spin_lock_irq ( & up - > port . lock ) ;
mode = serial_inp ( up , UART_RSA_MSR ) ;
result = ! ( mode & UART_RSA_MSR_FIFO ) ;
if ( ! result ) {
serial_outp ( up , UART_RSA_MSR , mode & ~ UART_RSA_MSR_FIFO ) ;
mode = serial_inp ( up , UART_RSA_MSR ) ;
result = ! ( mode & UART_RSA_MSR_FIFO ) ;
}
if ( result )
up - > port . uartclk = SERIAL_RSA_BAUD_BASE_LO * 16 ;
spin_unlock_irq ( & up - > port . lock ) ;
}
}
# endif /* CONFIG_SERIAL_8250_RSA */
/*
* This is a quickie test to see how big the FIFO is .
* It doesn ' t work at all the time , more ' s the pity .
*/
static int size_fifo ( struct uart_8250_port * up )
{
unsigned char old_fcr , old_mcr , old_dll , old_dlm , old_lcr ;
int count ;
old_lcr = serial_inp ( up , UART_LCR ) ;
serial_outp ( up , UART_LCR , 0 ) ;
old_fcr = serial_inp ( up , UART_FCR ) ;
old_mcr = serial_inp ( up , UART_MCR ) ;
serial_outp ( up , UART_FCR , UART_FCR_ENABLE_FIFO |
UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT ) ;
serial_outp ( up , UART_MCR , UART_MCR_LOOP ) ;
serial_outp ( up , UART_LCR , UART_LCR_DLAB ) ;
old_dll = serial_inp ( up , UART_DLL ) ;
old_dlm = serial_inp ( up , UART_DLM ) ;
serial_outp ( up , UART_DLL , 0x01 ) ;
serial_outp ( up , UART_DLM , 0x00 ) ;
serial_outp ( up , UART_LCR , 0x03 ) ;
for ( count = 0 ; count < 256 ; count + + )
serial_outp ( up , UART_TX , count ) ;
mdelay ( 20 ) ; /* FIXME - schedule_timeout */
for ( count = 0 ; ( serial_inp ( up , UART_LSR ) & UART_LSR_DR ) & &
( count < 256 ) ; count + + )
serial_inp ( up , UART_RX ) ;
serial_outp ( up , UART_FCR , old_fcr ) ;
serial_outp ( up , UART_MCR , old_mcr ) ;
serial_outp ( up , UART_LCR , UART_LCR_DLAB ) ;
serial_outp ( up , UART_DLL , old_dll ) ;
serial_outp ( up , UART_DLM , old_dlm ) ;
serial_outp ( up , UART_LCR , old_lcr ) ;
return count ;
}
/*
* Read UART ID using the divisor method - set DLL and DLM to zero
* and the revision will be in DLL and device type in DLM . We
* preserve the device state across this .
*/
static unsigned int autoconfig_read_divisor_id ( struct uart_8250_port * p )
{
unsigned char old_dll , old_dlm , old_lcr ;
unsigned int id ;
old_lcr = serial_inp ( p , UART_LCR ) ;
serial_outp ( p , UART_LCR , UART_LCR_DLAB ) ;
old_dll = serial_inp ( p , UART_DLL ) ;
old_dlm = serial_inp ( p , UART_DLM ) ;
serial_outp ( p , UART_DLL , 0 ) ;
serial_outp ( p , UART_DLM , 0 ) ;
id = serial_inp ( p , UART_DLL ) | serial_inp ( p , UART_DLM ) < < 8 ;
serial_outp ( p , UART_DLL , old_dll ) ;
serial_outp ( p , UART_DLM , old_dlm ) ;
serial_outp ( p , UART_LCR , old_lcr ) ;
return id ;
}
/*
* This is a helper routine to autodetect StarTech / Exar / Oxsemi UART ' s .
* When this function is called we know it is at least a StarTech
* 16650 V2 , but it might be one of several StarTech UARTs , or one of
* its clones . ( We treat the broken original StarTech 16650 V1 as a
* 16550 , and why not ? Startech doesn ' t seem to even acknowledge its
* existence . )
*
* What evil have men ' s minds wrought . . .
*/
static void autoconfig_has_efr ( struct uart_8250_port * up )
{
unsigned int id1 , id2 , id3 , rev ;
/*
* Everything with an EFR has SLEEP
*/
up - > capabilities | = UART_CAP_EFR | UART_CAP_SLEEP ;
/*
* First we check to see if it ' s an Oxford Semiconductor UART .
*
* If we have to do this here because some non - National
* Semiconductor clone chips lock up if you try writing to the
* LSR register ( which serial_icr_read does )
*/
/*
* Check for Oxford Semiconductor 16 C950 .
*
* EFR [ 4 ] must be set else this test fails .
*
* This shouldn ' t be necessary , but Mike Hudson ( Exoray @ isys . ca )
* claims that it ' s needed for 952 dual UART ' s ( which are not
* recommended for new designs ) .
*/
up - > acr = 0 ;
serial_out ( up , UART_LCR , 0xBF ) ;
serial_out ( up , UART_EFR , UART_EFR_ECB ) ;
serial_out ( up , UART_LCR , 0x00 ) ;
id1 = serial_icr_read ( up , UART_ID1 ) ;
id2 = serial_icr_read ( up , UART_ID2 ) ;
id3 = serial_icr_read ( up , UART_ID3 ) ;
rev = serial_icr_read ( up , UART_REV ) ;
DEBUG_AUTOCONF ( " 950id=%02x:%02x:%02x:%02x " , id1 , id2 , id3 , rev ) ;
if ( id1 = = 0x16 & & id2 = = 0xC9 & &
( id3 = = 0x50 | | id3 = = 0x52 | | id3 = = 0x54 ) ) {
up - > port . type = PORT_16C950 ;
2005-06-23 13:43:04 +04:00
/*
* Enable work around for the Oxford Semiconductor 952 rev B
* chip which causes it to seriously miscalculate baud rates
* when DLL is 0.
*/
if ( id3 = = 0x52 & & rev = = 0x01 )
up - > bugs | = UART_BUG_QUOT ;
2005-04-17 02:20:36 +04:00
return ;
}
/*
* We check for a XR16C850 by setting DLL and DLM to 0 , and then
* reading back DLL and DLM . The chip type depends on the DLM
* value read back :
* 0x10 - XR16C850 and the DLL contains the chip revision .
* 0x12 - XR16C2850 .
* 0x14 - XR16C854 .
*/
id1 = autoconfig_read_divisor_id ( up ) ;
DEBUG_AUTOCONF ( " 850id=%04x " , id1 ) ;
id2 = id1 > > 8 ;
if ( id2 = = 0x10 | | id2 = = 0x12 | | id2 = = 0x14 ) {
up - > port . type = PORT_16850 ;
return ;
}
/*
* It wasn ' t an XR16C850 .
*
* We distinguish between the ' 654 and the ' 650 by counting
* how many bytes are in the FIFO . I ' m using this for now ,
* since that ' s the technique that was sent to me in the
* serial driver update , but I ' m not convinced this works .
* I ' ve had problems doing this in the past . - TYT
*/
if ( size_fifo ( up ) = = 64 )
up - > port . type = PORT_16654 ;
else
up - > port . type = PORT_16650V2 ;
}
/*
* We detected a chip without a FIFO . Only two fall into
* this category - the original 8250 and the 16450. The
* 16450 has a scratch register ( accessible with LCR = 0 )
*/
static void autoconfig_8250 ( struct uart_8250_port * up )
{
unsigned char scratch , status1 , status2 ;
up - > port . type = PORT_8250 ;
scratch = serial_in ( up , UART_SCR ) ;
serial_outp ( up , UART_SCR , 0xa5 ) ;
status1 = serial_in ( up , UART_SCR ) ;
serial_outp ( up , UART_SCR , 0x5a ) ;
status2 = serial_in ( up , UART_SCR ) ;
serial_outp ( up , UART_SCR , scratch ) ;
if ( status1 = = 0xa5 & & status2 = = 0x5a )
up - > port . type = PORT_16450 ;
}
static int broken_efr ( struct uart_8250_port * up )
{
/*
* Exar ST16C2550 " A2 " devices incorrectly detect as
* having an EFR , and report an ID of 0x0201 . See
* http : //www.exar.com/info.php?pdf=dan180_oct2004.pdf
*/
if ( autoconfig_read_divisor_id ( up ) = = 0x0201 & & size_fifo ( up ) = = 16 )
return 1 ;
return 0 ;
}
/*
* We know that the chip has FIFOs . Does it have an EFR ? The
* EFR is located in the same register position as the IIR and
* we know the top two bits of the IIR are currently set . The
* EFR should contain zero . Try to read the EFR .
*/
static void autoconfig_16550a ( struct uart_8250_port * up )
{
unsigned char status1 , status2 ;
unsigned int iersave ;
up - > port . type = PORT_16550A ;
up - > capabilities | = UART_CAP_FIFO ;
/*
* Check for presence of the EFR when DLAB is set .
* Only ST16C650V1 UARTs pass this test .
*/
serial_outp ( up , UART_LCR , UART_LCR_DLAB ) ;
if ( serial_in ( up , UART_EFR ) = = 0 ) {
serial_outp ( up , UART_EFR , 0xA8 ) ;
if ( serial_in ( up , UART_EFR ) ! = 0 ) {
DEBUG_AUTOCONF ( " EFRv1 " ) ;
up - > port . type = PORT_16650 ;
up - > capabilities | = UART_CAP_EFR | UART_CAP_SLEEP ;
} else {
DEBUG_AUTOCONF ( " Motorola 8xxx DUART " ) ;
}
serial_outp ( up , UART_EFR , 0 ) ;
return ;
}
/*
* Maybe it requires 0xbf to be written to the LCR .
* ( other ST16C650V2 UARTs , TI16C752A , etc )
*/
serial_outp ( up , UART_LCR , 0xBF ) ;
if ( serial_in ( up , UART_EFR ) = = 0 & & ! broken_efr ( up ) ) {
DEBUG_AUTOCONF ( " EFRv2 " ) ;
autoconfig_has_efr ( up ) ;
return ;
}
/*
* Check for a National Semiconductor SuperIO chip .
* Attempt to switch to bank 2 , read the value of the LOOP bit
* from EXCR1 . Switch back to bank 0 , change it in MCR . Then
* switch back to bank 2 , read it from EXCR1 again and check
* it ' s changed . If so , set baud_base in EXCR2 to 921600. - - dwmw2
*/
serial_outp ( up , UART_LCR , 0 ) ;
status1 = serial_in ( up , UART_MCR ) ;
serial_outp ( up , UART_LCR , 0xE0 ) ;
status2 = serial_in ( up , 0x02 ) ; /* EXCR1 */
if ( ! ( ( status2 ^ status1 ) & UART_MCR_LOOP ) ) {
serial_outp ( up , UART_LCR , 0 ) ;
serial_outp ( up , UART_MCR , status1 ^ UART_MCR_LOOP ) ;
serial_outp ( up , UART_LCR , 0xE0 ) ;
status2 = serial_in ( up , 0x02 ) ; /* EXCR1 */
serial_outp ( up , UART_LCR , 0 ) ;
serial_outp ( up , UART_MCR , status1 ) ;
if ( ( status2 ^ status1 ) & UART_MCR_LOOP ) {
2005-05-21 18:52:23 +04:00
unsigned short quot ;
2005-04-17 02:20:36 +04:00
serial_outp ( up , UART_LCR , 0xE0 ) ;
2005-05-21 18:52:23 +04:00
quot = serial_inp ( up , UART_DLM ) < < 8 ;
quot + = serial_inp ( up , UART_DLL ) ;
quot < < = 3 ;
2005-04-17 02:20:36 +04:00
status1 = serial_in ( up , 0x04 ) ; /* EXCR1 */
status1 & = ~ 0xB0 ; /* Disable LOCK, mask out PRESL[01] */
status1 | = 0x10 ; /* 1.625 divisor for baud_base --> 921600 */
serial_outp ( up , 0x04 , status1 ) ;
2005-05-21 18:52:23 +04:00
serial_outp ( up , UART_DLL , quot & 0xff ) ;
serial_outp ( up , UART_DLM , quot > > 8 ) ;
2005-04-17 02:20:36 +04:00
serial_outp ( up , UART_LCR , 0 ) ;
2005-05-21 18:52:23 +04:00
up - > port . uartclk = 921600 * 16 ;
2005-04-17 02:20:36 +04:00
up - > port . type = PORT_NS16550A ;
up - > capabilities | = UART_NATSEMI ;
return ;
}
}
/*
* No EFR . Try to detect a TI16750 , which only sets bit 5 of
* the IIR when 64 byte FIFO mode is enabled when DLAB is set .
* Try setting it with and without DLAB set . Cheap clones
* set bit 5 without DLAB set .
*/
serial_outp ( up , UART_LCR , 0 ) ;
serial_outp ( up , UART_FCR , UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE ) ;
status1 = serial_in ( up , UART_IIR ) > > 5 ;
serial_outp ( up , UART_FCR , UART_FCR_ENABLE_FIFO ) ;
serial_outp ( up , UART_LCR , UART_LCR_DLAB ) ;
serial_outp ( up , UART_FCR , UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE ) ;
status2 = serial_in ( up , UART_IIR ) > > 5 ;
serial_outp ( up , UART_FCR , UART_FCR_ENABLE_FIFO ) ;
serial_outp ( up , UART_LCR , 0 ) ;
DEBUG_AUTOCONF ( " iir1=%d iir2=%d " , status1 , status2 ) ;
if ( status1 = = 6 & & status2 = = 7 ) {
up - > port . type = PORT_16750 ;
up - > capabilities | = UART_CAP_AFE | UART_CAP_SLEEP ;
return ;
}
/*
* Try writing and reading the UART_IER_UUE bit ( b6 ) .
* If it works , this is probably one of the Xscale platform ' s
* internal UARTs .
* We ' re going to explicitly set the UUE bit to 0 before
* trying to write and read a 1 just to make sure it ' s not
* already a 1 and maybe locked there before we even start start .
*/
iersave = serial_in ( up , UART_IER ) ;
serial_outp ( up , UART_IER , iersave & ~ UART_IER_UUE ) ;
if ( ! ( serial_in ( up , UART_IER ) & UART_IER_UUE ) ) {
/*
* OK it ' s in a known zero state , try writing and reading
* without disturbing the current state of the other bits .
*/
serial_outp ( up , UART_IER , iersave | UART_IER_UUE ) ;
if ( serial_in ( up , UART_IER ) & UART_IER_UUE ) {
/*
* It ' s an Xscale .
* We ' ll leave the UART_IER_UUE bit set to 1 ( enabled ) .
*/
DEBUG_AUTOCONF ( " Xscale " ) ;
up - > port . type = PORT_XSCALE ;
up - > capabilities | = UART_CAP_UUE ;
return ;
}
} else {
/*
* If we got here we couldn ' t force the IER_UUE bit to 0.
* Log it and continue .
*/
DEBUG_AUTOCONF ( " Couldn't force IER_UUE to 0 " ) ;
}
serial_outp ( up , UART_IER , iersave ) ;
}
/*
* 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 status1 , scratch , scratch2 , scratch3 ;
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%p): " ,
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();
up - > capabilities = 0 ;
2005-06-23 13:43:04 +04:00
up - > bugs = 0 ;
2005-04-17 02:20:36 +04:00
if ( ! ( up - > port . flags & UPF_BUGGY_UART ) ) {
/*
* Do a simple existence test first ; if we fail this ,
* there ' s no point trying anything else .
*
* 0x80 is used as a nonsense port to prevent against
* false positives due to ISA bus float . The
* assumption is that 0x80 is a non - existent port ;
* which should be safe since include / asm / io . h also
* makes this assumption .
*
* Note : this is safe as long as MCR bit 4 is clear
* and the device is in " PC " mode .
*/
scratch = serial_inp ( up , UART_IER ) ;
serial_outp ( up , UART_IER , 0 ) ;
# ifdef __i386__
outb ( 0xff , 0x080 ) ;
# endif
scratch2 = serial_inp ( up , UART_IER ) ;
serial_outp ( up , UART_IER , 0x0F ) ;
# ifdef __i386__
outb ( 0 , 0x080 ) ;
# endif
scratch3 = serial_inp ( up , UART_IER ) ;
serial_outp ( up , UART_IER , scratch ) ;
if ( scratch2 ! = 0 | | scratch3 ! = 0x0F ) {
/*
* We failed ; there ' s nothing here
*/
DEBUG_AUTOCONF ( " IER test failed (%02x, %02x) " ,
scratch2 , scratch3 ) ;
goto out ;
}
}
save_mcr = serial_in ( up , UART_MCR ) ;
save_lcr = serial_in ( up , UART_LCR ) ;
/*
* Check to see if a UART is really there . Certain broken
* internal modems based on the Rockwell chipset fail this
* test , because they apparently don ' t implement the loopback
* test mode . So this test is skipped on the COM 1 through
* COM 4 ports . This * should * be safe , since no board
* manufacturer would be stupid enough to design a board
* that conflicts with COM 1 - 4 - - - we hope !
*/
if ( ! ( up - > port . flags & UPF_SKIP_TEST ) ) {
serial_outp ( up , UART_MCR , UART_MCR_LOOP | 0x0A ) ;
status1 = serial_inp ( up , UART_MSR ) & 0xF0 ;
serial_outp ( up , UART_MCR , save_mcr ) ;
if ( status1 ! = 0x90 ) {
DEBUG_AUTOCONF ( " LOOP test failed (%02x) " ,
status1 ) ;
goto out ;
}
}
/*
* We ' re pretty sure there ' s a port here . Lets find out what
* type of port it is . The IIR top two bits allows us to find
* out if its 8250 or 16450 , 16550 , 16550 A or later . This
* determines what we test for next .
*
* We also initialise the EFR ( if any ) to zero for later . The
* EFR occupies the same register location as the FCR and IIR .
*/
serial_outp ( up , UART_LCR , 0xBF ) ;
serial_outp ( up , UART_EFR , 0 ) ;
serial_outp ( up , UART_LCR , 0 ) ;
serial_outp ( up , UART_FCR , UART_FCR_ENABLE_FIFO ) ;
scratch = serial_in ( up , UART_IIR ) > > 6 ;
DEBUG_AUTOCONF ( " iir=%d " , scratch ) ;
switch ( scratch ) {
case 0 :
autoconfig_8250 ( up ) ;
break ;
case 1 :
up - > port . type = PORT_UNKNOWN ;
break ;
case 2 :
up - > port . type = PORT_16550 ;
break ;
case 3 :
autoconfig_16550a ( up ) ;
break ;
}
# ifdef CONFIG_SERIAL_8250_RSA
/*
* Only probe for RSA ports if we got the region .
*/
if ( up - > port . type = = PORT_16550A & & probeflags & PROBE_RSA ) {
int i ;
for ( i = 0 ; i < probe_rsa_count ; + + i ) {
if ( probe_rsa [ i ] = = up - > port . iobase & &
__enable_rsa ( up ) ) {
up - > port . type = PORT_RSA ;
break ;
}
}
}
# endif
serial_outp ( up , UART_LCR , save_lcr ) ;
if ( up - > capabilities ! = uart_config [ up - > port . type ] . flags ) {
printk ( KERN_WARNING
" ttyS%d: detected caps %08x should be %08x \n " ,
up - > port . line , up - > capabilities ,
uart_config [ up - > port . type ] . flags ) ;
}
up - > port . fifosize = uart_config [ up - > port . type ] . fifo_size ;
up - > capabilities = uart_config [ up - > port . type ] . flags ;
up - > tx_loadsz = uart_config [ up - > port . type ] . tx_loadsz ;
if ( up - > port . type = = PORT_UNKNOWN )
goto out ;
/*
* Reset the UART .
*/
# ifdef CONFIG_SERIAL_8250_RSA
if ( up - > port . type = = PORT_RSA )
serial_outp ( up , UART_RSA_FRR , 0 ) ;
# endif
serial_outp ( up , UART_MCR , save_mcr ) ;
serial8250_clear_fifos ( up ) ;
( 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 ) ;
}
static void autoconfig_irq ( struct uart_8250_port * up )
{
unsigned char save_mcr , save_ier ;
unsigned char save_ICP = 0 ;
unsigned int ICP = 0 ;
unsigned long irqs ;
int irq ;
if ( up - > port . flags & UPF_FOURPORT ) {
ICP = ( up - > port . iobase & 0xfe0 ) | 0x1f ;
save_ICP = inb_p ( ICP ) ;
outb_p ( 0x80 , ICP ) ;
( void ) inb_p ( ICP ) ;
}
/* forget possible initially masked and pending IRQ */
probe_irq_off ( probe_irq_on ( ) ) ;
save_mcr = serial_inp ( up , UART_MCR ) ;
save_ier = serial_inp ( up , UART_IER ) ;
serial_outp ( up , UART_MCR , UART_MCR_OUT1 | UART_MCR_OUT2 ) ;
irqs = probe_irq_on ( ) ;
serial_outp ( up , UART_MCR , 0 ) ;
udelay ( 10 ) ;
if ( up - > port . flags & UPF_FOURPORT ) {
serial_outp ( up , UART_MCR ,
UART_MCR_DTR | UART_MCR_RTS ) ;
} else {
serial_outp ( up , UART_MCR ,
UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2 ) ;
}
serial_outp ( up , UART_IER , 0x0f ) ; /* enable all intrs */
( void ) serial_inp ( up , UART_LSR ) ;
( void ) serial_inp ( up , UART_RX ) ;
( void ) serial_inp ( up , UART_IIR ) ;
( void ) serial_inp ( up , UART_MSR ) ;
serial_outp ( up , UART_TX , 0xFF ) ;
udelay ( 20 ) ;
irq = probe_irq_off ( irqs ) ;
serial_outp ( up , UART_MCR , save_mcr ) ;
serial_outp ( up , UART_IER , save_ier ) ;
if ( up - > port . flags & UPF_FOURPORT )
outb_p ( save_ICP , ICP ) ;
up - > port . irq = ( irq > 0 ) ? irq : 0 ;
}
2005-06-29 21:41:51 +04:00
static inline void __stop_tx ( struct uart_8250_port * p )
{
if ( p - > ier & UART_IER_THRI ) {
p - > ier & = ~ UART_IER_THRI ;
serial_out ( p , UART_IER , p - > ier ) ;
}
}
2005-04-17 02:20:36 +04:00
static void serial8250_stop_tx ( struct uart_port * port , unsigned int tty_stop )
{
struct uart_8250_port * up = ( struct uart_8250_port * ) port ;
2005-06-29 21:41:51 +04:00
__stop_tx ( up ) ;
2005-04-17 02:20:36 +04:00
/*
2005-06-29 21:41:51 +04:00
* We really want to stop the transmitter from sending .
2005-04-17 02:20:36 +04:00
*/
2005-06-29 21:41:51 +04:00
if ( up - > port . type = = PORT_16C950 ) {
2005-04-17 02:20:36 +04:00
up - > acr | = UART_ACR_TXDIS ;
serial_icr_write ( up , UART_ACR , up - > acr ) ;
}
}
2005-06-23 18:05:41 +04:00
static void transmit_chars ( struct uart_8250_port * up ) ;
2005-04-17 02:20:36 +04:00
static void serial8250_start_tx ( struct uart_port * port , unsigned int tty_start )
{
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-06-23 18:05:41 +04:00
2005-06-24 01:26:43 +04:00
if ( up - > bugs & UART_BUG_TXEN ) {
2005-06-23 18:05:41 +04:00
unsigned char lsr , iir ;
lsr = serial_in ( up , UART_LSR ) ;
iir = serial_in ( up , UART_IIR ) ;
if ( lsr & UART_LSR_TEMT & & iir & UART_IIR_NO_INT )
transmit_chars ( up ) ;
}
2005-04-17 02:20:36 +04:00
}
2005-06-29 21:41:51 +04:00
2005-04-17 02:20:36 +04:00
/*
2005-06-29 21:41:51 +04:00
* Re - enable the transmitter if we disabled it .
2005-04-17 02:20:36 +04:00
*/
2005-06-29 21:41:51 +04:00
if ( up - > port . type = = PORT_16C950 & & up - > acr & UART_ACR_TXDIS ) {
2005-04-17 02:20:36 +04:00
up - > acr & = ~ UART_ACR_TXDIS ;
serial_icr_write ( up , UART_ACR , up - > acr ) ;
}
}
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 , lsr = * status ;
int max_count = 256 ;
char flag ;
do {
/* The following is not allowed by the tty layer and
unsafe . It should be fixed ASAP */
if ( unlikely ( tty - > flip . count > = TTY_FLIPBUF_SIZE ) ) {
if ( tty - > low_latency ) {
spin_unlock ( & up - > port . lock ) ;
tty_flip_buffer_push ( tty ) ;
spin_lock ( & up - > port . lock ) ;
}
2005-04-17 02:26:39 +04:00
/*
* If this failed then we will throw away the
* bytes but must do so to clear interrupts
*/
2005-04-17 02:20:36 +04:00
}
ch = serial_inp ( up , UART_RX ) ;
flag = TTY_NORMAL ;
up - > port . icount . rx + + ;
# ifdef CONFIG_SERIAL_8250_CONSOLE
/*
* Recover the break flag from console xmit
*/
if ( up - > port . line = = up - > port . cons - > index ) {
lsr | = up - > lsr_break_flag ;
up - > lsr_break_flag = 0 ;
}
# endif
if ( unlikely ( lsr & ( UART_LSR_BI | UART_LSR_PE |
UART_LSR_FE | UART_LSR_OE ) ) ) {
/*
* For statistics only
*/
if ( lsr & UART_LSR_BI ) {
lsr & = ~ ( 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 ( lsr & UART_LSR_PE )
up - > port . icount . parity + + ;
else if ( lsr & UART_LSR_FE )
up - > port . icount . frame + + ;
if ( lsr & UART_LSR_OE )
up - > port . icount . overrun + + ;
/*
2005-04-17 02:26:39 +04:00
* Mask off conditions which should be ignored .
2005-04-17 02:20:36 +04:00
*/
lsr & = up - > port . read_status_mask ;
if ( lsr & UART_LSR_BI ) {
DEBUG_INTR ( " handling break.... " ) ;
flag = TTY_BREAK ;
} else if ( lsr & UART_LSR_PE )
flag = TTY_PARITY ;
else if ( lsr & UART_LSR_FE )
flag = TTY_FRAME ;
}
if ( uart_handle_sysrq_char ( & up - > port , ch , regs ) )
goto ignore_char ;
2005-05-10 02:21:59 +04:00
uart_insert_char ( & up - > port , lsr , UART_LSR_OE , ch , flag ) ;
2005-04-17 02:20:36 +04:00
ignore_char :
lsr = serial_inp ( up , UART_LSR ) ;
} while ( ( lsr & UART_LSR_DR ) & & ( max_count - - > 0 ) ) ;
spin_unlock ( & up - > port . lock ) ;
tty_flip_buffer_push ( tty ) ;
spin_lock ( & up - > port . lock ) ;
* status = lsr ;
}
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-06-29 21:41:51 +04:00
__stop_tx ( up ) ;
2005-04-17 02:20:36 +04:00
return ;
}
count = up - > tx_loadsz ;
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-06-29 21:41:51 +04:00
__stop_tx ( up ) ;
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 , handled = 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 ) ;
handled = 1 ;
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 " ) ;
return IRQ_RETVAL ( 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 | up - > mcr ;
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 ;
2005-06-23 18:05:41 +04:00
unsigned char lsr , iir ;
2005-04-17 02:20:36 +04:00
int retval ;
up - > capabilities = uart_config [ up - > port . type ] . flags ;
up - > mcr = 0 ;
if ( up - > port . type = = PORT_16C950 ) {
/* Wake up and initialize UART */
up - > acr = 0 ;
serial_outp ( up , UART_LCR , 0xBF ) ;
serial_outp ( up , UART_EFR , UART_EFR_ECB ) ;
serial_outp ( up , UART_IER , 0 ) ;
serial_outp ( up , UART_LCR , 0 ) ;
serial_icr_write ( up , UART_CSR , 0 ) ; /* Reset the UART */
serial_outp ( up , UART_LCR , 0xBF ) ;
serial_outp ( up , UART_EFR , UART_EFR_ECB ) ;
serial_outp ( up , UART_LCR , 0 ) ;
}
# ifdef CONFIG_SERIAL_8250_RSA
/*
* If this is an RSA port , see if we can kick it up to the
* higher speed clock .
*/
enable_rsa ( up ) ;
# endif
/*
* Clear the FIFO buffers and disable them .
* ( they will be reeanbled in set_termios ( ) )
*/
serial8250_clear_fifos ( up ) ;
/*
* 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 ;
}
/*
* For a XR16C850 , we need to set the trigger levels
*/
if ( up - > port . type = = PORT_16850 ) {
unsigned char fctr ;
serial_outp ( up , UART_LCR , 0xbf ) ;
fctr = serial_inp ( up , UART_FCTR ) & ~ ( UART_FCTR_RX | UART_FCTR_TX ) ;
serial_outp ( up , UART_FCTR , fctr | UART_FCTR_TRGD | UART_FCTR_RX ) ;
serial_outp ( up , UART_TRG , UART_TRG_96 ) ;
serial_outp ( up , UART_FCTR , fctr | UART_FCTR_TRGD | UART_FCTR_TX ) ;
serial_outp ( up , UART_TRG , UART_TRG_96 ) ;
serial_outp ( up , UART_LCR , 0 ) ;
}
/*
* If the " interrupt " for this port doesn ' t correspond with any
* hardware interrupt , we use a timer - based system . The original
* driver used to do this with IRQ0 .
*/
if ( ! is_real_interrupt ( up - > port . irq ) ) {
unsigned int timeout = up - > port . timeout ;
timeout = timeout > 6 ? ( timeout / 2 - 2 ) : 1 ;
up - > timer . data = ( unsigned long ) up ;
mod_timer ( & up - > timer , jiffies + timeout ) ;
} else {
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 ) ;
2005-06-23 18:05:41 +04:00
/*
* Do a quick test to see if we receive an
* interrupt when we enable the TX irq .
*/
serial_outp ( up , UART_IER , UART_IER_THRI ) ;
lsr = serial_in ( up , UART_LSR ) ;
iir = serial_in ( up , UART_IIR ) ;
serial_outp ( up , UART_IER , 0 ) ;
if ( lsr & UART_LSR_TEMT & & iir & UART_IIR_NO_INT ) {
2005-06-24 01:26:43 +04:00
if ( ! ( up - > bugs & UART_BUG_TXEN ) ) {
up - > bugs | = UART_BUG_TXEN ;
2005-06-23 18:05:41 +04:00
pr_debug ( " ttyS%d - enabling bad tx status workarounds \n " ,
port - > line ) ;
}
} else {
2005-06-24 01:26:43 +04:00
up - > bugs & = ~ UART_BUG_TXEN ;
2005-06-23 18:05:41 +04:00
}
2005-04-17 02:20:36 +04:00
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 ) ;
serial8250_clear_fifos ( up ) ;
# ifdef CONFIG_SERIAL_8250_RSA
/*
* Reset the RSA board back to 115 kbps compat mode .
*/
disable_rsa ( up ) ;
# endif
/*
* 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 ) ;
/*
2005-06-23 13:43:04 +04:00
* Oxford Semi 952 rev B workaround
2005-04-17 02:20:36 +04:00
*/
2005-06-23 13:43:04 +04:00
if ( up - > bugs & UART_BUG_QUOT & & ( quot & 0xff ) = = 0 )
2005-04-17 02:20:36 +04:00
quot + + ;
if ( up - > capabilities & UART_CAP_FIFO & & up - > port . fifosize > 1 ) {
if ( baud < 2400 )
fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1 ;
else
fcr = uart_config [ up - > port . type ] . fcr ;
}
/*
* MCR - based auto flow control . When AFE is enabled , RTS will be
* deasserted when the receive FIFO contains more characters than
* the trigger , or the MCR RTS bit is cleared . In the case where
* the remote UART is not using CTS auto flow control , we must
* have sufficient FIFO entries for the latency of the remote
* UART to respond . IOW , at least 32 bytes of FIFO .
*/
if ( up - > capabilities & UART_CAP_AFE & & up - > port . fifosize > = 32 ) {
up - > mcr & = ~ UART_MCR_AFE ;
if ( termios - > c_cflag & CRTSCTS )
up - > mcr | = UART_MCR_AFE ;
}
/*
* 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 ;
if ( up - > capabilities & UART_CAP_UUE )
up - > ier | = UART_IER_UUE | UART_IER_RTOIE ;
serial_out ( up , UART_IER , up - > ier ) ;
if ( up - > capabilities & UART_CAP_EFR ) {
unsigned char efr = 0 ;
/*
* TI16C752 / Startech hardware flow control . FIXME :
* - TI16C752 requires control thresholds to be set .
* - UART_MCR_RTS is ineffective if auto - RTS mode is enabled .
*/
if ( termios - > c_cflag & CRTSCTS )
efr | = UART_EFR_CTS ;
serial_outp ( up , UART_LCR , 0xBF ) ;
serial_outp ( up , UART_EFR , efr ) ;
}
if ( up - > capabilities & UART_NATSEMI ) {
/* Switch to bank 2 not bank 1, to avoid resetting EXCR2 */
serial_outp ( up , UART_LCR , 0xe0 ) ;
} else {
serial_outp ( up , UART_LCR , cval | UART_LCR_DLAB ) ; /* set DLAB */
}
serial_outp ( up , UART_DLL , quot & 0xff ) ; /* LS of divisor */
serial_outp ( up , UART_DLM , quot > > 8 ) ; /* MS of divisor */
/*
* LCR DLAB must be set to enable 64 - byte FIFO mode . If the FCR
* is written without DLAB set , this mode will be disabled .
*/
if ( up - > port . type = = PORT_16750 )
serial_outp ( up , UART_FCR , fcr ) ;
serial_outp ( up , UART_LCR , cval ) ; /* reset DLAB */
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 */
}
serial8250_set_mctrl ( & up - > port , up - > port . mctrl ) ;
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 * p = ( struct uart_8250_port * ) port ;
serial8250_set_sleep ( p , state ! = 0 ) ;
if ( p - > pm )
p - > pm ( port , state , oldstate ) ;
}
/*
* Resource handling .
*/
static int serial8250_request_std_resource ( struct uart_8250_port * up )
{
unsigned int size = 8 < < up - > port . regshift ;
int ret = 0 ;
switch ( up - > port . iotype ) {
case UPIO_MEM :
if ( ! up - > port . mapbase )
break ;
if ( ! request_mem_region ( up - > port . mapbase , size , " serial " ) ) {
ret = - EBUSY ;
break ;
}
if ( up - > port . flags & UPF_IOREMAP ) {
up - > port . membase = ioremap ( up - > port . mapbase , size ) ;
if ( ! up - > port . membase ) {
release_mem_region ( up - > port . mapbase , size ) ;
ret = - ENOMEM ;
}
}
break ;
case UPIO_HUB6 :
case UPIO_PORT :
if ( ! request_region ( up - > port . iobase , size , " serial " ) )
ret = - EBUSY ;
break ;
}
return ret ;
}
static void serial8250_release_std_resource ( struct uart_8250_port * up )
{
unsigned int size = 8 < < up - > port . regshift ;
switch ( up - > port . iotype ) {
case UPIO_MEM :
if ( ! up - > port . mapbase )
break ;
if ( up - > port . flags & UPF_IOREMAP ) {
iounmap ( up - > port . membase ) ;
up - > port . membase = NULL ;
}
release_mem_region ( up - > port . mapbase , size ) ;
break ;
case UPIO_HUB6 :
case UPIO_PORT :
release_region ( up - > port . iobase , size ) ;
break ;
}
}
static int serial8250_request_rsa_resource ( struct uart_8250_port * up )
{
unsigned long start = UART_RSA_BASE < < up - > port . regshift ;
unsigned int size = 8 < < up - > port . regshift ;
int ret = 0 ;
switch ( up - > port . iotype ) {
case UPIO_MEM :
ret = - EINVAL ;
break ;
case UPIO_HUB6 :
case UPIO_PORT :
start + = up - > port . iobase ;
if ( ! request_region ( start , size , " serial-rsa " ) )
ret = - EBUSY ;
break ;
}
return ret ;
}
static void serial8250_release_rsa_resource ( struct uart_8250_port * up )
{
unsigned long offset = UART_RSA_BASE < < up - > port . regshift ;
unsigned int size = 8 < < up - > port . regshift ;
switch ( up - > port . iotype ) {
case UPIO_MEM :
break ;
case UPIO_HUB6 :
case UPIO_PORT :
release_region ( up - > port . iobase + offset , size ) ;
break ;
}
}
static void serial8250_release_port ( struct uart_port * port )
{
struct uart_8250_port * up = ( struct uart_8250_port * ) port ;
serial8250_release_std_resource ( up ) ;
if ( up - > port . type = = PORT_RSA )
serial8250_release_rsa_resource ( up ) ;
}
static int serial8250_request_port ( struct uart_port * port )
{
struct uart_8250_port * up = ( struct uart_8250_port * ) port ;
int ret = 0 ;
ret = serial8250_request_std_resource ( up ) ;
if ( ret = = 0 & & up - > port . type = = PORT_RSA ) {
ret = serial8250_request_rsa_resource ( up ) ;
if ( ret < 0 )
serial8250_release_std_resource ( up ) ;
}
return ret ;
}
static void serial8250_config_port ( struct uart_port * port , int flags )
{
struct uart_8250_port * up = ( struct uart_8250_port * ) port ;
int probeflags = PROBE_ANY ;
int ret ;
/*
* Don ' t probe for MCA ports on non - MCA machines .
*/
if ( up - > port . flags & UPF_BOOT_ONLYMCA & & ! MCA_bus )
return ;
/*
* Find the region that we can probe for . This in turn
* tells us whether we can probe for the type of port .
*/
ret = serial8250_request_std_resource ( up ) ;
if ( ret < 0 )
return ;
ret = serial8250_request_rsa_resource ( up ) ;
if ( ret < 0 )
probeflags & = ~ PROBE_RSA ;
if ( flags & UART_CONFIG_TYPE )
autoconfig ( up , probeflags ) ;
if ( up - > port . type ! = PORT_UNKNOWN & & flags & UART_CONFIG_IRQ )
autoconfig_irq ( up ) ;
if ( up - > port . type ! = PORT_RSA & & probeflags & PROBE_RSA )
serial8250_release_rsa_resource ( up ) ;
if ( up - > port . type = = PORT_UNKNOWN )
serial8250_release_std_resource ( up ) ;
}
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 > = ARRAY_SIZE ( uart_config ) | | 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 ; i < UART_NR ; i + + ) {
struct uart_8250_port * up = & serial8250_ports [ i ] ;
up - > port . line = i ;
spin_lock_init ( & up - > port . lock ) ;
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 ;
up - > port . ops = & serial8250_pops ;
}
2005-07-01 01:41:22 +04:00
for ( i = 0 , up = serial8250_ports ;
i < ARRAY_SIZE ( old_serial_port ) & & i < UART_NR ;
2005-04-17 02:20:36 +04:00
i + + , up + + ) {
up - > port . iobase = old_serial_port [ i ] . port ;
up - > port . irq = irq_canonicalize ( old_serial_port [ i ] . irq ) ;
up - > port . uartclk = old_serial_port [ i ] . baud_base * 16 ;
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 ;
if ( share_irqs )
up - > port . flags | = UPF_SHARE_IRQ ;
}
}
static void __init
serial8250_register_ports ( struct uart_driver * drv , struct device * dev )
{
int i ;
serial8250_isa_init_ports ( ) ;
for ( i = 0 ; i < UART_NR ; i + + ) {
struct uart_8250_port * up = & serial8250_ports [ i ] ;
up - > port . dev = dev ;
uart_add_one_port ( drv , & up - > port ) ;
}
}
# ifdef CONFIG_SERIAL_8250_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 ) ;
if ( up - > capabilities & UART_CAP_UUE )
serial_out ( up , UART_IER , UART_IER_UUE ) ;
else
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 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 ;
if ( ! port - > iobase & & ! port - > membase )
return - ENODEV ;
if ( options )
uart_parse_options ( options , & baud , & parity , & bits , & flow ) ;
return uart_set_options ( port , co , baud , parity , bits , flow ) ;
}
static 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 ) ;
static int __init find_port ( struct uart_port * p )
{
int line ;
struct uart_port * port ;
for ( line = 0 ; line < UART_NR ; line + + ) {
port = & serial8250_ports [ line ] . port ;
if ( p - > iotype = = port - > iotype & &
p - > iobase = = port - > iobase & &
p - > membase = = port - > membase )
return line ;
}
return - ENODEV ;
}
int __init serial8250_start_console ( struct uart_port * port , char * options )
{
int line ;
line = find_port ( port ) ;
if ( line < 0 )
return - ENODEV ;
add_preferred_console ( " ttyS " , line , options ) ;
printk ( " Adding console on ttyS%d at %s 0x%lx (options '%s') \n " ,
line , port - > iotype = = UPIO_MEM ? " MMIO " : " I/O port " ,
port - > iotype = = UPIO_MEM ? ( unsigned long ) port - > mapbase :
( unsigned long ) port - > iobase , options ) ;
if ( ! ( serial8250_console . flags & CON_ENABLED ) ) {
serial8250_console . flags & = ~ CON_PRINTBUFFER ;
register_console ( & serial8250_console ) ;
}
return line ;
}
# 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 )
{
if ( port - > line > = ARRAY_SIZE ( serial8250_ports ) )
return - ENODEV ;
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 ) ;
}
/*
* Register a set of serial devices attached to a platform device . The
* list is terminated with a zero flags entry , which means we expect
* all entries to have at least UPF_BOOT_AUTOCONF set .
*/
static int __devinit serial8250_probe ( struct device * dev )
{
struct plat_serial8250_port * p = dev - > platform_data ;
struct uart_port port ;
2005-06-27 14:12:54 +04:00
int ret , i ;
2005-04-17 02:20:36 +04:00
memset ( & port , 0 , sizeof ( struct uart_port ) ) ;
2005-06-27 14:12:54 +04:00
for ( i = 0 ; p & & p - > flags ! = 0 ; p + + , i + + ) {
2005-04-17 02:20:36 +04:00
port . iobase = p - > iobase ;
port . membase = p - > membase ;
port . irq = p - > irq ;
port . uartclk = p - > uartclk ;
port . regshift = p - > regshift ;
port . iotype = p - > iotype ;
port . flags = p - > flags ;
port . mapbase = p - > mapbase ;
2005-06-27 14:12:54 +04:00
port . hub6 = p - > hub6 ;
2005-04-17 02:20:36 +04:00
port . dev = dev ;
if ( share_irqs )
port . flags | = UPF_SHARE_IRQ ;
2005-06-27 14:12:54 +04:00
ret = serial8250_register_port ( & port ) ;
if ( ret < 0 ) {
dev_err ( dev , " unable to register port at index %d "
" (IO%lx MEM%lx IRQ%d): %d \n " , i ,
p - > iobase , p - > mapbase , p - > irq , ret ) ;
}
2005-04-17 02:20:36 +04:00
}
return 0 ;
}
/*
* Remove serial ports registered against a platform device .
*/
static int __devexit serial8250_remove ( struct device * dev )
{
int i ;
for ( i = 0 ; i < UART_NR ; i + + ) {
struct uart_8250_port * up = & serial8250_ports [ i ] ;
if ( up - > port . dev = = dev )
serial8250_unregister_port ( i ) ;
}
return 0 ;
}
static int serial8250_suspend ( struct device * dev , pm_message_t state , u32 level )
{
int i ;
if ( level ! = SUSPEND_DISABLE )
return 0 ;
for ( i = 0 ; i < UART_NR ; i + + ) {
struct uart_8250_port * up = & serial8250_ports [ i ] ;
if ( up - > port . type ! = PORT_UNKNOWN & & up - > port . dev = = dev )
uart_suspend_port ( & serial8250_reg , & up - > port ) ;
}
return 0 ;
}
static int serial8250_resume ( struct device * dev , u32 level )
{
int i ;
if ( level ! = RESUME_ENABLE )
return 0 ;
for ( i = 0 ; i < UART_NR ; i + + ) {
struct uart_8250_port * up = & serial8250_ports [ i ] ;
if ( up - > port . type ! = PORT_UNKNOWN & & up - > port . dev = = dev )
uart_resume_port ( & serial8250_reg , & up - > port ) ;
}
return 0 ;
}
static struct device_driver serial8250_isa_driver = {
. name = " serial8250 " ,
. bus = & platform_bus_type ,
. probe = serial8250_probe ,
. remove = __devexit_p ( serial8250_remove ) ,
. suspend = serial8250_suspend ,
. resume = serial8250_resume ,
} ;
/*
* This " device " covers _all_ ISA 8250 - compatible serial devices listed
* in the table in include / asm / serial . h
*/
static struct platform_device * serial8250_isa_devs ;
/*
* serial8250_register_port and serial8250_unregister_port allows for
* 16 x50 serial ports to be configured at run - time , to support PCMCIA
* modems and PCI multiport cards .
*/
static DECLARE_MUTEX ( serial_sem ) ;
static struct uart_8250_port * serial8250_find_match_or_unused ( struct uart_port * port )
{
int i ;
/*
* First , find a port entry which matches .
*/
for ( i = 0 ; i < UART_NR ; i + + )
if ( uart_match_port ( & serial8250_ports [ i ] . port , port ) )
return & serial8250_ports [ i ] ;
/*
* We didn ' t find a matching entry , so look for the first
* free entry . We look for one which hasn ' t been previously
* used ( indicated by zero iobase ) .
*/
for ( i = 0 ; i < UART_NR ; i + + )
if ( serial8250_ports [ i ] . port . type = = PORT_UNKNOWN & &
serial8250_ports [ i ] . port . iobase = = 0 )
return & serial8250_ports [ i ] ;
/*
* That also failed . Last resort is to find any entry which
* doesn ' t have a real port associated with it .
*/
for ( i = 0 ; i < UART_NR ; i + + )
if ( serial8250_ports [ i ] . port . type = = PORT_UNKNOWN )
return & serial8250_ports [ i ] ;
return NULL ;
}
/**
* serial8250_register_port - register a serial port
* @ port : serial port template
*
* Configure the serial port specified by the request . If the
* port exists and is in use , it is hung up and unregistered
* first .
*
* The port is then probed and if necessary the IRQ is autodetected
* If this fails an error is returned .
*
* On success the port is ready to use and the line number is returned .
*/
int serial8250_register_port ( struct uart_port * port )
{
struct uart_8250_port * uart ;
int ret = - ENOSPC ;
if ( port - > uartclk = = 0 )
return - EINVAL ;
down ( & serial_sem ) ;
uart = serial8250_find_match_or_unused ( port ) ;
if ( uart ) {
uart_remove_one_port ( & serial8250_reg , & uart - > port ) ;
uart - > port . iobase = port - > iobase ;
uart - > port . membase = port - > membase ;
uart - > port . irq = port - > irq ;
uart - > port . uartclk = port - > uartclk ;
uart - > port . fifosize = port - > fifosize ;
uart - > port . regshift = port - > regshift ;
uart - > port . iotype = port - > iotype ;
uart - > port . flags = port - > flags | UPF_BOOT_AUTOCONF ;
uart - > port . mapbase = port - > mapbase ;
if ( port - > dev )
uart - > port . dev = port - > dev ;
ret = uart_add_one_port ( & serial8250_reg , & uart - > port ) ;
if ( ret = = 0 )
ret = uart - > port . line ;
}
up ( & serial_sem ) ;
return ret ;
}
EXPORT_SYMBOL ( serial8250_register_port ) ;
/**
* serial8250_unregister_port - remove a 16 x50 serial port at runtime
* @ line : serial line number
*
* Remove one serial port . This may not be called from interrupt
* context . We hand the port back to the our control .
*/
void serial8250_unregister_port ( int line )
{
struct uart_8250_port * uart = & serial8250_ports [ line ] ;
down ( & serial_sem ) ;
uart_remove_one_port ( & serial8250_reg , & uart - > port ) ;
if ( serial8250_isa_devs ) {
uart - > port . flags & = ~ UPF_BOOT_AUTOCONF ;
uart - > port . type = PORT_UNKNOWN ;
uart - > port . dev = & serial8250_isa_devs - > dev ;
uart_add_one_port ( & serial8250_reg , & uart - > port ) ;
} else {
uart - > port . dev = NULL ;
}
up ( & serial_sem ) ;
}
EXPORT_SYMBOL ( serial8250_unregister_port ) ;
static int __init serial8250_init ( void )
{
int ret , i ;
printk ( KERN_INFO " Serial: 8250/16550 driver $Revision: 1.90 $ "
" %d ports, IRQ sharing %sabled \n " , ( int ) UART_NR ,
share_irqs ? " en " : " dis " ) ;
for ( i = 0 ; i < NR_IRQS ; i + + )
spin_lock_init ( & irq_lists [ i ] . lock ) ;
ret = uart_register_driver ( & serial8250_reg ) ;
if ( ret )
goto out ;
serial8250_isa_devs = platform_device_register_simple ( " serial8250 " ,
- 1 , NULL , 0 ) ;
if ( IS_ERR ( serial8250_isa_devs ) ) {
ret = PTR_ERR ( serial8250_isa_devs ) ;
goto unreg ;
}
serial8250_register_ports ( & serial8250_reg , & serial8250_isa_devs - > dev ) ;
ret = driver_register ( & serial8250_isa_driver ) ;
if ( ret = = 0 )
goto out ;
platform_device_unregister ( serial8250_isa_devs ) ;
unreg :
uart_unregister_driver ( & serial8250_reg ) ;
out :
return ret ;
}
static void __exit serial8250_exit ( void )
{
struct platform_device * isa_dev = serial8250_isa_devs ;
/*
* This tells serial8250_unregister_port ( ) not to re - register
* the ports ( thereby making serial8250_isa_driver permanently
* in use . )
*/
serial8250_isa_devs = NULL ;
driver_unregister ( & serial8250_isa_driver ) ;
platform_device_unregister ( isa_dev ) ;
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 ( " Generic 8250/16x50 serial driver $Revision: 1.90 $ " ) ;
module_param ( share_irqs , uint , 0644 ) ;
MODULE_PARM_DESC ( share_irqs , " Share IRQs with other non-8250/16x50 devices "
" (unsafe) " ) ;
# ifdef CONFIG_SERIAL_8250_RSA
module_param_array ( probe_rsa , ulong , & probe_rsa_count , 0444 ) ;
MODULE_PARM_DESC ( probe_rsa , " Probe I/O ports for RSA " ) ;
# endif
MODULE_ALIAS_CHARDEV_MAJOR ( TTY_MAJOR ) ;
/**
* register_serial - configure a 16 x50 serial port at runtime
* @ req : request structure
*
* Configure the serial port specified by the request . If the
* port exists and is in use an error is returned . If the port
* is not currently in the table it is added .
*
* The port is then probed and if necessary the IRQ is autodetected
* If this fails an error is returned .
*
* On success the port is ready to use and the line number is returned .
2005-04-17 02:26:39 +04:00
*
* Note : this function is deprecated - use serial8250_register_port
* instead .
2005-04-17 02:20:36 +04:00
*/
int register_serial ( struct serial_struct * req )
{
struct uart_port port ;
port . iobase = req - > port ;
port . membase = req - > iomem_base ;
port . irq = req - > irq ;
port . uartclk = req - > baud_base * 16 ;
port . fifosize = req - > xmit_fifo_size ;
port . regshift = req - > iomem_reg_shift ;
port . iotype = req - > io_type ;
port . flags = req - > flags | UPF_BOOT_AUTOCONF ;
port . mapbase = req - > iomap_base ;
port . dev = NULL ;
if ( share_irqs )
port . flags | = UPF_SHARE_IRQ ;
if ( HIGH_BITS_OFFSET )
port . iobase | = ( long ) req - > port_high < < HIGH_BITS_OFFSET ;
/*
* If a clock rate wasn ' t specified by the low level driver , then
* default to the standard clock rate . This should be 115200 ( * 16 )
* and should not depend on the architecture ' s BASE_BAUD definition .
* However , since this API will be deprecated , it ' s probably a
* better idea to convert the drivers to use the new API
* ( serial8250_register_port and serial8250_unregister_port ) .
*/
if ( port . uartclk = = 0 ) {
printk ( KERN_WARNING
" Serial: registering port at [%08x,%08lx,%p] irq %d with zero baud_base \n " ,
port . iobase , port . mapbase , port . membase , port . irq ) ;
printk ( KERN_WARNING " Serial: see %s:%d for more information \n " ,
__FILE__ , __LINE__ ) ;
dump_stack ( ) ;
/*
* Fix it up for now , but this is only a temporary measure .
*/
port . uartclk = BASE_BAUD * 16 ;
}
return serial8250_register_port ( & port ) ;
}
EXPORT_SYMBOL ( register_serial ) ;
/**
* unregister_serial - remove a 16 x50 serial port at runtime
* @ line : serial line number
*
* Remove one serial port . This may not be called from interrupt
* context . We hand the port back to our local PM control .
2005-04-17 02:26:39 +04:00
*
* Note : this function is deprecated - use serial8250_unregister_port
* instead .
2005-04-17 02:20:36 +04:00
*/
void unregister_serial ( int line )
{
serial8250_unregister_port ( line ) ;
}
EXPORT_SYMBOL ( unregister_serial ) ;