📄 serial_44b0.c
字号:
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 + -