📄 serial_sicc.c
字号:
} while (quot == 0 && old_termios); /* As a last resort, if the quotient is zero, default to 9600 bps */ if (!quot) quot = (info->port->uartclk / (16 * 9600)) - 1; info->timeout = info->port->fifosize * HZ * bits / baud; info->timeout += HZ/50; /* Add .02 seconds of slop */ if (cflag & CRTSCTS) info->flags |= ASYNC_CTS_FLOW; else info->flags &= ~ASYNC_CTS_FLOW; if (cflag & CLOCAL) info->flags &= ~ASYNC_CHECK_CD; else info->flags |= ASYNC_CHECK_CD; /* * Set up parity check flag */#define RELEVENT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) info->read_status_mask = _LSR_OE_MASK; if (I_INPCK(info->tty)) info->read_status_mask |= _LSR_FE_MASK | _LSR_PE_MASK; if (I_BRKINT(info->tty) || I_PARMRK(info->tty)) info->read_status_mask |= _LSR_LB_MASK; /* * Characters to ignore */ info->ignore_status_mask = 0; if (I_IGNPAR(info->tty)) info->ignore_status_mask |= _LSR_FE_MASK | _LSR_PE_MASK; if (I_IGNBRK(info->tty)) { info->ignore_status_mask |= _LSR_LB_MASK; /* * If we're ignoring parity and break indicators, * ignore overruns to (for real raw support). */ if (I_IGNPAR(info->tty)) info->ignore_status_mask |= _LSR_OE_MASK; } /* first, disable everything */ save_flags(flags); cli(); old_rcr = readb(info->port->uart_base + BL_SICC_RCR); old_tcr = readb(info->port->uart_base + BL_SICC_TxCR); writeb(0, info->port->uart_base + BL_SICC_RCR); writeb(0, info->port->uart_base + BL_SICC_TxCR); /*RLBtrace (&ppc403Chan0, 0x2000000c, 0, 0);*/ restore_flags(flags); /* Set baud rate */ writeb((quot & 0x00000F00)>>8, info->port->uart_base + BL_SICC_BRDH ); writeb( quot & 0x00000FF, info->port->uart_base + BL_SICC_BRDL ); /* Set CTL2 reg to use external clock (ExtClk) and enable FIFOs. */ /* For now, do NOT use FIFOs since 403 UART did not have this */ /* capability and this driver was inherited from 403UART. */ writeb(_CTL2_EXTERN, info->port->uart_base + BL_SICC_CTL2); writeb(lcr_h, info->port->uart_base + BL_SICC_LCR); writeb(old_rcr, info->port->uart_base + BL_SICC_RCR); // restore rcr writeb(old_tcr, info->port->uart_base + BL_SICC_TxCR); // restore txcr}static void siccuart_put_char(struct tty_struct *tty, u_char ch){ struct SICC_info *info = tty->driver_data; unsigned long flags; if (!tty || !info->xmit.buf) return; save_flags(flags); cli(); if (CIRC_SPACE(info->xmit.head, info->xmit.tail, SICC_XMIT_SIZE) != 0) { info->xmit.buf[info->xmit.head] = ch; info->xmit.head = (info->xmit.head + 1) & (SICC_XMIT_SIZE - 1); } restore_flags(flags);}static void siccuart_flush_chars(struct tty_struct *tty){ struct SICC_info *info = tty->driver_data; unsigned long flags; if (info->xmit.head == info->xmit.tail || tty->stopped || tty->hw_stopped || !info->xmit.buf) return; save_flags(flags); cli(); siccuart_enable_tx_interrupt(info); restore_flags(flags);}static int siccuart_write(struct tty_struct *tty, int from_user, const u_char * buf, int count){ struct SICC_info *info = tty->driver_data; unsigned long flags; int c, ret = 0; if (!tty || !info->xmit.buf || !tmp_buf) return 0; save_flags(flags); if (from_user) { down(&tmp_buf_sem); while (1) { int c1; c = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail, SICC_XMIT_SIZE); if (count < c) c = count; if (c <= 0) break; c -= copy_from_user(tmp_buf, buf, c); if (!c) { if (!ret) ret = -EFAULT; break; } cli(); c1 = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail, SICC_XMIT_SIZE); if (c1 < c) c = c1; memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c); info->xmit.head = (info->xmit.head + c) & (SICC_XMIT_SIZE - 1); restore_flags(flags); buf += c; count -= c; ret += c; } up(&tmp_buf_sem); } else { cli(); while (1) { c = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail, SICC_XMIT_SIZE); if (count < c) c = count; if (c <= 0) break; memcpy(info->xmit.buf + info->xmit.head, buf, c); info->xmit.head = (info->xmit.head + c) & (SICC_XMIT_SIZE - 1); buf += c; count -= c; ret += c; } restore_flags(flags); } if (info->xmit.head != info->xmit.tail && !tty->stopped && !tty->hw_stopped) siccuart_enable_tx_interrupt(info); return ret;}static int siccuart_write_room(struct tty_struct *tty){ struct SICC_info *info = tty->driver_data; return CIRC_SPACE(info->xmit.head, info->xmit.tail, SICC_XMIT_SIZE);}static int siccuart_chars_in_buffer(struct tty_struct *tty){ struct SICC_info *info = tty->driver_data; return CIRC_CNT(info->xmit.head, info->xmit.tail, SICC_XMIT_SIZE);}static void siccuart_flush_buffer(struct tty_struct *tty){ struct SICC_info *info = tty->driver_data; unsigned long flags;#if DEBUG printk("siccuart_flush_buffer(%d) called\n", MINOR(tty->device) - tty->driver.minor_start);#endif save_flags(flags); cli(); info->xmit.head = info->xmit.tail = 0; restore_flags(flags); wake_up_interruptible(&tty->write_wait); if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup)(tty);}/* * This function is used to send a high-priority XON/XOFF character to * the device */static void siccuart_send_xchar(struct tty_struct *tty, char ch){ struct SICC_info *info = tty->driver_data; info->x_char = ch; if (ch) siccuart_enable_tx_interrupt(info);}static void siccuart_throttle(struct tty_struct *tty){ struct SICC_info *info = tty->driver_data; unsigned long flags; if (I_IXOFF(tty)) siccuart_send_xchar(tty, STOP_CHAR(tty)); if (tty->termios->c_cflag & CRTSCTS) { save_flags(flags); cli(); info->mctrl &= ~TIOCM_RTS; info->port->set_mctrl(info->port, info->mctrl); restore_flags(flags); }}static void siccuart_unthrottle(struct tty_struct *tty){ struct SICC_info *info = (struct SICC_info *) tty->driver_data; unsigned long flags; if (I_IXOFF(tty)) { if (info->x_char) info->x_char = 0; else siccuart_send_xchar(tty, START_CHAR(tty)); } if (tty->termios->c_cflag & CRTSCTS) { save_flags(flags); cli(); info->mctrl |= TIOCM_RTS; info->port->set_mctrl(info->port, info->mctrl); restore_flags(flags); }}static int get_serial_info(struct SICC_info *info, struct serial_struct *retinfo){ struct SICC_state *state = info->state; struct SICC_port *port = info->port; struct serial_struct tmp; memset(&tmp, 0, sizeof(tmp)); tmp.type = 0; tmp.line = state->line; tmp.port = port->uart_base; if (HIGH_BITS_OFFSET) tmp.port_high = port->uart_base >> HIGH_BITS_OFFSET; tmp.irq = port->irqrx; tmp.flags = 0; tmp.xmit_fifo_size = port->fifosize; tmp.baud_base = port->uartclk / 16; tmp.close_delay = state->close_delay; tmp.closing_wait = state->closing_wait; tmp.custom_divisor = state->custom_divisor; if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) return -EFAULT; return 0;}static int set_serial_info(struct SICC_info *info, struct serial_struct *newinfo){ struct serial_struct new_serial; struct SICC_state *state, old_state; struct SICC_port *port; unsigned long new_port; unsigned int i, change_irq, change_port; int retval = 0; if (copy_from_user(&new_serial, newinfo, sizeof(new_serial))) return -EFAULT; state = info->state; old_state = *state; port = info->port; new_port = new_serial.port; if (HIGH_BITS_OFFSET) new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET; change_irq = new_serial.irq != port->irqrx; change_port = new_port != port->uart_base; if (!capable(CAP_SYS_ADMIN)) { if (change_irq || change_port || (new_serial.baud_base != port->uartclk / 16) || (new_serial.close_delay != state->close_delay) || (new_serial.xmit_fifo_size != port->fifosize) || ((new_serial.flags & ~ASYNC_USR_MASK) != (state->flags & ~ASYNC_USR_MASK))) return -EPERM; state->flags = ((state->flags & ~ASYNC_USR_MASK) | (new_serial.flags & ASYNC_USR_MASK)); info->flags = ((info->flags & ~ASYNC_USR_MASK) | (new_serial.flags & ASYNC_USR_MASK)); state->custom_divisor = new_serial.custom_divisor; goto check_and_exit; } if ((new_serial.irq >= NR_IRQS) || (new_serial.irq < 0) || (new_serial.baud_base < 9600)) return -EINVAL; if (new_serial.type && change_port) { for (i = 0; i < SERIAL_SICC_NR; i++) if ((port != sicc_ports + i) && sicc_ports[i].uart_base != new_port) return -EADDRINUSE; } if ((change_port || change_irq) && (state->count > 1)) return -EBUSY; /* * OK, past this point, all the error checking has been done. * At this point, we start making changes..... */ port->uartclk = new_serial.baud_base * 16; state->flags = ((state->flags & ~ASYNC_FLAGS) | (new_serial.flags & ASYNC_FLAGS)); info->flags = ((state->flags & ~ASYNC_INTERNAL_FLAGS) | (info->flags & ASYNC_INTERNAL_FLAGS)); state->custom_divisor = new_serial.custom_divisor; state->close_delay = new_serial.close_delay * HZ / 100; state->closing_wait = new_serial.closing_wait * HZ / 100; info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; port->fifosize = new_serial.xmit_fifo_size; if (change_port || change_irq) { /* * We need to shutdown the serial port at the old * port/irq combination. */ siccuart_shutdown(info); port->irqrx = new_serial.irq; port->uart_base = new_port; }check_and_exit: if (!port->uart_base) return 0; if (info->flags & ASYNC_INITIALIZED) { if ((old_state.flags & ASYNC_SPD_MASK) != (state->flags & ASYNC_SPD_MASK) || (old_state.custom_divisor != state->custom_divisor)) { if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) info->tty->alt_speed = 57600; if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) info->tty->alt_speed = 115200; if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) info->tty->alt_speed = 230400; if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) info->tty->alt_speed = 460800; siccuart_change_speed(info, NULL); } } else retval = siccuart_startup(info); return retval;}/* * get_lsr_info - get line status register info */static int get_lsr_info(struct SICC_info *info, unsigned int *value){ unsigned int result, status; unsigned long flags; save_flags(flags); cli(); status = readb(info->port->uart_base + BL_SICC_LSR); restore_flags(flags); result = status & _LSR_TSR_EMPTY ? TIOCSER_TEMT : 0; /* * If we're about to load something into the transmit * register, we'll pretend the transmitter isn't empty to * avoid a race condition (depending on when the transmit * interrupt happens). */ if (info->x_char || ((CIRC_CNT(info->xmit.head, info->xmit.tail, SICC_XMIT_SIZE) > 0) && !info->tty->stopped && !info->tty->hw_stopped)) result &= TIOCSER_TEMT; return put_user(result, value);}static int get_modem_info(struct SICC_info *info, unsigned int *value){ unsigned int result = info->mctrl; return put_user(result, value);}static int set_modem_info(struct SICC_info *info, unsigned int cmd, unsigned int *value){ unsigned int arg, old;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -