今天大家都在抢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;
}
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)
这一段描述我也不太能理解,希望有大神指导指导。我认为这一句作用与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;
};
..
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 */
..
此句之所以值得关注是因为.在这里将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,
};
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 要往哪里去?关于最后这个问题欢迎大家留言指导一下