specialix.c
来自「linux 内核源代码」· C语言 代码 · 共 2,562 行 · 第 1/5 页
C
2,562 行
func_exit(); return; } bp = port_Board(port); if ((tty->count == 1) && (port->count != 1)) { printk(KERN_ERR "sx%d: sx_close: bad port count;" " tty->count is 1, port count is %d\n", board_No(bp), port->count); port->count = 1; } if (port->count > 1) { port->count--; bp->count--; spin_unlock_irqrestore(&port->lock, flags); func_exit(); return; } port->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; spin_unlock_irqrestore(&port->lock, flags); dprintk (SX_DEBUG_OPEN, "Closing\n"); if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) { tty_wait_until_sent(tty, port->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. */ dprintk (SX_DEBUG_OPEN, "Closed\n"); port->IER &= ~IER_RXD; if (port->flags & ASYNC_INITIALIZED) { port->IER &= ~IER_TXRDY; port->IER |= IER_TXEMPTY; spin_lock_irqsave(&bp->lock, flags); sx_out(bp, CD186x_CAR, port_No(port)); sx_out(bp, CD186x_IER, port->IER); spin_unlock_irqrestore(&bp->lock, flags); /* * Before we drop DTR, make sure the UART transmitter * has completely drained; this is especially * important if there is a transmit FIFO! */ timeout = jiffies+HZ; while(port->IER & IER_TXEMPTY) { set_current_state (TASK_INTERRUPTIBLE); msleep_interruptible(jiffies_to_msecs(port->timeout)); if (time_after(jiffies, timeout)) { printk (KERN_INFO "Timeout waiting for close\n"); break; } } } if (--bp->count < 0) { printk(KERN_ERR "sx%d: sx_shutdown_port: bad board count: %d port: %d\n", board_No(bp), bp->count, tty->index); bp->count = 0; } if (--port->count < 0) { printk(KERN_ERR "sx%d: sx_close: bad port count for tty%d: %d\n", board_No(bp), port_No(port), port->count); port->count = 0; } sx_shutdown_port(bp, port); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); tty_ldisc_flush(tty); spin_lock_irqsave(&port->lock, flags); tty->closing = 0; port->event = 0; port->tty = NULL; spin_unlock_irqrestore(&port->lock, flags); if (port->blocked_open) { if (port->close_delay) { msleep_interruptible(jiffies_to_msecs(port->close_delay)); } wake_up_interruptible(&port->open_wait); } port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&port->close_wait); func_exit();}static int sx_write(struct tty_struct * tty, const unsigned char *buf, int count){ struct specialix_port *port = (struct specialix_port *)tty->driver_data; struct specialix_board *bp; int c, total = 0; unsigned long flags; func_enter(); if (sx_paranoia_check(port, tty->name, "sx_write")) { func_exit(); return 0; } bp = port_Board(port); if (!port->xmit_buf) { func_exit(); return 0; } while (1) { spin_lock_irqsave(&port->lock, flags); c = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, SERIAL_XMIT_SIZE - port->xmit_head)); if (c <= 0) { spin_unlock_irqrestore(&port->lock, flags); break; } memcpy(port->xmit_buf + port->xmit_head, buf, c); port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1); port->xmit_cnt += c; spin_unlock_irqrestore(&port->lock, flags); buf += c; count -= c; total += c; } spin_lock_irqsave(&bp->lock, flags); if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped && !(port->IER & IER_TXRDY)) { port->IER |= IER_TXRDY; sx_out(bp, CD186x_CAR, port_No(port)); sx_out(bp, CD186x_IER, port->IER); } spin_unlock_irqrestore(&bp->lock, flags); func_exit(); return total;}static void sx_put_char(struct tty_struct * tty, unsigned char ch){ struct specialix_port *port = (struct specialix_port *)tty->driver_data; unsigned long flags; struct specialix_board * bp; func_enter(); if (sx_paranoia_check(port, tty->name, "sx_put_char")) { func_exit(); return; } dprintk (SX_DEBUG_TX, "check tty: %p %p\n", tty, port->xmit_buf); if (!port->xmit_buf) { func_exit(); return; } bp = port_Board(port); spin_lock_irqsave(&port->lock, flags); dprintk (SX_DEBUG_TX, "xmit_cnt: %d xmit_buf: %p\n", port->xmit_cnt, port->xmit_buf); if ((port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) || (!port->xmit_buf)) { spin_unlock_irqrestore(&port->lock, flags); dprintk (SX_DEBUG_TX, "Exit size\n"); func_exit(); return; } dprintk (SX_DEBUG_TX, "Handle xmit: %p %p\n", port, port->xmit_buf); port->xmit_buf[port->xmit_head++] = ch; port->xmit_head &= SERIAL_XMIT_SIZE - 1; port->xmit_cnt++; spin_unlock_irqrestore(&port->lock, flags); func_exit();}static void sx_flush_chars(struct tty_struct * tty){ struct specialix_port *port = (struct specialix_port *)tty->driver_data; unsigned long flags; struct specialix_board * bp = port_Board(port); func_enter(); if (sx_paranoia_check(port, tty->name, "sx_flush_chars")) { func_exit(); return; } if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || !port->xmit_buf) { func_exit(); return; } spin_lock_irqsave(&bp->lock, flags); port->IER |= IER_TXRDY; sx_out(port_Board(port), CD186x_CAR, port_No(port)); sx_out(port_Board(port), CD186x_IER, port->IER); spin_unlock_irqrestore(&bp->lock, flags); func_exit();}static int sx_write_room(struct tty_struct * tty){ struct specialix_port *port = (struct specialix_port *)tty->driver_data; int ret; func_enter(); if (sx_paranoia_check(port, tty->name, "sx_write_room")) { func_exit(); return 0; } ret = SERIAL_XMIT_SIZE - port->xmit_cnt - 1; if (ret < 0) ret = 0; func_exit(); return ret;}static int sx_chars_in_buffer(struct tty_struct *tty){ struct specialix_port *port = (struct specialix_port *)tty->driver_data; func_enter(); if (sx_paranoia_check(port, tty->name, "sx_chars_in_buffer")) { func_exit(); return 0; } func_exit(); return port->xmit_cnt;}static void sx_flush_buffer(struct tty_struct *tty){ struct specialix_port *port = (struct specialix_port *)tty->driver_data; unsigned long flags; struct specialix_board * bp; func_enter(); if (sx_paranoia_check(port, tty->name, "sx_flush_buffer")) { func_exit(); return; } bp = port_Board(port); spin_lock_irqsave(&port->lock, flags); port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; spin_unlock_irqrestore(&port->lock, flags); tty_wakeup(tty); func_exit();}static int sx_tiocmget(struct tty_struct *tty, struct file *file){ struct specialix_port *port = (struct specialix_port *)tty->driver_data; struct specialix_board * bp; unsigned char status; unsigned int result; unsigned long flags; func_enter(); if (sx_paranoia_check(port, tty->name, __FUNCTION__)) { func_exit(); return -ENODEV; } bp = port_Board(port); spin_lock_irqsave (&bp->lock, flags); sx_out(bp, CD186x_CAR, port_No(port)); status = sx_in(bp, CD186x_MSVR); spin_unlock_irqrestore(&bp->lock, flags); dprintk (SX_DEBUG_INIT, "Got msvr[%d] = %02x, car = %d.\n", port_No(port), status, sx_in (bp, CD186x_CAR)); dprintk (SX_DEBUG_INIT, "sx_port = %p, port = %p\n", sx_port, port); if (SX_CRTSCTS(port->tty)) { result = /* (status & MSVR_RTS) ? */ TIOCM_DTR /* : 0) */ | ((status & MSVR_DTR) ? TIOCM_RTS : 0) | ((status & MSVR_CD) ? TIOCM_CAR : 0) |/* ((status & MSVR_DSR) ? */ TIOCM_DSR /* : 0) */ | ((status & MSVR_CTS) ? TIOCM_CTS : 0); } else { result = /* (status & MSVR_RTS) ? */ TIOCM_RTS /* : 0) */ | ((status & MSVR_DTR) ? TIOCM_DTR : 0) | ((status & MSVR_CD) ? TIOCM_CAR : 0) |/* ((status & MSVR_DSR) ? */ TIOCM_DSR /* : 0) */ | ((status & MSVR_CTS) ? TIOCM_CTS : 0); } func_exit(); return result;}static int sx_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear){ struct specialix_port *port = (struct specialix_port *)tty->driver_data; unsigned long flags; struct specialix_board *bp; func_enter(); if (sx_paranoia_check(port, tty->name, __FUNCTION__)) { func_exit(); return -ENODEV; } bp = port_Board(port); spin_lock_irqsave(&port->lock, flags); /* if (set & TIOCM_RTS) port->MSVR |= MSVR_RTS; */ /* if (set & TIOCM_DTR) port->MSVR |= MSVR_DTR; */ if (SX_CRTSCTS(port->tty)) { if (set & TIOCM_RTS) port->MSVR |= MSVR_DTR; } else { if (set & TIOCM_DTR) port->MSVR |= MSVR_DTR; } /* if (clear & TIOCM_RTS) port->MSVR &= ~MSVR_RTS; */ /* if (clear & TIOCM_DTR) port->MSVR &= ~MSVR_DTR; */ if (SX_CRTSCTS(port->tty)) { if (clear & TIOCM_RTS) port->MSVR &= ~MSVR_DTR; } else { if (clear & TIOCM_DTR) port->MSVR &= ~MSVR_DTR; } spin_lock_irqsave(&bp->lock, flags); sx_out(bp, CD186x_CAR, port_No(port)); sx_out(bp, CD186x_MSVR, port->MSVR); spin_unlock_irqrestore(&bp->lock, flags); spin_unlock_irqrestore(&port->lock, flags); func_exit(); return 0;}static inline void sx_send_break(struct specialix_port * port, unsigned long length){ struct specialix_board *bp = port_Board(port); unsigned long flags; func_enter(); spin_lock_irqsave (&port->lock, flags); port->break_length = SPECIALIX_TPS / HZ * length; port->COR2 |= COR2_ETC; port->IER |= IER_TXRDY; spin_lock_irqsave(&bp->lock, flags); sx_out(bp, CD186x_CAR, port_No(port)); sx_out(bp, CD186x_COR2, port->COR2); sx_out(bp, CD186x_IER, port->IER); spin_unlock_irqrestore(&bp->lock, flags); spin_unlock_irqrestore (&port->lock, flags); sx_wait_CCR(bp); spin_lock_irqsave(&bp->lock, flags); sx_out(bp, CD186x_CCR, CCR_CORCHG2); spin_unlock_irqrestore(&bp->lock, flags); sx_wait_CCR(bp); func_exit();}static inline int sx_set_serial_info(struct specialix_port * port, struct serial_struct __user * newinfo){ struct serial_struct tmp; struct specialix_board *bp = port_Board(port); int change_speed; func_enter(); /* if (!access_ok(VERIFY_READ, (void *) newinfo, sizeof(tmp))) { func_exit(); return -EFAULT; } */ if (copy_from_user(&tmp, newinfo, sizeof(tmp))) { func_enter(); return -EFAULT; }#if 0 if ((tmp.irq != bp->irq) || (tmp.port != bp->base) || (tmp.type != PORT_CIRRUS) || (tmp.baud_base != (SX_OSCFREQ + CD186x_TPC/2) / CD186x_TPC) || (tmp.custom_divisor != 0) || (tmp.xmit_fifo_size != CD186x_NFIFO) || (tmp.flags & ~SPECIALIX_LEGAL_FLAGS)) { func_exit(); return -EINVAL; }#endif change_speed = ((port->flags & ASYNC_SPD_MASK) != (tmp.flags & ASYNC_SPD_MASK)); change_speed |= (tmp.custom_divisor != port->custom_divisor); if (!capable(CAP_SYS_ADMIN)) { if ((tmp.close_delay != port->close_delay) || (tmp.closing_wait != port->closing_wait) || ((tmp.flags & ~ASYNC_USR_MASK) != (port->flags & ~ASYNC_USR_MASK))) { func_exit(); return -EPERM; } port->flags = ((port->flags & ~ASYNC_USR_MASK) | (tmp.flags & ASYNC_USR_MASK)); port->custom_divisor = tmp.custom_divisor; } else { port->flags = ((port->flags & ~ASYNC_FLAGS) | (tmp.flags & ASYNC_FLAGS)); port->close_delay = tmp.close_delay; port->closing_wait = tmp.closing_wait; port->custom_divisor = tmp.custom_divisor; } if (change_speed) { sx_change_speed(bp, port); } func_exit(); return 0;}static inline int sx_get_serial_info(struct specialix_port * port, struct serial_struct __user *retinfo){ struct serial_struct tmp; struct specialix_board *bp = port_Board(port); func_enter(); /* if (!access_ok(VERIFY_WRITE, (void *) retinfo, sizeof(tmp))) return -EFAULT; */ memset(&tmp, 0, sizeof(tmp)); tmp.type = PORT_CIRRUS; tmp.line = port - sx_port; tmp.port = bp->base; tmp.irq = bp->irq; tmp.flags = port->flags; tmp.baud_base = (SX_OSCFREQ + CD186x_TPC/2) / CD186x_TPC; tmp.close_delay = port->close_delay * HZ/100; tmp.closing_wait = port->closing_wait * HZ/100; tmp.custom_divisor = port->custom_divisor; tmp.xmit_fifo_size = CD186x_NFIFO; if (copy_to_user(retinfo, &tmp, sizeof(tmp))) { func_exit(); return -EFAULT; } func_exit(); return 0;}static int sx_ioctl(struct tty_struct * tty, struct file * filp, unsigned int cmd, unsigned long arg){ struct specialix_port *port = (struct specialix_port *)tty->driver_data; int retval; void __user *argp = (void __user *)arg; func_enter(); if (sx_paranoia_check(port, tty->name, "sx_ioctl")) { func_exit(); return -ENODEV; } switch (cmd) { case TCSBRK: /* SVID version: non-zero arg --> no break */ retval = tty_check_change(tty); if (retval) { func_exit(); return retval; } tty_wait_until_sent(tty, 0); if (!arg)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?