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

📄 serial_44b0.c

📁 serial port driver in linux
💻 C
📖 第 1 页 / 共 5 页
字号:
	unsigned long flags;

	if (serial_paranoia_check(info, tty->device, "rs_stop"))
		return;
	
	save_flags(flags); cli();
	disable_uart_tx_interrupt(info->line); 
	restore_flags(flags);
}
_INLINE_ void disable_uart_tx_interrupt(int line)	
{
	unsigned int tmp;
	unsigned int addr;
	switch(line)
	{
	    case 0:
		INT_DISABLE(INT_UTXD0);	
		CLEAR_PEND_INT(INT_UTXD0);	
		break;
	    case 1:
		INT_DISABLE(INT_UTXD1);	
		CLEAR_PEND_INT(INT_UTXD1);	
		break;
	    /*case 2:                                            */
		/*addr=GetOutAddr(GetInterAddr(ADDR_SERIAL_A)+1);*/
		/*tmp=CSR_READ(addr);                            */
		/*tmp&=~0x02;                                    */
		/*CSR_WRITE(addr,tmp);                           */
		/*break;                                         */
	    /*case 3:                                            */
		/*addr=GetOutAddr(GetInterAddr(ADDR_SERIAL_B)+1);*/
		/*tmp=CSR_READ(addr);                            */
		/*tmp&=~0x02;                                    */
		/*CSR_WRITE(addr,tmp);                           */
		/*break;                                         */
	    default:
		break;
	}
}

_INLINE_ void disable_uart_rx_interrupt(int line)	
{
	unsigned int tmp;
	unsigned int addr;
	switch(line)
	{
	    case 0:
		INT_DISABLE(INT_URXD0);
		CLEAR_PEND_INT(INT_URXD0);
		break;
	    case 1:
		INT_DISABLE(INT_URXD1);
		CLEAR_PEND_INT(INT_URXD1);
		break;
	    /*case 2:                                            */
		/*addr=GetOutAddr(GetInterAddr(ADDR_SERIAL_A)+1);*/
		/*tmp=CSR_READ(addr);                            */
		/*tmp&=~0x01;                                    */
		/*CSR_WRITE(addr,tmp);                           */
		/*break;                                         */
	    /*case 3:                                            */
		/*addr=GetOutAddr(GetInterAddr(ADDR_SERIAL_B)+1);*/
		/*tmp=CSR_READ(addr);                            */
		/*tmp&=~0x01;                                    */
		/*CSR_WRITE(addr,tmp);                           */
		/*break;                                         */
	    default:
		break;
	}
}

_INLINE_ void enable_uart_tx_interrupt(int line)	
{
	unsigned int tmp;
	unsigned int addr;

	switch(line)
	{
	    case 0:
		INT_ENABLE(INT_UTXD0);	
		break;
	    case 1:
		INT_ENABLE(INT_UTXD1);
		break;
	    /*case 2:                                            */
		/*addr=GetOutAddr(GetInterAddr(ADDR_SERIAL_A)+1);*/
		/*tmp=CSR_READ(addr);                            */
		/*tmp|=0x02;                                     */
		/*CSR_WRITE(addr,tmp);                           */
		/*break;                                         */
	    /*case 3:                                            */
		/*addr=GetOutAddr(GetInterAddr(ADDR_SERIAL_B)+1);*/
		/*tmp=CSR_READ(addr);                            */
		/*tmp|=0x02;                                     */
		/*CSR_WRITE(addr,tmp);                           */
		/*break;                                         */
	    default:
		break;
	}
}

_INLINE_ void enable_uart_rx_interrupt(int line)
{
	unsigned int tmp;
	unsigned int addr;
	switch(line)
	{
	    case 0:
		INT_ENABLE(INT_URXD0);
		break;
	    case 1:
		INT_ENABLE(INT_URXD1);
		break;
	    /*case 2:                                            */
		/*addr=GetOutAddr(GetInterAddr(ADDR_SERIAL_A)+1);*/
		/*tmp=CSR_READ(addr);                            */
		/*tmp|=0x01;                                     */
		/*CSR_WRITE(addr,tmp);                           */
		/*break;                                         */
	    /*case 3:                                            */
		/*addr=GetOutAddr(GetInterAddr(ADDR_SERIAL_B)+1);*/
		/*tmp=CSR_READ(addr);                            */
		/*tmp|=0x01;                                     */
		/*CSR_WRITE(addr,tmp);                           */
		/*break;                                         */
	    default:
		break;
	}
}


static void rs_start(struct tty_struct *tty)
{
	struct async_struct *info = (struct async_struct *)tty->driver_data;
	unsigned long flags;
	
	if (serial_paranoia_check(info, tty->device, "rs_start"))
		return;
	
	save_flags(flags); cli();
	if (info->xmit.head != info->xmit.tail
	    && info->xmit.buf) {
		enable_uart_tx_interrupt(info->line);
	}
	restore_flags(flags);
}

/*
 * ----------------------------------------------------------------------
 *
 * Here starts the interrupt handling routines.  All of the following
 * subroutines are declared as inline and are folded into
 * rs_interrupt().  They were separated out for readability's sake.
 *
 * Note: rs_interrupt() is a "fast" interrupt, which means that it
 * runs with interrupts turned off.  People who may want to modify
 * rs_interrupt() should try to keep the interrupt handler as fast as
 * possible.  After you are done making modifications, it is not a bad
 * idea to do:
 * 
 * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
 *
 * and look at the resulting assemble code in serial.s.
 *
 * 				- Ted Ts'o (tytso@mit.edu), 7-Mar-93
 * -----------------------------------------------------------------------
 */

/*
 * This routine is used by the interrupt handler to schedule
 * processing in the software interrupt portion of the driver.
 */
static _INLINE_ void rs_sched_event(struct async_struct *info,
				  int event)
{
	info->event |= 1 << event;
	queue_task(&info->tqueue, &tq_serial);
	mark_bh(SERIAL_BH);
}

static _INLINE_ void receive_chars(struct async_struct *info,
				 int *status, struct pt_regs * regs)
{
	struct tty_struct *tty = info->tty;
	unsigned char ch;
	struct	async_icount *icount;
	int	max_count = 256;

#ifdef CONFIG_LEDMAN
	ledman_cmd(LEDMAN_CMD_SET,
		(info->line == 0) ? LEDMAN_COM1_RX : LEDMAN_COM2_RX);
#endif

	icount = &info->state->icount;
	do {
		if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
			tty->flip.tqueue.routine((void *) tty);
			if (tty->flip.count >= TTY_FLIPBUF_SIZE)
				return;		// if TTY_DONT_FLIP is set
		}
		if(info->line==0||info->line==1)
			ch = uart_in(info, UART_RX);
		/*                                       */
		/*else                                   */
		/*        ch = uart_in(info, EX_UART_RX);*/
		*tty->flip.char_buf_ptr = ch;
		icount->rx++;
		
#ifdef SERIAL_DEBUG_INTR
		printk("DR%02x:%02x...", ch, *status);
#endif
		*tty->flip.flag_buf_ptr = 0;
/*
		if (*status & (UART_LSR_BI | UART_LSR_PE |
			       UART_LSR_FE | UART_LSR_OE)) {
			//
			// For statistics only
			//
			if (*status & UART_LSR_BI) {
				*status &= ~(UART_LSR_FE | UART_LSR_PE);
				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 defined(CONFIG_SERIAL_SAMSUNG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
				if (info->line == sercons.index) {
					if (!break_pressed) {
						break_pressed = jiffies;
						goto ignore_char;
					}
					break_pressed = 0;
				}
#endif
				if (info->flags & ASYNC_SAK)
					do_SAK(tty);
			} else if (*status & UART_LSR_PE)
				icount->parity++;
			else if (*status & UART_LSR_FE)
				icount->frame++;
			if (*status & UART_LSR_OE)
				icount->overrun++;
*/
			//
			// Mask off conditions which should be ignored.
			//
			*status &= info->read_status_mask;

#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE
			if (info->line == sercons.index) {
				// Recover the break flag from console xmit
				*status |= lsr_break_flag;
				lsr_break_flag = 0;
			}
#endif

/*			if (*status & (UART_LSR_BI)) {
#ifdef SERIAL_DEBUG_INTR
				printk("handling break....");
#endif
				*tty->flip.flag_buf_ptr = TTY_BREAK;
			} else if (*status & UART_LSR_PE)
				*tty->flip.flag_buf_ptr = TTY_PARITY;
			else if (*status & UART_LSR_FE)
				*tty->flip.flag_buf_ptr = TTY_FRAME;
		}*/
#if defined(CONFIG_SERIAL_SAMSUNG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
		if (break_pressed && info->line == sercons.index) {
			if (ch != 0 &&
			    time_before(jiffies, break_pressed + HZ*5)) {
				handle_sysrq(ch, regs, NULL, NULL);
				break_pressed = 0;
				goto ignore_char;
			}
			break_pressed = 0;
		}
#endif
		if ((*status & info->ignore_status_mask) == 0) {
			tty->flip.flag_buf_ptr++;
			tty->flip.char_buf_ptr++;
			tty->flip.count++;
		}
/*		if ((*status & UART_LSR_OE) &&
		    (tty->flip.count < TTY_FLIPBUF_SIZE)) {
			//
			// Overrun is special, since it's reported
			// immediately, and doesn't affect the current
			// character
			//
			*tty->flip.flag_buf_ptr = TTY_OVERRUN;
			tty->flip.count++;
			tty->flip.flag_buf_ptr++;
			tty->flip.char_buf_ptr++;
		}*/
#if defined(CONFIG_SERIAL_SAMSUNG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
	ignore_char:
#endif
		if(info->line==0||info->line==1)
			*status = serial_inp(info, UART_LSR);
		else
			*status = serial_inp(info, EX_UART_LSR);
		    
	} while ((*status & UART_LSR_DR) && (max_count-- > 0));
#if (LINUX_VERSION_CODE > 131394) // 2.1.66
	tty_flip_buffer_push(tty);
#else
	queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
#endif	
}

static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done)
{
	int count;
	unsigned int status;
	
#ifdef CONFIG_LEDMAN
	ledman_cmd(LEDMAN_CMD_SET,
		(info->line == 0) ? LEDMAN_COM1_TX : LEDMAN_COM2_TX);
#endif

	/*if(info->line==2)             */
	    /*printk("串口2发送\n");    */
	/*else                          */
	    /*if(info->line==3)         */
		/*printk("串口3发送\n");*/
	if (info->x_char) {
		if(info->line==0||info->line==1)
			uart_out(info, UART_TX, info->x_char);
		/*else                                             */
			/*uart_out(info, EX_UART_TX, info->x_char);*/
		info->state->icount.tx++;
		info->x_char = 0;
		if (intr_done)
			*intr_done = 0;
		return;
	}
	if (info->xmit.head == info->xmit.tail
	    || info->tty->stopped
	    || info->tty->hw_stopped) {
		disable_uart_tx_interrupt(info->line);
		return;
	}
	
	count = info->xmit_fifo_size;
	do {
		if(info->line==0||info->line==1)
			uart_out(info, UART_TX, info->xmit.buf[info->xmit.tail]);
		/*else                                                                */
			/*uart_out(info, EX_UART_TX, info->xmit.buf[info->xmit.tail]);*/
		    
		info->xmit.tail = (info->xmit.tail + 1) & (SERIAL_XMIT_SIZE-1);
		info->state->icount.tx++;
		if (info->xmit.head == info->xmit.tail)
			break;
		wait_for_xmitr(info);
		status&=(~(UART_LSR_TEMT | UART_LSR_THRE));
		if(info->line==0||info->line==1)
			serial_out(info,UART_LSR,status);
		/*else                                        */
			/*serial_out(info,EX_UART_LSR,status);*/
		    
	} while (--count > 0);
	
	if (CIRC_CNT(info->xmit.head,
		     info->xmit.tail,
		     SERIAL_XMIT_SIZE) < WAKEUP_CHARS)
		rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);

#ifdef SERIAL_DEBUG_INTR
	printk("THRE...");
#endif
	if (intr_done)
		*intr_done = 0;

	if (info->xmit.head == info->xmit.tail) {
		disable_uart_tx_interrupt(info->line);
	}
}


/*
 * This is the serial driver's interrupt routine for a single port
 */
static void rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs)
{
	int status;
	int pass_counter = 0;
	struct async_struct * info;

	info = IRQ_ports[irq];
	if (!info || !info->tty)
		return;

    if ((irq == INT_URXD1) || (irq == INT_URXD0)){ // Qinwei 2002.09.16		if (status & UART_LSR_THRE)
	    do {
		if(info->line==0||info->line==1)
			status = serial_inp(info, UART_LSR);
		else
    			status = serial_inp(info, EX_UART_LSR);

    		if (status & UART_LSR_DR)
    			receive_chars(info, &status, regs);
    
    		if (pass_counter++ > RS_ISR_PASS_LIMIT) {
    			break;
    		}
    	} while (status & UART_LSR_DR );
	    info->last_active = jiffies;
    	return;
    }
    
   if ((irq == INT_UTXD1) || (irq == INT_UTXD0)){ // Qinwei 2002.09.16		if (status & UART_LSR_THRE)
        transmit_chars(info, 0);
        info->last_active = jiffies;
        return;
    }
}
/******************************************************************************
 * 	功能:		83977串行中断程序
 ******************************************************************************/
/*inline void do_com_interrupt(struct async_struct * info,int * status,struct pt_regs * regs)*/
/*{                                                                                          */
/*        unsigned char bInterruptNo;                                                        */
/*        //bInterruptNo=0x07&inb(GetOutAddr(wInterAddr+2));                                 */
/*        bInterruptNo=0x07&serial_in(info,2);                                               */
/*        switch(bInterruptNo)                                                               */
/*        {                                                                                  */
/*                case 0:                                                                    */
/*                        //modem_status                                                     */
/*                        serial_in(info,6);                                                 */
/*                        break;                                                             */
/*                case 2:                                                                    */
/*                        //write_char                                                       */
/*                        transmit_chars(info, 0);	                                     */
/*                        break;                                                             */
/*                case 4:                                                                    */
/*                        //read_char                                                        */
/*                        receive_chars(info, status, regs);                                 */
/*                        break;                                                             */
/*                case 6:                                                                    */
/*                        //line_status                                                      */
/*                        serial_in(info,5);                                                 */
/*                        break;                                                             */
/*                default:                                                                   */

⌨️ 快捷键说明

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