www.pudn.com > ST16C554-linux2.6.14.rar > ST16C554.c


#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
 
#define CONFIG_HUB6 1 
#include  
 
#include  
#include  
 
#include "ST16C554.h" 
 
 
/*------------ 接口全局变量------------*/ 
static unsigned char * ST16C554PortBase; 
static struct platform_device *serial16c554_devs; 
struct st16c554_uart_port st16c554_ports[UART_16C554_NUM]; 
static DECLARE_MUTEX(serial16c554_sem); 
static char PortIsOpen[UART_16C554_NR]; 
 
/*------------ 接口操作函数------------*/ 
static struct uart_ops st16c554_pops = { 
	.tx_empty	= st16c554_tx_empty, 
	.set_mctrl	= st16c554_set_mctrl, 
	.get_mctrl	= st16c554_get_mctrl, 
	.stop_tx	= st16c554_stop_tx, 
	.start_tx	= st16c554_start_tx, 
	.stop_rx	= st16c554_stop_rx, 
	.enable_ms	= st16c554_enable_ms, 
	.break_ctl	= st16c554_break_ctl, 
	.startup	= st16c554_startup, 
	.shutdown	= st16c554_shutdown, 
	.set_termios	= st16c554_set_termios, 
	.pm		= st16c554_pm, 
	.type		= st16c554_type, 
	.release_port	= st16c554_release_port, 
	.request_port	= st16c554_request_port, 
	.config_port	= st16c554_config_port, 
	.verify_port	= st16c554_verify_port, 
}; 
 
struct uart_driver st16c554_reg = { 
	.owner			= THIS_MODULE, 
	.driver_name	= ST16C554_DRIVER_NAME, 
	.devfs_name		= ST16C554_DEVFS_NAME, 
	.dev_name		= ST16C554_DEV_NAME, 
	.major			= ST16C554_MAJOR, 
	.minor			= ST16C554_MINOR, 
	.nr				= UART_16C554_NR, 
	.cons			= ST16C554_CONSOLE, 
}; 
static unsigned int serial_in(struct uart_port *up, int offset) 
{ 
	switch(offset) { 
	case UART_RX: //0 
	//case UART_TX: //0 
	//case UART_DLL: //0 
		return UART_URXH(up); 
	case UART_IER: //1 
	//case UART_DLM: //1 
		return UART_UIER(up); 
	case UART_FCR://2 
	//case UART_IIR: //2 
		return UART_UFCON(up); 
	case UART_LCR://3 
		return UART_ULCON(up); 
	case UART_MCR: //4 
		return UART_UMCON(up); 
	case UART_LSR://5 
		return UART_ULSTAT(up); 
	case UART_MSR://6 
		return UART_UMSTAT(up); 
	case UART_SCR://7 
		return UART_URSCRR(up); 
	default: 
		return 0; 
	} 
} 
 
/*************************************** 
 
  **************************************/ 
unsigned int st16c554_tx_empty(struct uart_port *port) 
{ 
	unsigned long flags; 
	unsigned int ret; 
	 
	spin_lock_irqsave(&port->lock, flags); 
	ret = serial_in(port, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0; 
	spin_unlock_irqrestore(&port->lock, flags); 
 
	return 1; 
} 
 
/*************************************** 
 
  **************************************/ 
void st16c554_set_mctrl(struct uart_port *port, unsigned int mctrl) 
{ 
	unsigned char mcr = 0; 
 
	//printk("Now Start st16c554_set_mctrl,line= %d\n",port->line); 
		 
	if (mctrl & TIOCM_RTS) 
		mcr |= 0x02; 
	if (mctrl & TIOCM_DTR) 
		mcr |= 0x01; 
	if (mctrl & TIOCM_OUT1) 
		mcr |= 0x04; 
	if (mctrl & TIOCM_OUT2) 
		mcr |= 0x80; 
	if (mctrl & TIOCM_LOOP) 
		mcr |= 0x10; 
	 
	/* Enable interrupt */ 
	mcr |= 0x08; 
	UART_UMCON(port) = mcr; 
	//printk("st16c554_set_mctrl->set MCR to 0x%02x\n",mcr); 
	return; 
} 
 
/*************************************** 
 
  **************************************/ 
unsigned int st16c554_get_mctrl(struct uart_port *port) 
{ 
	unsigned char status; 
	unsigned int ret; 
 
	//printk("Now Start st16c554_get_mctrl,line= %d\n",port->line); 
	status = UART_UMSTAT(port); 
	 
	ret = 0; 
	if (status & 0x80) 
		ret |= TIOCM_CAR; 
	if (status & 0x40) 
		ret |= TIOCM_RNG; 
	if (status & 0x20) 
		ret |= TIOCM_DSR; 
	if (status & 0x10) 
		ret |= TIOCM_CTS; 
	return ret; 
} 
 
/*************************************** 
 
  **************************************/ 
void st16c554_stop_tx(struct uart_port *port) 
{ 
	struct st16c554_uart_port *up; 
 
	//printk("Now Start st16c554_stop_tx,line= %d\n",port->line); 
	up=&st16c554_ports[port->line]; 
	up->ier&= ~0x02; 
	UART_UIER(port) = up->ier; 
	return; 
} 
 
/*************************************** 
 
  **************************************/ 
void st16c554_start_tx(struct uart_port *port) 
{ 
	struct uart_info *info; 
	struct st16c554_uart_port *up; 
	 
	//printk("Now Start st16c554_start_tx,line= %d\n",port->line); 
	info=port->info; 
	up=&st16c554_ports[port->line]; 
 
	up->ier|= 0x02; 
	UART_UIER(port) = up->ier; 
	tx_interrupt(info, port); 
	return ; 
} 
 
/*************************************** 
 
  **************************************/ 
void st16c554_stop_rx(struct uart_port *port) 
{ 
	struct st16c554_uart_port *up; 
	 
	//printk("Now Start st16c554_stop_rx,line= %d\n",port->line); 
	up=&st16c554_ports[port->line]; 
	up->ier&= ~0x01; 
	UART_UIER(port) = up->ier; 
	return; 
} 
 
/*************************************** 
开启Modem中断 
  **************************************/ 
void st16c554_enable_ms(struct uart_port *port) 
{ 
	struct st16c554_uart_port *up; 
	 
	//printk("Now Start st16c554_enable_ms,line= %d\n",port->line); 
	up=&st16c554_ports[port->line]; 
	up->ier |= 0x08; 
	UART_UIER(port) = up->ier; 
	return; 
} 
 
/*************************************** 
break_state!=0:发送break信号,否则,恢复正常模式 
  **************************************/ 
void st16c554_break_ctl(struct uart_port *port, int break_state) 
{ 
	//printk("Now Start st16c554_break_ctl,line= %d\n",port->line); 
	 
	struct st16c554_uart_port *up = &st16c554_ports[port->line]; 
	unsigned long flags; 
	 
	spin_lock_irqsave(&port->lock, flags); 
	if (break_state == -1) 
		up->lcr |= UART_LCR_SBC; 
	else 
		up->lcr &= ~UART_LCR_SBC; 
	UART_ULCON(port)=up->lcr; 
	spin_unlock_irqrestore(&port->lock, flags); 
	 
	return; 
} 
 
 
/*************************************** 
Need debug 
注意: 
不能直接操作IRQ,因为别的端口与这个端口的IRQ相同 
  **************************************/ 
int st16c554_startup(struct uart_port *port) 
{ 
	struct st16c554_uart_port *up = &st16c554_ports[port->line]; 
	unsigned long Ret; 
	unsigned char Data; 
 
	//printk("Now Start st16c554_startup,line= %d\n",port->line); 
	 
	//UART_UIER(port)  = 0x07; 
	 
	//UART_UFCON(port) = 0x07; 
	UART_UFCON(port) = 0xcf; 
	udelay(10000); 
	UART_UFCON(port) = 0xc9; 
	st16c554_set_mctrl(port,port->mctrl); 
 
	UART_ULCON(port) = up->lcr=0x83; 
	UART_UBRDIVL(port)= (0x0c); //default is 9600 bps 
	UART_UBRDIVM(port)= (0x00); 
	UART_ULCON(port) =  up->lcr=0x03; 
	//空读一次 
	Data=UART_ULCON(port) ; 
	 
	//确保收状态 
	Ret=1; 
	while(Ret){ 
		Data=UART_ULSTAT(port); 
		if(Data&0x01){ 
			//printk("st16c554_startup->Receive FIFO is not ready.\n"); 
			Data=UART_URXH(port); 
		}else{ 
			Ret=0; 
		} 
	} 
	//指示已经打开的端口 
	PortIsOpen[port->line]=1; 
	//printk("st16c554_startup->Now Set line %d to 1\n",port->line); 
	 
	up->ier = UART_IER_RLSI | UART_IER_RDI; 
	UART_UIER(port)  = up->ier; 
	return 0; 
} 
 
/*************************************** 
  Need debug 
  注意: 
		不能直接删除IRQ,因为别的端口与这个端口的IRQ相同 
  **************************************/ 
void st16c554_shutdown(struct uart_port *port) 
{	 
	unsigned long flags; 
	struct st16c554_uart_port *up = &st16c554_ports[port->line]; 
	 
	//printk("Now Start st16c554_shutdown,line= %d\n",port->line); 
	 
	up->ier = 0; 
	UART_UIER(port)  = up->ier; 
	 
	spin_lock_irqsave(&port->lock, flags); 
 
	port->mctrl &= ~TIOCM_OUT2; 
	st16c554_set_mctrl(port,port->mctrl); 
	spin_unlock_irqrestore(&port->lock, flags); 
	UART_ULCON(port) = 0x00; 
	UART_UFCON(port) = 0x00; 
 
	flags=(unsigned long )UART_URXH(port); 
	//指示已经关闭的端口 
	PortIsOpen[port->line]=0; 
	//printk("st16c554_shutdown->Now Set line %d to 0\n",port->line); 
	return; 
} 
 
 
/*************************************** 
Need Write by myself 
  **************************************/ 
void st16c554_set_termios(struct uart_port *port, struct termios *termios, 
		       struct termios *old) 
{ 
	struct st16c554_uart_port *up = (struct st16c554_uart_port *)port; 
	unsigned char cval; //LCR Value 
	unsigned char fcr = 0; 
	unsigned long flags; 
	unsigned int baud, quot; 
	 
	//printk("Now Start st16c554_set_termios,line= %d\n",port->line);	 
	//set word length 
	cval=0; 
	switch (termios->c_cflag & CSIZE) { 
	case CS5: 
		cval = UART_LCR_WLEN5; 
		break; 
	case CS6: 
		cval = UART_LCR_WLEN6; 
		break; 
	case CS7: 
		cval = UART_LCR_WLEN7; 
		break; 
	default: 
	case CS8: 
		cval = UART_LCR_WLEN8; 
		break; 
	} 
 
	if (termios->c_cflag & CSTOPB) 
		cval |= UART_LCR_STOP; 
	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 is the last baud,such as 9600,115200 etc. 
	 */ 
	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);  
	//printk("set_termios->baud=%d port=%d,CBAUD=0x%08x\n",baud,port->uartclk,CBAUD); 
	quot = st16c554_get_divisor(port, baud); 
 
	/* 
	 * 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; 
	up->ier |= 0x05; 
	UART_UIER(port)=up->ier; 
	//printk("tx_interrupt->set IER to 0x%02x\n",up->ier); 
 
	UART_ULCON(port)=cval | UART_LCR_DLAB;/* set DLAB;UART_LCR_DLAB=0x80*/ 
	//printk("tx_interrupt->set LCR to 0x%02x\n",cval | UART_LCR_DLAB); 
 
	 
	UART_UBRDIVL(port)=quot & 0xff;	/* LS of divisor */ 
	//printk("tx_interrupt->set DLL to 0x%02x\n",quot & 0xff); 
	UART_UBRDIVM(port)=quot >> 8;		/* MS of divisor */ 
	//printk("tx_interrupt->set DLM to 0x%02x\n",quot >> 8); 
 
	cval&=0x7f; 
	UART_ULCON(port)=cval;		/* reset DLAB */ 
	up->lcr = cval;					/* Save LCR */ 
	//printk("tx_interrupt->set LCR to 0x%02x\n",cval); 
 
	fcr=0xcf; 
	UART_UFCON(port)=fcr;		/* set fcr */ 
	udelay(10000); 
	fcr=0xc9; 
	UART_UFCON(port)=fcr;		/* set fcr */ 
	//printk("tx_interrupt->set FCR to 0x%02x\n",fcr); 
	 
	st16c554_set_mctrl(&up->port, up->port.mctrl); 
	spin_unlock_irqrestore(&up->port.lock, flags); 
	return; 
} 
 
/*************************************** 
Power Management 
No Action by wangjm 
  **************************************/ 
void st16c554_pm(struct uart_port *port, unsigned int state, 
			  unsigned int oldstate) 
{ 
	//printk("Now Start st16c554_pm,line= %d\n",port->line); 
	return; 
} 
 
 
/*************************************** 
 
  **************************************/ 
const char * st16c554_type(struct uart_port *port) 
{ 
	//printk("Now Start st16c554_type,line= %d\n",port->line); 
    return (port->type == PORT_16550A) ? "ST16C554" : NULL; 
} 
 
/*************************************** 
OK! 
  **************************************/ 
void st16c554_release_port(struct uart_port *port) 
{ 
	//printk("Now Start st16c554_release_port,line= %d\n",port->line); 
 
	return; 
} 
 
 
/*************************************** 
No Action! 
  **************************************/ 
int st16c554_request_port(struct uart_port *port) 
{ 
	int ret = 0; 
 
	//printk("Now Start st16c554_request_port,line= %d\n",port->line); 
	return ret; 
} 
 
 
/*************************************** 
Need debug 
执行串口控制器的自动配置 
  **************************************/ 
void st16c554_config_port(struct uart_port *port, int flags) 
{ 
	//printk("Now Start st16c554_config_port line=%d\n",port->line); 
	 
	if((port->mapbase == ST16C554_PHY_ADDRESS)|| 
		(port->mapbase == ST16C554_PHY_ADDRESS +8)|| 
		(port->mapbase == ST16C554_PHY_ADDRESS +2*8)|| 
		(port->mapbase == ST16C554_PHY_ADDRESS +3*8)){ 
		 
		port->line=(port->mapbase-ST16C554_PHY_ADDRESS)/8; 
 
		spin_lock_init(&(port->lock)); 
		port->ops = &st16c554_pops; 
		 
		port->iobase = (unsigned int)(ST16C554PortBase +port->line*8); //map以后的虚拟地址 
		port->membase = (unsigned char *)(ST16C554PortBase +port->line*8); 
		port->irq = ST16C554_IRQ; //CPU 中断号码 
		port->uartclk = 1843200; //=1.8432MHz 
		port->fifosize = 16; //发送的FIFO大小 
		port->type = PORT_16550A; 
		 
 
		port->flags = ASYNC_SKIP_TEST ;//| ASYNC_BOOT_AUTOCONF; 
		port->iotype   = SERIAL_IO_MEM; 
	} 
 
	return;  
} 
/*************************************** 
检验端口是否是OK的。 
  **************************************/ 
int st16c554_verify_port(struct uart_port *port, struct serial_struct *ser) 
{ 
	 
	//printk("Now Start st16c554_verify_port,line= %d\n",port->line); 
	if (ser->irq !=ST16C554_IRQ || 
		ser->baud_base < 9600 || ser->type != PORT_16550A){ 
		printk("st16c554_verify_port-> Invalid param.\n"); 
		return -EINVAL; 
	} 
	return 0; 
} 
 
/*************************************** 
 
  **************************************/ 
static void tx_interrupt(struct uart_info *info, struct uart_port *port)  
{ 
	struct uart_state *state = info->tty->driver_data; 
	 
 
	//printk("Now Start tx_interrupt\n"); 
	if (port->x_char) { 
		UART_UTXH(port) = port->x_char; 
		port->icount.tx++; 
		port->x_char = 0; 
		//printk("tx_interrupt: x_char.\n"); 
		return; 
	} 
	 
	if (info->xmit.head == info->xmit.tail 
		|| info->tty->stopped || info->tty->hw_stopped) { 
		st16c554_stop_tx(state->port); 
		//printk("tx_interrupt: head=tail.\n"); 
		return; 
	} 
	 
	do { 
		/**/ 
		while(!(UART_ULSTAT(port)&0x20)){//确保TXH为空 
			//printk("tx_interrupt->LSR=0x%02x\n",UART_ULSTAT(port)); 
			udelay(100); 
		} 
		/**/ 
		UART_UTXH(port) = info->xmit.buf[info->xmit.tail]; 
		info->xmit.tail = (info->xmit.tail + 1) & (UART_XMIT_SIZE - 1); 
		port->icount.tx++; 
		if (info->xmit.head == info->xmit.tail) 
			break; 
	} while (1); 
	if (info->xmit.head == info->xmit.tail) 
		st16c554_stop_tx(state->port); 
 
} 
 
/*************************************** 
 
  **************************************/ 
//static void err_interrupt( struct uart_info *info,struct tty_struct *tty,struct uart_port *port) 
static void err_interrupt( struct uart_port *port, struct pt_regs *regs) 
{ 
	unsigned char err; 
	struct tty_struct *tty; 
	unsigned int ch, flg; 
 
	 
	err= UART_ULSTAT(port)& 0x1E; /* Do not include the break int */ 
	tty = port->info->tty; 
	ch = UART_URXH(port); 
	 
	//printk("Now Start err_interrupt,LSR=0x%02x\n",err); 
	if (!(err & (0x10 | 0x08 | 0x04 | 0x02 ))) 
		return; 
	 
	if (err & 0x10) 
		port->icount.brk++; 
	if (err & 0x08) 
		port->icount.frame++; 
	if (err & 0x04) 
		port->icount.parity++; 
	if (err & 0x02) 
		port->icount.overrun++; 
	 
	err &= port->read_status_mask; 
	 
	if (err & 0x04) 
		flg = TTY_PARITY; 
	else if (err & 0x08) 
		flg = TTY_FRAME; 
	else 
		flg = TTY_NORMAL; 
	 
	if (err & 0x02) { 
		*tty->flip.char_buf_ptr = ch; 
		*tty->flip.flag_buf_ptr = flg; 
		tty->flip.flag_buf_ptr++; 
		tty->flip.char_buf_ptr++; 
		tty->flip.count++; 
		if (tty->flip.count < TTY_FLIPBUF_SIZE) { 
			ch = 0; 
			flg = TTY_OVERRUN; 
		} 
	} 
	 
	*tty->flip.flag_buf_ptr++ = flg; 
	*tty->flip.char_buf_ptr++ = ch; 
	tty->flip.count++; 
	return; 
} 
 
/*************************************** 
 
  **************************************/ 
//static void rx_interrupt(struct uart_info *info, struct tty_struct *tty, struct uart_port *port)  
static void rx_interrupt(struct uart_port *port, struct pt_regs *regs)  
{ 
	struct tty_struct *tty = port->info->tty; 
	unsigned char ch, lsr; 
	int max_count = 256; 
	char flag; 
	 
	lsr=UART_ULSTAT(port); 
	//printk("Now Start rx_interrupt,LSR=0x%02x\n",lsr); 
	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(&port->lock); 
				tty_flip_buffer_push(tty); 
				spin_lock(&port->lock); 
			} 
			/* 
			* If this failed then we will throw away the 
			* bytes but must do so to clear interrupts 
			*/ 
		} 
		ch = serial_in(port, UART_RX); 
		flag = TTY_NORMAL; 
		port->icount.rx++; 
		 
		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); 
				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(port)) 
					goto ignore_char; 
			} else if (lsr & UART_LSR_PE) 
				port->icount.parity++; 
			else if (lsr & UART_LSR_FE) 
				port->icount.frame++; 
			if (lsr & UART_LSR_OE) 
				port->icount.overrun++; 
			 
			if (lsr & UART_LSR_BI) { 
				//printk("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(port, ch, regs)) 
			goto ignore_char; 
		 
		uart_insert_char(port, lsr, UART_LSR_OE, ch, flag); 
		 
ignore_char: 
		lsr = serial_in(port, UART_LSR); 
	} while ((lsr & UART_LSR_DR) && (max_count-- > 0)); 
	spin_unlock(port->lock); 
	tty_flip_buffer_push(tty); 
	spin_lock(port->lock); 
	 
} 
/*************************************** 
give the wanted baudrate,return the divider 
  **************************************/ 
static unsigned int st16c554_get_divisor(struct uart_port *port, unsigned int baud) 
{ 
	//printk("Now Start st16c554_get_divisor,line= %d baud=%d\n",port->line,baud); 
	return(1843200/(16*baud)); 
} 
 
/*************************************** 
 
  **************************************/ 
static void serial16c554_timeout(unsigned long data) 
{ 
	//printk("Now Start serial16c554_timeout\n"); 
	return; 
} 
 
/*************************************** 
 
  **************************************/ 
static void serial16c554_print_port(struct st16c554_uart_port *up) 
{ 
	printk("----------------- port %d---------------------\n",up->port.line); 
	printk("mcr_mask:\t0x%x\n",up->mcr_mask); 
	printk("mcr_force:\t0x%x\n",up->mcr_force); 
	printk("port.iobase:\t0x%x\n",up->port.iobase ); 
	printk("port.irq:\t0x%x\n",up->port.irq); 
	printk("port.uartclk:\t0x%x\n",up->port.uartclk); 
	printk("port.flags:\t0x%x\n",up->port.flags); 
	printk("port.hub6:\t0x%x\n",up->port.hub6); 
	printk("port.membase:\t0x%x\n",(unsigned int)(up->port.membase)); 
	printk("port.iotype:\t0x%x\n",up->port.iotype); 
	printk("port.regshift:\t0x%x\n",up->port.regshift); 
	printk("----------------------------------------------\n"); 
	return ;	 
} 
/*************************************** 
//address_map 
  **************************************/ 
int st16c554_AddressMap(void) 
{	 
	ST16C554PortBase=(unsigned char *)ioremap(ST16C554_PHY_ADDRESS,ST16C554_REMAP_SIZE); 
	if(ST16C554PortBase==NULL){ 
		return -1; 
	} 
	//printk("ST16c554 Base Address:0x%08x is mapped to 0x%08x\n", 
	//	(unsigned int)ST16C554_PHY_ADDRESS,	 
	//	(unsigned int)ST16C554PortBase); 
	return 0; 
} 
 
/*************************************** 
 
  **************************************/ 
int st16c554_InitUARTPort( struct st16c554_uart_port * pUARTPort) 
{ 
	int i; 
	struct uart_port *pPort; 
	 
	for(i=0;iline = i;//+ST16C554_PORT_INDEX; 
		spin_lock_init(&(pPort->lock)); 
		 
		init_timer(&(pUARTPort[i].timer)); 
		pUARTPort[i].timer.function = serial16c554_timeout; 
				 
		pPort->ops = &st16c554_pops; 
		 
		pPort->iobase = (unsigned int)(ST16C554PortBase +i*8); //map以后的虚拟地址 
		pPort->membase = (unsigned char *)(ST16C554PortBase +i*8); 
		pPort->mapbase = ST16C554_PHY_ADDRESS + i*8; 
		pPort->irq = ST16C554_IRQ; //CPU 中断号码 
		pPort->uartclk = 1843200; //=1.8432MHz 
		pPort->fifosize = 16; //发送的FIFO大小 
		pPort->type = PORT_16550A; 
		 
 
		pPort->flags = ASYNC_SKIP_TEST ;//| ASYNC_BOOT_AUTOCONF; 
		pPort->iotype   = SERIAL_IO_MEM; 
		//serial16c554_print_port(&pUARTPort[i]); 
	} 
	return 0; 
} 
 
/*************************************** 
 
  **************************************/ 
int st16c554_InitReg( void) 
{ 
	unsigned char Data,i; 
	struct uart_port *pPort; 
 
	for(i=0;iNow set %d to 0\n",i); 
	} 
	 
	return 0; 
} 
 
/*************************************** 
 
  **************************************/ 
static int serial16c554_register_ports(struct uart_driver *drv, struct device *dev) 
{ 
	int i,Ret; 
	struct st16c554_uart_port *pPort; 
		 
	for (i = 0; i < UART_16C554_NUM; i++) { 
		pPort = &st16c554_ports[i]; 
		 
		pPort->port.dev = dev; 
		Ret=uart_add_one_port(drv, &(pPort->port)); 
		if(Ret) 
			printk("serial16c554_register_ports->add port error %d->Ret:%d\n",i,Ret); 
	} 
	return 0; 
} 
 
/* 
  中断服务函数 
*/ 
static irqreturn_t serial16c554_interrupt(int irq, void *dev_id, struct pt_regs *regs) 
{ 
	struct uart_port *port; 
	struct uart_state *state; 
	unsigned char i,isr,PortNum; 
	struct uart_driver *drv=(struct uart_driver *)dev_id; 
 
	//printk("Now Start serial16c554_interrupt,dev_id=0x%08x irq=%d,regs=0x%08x\n",(unsigned int)dev_id,irq,(unsigned int)regs); 
	for(i=0;iport is not opened.line=%d,%d\n",PortNum,i); 
			continue; 
		} 
		state = drv->state +i; 
		port=state->port; 
		 
		spin_lock(&port->lock); 
		PortNum=port->line; 
		 
		isr=UART_UISTAT(port); 
		//printk("serial16c554_interrupt->line=%d ISR=0x%02x\n",i,isr); 
 
		while(!(isr&0x01)) { 
			isr=(isr&0x0E)>>1; 
			switch(isr) { 
			case 3: 
				err_interrupt(port,regs); 		 
				break; 
			case 4: 
			case 2: 
			case 6: 
				rx_interrupt(port,regs); 		 
				break; 
			case 0: 
				check_modem_status(port,regs); 
			default: 
				printk("Unknow interrupt type!"); 
				break; 
			} 
			isr=UART_UISTAT(port); 
		}//end while 
		 
		spin_unlock(&port->lock); 
 
	}//end for 
	return 1; 
} 
 
/*************************************** 
 
  **************************************/ 
//static void check_modem_status(struct uart_info *info, struct uart_port *port) 
static void check_modem_status(struct uart_port *port, struct pt_regs *regs) 
{ 
	int status; 
	 
	status = UART_UMSTAT(port); 
	//printk("check_modem_status->MSR=0x%02x\n",status); 
	return; 
} 
 
/************----------- 模块初始化相关函数 --------------------***************/ 
/*************************************** 
 
  **************************************/ 
int st16c554uart_init(void) 
{ 
	int Ret; 
 
	Ret=st16c554_AddressMap(); 
	if(Ret<0){ 
		printk("ERROR:st16c554_AddressMap Failure.\n"); 
		return Ret; 
	} 
	 
	Ret=st16c554_InitUARTPort(st16c554_ports); 
	if(Ret<0){ 
		printk("ERROR:st16c554_InitUARTPort Failure.Ret:0x%x\n",Ret); 
		return Ret; 
	} 
	Ret=st16c554_InitReg(); 
	if(Ret<0){ 
		printk("ERROR:st16c554_InitReg Failure.Ret:0x%x\n",Ret); 
		return Ret; 
	} 
	//printk("Now Start To register uart driver.\n"); 
	Ret=uart_register_driver(&st16c554_reg); 
	if(Ret){ 
		//failed 
		printk("Register st16c554 serial driver Failure.No=0x%x\n",Ret); 
		return Ret; 
	} 
	serial16c554_devs = platform_device_register_simple("serial16C554", 
		PLAT8250_DEV_LEGACY, NULL, 0); 
	if (IS_ERR(serial16c554_devs)) { 
		Ret = PTR_ERR(serial16c554_devs); 
		goto  st16c554_init_out; 
	} 
 
	//printk("Now Start To register ports.\n"); 
	Ret=serial16c554_register_ports(&st16c554_reg, &serial16c554_devs->dev); 
	if(Ret!=0){ 
		printk("register ports failed. Return %d\n",Ret); 
		goto  st16c554_init_out; 
	} 
	 
	//printk("Now Start To register interrupt functions.\n"); 
	free_irq(st16c554_ports[0].port.irq,NULL); 
	Ret = request_irq(st16c554_ports[0].port.irq, serial16c554_interrupt, 
		SA_INTERRUPT|SA_SHIRQ, "serial 16c554", &st16c554_reg); 
	if (Ret < 0){ 
		printk("serial st16c554:interrupt %d request failled. return %d\n",st16c554_ports[0].port.irq,Ret); 
		goto  st16c554_init_out; 
	} 
	 
	printk("Register ST16C554 Driver OK.\n"); 
	return Ret; 
st16c554_init_out: 
	printk("driver register failed. Return %d\n",Ret); 
	uart_unregister_driver(&st16c554_reg); 
	return Ret; 
} 
 
 
/*************************************** 
 
  **************************************/ 
void __exit st16c554uart_exit(void) 
{ 
	platform_device_unregister(serial16c554_devs); 
	uart_unregister_driver(&st16c554_reg); 
	free_irq(st16c554_ports[0].port.irq,NULL); 
	printk("Unregister st16c554 serial driver.\n"); 
} 
 
module_init(st16c554uart_init); 
module_exit(st16c554uart_exit); 
 
MODULE_AUTHOR("Jemywolf Research Inc"); 
MODULE_LICENSE("GPL"); 
MODULE_DESCRIPTION("Generic ST16C554 serial driver Revision: 1.0.0"); 
MODULE_ALIAS_CHARDEV_MAJOR(ST16C554_MAJOR);