NVIDIA Tegra-TK1串口驱动代码初探


今天大家都在抢iphoen X,我也来强行装一波X,讲讲最近读的TK1串口驱动serial-tegra.c

照旧从驱动的init函数看起。(千万别从头看起)

static int __init tegra_uart_init(void)
{
	int ret;

	ret = uart_register_driver(&tegra_uart_driver);
	if (ret < 0) {
		pr_err("Could not register %s driver\n",
			tegra_uart_driver.driver_name);
		return ret;
	}

	ret = platform_driver_register(&tegra_uart_platform_driver);
	if (ret < 0) {
		pr_err("Uart platfrom driver register failed, e = %d\n", ret);
		uart_unregister_driver(&tegra_uart_driver);
		return ret;
	}
	return 0;
}

uart_register_driver注册tegra_uart_driver,tegra_uart_driver结构如下:

static struct uart_driver tegra_uart_driver = {
	.owner		= THIS_MODULE,
	.driver_name	= "serial-hs-tegra",
	.dev_name	= "ttyTHS",
	.cons		= NULL,
	.nr		= TEGRA_UART_MAXIMUM,
};
uart_register_driver 函数定义在 kernel/drivers/tty/serial/serial_core.c 文件中,

int uart_register_driver(struct uart_driver *drv)
{
	struct tty_driver *normal;
	int i, retval;

	BUG_ON(drv->state);

	/*
	 * Maybe we should be using a slab cache for this, especially if
	 * we have a large number of ports to handle.
	 */
	drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);
	if (!drv->state)
		goto out;

	normal = alloc_tty_driver(drv->nr);
	if (!normal)
		goto out_kfree;

	drv->tty_driver = normal;

	normal->driver_name	= drv->driver_name;
	normal->name		= drv->dev_name;
	normal->major		= drv->major;
	normal->minor_start	= drv->minor;
	normal->type		= TTY_DRIVER_TYPE_SERIAL;
	normal->subtype		= SERIAL_TYPE_NORMAL;
	normal->init_termios	= tty_std_termios;
	normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
	normal->init_termios.c_ispeed = normal->init_termios.c_ospeed = 9600;
	normal->flags		= TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
	normal->driver_state    = drv;
	tty_set_operations(normal, &uart_ops);

	/*
	 * Initialise the UART state(s).
	 */
	for (i = 0; i < drv->nr; i++) {
		struct uart_state *state = drv->state + i;
		struct tty_port *port = &state->port;

		tty_port_init(port);
		port->ops = &uart_port_ops;
		port->close_delay     = HZ / 2;	/* .5 seconds */
		//port->closing_wait    = 30 * HZ;/* 30 seconds */
		port->closing_wait    = 10 * HZ;
	}

	retval = tty_register_driver(normal);
	if (retval >= 0)
		return retval;

	for (i = 0; i < drv->nr; i++)
		tty_port_destroy(&drv->state[i].port);
	put_tty_driver(normal);
out_kfree:
	kfree(drv->state);
out:
	return -ENOMEM;
}



1.drv->tty_driver = normal;将tegra_usrt_driver中的tty_driver 与tty_driver normal同步

2.normal->driver_state    = drv;

这样一来只要将serial8250_ops结构体成员的值赋给我们uart_dirver就可以了,那么这个过程在哪呢?就是在uart_add_one_port()函数中,这个函数是从serial8250_init->serial8250_register_ports()->uart_add_one_port()逐步调用过来的,这一步就将port和uart_driver联系起来了。(uart_ops<=>uart_driver:8250.c)

摘自:http://developer.51cto.com/art/201209/357501_all.htm

这一段描述我也不太能理解,希望有大神指导指导。我认为这一句作用与1差不多,都是将tegra_usrt_driver中的tty_driver 与tty_driver normal同步,这样子tty_drivers调用ops操作函数的时候自然会调用到tegra_uart_ops

     uart_add_one_port()代码如下:

int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
{
	struct uart_state *state;
	struct tty_port *port;
	int ret = 0;
	struct device *tty_dev;

	BUG_ON(in_interrupt());

	if (uport->line >= drv->nr)
		return -EINVAL;

	state = drv->state + uport->line;
	port = &state->port;

	mutex_lock(&port_mutex);
	mutex_lock(&port->mutex);
	if (state->uart_port) {
		ret = -EINVAL;
		goto out;
	}
/* 重要一句 */   driver->state->uart_port与  uport划上等号
	state->uart_port = uport;
	state->pm_state = -1;

	uport->cons = drv->cons;
	uport->state = state;

	/*
	 * If this port is a console, then the spinlock is already
	 * initialised.
	 */
	if (!(uart_console(uport) && (uport->cons->flags & CON_ENABLED))) {
		spin_lock_init(&uport->lock);
		lockdep_set_class(&uport->lock, &port_lock_key);
	}
/* 实际调用 port->ops->config_port(port, flags) 稍后再看 */
	uart_configure_port(drv, state, uport);

	/*
	 * 上一篇文章中,我们提到tty注册了一个字符设备 “ttySAC ”
	 * 那么,我们平时看到的 “ttySAC0”“ttySAC1”等就是在这里注册的
	 */
	tty_dev = tty_register_device(drv->tty_driver, uport->line, uport->dev);
	if (likely(!IS_ERR(tty_dev))) {
		device_init_wakeup(tty_dev, 1);
		device_set_wakeup_enable(tty_dev, 0);
	} else
		printk(KERN_ERR "Cannot register tty device on line %d\n",
		       uport->line);

	/*
	 * Ensure UPF_DEAD is not set.
	 */
	uport->flags &= ~UPF_DEAD;

 out:
	mutex_unlock(&port->mutex);
	mutex_unlock(&port_mutex);

	return ret;
}

所以基本上两者是通过uart_state来绑定的,有必要上uart_state的定义:

struct uart_state {
	struct tty_port		port;

	enum uart_pm_state	pm_state;
	struct circ_buf		xmit;

	struct uart_port	*uart_port;
};

struct uart_port的定义如下(节选):

..
unsigned int		read_status_mask;	/* driver specific */
	unsigned int		ignore_status_mask;	/* driver specific */
	struct uart_state	*state;			/* pointer to parent state */
	struct uart_icount	icount;			/* statistics */
..

3.tty_set_operations(normal, &uart_ops); 

此句之所以值得关注是因为.在这里将tty_driver的操作集统一设为了uart_ops.这样就使得从用户空间下来的操作可以找到正确的serial_core的操作函数,uart_ops是在serial_core.c中的:所以结合

static const struct tty_operations uart_ops = {  
    .open       = uart_open,  
    .close      = uart_close,  
    .write      = uart_write,  
    .put_char   = uart_put_char,  
    .flush_chars    = uart_flush_chars,  
    .write_room = uart_write_room,  
    .chars_in_buffer= uart_chars_in_buffer,  
    .flush_buffer   = uart_flush_buffer,  
    .ioctl      = uart_ioctl,  
    .throttle   = uart_throttle,  
    .unthrottle = uart_unthrottle,  
    .send_xchar = uart_send_xchar,  
    .set_termios    = uart_set_termios,  
    .set_ldisc  = uart_set_ldisc,  
    .stop       = uart_stop,  
    .start      = uart_start,  
    .hangup     = uart_hangup,  
    .break_ctl  = uart_break_ctl,  
    .wait_until_sent= uart_wait_until_sent,  
#ifdef CONFIG_PROC_FS  
    .read_proc  = uart_read_proc,  
#endif  
    .tiocmget   = uart_tiocmget,  
    .tiocmset   = uart_tiocmset,  
#ifdef CONFIG_CONSOLE_POLL  
    .poll_init  = uart_poll_init,  
    .poll_get_char  = uart_poll_get_char,  
    .poll_put_char  = uart_poll_put_char,  
#endif  
};
未完待续,感觉对前面的分析有点重复造轮子的嫌疑,毕竟前面的驱动代码都是差不多的,当是自己的阅读总结吧。

直接分析tegra_uart_ops部分代码:

static struct uart_ops tegra_uart_ops = {
	.tx_empty	= tegra_uart_tx_empty,
	.set_mctrl	= tegra_uart_set_mctrl,
	.get_mctrl	= tegra_uart_get_mctrl,
	.stop_tx	= tegra_uart_stop_tx,
	.start_tx	= tegra_uart_start_tx,
	.stop_rx	= tegra_uart_stop_rx,
	.flush_buffer	= tegra_uart_flush_buffer,
	.enable_ms	= tegra_uart_enable_ms,
	.break_ctl	= tegra_uart_break_ctl,
	.startup	= tegra_uart_startup,
	.shutdown	= tegra_uart_shutdown,
	.set_termios	= tegra_uart_set_termios,
	.type		= tegra_uart_type,
	.request_port	= tegra_uart_request_port,
	.release_port	= tegra_uart_release_port,
};

先看start_up操作,


static int tegra_uart_startup(struct uart_port *u)
{
	struct tegra_uart_port *tup = to_tegra_uport(u);
	int ret;

	ret = tegra_uart_dma_channel_allocate(tup, false);
	if (ret < 0) {
		dev_err(u->dev, "Tx Dma allocation failed, err = %d\n", ret);
		return ret;
	}

	if (!tup->use_rx_pio) {
		ret = tegra_uart_dma_channel_allocate(tup, true);
		if (ret < 0) {
			dev_err(u->dev, "Rx Dma allocation failed, err = %d\n",
					ret);
			goto fail_rx_dma;
		}
	}

	ret = tegra_uart_hw_init(tup);
	if (ret < 0) {
		dev_err(u->dev, "Uart HW init failed, err = %d\n", ret);
		goto fail_hw_init;
	}

	ret = request_irq(u->irq, tegra_uart_isr, IRQF_DISABLED,
				dev_name(u->dev), tup);//fast interrupt IQRF_DISABLED
	if (ret < 0) {
		dev_err(u->dev, "Failed to register ISR for IRQ %d\n", u->irq);
		goto fail_hw_init;
	}
	return 0;

fail_hw_init:
	if (!tup->use_rx_pio)
		tegra_uart_dma_channel_free(tup, true);
fail_rx_dma:
	tegra_uart_dma_channel_free(tup, false);
	return ret;
}
最重要的看到注册中断,
request_irq(u->irq, tegra_uart_isr, IRQF_DISABLED,
				dev_name(u->dev), tup);

进入中断处理函数:

static irqreturn_t tegra_uart_isr(int irq, void *data)
{
	struct tegra_uart_port *tup = data;
	struct uart_port *u = &tup->uport;
	unsigned long iir;
	unsigned long ier;
	bool is_rx_int = false;
	unsigned long flags;
	int ret;
	//struct timeval tstart,tend;


	spin_lock_irqsave(&u->lock, flags);
	while (1) {
		iir = tegra_uart_read(tup, UART_IIR);
		if (iir & UART_IIR_NO_INT) {	
			if (!tup->use_rx_pio && is_rx_int) {
				ret = tegra_uart_handle_rx_dma(tup);
				if (ret) {
					spin_unlock_irqrestore(&u->lock, flags);
					return IRQ_HANDLED;
				}
				if (tup->rx_in_progress) {
					ier = tup->ier_shadow;
					ier |= (UART_IER_RLSI | UART_IER_RTOIE |
						TEGRA_UART_IER_EORD);
					tup->ier_shadow = ier;
					tegra_uart_write(tup, ier, UART_IER);
				}
			}
			spin_unlock_irqrestore(&u->lock, flags);
			return IRQ_HANDLED;
		}

		switch ((iir >> 1) & 0x7) {
		case 0: /* Modem signal change interrupt */
			tegra_uart_handle_modem_signal_change(u);
			break;

		case 1: /* Transmit interrupt only triggered when using PIO */
			tup->ier_shadow &= ~UART_IER_THRI;
			tegra_uart_write(tup, tup->ier_shadow, UART_IER);
			tegra_uart_handle_tx_pio(tup);
			break;

		case 4: /* End of data */
		case 6: /* Rx timeout */
			//printk(KERN_ALERT"rx timeout \n");
		case 2: /* Receive */
			if (!tup->use_rx_pio && !is_rx_int) {
				is_rx_int = true;
				/* Disable Rx interrupts */
				ier = tup->ier_shadow;
				ier |= UART_IER_RDI;
				tegra_uart_write(tup, ier, UART_IER);
				ier &= ~(UART_IER_RDI | UART_IER_RLSI |
						UART_IER_RTOIE |
						TEGRA_UART_IER_EORD);
				tup->ier_shadow = ier;
				tegra_uart_write(tup, ier, UART_IER);
			} else
				do_handle_rx_pio(tup);
			break;

		case 3: /* Receive error */
			tegra_uart_decode_rx_error(tup,
					tegra_uart_read(tup, UART_LSR));
			break;

		case 5: /* break nothing to handle */
		case 7: /* break nothing to handle */
			break;
		}
	}
}
这里也很好理解,中断触发进来,进入while循环,再进入switch函数,这里我们看到有好几种case .case 4, 6, 2都会进入case2的receive处理函数中

is_rx_int = true;
is_rx_int置1,while loop 进入
ret = tegra_uart_handle_rx_dma(tup);
static int tegra_uart_handle_rx_dma(struct tegra_uart_port *tup)
{
	struct timeval tstart,tend;
	struct dma_tx_state state;
	struct tty_struct *tty = tty_port_tty_get(&tup->uport.state->port);
	struct tty_port *port = &tup->uport.state->port;
	int count;
	int rx_level = 0;
	struct dma_async_tx_descriptor *prev_rx_dma_desc;
	int ret;

	/* Deactivate flow control to stop sender */
	if (tup->rts_active)
		set_rts(tup, false);

	dmaengine_terminate_all(tup->rx_dma_chan);
	dmaengine_tx_status(tup->rx_dma_chan,  tup->rx_cookie, &state);
	prev_rx_dma_desc = tup->rx_dma_desc;
	count = tup->rx_bytes_requested - state.residue;

	/* If we are here, DMA is stopped */
	if (count) {
		do_gettimeofday(&tstart);
		ret = tegra_uart_copy_rx_to_tty(tup, port, count);//copy rx_dma_data to  tty_buffer
		do_gettimeofday(&tend);
		 printk("tegra_uart_copy_rx_to_tty  taken: %ld us\n",1000000* (tend.tv_sec - tstart.tv_sec) +(tend.tv_usec - tstart.tv_usec) );
		if (ret)
			goto skip_pio;
	}
	do_gettimeofday(&tstart);
	ret = tegra_uart_handle_rx_pio(tup, port);
	do_gettimeofday(&tend);
	 printk("tegra_uart_handle_rx_pio taken: %ld us\n",1000000* (tend.tv_sec - tstart.tv_sec) +(tend.tv_usec - tstart.tv_usec) );
skip_pio:
	if (tup->enable_rx_buffer_throttle) {
		rx_level = tty_buffer_get_level(port);
		if (rx_level > 70)
			mod_timer(&tup->timer,
					jiffies + tup->timer_timeout_jiffies);
	}

	if (tty) {
		do_gettimeofday(&tstart);
		tty_flip_buffer_push(port);//flip data of tty_buffer to read_buffer(user space and operated by read())
		do_gettimeofday(&tend);
		printk("tty_flip_buffer_push taken: %ld us\n",1000000* (tend.tv_sec - tstart.tv_sec) +(tend.tv_usec - tstart.tv_usec) );
		tty_kref_put(tty);
	}
	tegra_uart_start_rx_dma(tup);
	async_tx_ack(prev_rx_dma_desc);

	if (tup->enable_rx_buffer_throttle) {
		if ((rx_level <= 70) && tup->rts_active)
			set_rts(tup, true);
	} else if (tup->rts_active)
		set_rts(tup, true);

	return ret;
}

然后触发中断的条件是什么呢?这是关键点

查看TegraK1_TRM_DP06905001_public_v03p.pdf(Technical Reference Manual),关于uart_fifo  寄存器的说明

与上边代码中所有的case对应,case 6:rx_timeout_intr表示fifo 中有数据当没有达到trigger level,经过4 bytes的传输时间仍未有数据到达,触发rx_timeout

                                                      case 4:eord_timeout_intr(eord即 end of data),表示当fifo中无数据,经过4bytes的传输时间仍未有数据到达。触发eord中断。两种情况加以区分,如有纰漏敬请指出。 


接下来进入tegra_uart_handle_rx_dma,代码如下:

static int tegra_uart_handle_rx_dma(struct tegra_uart_port *tup)
{
	struct dma_tx_state state;
	struct tty_struct *tty = tty_port_tty_get(&tup->uport.state->port);
	struct tty_port *port = &tup->uport.state->port;
	int count;
	int rx_level = 0;
	struct dma_async_tx_descriptor *prev_rx_dma_desc;
	int ret;

	/* Deactivate flow control to stop sender */
	if (tup->rts_active)
		set_rts(tup, false);

	dmaengine_terminate_all(tup->rx_dma_chan);//停止dma传输,这一句花费较多时间,实机测试可能花费30us左右
	dmaengine_tx_status(tup->rx_dma_chan,  tup->rx_cookie, &state);//获得dma状态
	prev_rx_dma_desc = tup->rx_dma_desc;
	count = tup->rx_bytes_requested - state.residue;//获得dma中数据大小

	/* If we are here, DMA is stopped */
	if (count) {
		ret = tegra_uart_copy_rx_to_tty(tup, port, count);//将数据从dma的buffer拷贝到tty_buffer,实机测试可能花费16us
		if (ret)         //ret只有两种状态,0或者负数(即出现错误),所以正常情况下会继续执行tegra_uart_handle_rx_pio
			goto skip_pio;
	}

	ret = tegra_uart_handle_rx_pio(tup, port);

skip_pio:
	if (tup->enable_rx_buffer_throttle) {
		rx_level = tty_buffer_get_level(port);
		if (rx_level > 70)
			mod_timer(&tup->timer,
					jiffies + tup->timer_timeout_jiffies);
	}

	if (tty) {
		tty_flip_buffer_push(port);//将tty_buffer的数据push 到更上层的read_buf
		tty_kref_put(tty);
	}
	tegra_uart_start_rx_dma(tup);//启动dma
	async_tx_ack(prev_rx_dma_desc);

	if (tup->enable_rx_buffer_throttle) {
		if ((rx_level <= 70) && tup->rts_active)
			set_rts(tup, true);
	} else if (tup->rts_active)
		set_rts(tup, true);

	return ret;
}

tegra_uart_handle_rx_pio的作用:检查fifo中是否有残余数据或是新数据,并用pio mode读取数据。这样做虽然可以防止数据丢失,但是如果有新数据在此时到来,相比dma模式读取数据的效率大大降低。

                                                              如果把这一句注释掉 ,那么如果有新数据在此时到来,dma又已经关闭,fifo中数据触发了trigger level 要往哪里去?关于最后这个问题欢迎大家留言指导一下

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值