前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Linux串口驱动分析write

Linux串口驱动分析write

作者头像
DragonKingZhu
发布2022-05-08 15:40:50
9.5K0
发布2022-05-08 15:40:50
举报
代码语言:javascript
复制
/*和read的分析过程一样, 我们首先分析tty_write*/

/*最重要的就是do_tty_write函数。 前面都是一些合法性判断*/
static ssize_t tty_write(struct file *file, const char __user *buf,size_t count, loff_t *ppos)
{
	struct inode *inode = file->f_path.dentry->d_inode;
	struct tty_struct *tty = file_tty(file);
 	struct tty_ldisc *ld;
	ssize_t ret;

	if (tty_paranoia_check(tty, inode, "tty_write"))
		return -EIO;
	if (!tty || !tty->ops->write ||
		(test_bit(TTY_IO_ERROR, &tty->flags)))
			return -EIO;
	/* Short term debug to catch buggy drivers */
	if (tty->ops->write_room == NULL)
		printk(KERN_ERR "tty driver %s lacks a write_room method.\n",
			tty->driver->name);
	ld = tty_ldisc_ref_wait(tty);
	if (!ld->ops->write)
		ret = -EIO;
	else
		/*调用tty_ldisc_N_TTY中的write函数*/
		ret = do_tty_write(ld->ops->write, tty, file, buf, count);
	tty_ldisc_deref(ld);
	return ret;
}

/*调用uart_ops中的write函数*/
static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,const unsigned char *buf, size_t nr)
{
	c = tty->ops->write(tty, b, nr);
}

static int uart_write(struct tty_struct *tty,const unsigned char *buf, int count)
{
	struct uart_state *state = tty->driver_data;
	struct uart_port *port;
	struct circ_buf *circ;
	unsigned long flags;
	int c, ret = 0;

	/*
	 * This means you called this function _after_ the port was
	 * closed.  No cookie for you.
	 */
	if (!state) {
		WARN_ON(1);
		return -EL3HLT;
	}

  /*取出所对应的port和循环缓冲buf*/
	port = state->uart_port;
	circ = &state->xmit;

	if (!circ->buf)
		return 0;

	spin_lock_irqsave(&port->lock, flags);
	while (1) {
		/*计算循环缓冲的剩余空间 */
		c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE);
		if (count < c)
			c = count;
		if (c <= 0)
			break;
		/*拷贝数据到循环缓冲区*/
		memcpy(circ->buf + circ->head, buf, c);
		/*调正循环缓冲head的位置*/
		circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1);
		/*挪动buf当前的指针位置*/
		buf += c;
		count -= c;
		ret += c;
	}
	spin_unlock_irqrestore(&port->lock, flags);

	uart_start(tty);
	return ret;
}

/*判断循环缓冲是否为空等。 然后调用注册驱动时的ops。 也就是s3c24xx_serial_ops*/
static void __uart_start(struct tty_struct *tty)
{
	struct uart_state *state = tty->driver_data;
	struct uart_port *port = state->uart_port;

	if (!uart_circ_empty(&state->xmit) && state->xmit.buf &&
	    !tty->stopped && !tty->hw_stopped)
		port->ops->start_tx(port);
}

/*判断端口是否使能,如果没使能则使能端口。 然后使能tx中断
* 使能tx中断,则当有数据来时,则会触发tx中断,调用中断函数
*/
static void s3c24xx_serial_start_tx(struct uart_port *port)
{
	struct s3c24xx_uart_port *ourport = to_ourport(port);
	static int a =1;//temp
	if (port->line == 3) {
//		printk("485_start_tx\n");

		if(a){
			s3c_gpio_cfgpin(S3C64XX_GPK(5), S3C_GPIO_SFN(1));
			a=0;
		}
		gpio_set_value(S3C64XX_GPK(5), 1);
	}
	if (!tx_enabled(port)) {
		if (port->flags & UPF_CONS_FLOW)
			s3c24xx_serial_rx_disable(port);

		enable_irq(ourport->tx_irq);
		tx_enabled(port) = 1;
	}
}

/*tx中断触发函数*/
static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
{
	struct s3c24xx_uart_port *ourport = id;
	struct uart_port *port = &ourport->port;
	struct circ_buf *xmit = &port->state->xmit;
	int count = 256;

	/*判断x_char是否存在,如果存在则写进UTXH寄存器。清空x_char*/
	if (port->x_char) {
		wr_regb(port, S3C2410_UTXH, port->x_char);
		port->icount.tx++;
		port->x_char = 0;
		goto out;
	}

	/* if there isn't anything more to transmit, or the uart is now
	 * stopped, disable the uart and exit
	*/

	/*判断循环缓冲是否为空,或者tx是否为停止状态。 如果是则停止发送*/
	if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
		s3c24xx_serial_stop_tx(port);
		goto out;
	}

	/* try and drain the buffer... */

	/*当循环缓冲buff不为空,而且count是大于0的。则进入while循环*/
	while (!uart_circ_empty(xmit) && count-- > 0) {
		
		/*首先读取UFSTAT寄存器,然后判断tx_fifo是否为0.是则退出*/
		if (rd_regl(port, S3C2410_UFSTAT) & ourport->info->tx_fifofull)
			break;

		/*然后将循环buff中的数据读出到UTXH寄存器。然后设置tail的指针位置*/
		wr_regb(port, S3C2410_UTXH, xmit->buf[xmit->tail]);
		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
		port->icount.tx++;
	}

	/*判断循环缓冲中的数据是否小于WAKEUP_CHARS, 小于则启动接受*/
	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
		uart_write_wakeup(port);
		
	/*如果循环buff为空,则停止发送,退出*/
	if (uart_circ_empty(xmit))
		s3c24xx_serial_stop_tx(port);
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2015-01-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档