10_UART驱动情景分析_read#
UART驱动情景分析_read#
参考资料
参考代码:
硬件相关: drivers/tty/serial/imx.c drivers/tty/serial/stm32-usart.c 串口核心层: drivers/tty/serial/serial_core.c TTY层: drivers/tty/tty_io.c
1. 情景分析大纲#
注册过程分析
open过程分析
read过程分析
write过程分析
2. 源码框架回顾#
3. 使用哪个行规程#
3.1 行规程注册#
文件:drivers\tty\n_tty.c
void __init n_tty_init(void)
{
tty_register_ldisc(N_TTY, &n_tty_ops);
}
以后可以通过标号N_TTY找到这个行规程。
3.2 open设备时确定行规程#
tty_open
tty_open_by_driver
tty_init_dev
tty = alloc_tty_struct(driver, idx);
tty_ldisc_init(tty);
struct tty_ldisc *ld = tty_ldisc_get(tty, N_TTY);
tty->ldisc = ld;
4. read过程分析#
流程为:
APP读
使用行规程来读
无数据则休眠
UART接收到数据,产生中断
中断程序从硬件上读入数据
发给行规程
行规程处理后存入buffer
行规程唤醒APP
APP被唤醒后,从行规程buffer中读入数据,返回
4.1 tty_read#
文件:drivers\tty\tty_io.c
4.2 ldisk read#
文件:drivers\tty\n_tty.c
函数:n_tty_read
copy_from_read_buf
const unsigned char *from = read_buf_addr(ldata, tail);
// return &ldata->read_buf[i & (N_TTY_BUF_SIZE - 1)];
retval = copy_to_user(*b, from, n);
4.3 数据源头: 中断#
4.3.1 IMX6ULL#
文件:drivers\tty\serial\imx.c
函数:imx_rxint
imx_rxint
// 读取硬件状态
// 得到数据
// 在对应的uart_port中更新统计信息, 比如sport->port.icount.rx++;
// 把数据存入tty_port里的tty_buffer
tty_insert_flip_char(port, rx, flg)
// 通知行规程来处理
tty_flip_buffer_push(port);
tty_schedule_flip(port);
queue_work(system_unbound_wq, &buf->work); // 使用工作队列来处理
// 对应flush_to_ldisc函数
4.3.2 STM32MP157#
文件:drivers\tty\serial\stm32-usart.c
函数:stm32_usart_threaded_interrupt
stm32_usart_threaded_interrupt
stm32_usart_receive_chars(port, true);
// 通过DMA方式得到数据
stm32_usart_receive_chars_dma(port);
stm32_usart_push_buffer_dma(port, dma_size);
// 把数据存入tty_port里的tty_buffer
dma_count = tty_insert_flip_string(ttyport, dma_start, dma_size);
// 更新统计信息
port->icount.rx += dma_count;
// 通知行规程来处理
tty_flip_buffer_push(tport);
tty_schedule_flip(port);
queue_work(system_unbound_wq, &buf->work); // 使用工作队列来处理
// 对应flush_to_ldisc函数