📄 8253xtty.c
字号:
{ skb_unlink(port->active2.receive->HostVaddr); skb_queue_tail(port->sab8253xc_rcvbuflist, port->active2.receive->HostVaddr); skb_queue_head(port->sab8253xbuflist, skb); port->active2.receive->HostVaddr = skb; port->active2.receive->Count = (port->recv_fifo_size|OWN_SAB); } queue_task(&tty->flip.tqueue, &tq_timer); port->icount.brk++; } if (stat->images[ISR0_IDX] & SAB82532_ISR0_RFO) { port->active2.receive->HostVaddr->tail[0] = 0; port->active2.receive->HostVaddr->tail[1] = TTY_PARITY; port->active2.receive->HostVaddr->tail += 2; port->active2.receive->HostVaddr->data_len = 2; port->active2.receive->HostVaddr->len = 2; if(skb = dev_alloc_skb(port->recv_fifo_size), skb == NULL) { port->icount.buf_overrun++; port->active2.receive->HostVaddr->tail = port->active2.receive->HostVaddr->data; /* clear the buffer */ port->active2.receive->Count = (port->recv_fifo_size|OWN_SAB); port->active2.receive->HostVaddr->data_len = 0; port->active2.receive->HostVaddr->len = 0; } else { skb_unlink(port->active2.receive->HostVaddr); skb_queue_tail(port->sab8253xc_rcvbuflist, port->active2.receive->HostVaddr); skb_queue_head(port->sab8253xbuflist, skb); port->active2.receive->HostVaddr = skb; port->active2.receive->Count = (port->recv_fifo_size|OWN_SAB); } queue_task(&tty->flip.tqueue, &tq_timer); port->icount.overrun++; } check_modem: /* Checking DCD */ sig = &port->dcd; if (stat->images[sig->irq] & sig->irqmask) { sig->val = ISON(port,dcd); port->icount.dcd++; modem_change++; } /* Checking CTS */ sig = &port->cts; if (stat->images[sig->irq] & sig->irqmask) { sig->val = ISON(port,cts); port->icount.cts++; modem_change++; } /* Checking DSR */ sig = &port->dsr; if (stat->images[sig->irq] & sig->irqmask) { sig->val = ISON(port,dsr); port->icount.dsr++; modem_change++; } if (modem_change) { wake_up_interruptible(&port->delta_msr_wait); /* incase kernel proc level was waiting on modem change */ } sig = &port->dcd; if ((port->flags & FLAG8253X_CHECK_CD) && (stat->images[sig->irq] & sig->irqmask)) { if (sig->val) { wake_up_interruptible(&port->open_wait); /* in case waiting in block_til_ready */ } else if (!((port->flags & FLAG8253X_CALLOUT_ACTIVE) && (port->flags & FLAG8253X_CALLOUT_NOHUP))) { MOD_INC_USE_COUNT; /* in case a close is already in progress don't want structures to vanish during late processing of hangup */ if (schedule_task(&port->tqueue_hangup) == 0) { MOD_DEC_USE_COUNT; /* task schedule failed */ } } } sig = &port->cts; if (port->flags & FLAG8253X_CTS_FLOW) { if (port->tty->hw_stopped) { if (sig->val) { port->tty->hw_stopped = 0; sab8253x_sched_event(port, SAB8253X_EVENT_WRITE_WAKEUP); sab8253x_start_tx(port); } } else { if (!(sig->val)) { port->tty->hw_stopped = 1; } } }}/* * 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 * sab8253x_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 sab8253x_sched_event(), and they get done here. */ /* The following routine is installed */ /* in the bottom half -- just search */ /* for the init_bh() call */ /* The logic: sab8253x_sched_event() */ /* enqueues the tqueue port entry on */ /* the tq_8253x_serial task list -- */ /* whenever the bottom half is run */ /* sab8253x_do_softint is invoked for */ /* every port that has invoked the bottom */ /* half via sab8253x_sched_event(). */ /* currently only a write wakeevent */ /* wakeup is scheduled -- to tell the */ /* tty driver to send more chars */ /* down to the serial driver.*/static void sab8253x_do_serial_bh(void){ run_task_queue(&tq_8253x_serial);} /* I believe the reason for the */ /* bottom half processing below is */ /* the length of time needed to transfer */ /* characters to the TTY driver. */static void sab8253x_do_softint(void *private_){ struct sab_port *port = (struct sab_port *)private_; struct tty_struct *tty; tty = port->tty; if (!tty) { return; } port->DoingInterrupt = 1; if (test_and_clear_bit(SAB8253X_EVENT_WRITE_WAKEUP, &port->event)) { if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup)(tty); wake_up_interruptible(&tty->write_wait); /* in case tty driver waiting on write */ } port->DoingInterrupt = 0;}/* * This routine is called from the scheduler tqueue when the interrupt * routine has signalled that a hangup has occurred. The path of * hangup processing is: * * serial interrupt routine -> (scheduler tqueue) -> * do_serial_hangup() -> tty->hangup() -> sab8253x_hangup() * *//* This logic takes place at kernel *//* process context through the scheduler*//* schedule_task(tqueue_hangup) *//* takes place in the interrupt handler*/static void sab8253x_do_serial_hangup(void *private_){ struct sab_port *port = (struct sab_port *) private_; struct tty_struct *tty; tty = port->tty; if (tty) { tty_hangup(tty); } MOD_DEC_USE_COUNT; /* in case busy waiting to unload module */}static voidsab8253x_init_line(struct sab_port *port){ unsigned char stat; if(port->chip->c_cim) { if(port->chip->c_cim->ci_type == CIM_SP502) { aura_sp502_program(port, SP502_OFF_MODE); } } /* * Wait for any commands or immediate characters */ sab8253x_cec_wait(port); sab8253x_tec_wait(port); /* * Clear the FIFO buffers. */ WRITEB(port, cmdr, SAB82532_CMDR_RRES); sab8253x_cec_wait(port); WRITEB(port, cmdr, SAB82532_CMDR_XRES); /* * Clear the interrupt registers. */ stat = READB(port, isr0); stat = READB(port, isr1); /* * Now, initialize the UART */ WRITEB(port, ccr0, 0); /* power-down */ WRITEB(port, ccr0, SAB82532_CCR0_MCE | SAB82532_CCR0_SC_NRZ | SAB82532_CCR0_SM_ASYNC); WRITEB(port, ccr1, SAB82532_CCR1_ODS | SAB82532_CCR1_BCR | 7); WRITEB(port, ccr2, SAB82532_CCR2_BDF | SAB82532_CCR2_SSEL | SAB82532_CCR2_TOE); WRITEB(port, ccr3, 0); WRITEB(port, ccr4, SAB82532_CCR4_MCK4 | SAB82532_CCR4_EBRG); WRITEB(port, mode, SAB82532_MODE_RTS | SAB82532_MODE_FCTS | SAB82532_MODE_RAC); WRITEB(port, rfc, SAB82532_RFC_DPS | SAB82532_RFC_RFDF); switch (port->recv_fifo_size) { case 1: SET_REG_BIT(port,rfc,SAB82532_RFC_RFTH_1); break; case 4: SET_REG_BIT(port,rfc,SAB82532_RFC_RFTH_4); break; case 16: SET_REG_BIT(port,rfc,SAB82532_RFC_RFTH_16); break; default: port->recv_fifo_size = 32; case 32: SET_REG_BIT(port,rfc,SAB82532_RFC_RFTH_32); break; } /* power-up */ SET_REG_BIT(port, ccr0, SAB82532_CCR0_PU); if(port->chip->c_cim) { if(port->chip->c_cim->ci_type == CIM_SP502) { aura_sp502_program(port, port->sigmode); } }}static int sab8253x_startup(struct sab_port *port){ unsigned long flags; int retval = 0; save_flags(flags); cli(); if (port->flags & FLAG8253X_INITIALIZED) { goto errout; } port->msgbufindex = 0; port->xmit_buf = NULL; port->buffergreedy = 0; if (!port->regs) { if (port->tty) { set_bit(TTY_IO_ERROR, &port->tty->flags); } retval = -ENODEV; goto errout; } /* * Initialize the Hardware */ sab8253x_init_line(port); if (port->tty->termios->c_cflag & CBAUD) { /* Activate RTS */ RAISE(port,rts); /* Activate DTR */ RAISE(port,dtr); } /* * Initialize the modem signals values */ port->dcd.val=ISON(port,dcd); port->cts.val=ISON(port,cts); port->dsr.val=ISON(port,dsr); /* * Finally, enable interrupts */ port->interrupt_mask0 = SAB82532_IMR0_PERR | SAB82532_IMR0_FERR | SAB82532_IMR0_PLLA; WRITEB(port, imr0, port->interrupt_mask0); port->interrupt_mask1 = SAB82532_IMR1_BRKT | SAB82532_IMR1_XOFF | SAB82532_IMR1_TIN | SAB82532_IMR1_XON | SAB82532_IMR1_XPR; WRITEB(port, imr1, port->interrupt_mask1); port->all_sent = 1; if (port->tty) { clear_bit(TTY_IO_ERROR, &port->tty->flags); } port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; /* * and set the speed of the serial port */ sab8253x_change_speed(port); port->flags |= FLAG8253X_INITIALIZED; port->receive_chars = sab8253x_receive_chars; port->transmit_chars = sab8253x_transmit_chars; port->check_status = sab8253x_check_status; port->receive_test = (SAB82532_ISR0_TCD | SAB82532_ISR0_TIME | SAB82532_ISR0_RFO | SAB82532_ISR0_RPF); port->transmit_test = (SAB82532_ISR1_ALLS | SAB82532_ISR1_XPR); port->check_status_test = SAB82532_ISR1_BRK; 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 sab8253x_shutdown(struct sab_port *port){ unsigned long flags; if (!(port->flags & FLAG8253X_INITIALIZED)) { return; } 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(&port->delta_msr_wait); /* shutting down port modem status is pointless */ if (port->xmit_buf) { port->xmit_buf = NULL; } #ifdef XCONFIG_SERIAL_CONSOLE if (port->is_console) { port->interrupt_mask0 = SAB82532_IMR0_PERR | SAB82532_IMR0_FERR | /*SAB82532_IMR0_TIME |*/ SAB82532_IMR0_PLLA | SAB82532_IMR0_CDSC; WRITEB(port,imr0,port->interrupt_mask0); port->interrupt_mask1 = SAB82532_IMR1_BRKT | SAB82532_IMR1_ALLS | SAB82532_IMR1_XOFF | SAB82532_IMR1_TIN | SAB82532_IMR1_CSC | SAB82532_IMR1_XON | SAB82532_IMR1_XPR; WRITEB(port,imr1,port->interrupt_mask1); if (port->tty) { set_bit(TTY_IO_ERROR, &port->tty->flags); } port->flags &= ~FLAG8253X_INITIALIZED; restore_flags(flags); return; }#endif /* Disable Interrupts */ port->interrupt_mask0 = 0xff; WRITEB(port, imr0, port->interrupt_mask0); port->interrupt_mask1 = 0xff; WRITEB(port, imr1, port->interrupt_mask1); if (!port->tty || (port->tty->termios->c_cflag & HUPCL)) { LOWER(port,rts); LOWER(port,dtr); } /* Disable break condition */ CLEAR_REG_BIT(port,dafo,SAB82532_DAFO_XBRK); /* Disable Receiver */ CLEAR_REG_BIT(port,mode,SAB82532_MODE_RAC); /* Power Down */ CLEAR_REG_BIT(port,ccr0,SAB82532_CCR0_PU); if (port->tty) { set_bit(TTY_IO_ERROR, &port->tty->flags); } port->flags &= ~FLAG8253X_INITIALIZED; restore_flags(flags);}/* * This routine is called to set the UART divisor registers to match * the specified baud rate for a serial port. */static void sab8253x_change_speed(struct sab_port *port){ unsigned long flags,baud; tcflag_t cflag; u8 dafo,ccr2=0,ccr4=0,ebrg=0,mode; int i, bits;#ifdef DEBUGGING printk("Change speed! ");#endif if (!port->tty || !port->tty->termios) {#ifdef DEBUGGING printk("NOT!\n");#endif return; } #ifdef DEBUGGING printk(" for real.\n");#endif cflag = port->tty->termios->c_cflag; /* Byte size and parity */ switch (cflag & CSIZE) { case CS5: dafo = SAB82532_DAFO_CHL5; bits = 7; break; case CS6: dafo = SAB82532_DAFO_CHL6; bits = 8; break; case CS7: dafo = SAB82532_DAFO_CHL7; bits = 9; break; default: case CS8: dafo = SAB82532_DAFO_CHL8; bits = 10; break; } if (cflag & CSTOPB) { dafo |= SAB82532_DAFO_STOP; bits++; } if (cflag & PARENB) { dafo |= SAB82532_DAFO_PARE; bits++; } if (cflag & PARODD) {#ifdef CMSPAR if (cflag & CMSPAR) dafo |= SAB82532_DAFO_PAR_MARK; else#endif dafo |= SAB82532_DAFO_PAR_ODD; } else {#ifdef CMSPAR if (cflag & CMSPAR) dafo |= SAB82532_DAFO_PAR_SPACE; else#endif dafo |= SAB82532_DAFO_PAR_EVEN; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -