📄 sab82532.c
字号:
#endif } if (stat->sreg.isr1 & SAB82532_ISR1_CSC) { info->cts = readb(&info->regs->r.star) & SAB82532_STAR_CTS; info->icount.cts++; modem_change++;#ifdef SERIAL_DEBUG_MODEM printk("CTS change: %d, CTS %s\n", info->icount.cts, info->cts ? "on" : "off");#endif } if ((readb(&info->regs->r.pvr) & info->pvr_dsr_bit) ^ info->dsr) { info->dsr = (readb(&info->regs->r.pvr) & info->pvr_dsr_bit) ? 0 : 1; info->icount.dsr++; modem_change++;#ifdef SERIAL_DEBUG_MODEM printk("DSR change: %d\n", info->icount.dsr);#endif } if (modem_change) wake_up_interruptible(&info->delta_msr_wait); if ((info->flags & ASYNC_CHECK_CD) && (stat->sreg.isr0 & SAB82532_ISR0_CDSC)) {#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR)) printk("ttys%d CD now %s...", info->line, (info->dcd) ? "on" : "off");#endif if (info->dcd) wake_up_interruptible(&info->open_wait); else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) && (info->flags & ASYNC_CALLOUT_NOHUP))) {#ifdef SERIAL_DEBUG_OPEN printk("scheduling hangup...");#endif MOD_INC_USE_COUNT; if (schedule_task(&info->tqueue_hangup) == 0) MOD_DEC_USE_COUNT; } } if (info->flags & ASYNC_CTS_FLOW) { if (info->tty->hw_stopped) { if (info->cts) {#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) printk("CTS tx start...");#endif info->tty->hw_stopped = 0; sab82532_sched_event(info, RS_EVENT_WRITE_WAKEUP); info->interrupt_mask1 &= ~(SAB82532_IMR1_XPR); writeb(info->interrupt_mask1, &info->regs->w.imr1); sab82532_start_tx(info); } } else { if (!(info->cts)) {#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) printk("CTS tx stop...");#endif info->tty->hw_stopped = 1; } } }}/* * This is the serial driver's generic interrupt routine */static void sab82532_interrupt(int irq, void *dev_id, struct pt_regs *regs){ struct sab82532 *info = dev_id; union sab82532_irq_status status;#ifdef SERIAL_DEBUG_INTR printk("sab82532_interrupt(%d)...", irq);#endif status.stat = 0; if (readb(&info->regs->r.gis) & SAB82532_GIS_ISA0) status.sreg.isr0 = readb(&info->regs->r.isr0); if (readb(&info->regs->r.gis) & SAB82532_GIS_ISA1) status.sreg.isr1 = readb(&info->regs->r.isr1);#ifdef SERIAL_DEBUG_INTR printk("%d<%02x.%02x>", info->line, status.sreg.isr0, status.sreg.isr1);#endif if (!status.stat) goto next; if (status.sreg.isr0 & (SAB82532_ISR0_TCD | SAB82532_ISR0_TIME | SAB82532_ISR0_RFO | SAB82532_ISR0_RPF)) receive_chars(info, &status); if ((status.sreg.isr0 & SAB82532_ISR0_CDSC) || (status.sreg.isr1 & (SAB82532_ISR1_BRK | SAB82532_ISR1_CSC))) check_status(info, &status); if (status.sreg.isr1 & (SAB82532_ISR1_ALLS | SAB82532_ISR1_XPR)) transmit_chars(info, &status);next: info = info->next; status.stat = 0; if (readb(&info->regs->r.gis) & SAB82532_GIS_ISB0) status.sreg.isr0 = readb(&info->regs->r.isr0); if (readb(&info->regs->r.gis) & SAB82532_GIS_ISB1) status.sreg.isr1 = readb(&info->regs->r.isr1);#ifdef SERIAL_DEBUG_INTR printk("%d<%02x.%02x>", info->line, status.sreg.isr0, status.sreg.isr1);#endif if (!status.stat) goto done; if (status.sreg.isr0 & (SAB82532_ISR0_TCD | SAB82532_ISR0_TIME | SAB82532_ISR0_RFO | SAB82532_ISR0_RPF)) receive_chars(info, &status); if ((status.sreg.isr0 & SAB82532_ISR0_CDSC) || (status.sreg.isr1 & (SAB82532_ISR1_BRK | SAB82532_ISR1_CSC))) check_status(info, &status); if (status.sreg.isr1 & (SAB82532_ISR1_ALLS | SAB82532_ISR1_XPR)) transmit_chars(info, &status);done:#ifdef SERIAL_DEBUG_INTR printk("end.\n");#endif}/* * ------------------------------------------------------------------- * 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 * sab82532_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 sab82532_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 sab82532 *info = (struct sab82532 *)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); }}/* * 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() -> sab82532_hangup() * */static void do_serial_hangup(void *private_){ struct sab82532 *info = (struct sab82532 *) private_; struct tty_struct *tty; tty = info->tty; if (tty) tty_hangup(tty); MOD_DEC_USE_COUNT;}static voidsab82532_init_line(struct sab82532 *info){ unsigned char stat, tmp; /* * Wait for any commands or immediate characters */ sab82532_cec_wait(info); sab82532_tec_wait(info); /* * Clear the FIFO buffers. */ writeb(SAB82532_CMDR_RRES, &info->regs->w.cmdr); sab82532_cec_wait(info); writeb(SAB82532_CMDR_XRES, &info->regs->w.cmdr); /* * Clear the interrupt registers. */ stat = readb(&info->regs->r.isr0); stat = readb(&info->regs->r.isr1); /* * Now, initialize the UART */ writeb(0, &info->regs->w.ccr0); /* power-down */ writeb(SAB82532_CCR0_MCE | SAB82532_CCR0_SC_NRZ | SAB82532_CCR0_SM_ASYNC, &info->regs->w.ccr0); writeb(SAB82532_CCR1_ODS | SAB82532_CCR1_BCR | 7, &info->regs->w.ccr1); writeb(SAB82532_CCR2_BDF | SAB82532_CCR2_SSEL | SAB82532_CCR2_TOE, &info->regs->w.ccr2); writeb(0, &info->regs->w.ccr3); writeb(SAB82532_CCR4_MCK4 | SAB82532_CCR4_EBRG, &info->regs->w.ccr4); writeb(SAB82532_MODE_RTS | SAB82532_MODE_FCTS | SAB82532_MODE_RAC, &info->regs->w.mode); writeb(SAB82532_RFC_DPS | SAB82532_RFC_RFDF, &info->regs->w.rfc); switch (info->recv_fifo_size) { case 1: tmp = readb(&info->regs->w.rfc); tmp |= SAB82532_RFC_RFTH_1; writeb(tmp, &info->regs->w.rfc); break; case 4: tmp = readb(&info->regs->w.rfc); tmp |= SAB82532_RFC_RFTH_4; writeb(tmp, &info->regs->w.rfc); break; case 16: tmp = readb(&info->regs->w.rfc); tmp |= SAB82532_RFC_RFTH_16; writeb(tmp, &info->regs->w.rfc); break; default: info->recv_fifo_size = 32; /* fall through */ case 32: tmp = readb(&info->regs->w.rfc); tmp |= SAB82532_RFC_RFTH_32; writeb(tmp, &info->regs->w.rfc); break; } tmp = readb(&info->regs->rw.ccr0); tmp |= SAB82532_CCR0_PU; /* power-up */ writeb(tmp, &info->regs->rw.ccr0);}static int startup(struct sab82532 *info){ unsigned long flags; unsigned long page; int retval = 0; page = get_free_page(GFP_KERNEL); if (!page) return -ENOMEM; save_flags(flags); cli(); if (info->flags & ASYNC_INITIALIZED) { free_page(page); goto errout; } if (!info->regs) { if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); free_page(page); retval = -ENODEV; goto errout; } if (info->xmit_buf) free_page(page); else info->xmit_buf = (unsigned char *)page;#ifdef SERIAL_DEBUG_OPEN printk("starting up serial port %d...", info->line);#endif /* * Initialize the Hardware */ sab82532_init_line(info); if (info->tty->termios->c_cflag & CBAUD) { u8 tmp; tmp = readb(&info->regs->rw.mode); tmp &= ~(SAB82532_MODE_FRTS); tmp |= SAB82532_MODE_RTS; writeb(tmp, &info->regs->rw.mode); tmp = readb(&info->regs->rw.pvr); tmp &= ~(info->pvr_dtr_bit); writeb(tmp, &info->regs->rw.pvr); } /* * Finally, enable interrupts */ info->interrupt_mask0 = SAB82532_IMR0_PERR | SAB82532_IMR0_FERR | SAB82532_IMR0_PLLA; writeb(info->interrupt_mask0, &info->regs->w.imr0); info->interrupt_mask1 = SAB82532_IMR1_BRKT | SAB82532_IMR1_ALLS | SAB82532_IMR1_XOFF | SAB82532_IMR1_TIN | SAB82532_IMR1_CSC | SAB82532_IMR1_XON | SAB82532_IMR1_XPR; writeb(info->interrupt_mask1, &info->regs->w.imr1); info->all_sent = 1; if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; /* * and set the speed of the serial port */ change_speed(info); 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 sab82532 *info){ unsigned long flags; u8 tmp; if (!(info->flags & ASYNC_INITIALIZED)) return;#ifdef SERIAL_DEBUG_OPEN printk("Shutting down serial port %d...", info->line);#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); if (info->xmit_buf) { free_page((unsigned long)info->xmit_buf); info->xmit_buf = 0; }#ifdef CONFIG_SERIAL_CONSOLE if (info->is_console) { info->interrupt_mask0 = SAB82532_IMR0_PERR | SAB82532_IMR0_FERR | SAB82532_IMR0_PLLA | SAB82532_IMR0_CDSC; writeb(info->interrupt_mask0, &info->regs->w.imr0); info->interrupt_mask1 = SAB82532_IMR1_BRKT | SAB82532_IMR1_ALLS | SAB82532_IMR1_XOFF | SAB82532_IMR1_TIN | SAB82532_IMR1_CSC | SAB82532_IMR1_XON | SAB82532_IMR1_XPR; writeb(info->interrupt_mask1, &info->regs->w.imr1); if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); info->flags &= ~ASYNC_INITIALIZED; restore_flags(flags); return; }#endif /* Disable Interrupts */ info->interrupt_mask0 = 0xff; writeb(info->interrupt_mask0, &info->regs->w.imr0); info->interrupt_mask1 = 0xff; writeb(info->interrupt_mask1, &info->regs->w.imr1); if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) { writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_FRTS, &info->regs->rw.mode); writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_RTS, &info->regs->rw.mode); writeb(readb(&info->regs->rw.pvr) | info->pvr_dtr_bit, &info->regs->rw.pvr); } /* Disable break condition */ tmp = readb(&info->regs->rw.dafo); tmp &= ~(SAB82532_DAFO_XBRK); writeb(tmp, &info->regs->rw.dafo); /* Disable Receiver */ tmp = readb(&info->regs->rw.mode); tmp &= ~(SAB82532_MODE_RAC); writeb(tmp, &info->regs->rw.mode); /* Power Down */ tmp = readb(&info->regs->rw.ccr0); tmp &= ~(SAB82532_CCR0_PU); writeb(tmp, &info->regs->rw.ccr0); if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); info->flags &= ~ASYNC_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 change_speed(struct sab82532 *info){ unsigned long flags; unsigned int ebrg; tcflag_t cflag; unsigned char dafo; int i, bits; if (!info->tty || !info->tty->termios) return; cflag = info->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; case CS8: dafo = SAB82532_DAFO_CHL8; bits = 10; break; /* Never happens, but GCC is too dumb to figure it out */ default: dafo = SAB82532_DAFO_CHL5; bits = 7; 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; } /* Determine EBRG values based on baud rate */ i = cflag & CBAUD; if (i & CBAUDEX) { i &= ~(CBAUDEX); if ((i < 1) || ((i + 15) >= NR_EBRG_VALUES)) info->tty->termios->c_cflag &= ~CBAUDEX; else i += 15; } ebrg = ebrg_table[i].n; ebrg |= (ebrg_table[i].m << 6); info->baud = ebrg_table[i].baud; if (info->baud) { info->timeout = (info->xmit_fifo_size * HZ * bits) / info->baud; info->tec_timeout = (10 * 1000000) / info->baud; info->cec_timeout = info->tec_timeout >> 2;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -