📄 serial_44b0.c
字号:
/* break; */
/* } */
/*} */
/*
static void rs_83977_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
unsigned int tmp;
int status;
struct async_struct * info;
info = IRQ_ports[irq];
if (!info || !info->tty)
return;
tmp=CSR_READ(rEXTINTPND);
if(tmp&0x01)
{
//串口3中断
printk("串口3中断\n");
do_com_interrupt(info,&status,regs);
CSR_WRITE(rEXTINTPND,tmp&(~0x01));
}
if(tmp&0x02)
{
//串口4中断
printk("串口4中断\n");
do_com_interrupt(info,&status,regs);
CSR_WRITE(rEXTINTPND,tmp&(~0x02));
}
}
*/
/*
* -------------------------------------------------------------------
* Here ends the serial interrupt routines.
* -------------------------------------------------------------------
*/
/*
* This routine is used to handle the "bottom half" processing for the
* serial driver, known also the "software interrupt" processing.
* This processing is done at the kernel interrupt level, after the
* rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This
* is where time-consuming activities which can not be done in the
* interrupt driver proper are done; the interrupt driver schedules
* them using rs_sched_event(), and they get done here.
*/
static void do_serial_bh(void)
{
run_task_queue(&tq_serial);
}
static void do_softint(void *private_)
{
struct async_struct *info = (struct async_struct *) private_;
struct tty_struct *tty;
tty = info->tty;
if (!tty)
return;
if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
tty->ldisc.write_wakeup)
(tty->ldisc.write_wakeup)(tty);
wake_up_interruptible(&tty->write_wait);
#ifdef SERIAL_HAVE_POLL_WAIT
wake_up_interruptible(&tty->poll_wait);
#endif
}
}
/*
* This subroutine is called when the RS_TIMER goes off. It is used
* by the serial driver to handle ports that do not have an interrupt
* (irq=0). This doesn't work very well for 16450's, but gives barely
* passable results for a 16550A. (Although at the expense of much
* CPU overhead).
*/
static void rs_timer(unsigned long dummy)
{
#ifndef UARTPOLLING
static unsigned long last_strobe;
struct async_struct *info;
unsigned int i;
unsigned long flags;
if ((jiffies - last_strobe) >= RS_STROBE_TIME) {
for (i=0; i < NR_IRQS; i++) {
info = IRQ_ports[i];
if (!info)
continue;
save_flags(flags); cli();
rs_interrupt_single(i, NULL, NULL);
restore_flags(flags);
}
}
last_strobe = jiffies;
mod_timer(&serial_timer, jiffies + RS_STROBE_TIME);
if (IRQ_ports[0]) {
save_flags(flags); cli();
rs_interrupt_single(0, NULL, NULL);
restore_flags(flags);
mod_timer(&serial_timer, jiffies + IRQ_timeout[0]);
}
#endif
}
/*
* ---------------------------------------------------------------
* Low level utility subroutines for the serial driver: routines to
* figure out the appropriate timeout for an interrupt chain, routines
* to initialize and startup a serial port, and routines to shutdown a
* serial port. Useful stuff like that.
* ---------------------------------------------------------------
*/
/*
* This routine figures out the correct timeout for a particular IRQ.
* It uses the smallest timeout of all of the serial ports in a
* particular interrupt chain. Now only used for IRQ 0....
*/
static void figure_IRQ_timeout(int irq)
{
struct async_struct *info;
int timeout = 60*HZ; // 60 seconds === a long time :-)
info = IRQ_ports[irq];
if (!info) {
IRQ_timeout[irq] = 60*HZ;
return;
}
while (info) {
if (info->timeout < timeout)
timeout = info->timeout;
info = info->next_port;
}
if (!irq)
timeout = timeout / 2;
IRQ_timeout[irq] = (timeout > 3) ? timeout-2 : 1;
}
static int startup(struct async_struct * info)
{
unsigned long flags;
int retval=0;
void (*handler)(int, void *, struct pt_regs *);
struct serial_state *state= info->state;
unsigned long page;
page = get_zeroed_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
save_flags(flags); cli();
if (info->flags & ASYNC_INITIALIZED) {
free_page(page);
goto errout;
}
if (!CONFIGURED_SERIAL_PORT(state) || !state->type) {
if (info->tty)
set_bit(TTY_IO_ERROR, &info->tty->flags);
free_page(page);
goto errout;
}
if (info->xmit.buf)
free_page(page);
else
info->xmit.buf = (unsigned char *) page;
#ifdef SERIAL_DEBUG_OPEN
printk("starting up ttys%d (irq %d)...", info->line, state->irq);
#endif
switch(info->line)
{
case 0:
case 1:
CLEAR_PEND_INT(state->irq); /* clear serial UART rx interrupt */
CLEAR_PEND_INT(state->irq-4); /* clear serial UART tx interrupt */
break;
/**/
/*case 2: */
/*case 3: */
/*disable_uart_tx_interrupt(info->line);*/
/*enable_uart_tx_interrupt(info->line); */
/*disable_uart_rx_interrupt(info->line);*/
/*enable_uart_rx_interrupt(info->line); */
/*break; */
default:
break;
}
//
// Allocate the IRQ if necessary
//
if (state->irq && (!IRQ_ports[state->irq] ||
!IRQ_ports[state->irq]->next_port)) {
if (IRQ_ports[state->irq]) {
retval = -EBUSY;
goto errout;
} else
{
if(info->line==0||info->line==1)
{
handler = rs_interrupt_single;
// Mac Wang register rx and tx seperatly
retval = request_irq(state->irq, handler, SA_SHIRQ,
"serial Rx", &IRQ_ports[state->irq]);
retval = request_irq(state->irq - 4, handler, SA_SHIRQ,
"serial Tx", &IRQ_ports[state->irq-4]);
}
/*
else
{
handler = rs_83977_interrupt;
printk("rs_83977_interrupt:%d\n",state->irq);
retval = request_irq(state->irq, handler, SA_SHIRQ,
"83977 serial Tx && Rx", &IRQ_ports[state->irq]);
}
*/
}
if (retval) {
if (capable(CAP_SYS_ADMIN)) {
if (info->tty)
set_bit(TTY_IO_ERROR,
&info->tty->flags);
retval = 0;
}
goto errout;
}
}
//
// Insert serial port into IRQ chain.
//
info->prev_port = 0;
info->next_port = IRQ_ports[state->irq];
if (info->next_port)
info->next_port->prev_port = info;
if(info->line==0||info->line==1)
{
IRQ_ports[state->irq] = info;
figure_IRQ_timeout(state->irq);
IRQ_ports[state->irq - 4] = info;
figure_IRQ_timeout(state->irq - 4);
}
/*
else
{
IRQ_ports[state->irq] = info;
figure_IRQ_timeout(state->irq);
}
*/
//
// Now, initialize the UART
//
/*
serial_outp(info, UART_LCR, UART_LCR_WLEN8); // reset DLAB
info->MCR = 0;
if (info->tty->termios->c_cflag & CBAUD)
info->MCR = UART_MCR_DTR | UART_MCR_RTS;
{
if (state->irq != 0)
info->MCR |= UART_MCR_OUT2;
}
info->MCR |= ALPHA_KLUDGE_MCR; // Don't ask
serial_outp(info, UART_MCR, info->MCR);
*/
#ifdef CONFIG_SERIAL_SAMSUNG_IRDA
if (info->line == 1){
serial_outp(info, UART_LCR, UART_LCR_WLEN8|UART_LCR_IRDA);
}
else
serial_outp(info, UART_LCR, UART_LCR_WLEN8); // UART0 don't support IRDA mode
#else
if(info->line==0||info->line==1)
serial_outp(info, UART_LCR, UART_LCR_WLEN8);
/*else */
/* serial_outp(info, EX_UART_LCR, UART_LCR_WLEN8);*/
#endif
/* Enable the I/O pins*/
if (info->line == 1)
{
CSR_WRITE(rPCONC,((3 << 20)|(3 << 22)|(3 << 24)| (3 << 26) | (3<<28)|(3 <<30))); // Enable UART1's Pin
CSR_WRITE(rPUPC,CSR_READ(rPUPC)|0xfc00); // set pull up
#ifdef CONFIG_SERIAL_SAMSUNG_IRDA
CSR_WRITE(rPCONE,CSR_READ(rPCONE)|1); // Enable UART0's Pin
CSR_WRITE(rPDATE,CSR_READ(rPDATE)&0xFE); // select enable IRDA
#endif
}
else
{
if(info->line==0)
{
CSR_WRITE(rPCONE,CSR_READ(rPCONE)|(2 << 2) | (2 << 4)); // Enable UART0's Pin
}
}
// serial_outp(info, UART_GCR, UART_GCR_RX_INT|UART_GCR_TX_INT|UART_GCR_RX_STAT_INT);
if(info->line==0||info->line==1)
{
serial_outp(info, UART_GCR, UART_GCR_RX_INT|UART_GCR_TX_INT);
}
/*else */
/*{ */
/*serial_outp(info, EX_UART_GCR, EX_UART_GCR_RX_INT|EX_UART_GCR_TX_INT);*/
/*} */
//
// Finally, enable interrupts
//
/*
info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
serial_outp(info, UART_IER, info->IER); // enable interrupts
*/
enable_uart_rx_interrupt(info->line) ;
//
// And clear the interrupt registers again for luck.
//
CLEAR_PEND_INT(state->irq); /* clear serial UART rx interrupt */
if(info->line==0||info->line==1)
{
CLEAR_PEND_INT(state->irq-4); /* clear serial UART tx interrupt */
}
if (info->tty)
clear_bit(TTY_IO_ERROR, &info->tty->flags);
info->xmit.head = info->xmit.tail = 0;
//
// Set up serial timers...
//
mod_timer(&serial_timer, jiffies + 2*HZ/100);
//
// Set up the tty->alt_speed kludge
//
#if (LINUX_VERSION_CODE >= 131394) // Linux 2.1.66
if (info->tty) {
if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
info->tty->alt_speed = 57600;
if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
info->tty->alt_speed = 115200;
if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
info->tty->alt_speed = 230400;
if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
info->tty->alt_speed = 460800;
}
#endif
//
// and set the speed of the serial port
//
change_speed(info, 0);
info->flags |= ASYNC_INITIALIZED;
restore_flags(flags);
return 0;
errout:
restore_flags(flags);
return retval;
}
/*
* This routine will shutdown a serial port; interrupts are disabled, and
* DTR is dropped if the hangup on close termio flag is on.
*/
static void shutdown(struct async_struct * info)
{
unsigned long flags;
struct serial_state *state;
int retval;
if (!(info->flags & ASYNC_INITIALIZED))
return;
state = info->state;
#ifdef SERIAL_DEBUG_OPEN
printk("Shutting down serial port %d (irq %d)....", info->line,
state->irq);
#endif
save_flags(flags); cli(); // Disable interrupts
//
// clear delta_msr_wait queue to avoid mem leaks: we may free the irq
// here so the queue might never be waken up
//
wake_up_interruptible(&info->delta_msr_wait);
//
// First unlink the serial port from the IRQ chain...
//
if (info->next_port)
info->next_port->prev_port = info->prev_port;
if (info->prev_port)
info->prev_port->next_port = info->next_port;
else
IRQ_ports[state->irq] = info->next_port;
figure_IRQ_timeout(state->irq);
//
// Free the IRQ, if necessary
//
// rx
if (state->irq && (!IRQ_ports[state->irq] ||
!IRQ_ports[state->irq]->next_port)) {
if (IRQ_ports[state->irq]) {
free_irq(state->irq, &IRQ_ports[state->irq]);
retval = request_irq(state->irq, rs_interrupt_single,
SA_SHIRQ, "serial",
&IRQ_ports[state->irq]);
if (retval)
printk("serial shutdown: request_irq: error %d"
" Couldn't reacquire IRQ.\n", retval);
} else
free_irq(state->irq, &IRQ_ports[state->irq]);
}
// tx
if (state->irq - 4 && (!IRQ_ports[state->irq - 4] ||
!IRQ_ports[state->irq - 4]->next_port)) {
free_irq(state->irq-4, &IRQ_ports[state->irq-4]);
}
if (info->xmit.buf) {
unsigned long pg = (unsigned long) info->xmit.buf;
info->xmit.buf = 0;
free_page(pg);
}
/*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -