📄 68360serial.c
字号:
!(tty->termios->c_cflag & CRTSCTS)) { tty->hw_stopped = 0; rs_360_start(tty); }#endif#if 0 /* * No need to wake up processes in open wait, since they * sample the CLOCAL flag once, and don't recheck it. * XXX It's not clear whether the current behavior is correct * or not. Hence, this may change..... */ if (!(old_termios->c_cflag & CLOCAL) && (tty->termios->c_cflag & CLOCAL)) wake_up_interruptible(&info->open_wait);#endif}/* * ------------------------------------------------------------ * rs_close() * * This routine is called when the serial port gets closed. First, we * wait for the last remaining data to be sent. Then, we unlink its * async structure from the interrupt chain if necessary, and we free * that IRQ if nothing is left in the chain. * ------------------------------------------------------------ */static void rs_360_close(struct tty_struct *tty, struct file * filp){ ser_info_t *info = (ser_info_t *)tty->driver_data; /* struct async_state *state; */ struct serial_state *state; unsigned long flags; int idx; volatile struct smc_regs *smcp; volatile struct scc_regs *sccp; if (!info || serial_paranoia_check(info, tty->name, "rs_close")) return; state = info->state; local_irq_save(flags); if (tty_hung_up_p(filp)) { DBG_CNT("before DEC-hung"); local_irq_restore(flags); return; } #ifdef SERIAL_DEBUG_OPEN printk("rs_close ttys%d, count = %d\n", info->line, state->count);#endif if ((tty->count == 1) && (state->count != 1)) { /* * Uh, oh. tty->count is 1, which means that the tty * structure will be freed. state->count should always * be one in these conditions. If it's greater than * one, we've got real problems, since it means the * serial port won't be shutdown. */ printk("rs_close: bad serial port count; tty->count is 1, " "state->count is %d\n", state->count); state->count = 1; } if (--state->count < 0) { printk("rs_close: bad serial port count for ttys%d: %d\n", info->line, state->count); state->count = 0; } if (state->count) { DBG_CNT("before DEC-2"); local_irq_restore(flags); return; } info->flags |= ASYNC_CLOSING; /* * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. */ tty->closing = 1; if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) tty_wait_until_sent(tty, info->closing_wait); /* * At this point we stop accepting input. To do this, we * disable the receive line status interrupts, and tell the * interrupt driver to stop checking the data ready bit in the * line status register. */ info->read_status_mask &= ~BD_SC_EMPTY; if (info->flags & ASYNC_INITIALIZED) { idx = PORT_NUM(info->state->smc_scc_num); if (info->state->smc_scc_num & NUM_IS_SCC) { sccp = &pquicc->scc_regs[idx]; sccp->scc_sccm &= ~UART_SCCM_RX; sccp->scc_gsmr.w.low &= ~SCC_GSMRL_ENR; } else { smcp = &pquicc->smc_regs[idx]; smcp->smc_smcm &= ~SMCM_RX; smcp->smc_smcmr &= ~SMCMR_REN; } /* * Before we drop DTR, make sure the UART transmitter * has completely drained; this is especially * important if there is a transmit FIFO! */ rs_360_wait_until_sent(tty, info->timeout); } shutdown(info); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); tty_ldisc_flush(tty); tty->closing = 0; info->event = 0; info->tty = 0; if (info->blocked_open) { if (info->close_delay) { msleep_interruptible(jiffies_to_msecs(info->close_delay)); } wake_up_interruptible(&info->open_wait); } info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); local_irq_restore(flags);}/* * rs_wait_until_sent() --- wait until the transmitter is empty */static void rs_360_wait_until_sent(struct tty_struct *tty, int timeout){ ser_info_t *info = (ser_info_t *)tty->driver_data; unsigned long orig_jiffies, char_time; /*int lsr;*/ volatile QUICC_BD *bdp; if (serial_paranoia_check(info, tty->name, "rs_wait_until_sent")) return;#ifdef maybe if (info->state->type == PORT_UNKNOWN) return;#endif orig_jiffies = jiffies; /* * Set the check interval to be 1/5 of the estimated time to * send a single character, and make it at least 1. The check * interval should also be less than the timeout. * * Note: we have to use pretty tight timings here to satisfy * the NIST-PCTS. */ char_time = 1; if (timeout) char_time = min(char_time, (unsigned long)timeout);#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time); printk("jiff=%lu...", jiffies);#endif /* We go through the loop at least once because we can't tell * exactly when the last character exits the shifter. There can * be at least two characters waiting to be sent after the buffers * are empty. */ do {#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT printk("lsr = %d (jiff=%lu)...", lsr, jiffies);#endif/* current->counter = 0; make us low-priority */ msleep_interruptible(jiffies_to_msecs(char_time)); if (signal_pending(current)) break; if (timeout && ((orig_jiffies + timeout) < jiffies)) break; /* The 'tx_cur' is really the next buffer to send. We * have to back up to the previous BD and wait for it * to go. This isn't perfect, because all this indicates * is the buffer is available. There are still characters * in the CPM FIFO. */ bdp = info->tx_cur; if (bdp == info->tx_bd_base) bdp += (TX_NUM_FIFO-1); else bdp--; } while (bdp->status & BD_SC_READY); current->state = TASK_RUNNING;#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);#endif}/* * rs_hangup() --- called by tty_hangup() when a hangup is signaled. */static void rs_360_hangup(struct tty_struct *tty){ ser_info_t *info = (ser_info_t *)tty->driver_data; struct serial_state *state = info->state; if (serial_paranoia_check(info, tty->name, "rs_hangup")) return; state = info->state; rs_360_flush_buffer(tty); shutdown(info); info->event = 0; state->count = 0; info->flags &= ~ASYNC_NORMAL_ACTIVE; info->tty = 0; wake_up_interruptible(&info->open_wait);}/* * ------------------------------------------------------------ * rs_open() and friends * ------------------------------------------------------------ */static int block_til_ready(struct tty_struct *tty, struct file * filp, ser_info_t *info){#ifdef DO_THIS_LATER DECLARE_WAITQUEUE(wait, current);#endif struct serial_state *state = info->state; int retval; int do_clocal = 0; /* * If the device is in the middle of being closed, then block * until it's done, and then try again. */ if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) { if (info->flags & ASYNC_CLOSING) interruptible_sleep_on(&info->close_wait);#ifdef SERIAL_DO_RESTART if (info->flags & ASYNC_HUP_NOTIFY) return -EAGAIN; else return -ERESTARTSYS;#else return -EAGAIN;#endif } /* * If non-blocking mode is set, or the port is not enabled, * then make the check up front and then exit. * If this is an SMC port, we don't have modem control to wait * for, so just get out here. */ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR)) || !(info->state->smc_scc_num & NUM_IS_SCC)) { info->flags |= ASYNC_NORMAL_ACTIVE; return 0; } if (tty->termios->c_cflag & CLOCAL) do_clocal = 1; /* * Block waiting for the carrier detect and the line to become * free (i.e., not in use by the callout). While we are in * this loop, state->count is dropped by one, so that * rs_close() knows when to free things. We restore it upon * exit, either normal or abnormal. */ retval = 0;#ifdef DO_THIS_LATER add_wait_queue(&info->open_wait, &wait);#ifdef SERIAL_DEBUG_OPEN printk("block_til_ready before block: ttys%d, count = %d\n", state->line, state->count);#endif local_irq_disable(); if (!tty_hung_up_p(filp)) state->count--; local_irq_enable(); info->blocked_open++; while (1) { local_irq_disable(); if (tty->termios->c_cflag & CBAUD) serial_out(info, UART_MCR, serial_inp(info, UART_MCR) | (UART_MCR_DTR | UART_MCR_RTS)); local_irq_enable(); set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)) {#ifdef SERIAL_DO_RESTART if (info->flags & ASYNC_HUP_NOTIFY) retval = -EAGAIN; else retval = -ERESTARTSYS; #else retval = -EAGAIN;#endif break; } if (!(info->flags & ASYNC_CLOSING) && (do_clocal || (serial_in(info, UART_MSR) & UART_MSR_DCD))) break; if (signal_pending(current)) { retval = -ERESTARTSYS; break; }#ifdef SERIAL_DEBUG_OPEN printk("block_til_ready blocking: ttys%d, count = %d\n", info->line, state->count);#endif schedule(); } current->state = TASK_RUNNING; remove_wait_queue(&info->open_wait, &wait); if (!tty_hung_up_p(filp)) state->count++; info->blocked_open--;#ifdef SERIAL_DEBUG_OPEN printk("block_til_ready after blocking: ttys%d, count = %d\n", info->line, state->count);#endif#endif /* DO_THIS_LATER */ if (retval) return retval; info->flags |= ASYNC_NORMAL_ACTIVE; return 0;}static int get_async_struct(int line, ser_info_t **ret_info){ struct serial_state *sstate; sstate = rs_table + line; if (sstate->info) { sstate->count++; *ret_info = (ser_info_t *)sstate->info; return 0; } else { return -ENOMEM; }}/* * This routine is called whenever a serial port is opened. It * enables interrupts for a serial port, linking in its async structure into * the IRQ chain. It also performs the serial-specific * initialization for the tty structure. */static int rs_360_open(struct tty_struct *tty, struct file * filp){ ser_info_t *info; int retval, line; line = tty->index; if ((line < 0) || (line >= NR_PORTS)) return -ENODEV; retval = get_async_struct(line, &info); if (retval) return retval; if (serial_paranoia_check(info, tty->name, "rs_open")) return -ENODEV;#ifdef SERIAL_DEBUG_OPEN printk("rs_open %s, count = %d\n", tty->name, info->state->count);#endif tty->driver_data = info; info->tty = tty; /* * Start up serial port */ retval = startup(info); if (retval) return retval; retval = block_til_ready(tty, filp, info); if (retval) {#ifdef SERIAL_DEBUG_OPEN printk("rs_open returning after block_til_ready with %d\n", retval);#endif return retval; }#ifdef SERIAL_DEBUG_OPEN printk("rs_open %s successful...", tty->name);#endif return 0;}/* * /proc fs routines.... */static inline int line_info(char *buf, struct serial_state *state){#ifdef notdef struct async_struct *info = state->info, scr_info; char stat_buf[30], control, status;#endif int ret; ret = sprintf(buf, "%d: uart:%s port:%X irq:%d", state->line, (state->smc_scc_num & NUM_IS_SCC) ? "SCC" : "SMC", (unsigned int)(state->port), state->irq); if (!state->port || (state->type == PORT_UNKNOWN)) { ret += sprintf(buf+ret, "\n"); return ret; }#ifdef notdef /* * Figure out the current RS-232 lines */ if (!info) { info = &scr_info; /* This is just for serial_{in,out} */ info->magic = SERIAL_MAGIC; info->port = state->port; info->flags = state->flags; info->quot = 0; info->tty = 0; } local_irq_disable(); status = serial_in(info, UART_MSR); control = info ? info->MCR : serial_in(info, UART_MCR); local_irq_enable(); stat_buf[0] = 0; stat_buf[1] = 0; if (control & UART_MCR_RTS) strcat(stat_buf, "|RTS"); if (status & UART_MSR_CTS) strcat(stat_buf, "|CTS"); if (control & UART_MCR_DTR) strcat(stat_buf, "|DTR"); if (status & UART_MSR_DSR) strcat(stat_buf, "|DSR"); if (status & UART_MSR_DCD) strcat(stat_buf, "|CD"); if (status & UART_MSR_RI) strcat(stat_buf, "|RI"); if (info->quot) { ret += sprintf(buf+ret, " baud:%d", state->baud_base / info->quot); } ret += sprintf(buf+ret, " tx:%d rx:%d", state->icount.tx, state->icount.rx); if (state->icount.frame) ret += sprintf(buf+ret, " fe:%d", state->icount.frame); if (state->icount.parity) ret += sprintf(buf+ret, " pe:%d", state->icount.parity); if (state->icount.brk) ret += sprintf(buf+ret, " brk:%d", state->icount.brk); if (state->icount.overrun) ret += sprintf(buf+ret, " oe:%d", state->icount.overrun); /* * Last thing is the RS-232 status lines */ ret += sprintf(buf+ret, " %s\n", stat_buf+1);#endif return ret;}int rs_360_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data){ int i, len = 0; off_t begin = 0; len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version); for (i = 0; i < NR_PORTS && len < 4000; i++) { len += line_info(page + len, &rs_table[i]); if (len+begin > off+count) goto done; if (len+begin < off) { begin += len; len = 0; } } *eof = 1;done: if (off >= len+begin) return 0; *start = page + (begin-off); return ((count < begin+len-off) ? count : begin+len-off);}/* * --------------------------------------------------------------------- * rs_init() and friends * * rs_init() is called at boot-time to initialize the serial driver. * --------------------------------------------------------------------- *//* * This routine prints out the appropriate serial driver version * number, and identifies which options were configured into this
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -