⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 at91_tl16c554.c

📁 嵌入式 linux 扩展串口 驱动 测试程序
💻 C
📖 第 1 页 / 共 2 页
字号:
/*----------------------------------------------------------**	linux/drivers/at91/at91_tl16c554.c**		****	Copyright (C) 2006 Hyesco Technology Co.,Ltd****	Author: casiawu <wujh@hyesco.com>****	History:****	2006.6   casiawu  <wujh@hyesco.com>**               Original from at91_serial.c**---------------------------------------------------------*/#include <linux/config.h>#include <linux/module.h>#include <linux/tty.h>#include <linux/ioport.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/serial.h>#include <linux/console.h>#include <linux/sysrq.h>#include <asm/mach/serial_at91rm9200.h>#include <asm/io.h>#include <asm/arch/pio.h>#include <linux/serial_core.h>#include "./at91_tl16c554.h"#undef DEBUG /* #define DEBUG 1 */#ifdef DEBUG#define DPRINTK( x... )  printk( ##x )#else#define DPRINTK( x... )#endif#define ISR_PASS_LIMIT	256#define UART_PUT_FCR(port,v)	((TL16C554PS_USART)(port)->membase)->US_FCR_IIR = v#define UART_GET_LCR(port)	  ((TL16C554PS_USART)(port)->membase)->US_LCR#define UART_PUT_LCR(port,v)	((TL16C554PS_USART)(port)->membase)->US_LCR = v#define UART_PUT_IER(port,v)	((TL16C554PS_USART)(port)->membase)->US_DLM_IER |= v#define UART_GET_IER(port)	((TL16C554PS_USART)(port)->membase)->US_DLM_IER #define UART_PUT_IDR(port,v)	((TL16C554PS_USART)(port)->membase)->US_DLM_IER &= ~v #define UART_GET_IIR(port)	  ((TL16C554PS_USART)(port)->membase)->US_FCR_IIR#define UART_GET_LSR(port)	  ((TL16C554PS_USART)(port)->membase)->US_LSR#define UART_GET_CHAR(port)	  ((TL16C554PS_USART)(port)->membase)->US_RBR_THR_DLL#define UART_PUT_CHAR(port,v)	((TL16C554PS_USART)(port)->membase)->US_RBR_THR_DLL = v#define UART_PUT_BRGR(port,v)	{ \	                              ((TL16C554PS_USART)(port)->membase)->US_LCR |= 0x80 ; \	                              ((TL16C554PS_USART)(port)->membase)->US_RBR_THR_DLL = v & 0xff ; \	                              ((TL16C554PS_USART)(port)->membase)->US_DLM_IER = (v & 0xff00)>>8 ; \	                              ((TL16C554PS_USART)(port)->membase)->US_LCR &= 0x7F ; }#define UART_PUT_MCR(port,v) 	  ((TL16C554PS_USART)(port)->membase)->US_MCR = v	                              #define UART_GET_MSR(port) 	  ((TL16C554PS_USART)(port)->membase)->US_MSR static struct uart_port tl16c554_ports[TL16C554_NR_UART];const int tl16c554_serialmap[TL16C554_NR_UART] = TL16C554_UART_MAP;static int (*tl16c554_open)(struct uart_port *);static void (*tl16c554_close)(struct uart_port *);/* * Return TIOCSER_TEMT when transmitter FIFO and Shift register is empty. */static u_int tl16c554_tx_empty(struct uart_port *port){    int ret=0 ,status;	  DPRINTK("\n\\rtl16c554_tx_empty!\n\r");        status = UART_GET_LSR(port);        if((status & TL16C554_US_THRE) || (status & TL16C554_US_TEMT))    ret = TIOCSER_TEMT;        return ret;}/* * Set state of the modem control output lines */static void tl16c554_set_mctrl(struct uart_port *port, u_int mctrl){    unsigned int control = 0; 	  DPRINTK("\n\\rtl16c554_set_mctrl!\n\r");        control = UART_GET_LCR(port);	  if (mctrl & TIOCM_RTS)		control |= TL16C554_US_RTSEN;	  else		control &= ~TL16C554_US_RTSEN;	  if (mctrl & TIOCM_DTR)		control |= TL16C554_US_DTREN;	  else		control &= ~TL16C554_US_DTREN;    UART_PUT_LCR(port,control);}/* * Get state of the modem control input lines */static u_int tl16c554_get_mctrl(struct uart_port *port){    unsigned int status, ret = 0;	  DPRINTK("\n\\rtl16c554_get_mctrl!\n\r");      status = UART_GET_MSR(port);        if (status & TL16C554_US_DCD)    ret |= TIOCM_CD;      if (status & TL16C554_US_CTS)    ret |= TIOCM_CTS;      if (status & TL16C554_US_DSR)    ret |= TIOCM_DSR;      if (status & TL16C554_US_RI)    ret |= TIOCM_RI;    return ret;}/* * Stop transmitting. */static void tl16c554_stop_tx(struct uart_port *port, u_int from_tty){//	  DPRINTK("\n\\rtl16c554_stop_tx!\n\r");        UART_PUT_IDR(port, TL16C554_TX_EMPTY );    port->read_status_mask &= ~(TL16C554_US_THRE | TL16C554_US_TEMT );}/* * Start transmitting. */static void tl16c554_start_tx(struct uart_port *port, u_int from_tty){	  unsigned long flags;	  //DPRINTK("\n\\rtl16c554_start_tx!\n\r");	  local_irq_save(flags);	  port->read_status_mask |= (TL16C554_US_THRE | TL16C554_US_TEMT );	  UART_PUT_IER(port, TL16C554_TX_EMPTY );	  local_irq_restore(flags);}/* * Stop receiving - port is in process of being closed. */static void tl16c554_stop_rx(struct uart_port *port){	  DPRINTK("\n\\rtl16c554_stop_rx!\n\r");    UART_PUT_IDR(port, TL16C554_RX_FULL);}/* * Enable modem status interrupts */static void tl16c554_enable_ms(struct uart_port *port){	  DPRINTK("\n\\rtl16c554_enable_ms!\n\r");        UART_PUT_IER(port, TL16C554_MODEM_INTER);}/* * Control the transmission of a break signal */static void tl16c554_break_ctl(struct uart_port *port, int break_state){    unsigned int mode;    	  DPRINTK("\n\\rtl16c554_break_ctl!\n\r");	            mode = UART_GET_LCR(port);        if (break_state != 0)    mode |= TL16C554_US_SETBRK;    else    mode &= ~(TL16C554_US_SETBRK);	    	    UART_PUT_LCR(port, mode); /* stop break */}/* * Characters received (called from interrupt handler) */static void tl16c554_rx_chars(struct uart_port *port, struct pt_regs *regs){	   struct tty_struct *tty = port->info->tty;	   unsigned int status, ch, flg, ignored = 0;	   DPRINTK("\n\\rtl16c554_rx_chars!\n\r");		   status = UART_GET_LSR(port);	  	   while (status & TL16C554_US_RXRDY ) 	  {		 ch = UART_GET_CHAR(port);	         DPRINTK("\n\\rreceiving the char!\n\r");		 if (tty->flip.count >= TTY_FLIPBUF_SIZE)		 goto ignore_char;		 		 port->icount.rx++;		 flg = TTY_NORMAL;		/*		 * note that the error handling code is		 * out of the main execution path		 */		if (status & (TL16C554_US_PARE | TL16C554_US_FRAME | TL16C554_US_OVRE | TL16C554_US_BREAKI))			goto handle_error;		if (uart_handle_sysrq_char(port, ch, regs))			goto ignore_char;error_return:		*tty->flip.flag_buf_ptr++ = flg;		*tty->flip.char_buf_ptr++ = ch;		tty->flip.count++;ignore_char:	   status = UART_GET_LSR(port);	  }	  out:    tty_flip_buffer_push(tty);    return;handle_error:	  if (status & TL16C554_US_BREAKI) 	  port->icount.brk++;	    if (status & (TL16C554_US_PARE))    port->icount.parity++;      else if (status & (TL16C554_US_FRAME))    port->icount.frame++;        if (status & (TL16C554_US_OVRE))    port->icount.overrun++;    if (status & port->ignore_status_mask)     {      if (++ignored > 100)      goto out;            goto ignore_char;    }    status &= port->read_status_mask;      if (status & TL16C554_US_PARE)    flg = TTY_PARITY;        else if (status & TL16C554_US_FRAME)    flg = TTY_FRAME;    if (status & TL16C554_US_OVRE)     {    /*     * overrun does *not* affect the character     * we read from the FIFO     */    *tty->flip.flag_buf_ptr++ = flg;    *tty->flip.char_buf_ptr++ = ch;    tty->flip.count++;        if (tty->flip.count >= TTY_FLIPBUF_SIZE)    goto ignore_char;        ch = 0;    flg = TTY_OVERRUN;    }    goto error_return;}/* * Transmit characters (called from interrupt handler) */static void tl16c554_tx_chars(struct uart_port *port){	  struct circ_buf *xmit = &port->info->xmit;	  unsigned int i=0;	 // DPRINTK("\n\\rtl16c554_tx_chars!\n\r");		  if (port->x_char) 	  {		  UART_PUT_CHAR(port, port->x_char);		  port->icount.tx++;		  port->x_char = 0;		  return;	  }		  if (uart_circ_empty(xmit) || uart_tx_stopped(port)) 	  {		  tl16c554_stop_tx(port, 0);		  return;	  }	  if(UART_GET_LSR(port) & TL16C554_US_THRE) 	  {		   for(i=0;i<TL16C554_NR_FIFO;i++)		   {		     UART_PUT_CHAR(port, xmit->buf[xmit->tail]);		     xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);		     port->icount.tx++;		   		     if (uart_circ_empty(xmit))			   break;			 }	  }	  if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)		uart_write_wakeup(port);	  if (uart_circ_empty(xmit))		tl16c554_stop_tx(port, 0);}/* * Interrupt handler */static void tl16c554_interrupt(int irq, void *dev_id, struct pt_regs *regs){	  struct uart_port *port = NULL;	  unsigned int tmp=0,status,i,pending, pass_counter = 0;	 	 // DPRINTK("\n\\rtl16c554_interrupt!\n\r");	  AT91_SYS->AIC_ICCR=0x1<<AT91C_ID_PIOA;		                    status  = AT91_SYS->PIOA_ISR & (TL16C554_PIO5 | TL16C554_PIO6 | TL16C554_PIO7 | TL16C554_PIO8) ;          if(!status)  return ;          	 	  tmp = AT91_SYS->PIOA_PDSR ;	  for (i = 0; i < TL16C554_NR_UART; i++)	  {	    if(tmp & tl16c554_ports[i].irq)	    {	    	port  = &tl16c554_ports[i];               // DPRINTK("\n\\rport = %d\n\r",i);	    	break;	    }          }              if(!port)    return ;		  pending = UART_GET_IIR(port);	  	  if (!(pending & TL16C554_IIR_NoInter)) 	  {             DPRINTK("\n\\rpending = %x\n\r",pending);		  do {			   if (pending & TL16C554_IIR_ReDataAvail)			   {                         	DPRINTK("\n\r rx inter \n\r");                                 tl16c554_rx_chars(port, regs);                           }				 				 else if(pending & TL16C554_IIR_THRE)         tl16c554_tx_chars(port);                  else         {         	 status  = UART_GET_MSR(port);			     // TODO: All reads to CSR will clear these interrupts!			     if (status & TL16C554_US_RIIC)  port->icount.rng++;			     if (status & TL16C554_US_DSRIC) port->icount.dsr++;			   			     if (status & TL16C554_US_DCDIC) 			     {				      port->icount.dcd++;				      uart_handle_dcd_change(port, status & TL16C554_US_DCD);			     }						     if (pending & TL16C554_US_CTSIC) 			     {				     port->icount.cts++;				     uart_handle_cts_change(port, status & TL16C554_US_CTS);			     }			  			     if (pending & (TL16C554_US_RIIC | TL16C554_US_DSRIC | TL16C554_US_DCDIC | TL16C554_US_CTSIC))				   wake_up_interruptible(&port->info->delta_msr_wait);			  			   }			  			  if (pass_counter++ > ISR_PASS_LIMIT)				break;	      pending = UART_GET_IIR(port);	      		} while (!(pending & TL16C554_IIR_NoInter));	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -