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 + -
显示快捷键?