代码走读记录

目录

1.  核心数据结构 ops

2. ops各个接口功能及在流程中的位置

2.1  cdns_uart_startup 即打开串口

2.2 start tx  即发送使能

2.3 中断发送与软件队列的同步

3. 中断处理程序

3.1 RX 中断处理



xilinx_uartps.c    drivers\tty\serial    49414    2021/10/26    885

1.  核心数据结构 ops

static const struct uart_ops cdns_uart_ops = {.set_mctrl    = cdns_uart_set_mctrl,.get_mctrl   = cdns_uart_get_mctrl,.start_tx    = cdns_uart_start_tx,.stop_tx  = cdns_uart_stop_tx,.stop_rx   = cdns_uart_stop_rx,.tx_empty  = cdns_uart_tx_empty,.break_ctl    = cdns_uart_break_ctl,.set_termios = cdns_uart_set_termios,.startup   = cdns_uart_startup,.shutdown  = cdns_uart_shutdown,.pm       = cdns_uart_pm,.type       = cdns_uart_type,.verify_port  = cdns_uart_verify_port,.request_port  = cdns_uart_request_port,.release_port = cdns_uart_release_port,.config_port  = cdns_uart_config_port,
#ifdef CONFIG_CONSOLE_POLL.poll_get_char    = cdns_uart_poll_get_char,.poll_put_char   = cdns_uart_poll_put_char,
#endif
};

2. ops各个接口功能及在流程中的位置

2.1  cdns_uart_startup 即打开串口

static int cdns_uart_startup(struct uart_port *port)
{struct cdns_uart *cdns_uart = port->private_data;bool is_brk_support;int ret;unsigned long flags;unsigned int status = 0;is_brk_support = cdns_uart->quirks & CDNS_UART_RXBS_SUPPORT;spin_lock_irqsave(&port->lock, flags); //这里采用锁,多个进程同时调用支持?为啥禁止中断/* Disable the TX and RX */writel(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS,port->membase + CDNS_UART_CR);   //禁用发送和接收/* Set the Control Register with TX/RX Enable, TX/RX Reset,* no break chars.*/writel(CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST,port->membase + CDNS_UART_CR);while (readl(port->membase + CDNS_UART_CR) &(CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST))cpu_relax();/** Clear the RX disable bit and then set the RX enable bit to enable* the receiver.*/status = readl(port->membase + CDNS_UART_CR);status &= ~CDNS_UART_CR_RX_DIS;status |= CDNS_UART_CR_RX_EN;writel(status, port->membase + CDNS_UART_CR);   //使能接收/* Set the Mode Register with normal mode,8 data bits,1 stop bit,* no parity.*/writel(CDNS_UART_MR_CHMODE_NORM | CDNS_UART_MR_STOPMODE_1_BIT| CDNS_UART_MR_PARITY_NONE | CDNS_UART_MR_CHARLEN_8_BIT,port->membase + CDNS_UART_MR);/** Set the RX FIFO Trigger level to use most of the FIFO, but it* can be tuned with a module parameter*/writel(rx_trigger_level, port->membase + CDNS_UART_RXWM); //接收FIFO门限设置。门限的大小和波特率相关,可以控制中断的数目/** Receive Timeout register is enabled but it* can be tuned with a module parameter*/writel(rx_timeout, port->membase + CDNS_UART_RXTOUT); // 设置接收超时,即某些字节在FIFO中,但软件一直没有读取,超过此时间设定后,硬件产生中断,通知软件获取,实际也和波特率相关。/* Clear out any pending interrupts before enabling them */writel(readl(port->membase + CDNS_UART_ISR),port->membase + CDNS_UART_ISR);     //  清除中断spin_unlock_irqrestore(&port->lock, flags);   //释放锁ret = request_irq(port->irq, cdns_uart_isr, 0, CDNS_UART_NAME, port);if (ret) {dev_err(port->dev, "request_irq '%d' failed with %d\n",port->irq, ret);return ret;}//使能接收中断,开始接收数据/* Set the Interrupt Registers with desired interrupts */if (is_brk_support)writel(CDNS_UART_RX_IRQS | CDNS_UART_IXR_BRK,port->membase + CDNS_UART_IER);elsewritel(CDNS_UART_RX_IRQS, port->membase + CDNS_UART_IER);return 0;
}

综上,代码open的主要操作为:

1) 禁用发送和接收

2) 使能接收

3)  设置串口工作模式

4) 接收FIFO门限设置。门限的大小和波特率相关,可以控制中断的数目

5)设置接收超时,即某些字节在FIFO中,但软件一直没有读取,超过此时间设定后,硬件产生中断,通知软件获取,实际也和波特率相关。

6)  清除中断

7)挂接中断处理

8) 使能接收中断,开始接收数据

以上代码流程中 spin_lock_irqsave 禁止中断与采取锁的背景考虑是? 多线程 是lock,那么中断,是怕在操作的过程中有串口中断上来,而此时中断处理程序还没上来?

2.2 start tx  即发送使能

将数据从软件缓存队列里面放到TX FIFO 中,并进行发送及tx fifo 空中断的使能控制

static void cdns_uart_start_tx(struct uart_port *port)
{unsigned int status;if (uart_tx_stopped(port))return;/** Set the TX enable bit and clear the TX disable bit to enable the* transmitter.*/status = readl(port->membase + CDNS_UART_CR);status &= ~CDNS_UART_CR_TX_DIS;status |= CDNS_UART_CR_TX_EN;writel(status, port->membase + CDNS_UART_CR);if (uart_circ_empty(&port->state->xmit))  //如果上层tty给的缓存里面没有数据,即实际没有数据需要发送,因而直接返回。return;cdns_uart_handle_tx(port); //如果软件有数据发送,则在此处填充硬件TX FIFO,此处填充,由于上面已经将TX 发送使能打开了,所以边往fifo里面写,串口边从FIFO读取并发送出去。writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_ISR);/* Enable the TX Empty interrupt */writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IER); //使能tx fifo空中断,这样
}

2.3 中断发送与软件队列的同步

即 硬件将软件缓存中的数据发送的差不多时,此时再次唤醒软件往缓存中增加数据.

static void cdns_uart_handle_tx(void *dev_id)
{struct uart_port *port = (struct uart_port *)dev_id;unsigned int numbytes;//从软件缓存里面取数据,然后写入到TX FIFO中。//以下这个代码用于唤醒软件进程继续往缓存里面写数据,当缓存中的数据小于 WAKUP_CHARS(此处是256)if (uart_circ_chars_pending(&port->state->xmit) < WAKEUP_CHARS)uart_write_wakeup(port);}
}

为什么不是软件一直往缓存里面写,而硬件一直从缓存里面读,而采取这种门限唤醒的机制呢?

serdev-ttyport.c    drivers\tty\serdev    7921    2021/10/26    189

// wake up a tty device
void tty_port_tty_wakeup(struct tty_port *port)
{port->client_ops->write_wakeup(port);
}static const struct tty_port_client_operations client_ops = {.receive_buf = ttyport_receive_buf,.write_wakeup = ttyport_write_wakeup, //
};
//等待write_wait 的接口
static void ttyport_wait_until_sent(struct serdev_controller *ctrl, long timeout)
{struct serport *serport = serdev_controller_get_drvdata(ctrl);struct tty_struct *tty = serport->tty;tty_wait_until_sent(tty, timeout);  //此处等待
}

3. 中断处理程序

分为接收和发送中断。

static irqreturn_t cdns_uart_isr(int irq, void *dev_id)
{struct uart_port *port = (struct uart_port *)dev_id; //支持多个串口,获取此中断对应的串口实例,以便获取资源信息,避免数据的混乱。unsigned int isrstatus;spin_lock(&port->lock);  //端口锁,无中断禁止操作/* Read the interrupt status register to determine which* interrupt(s) is/are active and clear them.*/isrstatus = readl(port->membase + CDNS_UART_ISR);writel(isrstatus, port->membase + CDNS_UART_ISR);if (isrstatus & CDNS_UART_IXR_TXEMPTY) {cdns_uart_handle_tx(dev_id);    //针对发送处理isrstatus &= ~CDNS_UART_IXR_TXEMPTY;}/** Skip RX processing if RX is disabled as RXEMPTY will never be set* as read bytes will not be removed from the FIFO.*/if (isrstatus & CDNS_UART_IXR_RXMASK &&!(readl(port->membase + CDNS_UART_CR) & CDNS_UART_CR_RX_DIS))cdns_uart_handle_rx(dev_id, isrstatus);  //针对接收处理spin_unlock(&port->lock);return IRQ_HANDLED;
}

3.1 RX 中断处理

static void cdns_uart_handle_rx(void *dev_id, unsigned int isrstatus)
{struct uart_port *port = (struct uart_port *)dev_id;struct cdns_uart *cdns_uart = port->private_data;char status = TTY_NORMAL;bool is_rxbs_support;is_rxbs_support = cdns_uart->quirks & CDNS_UART_RXBS_SUPPORT;// 主要过程循环读取RX FIFO中的数据,并判断数据的正确性while ((readl(port->membase + CDNS_UART_SR) &CDNS_UART_SR_RXEMPTY) != CDNS_UART_SR_RXEMPTY) {data = readl(port->membase + CDNS_UART_FIFO);port->icount.rx++;tty_insert_flip_char(&port->state->port, data, status); //写入到缓存isrstatus = 0;}tty_flip_buffer_push(&port->state->port); // 写入到缓存。这个接口比较重要
}

The Serial Device Bus (linuxfoundation.org)

Serial TTY overview - stm32mpu (stmicroelectronics.cn)

(3条消息) Linux tty驱动学习 - UART驱动的write操作流程_sbctsp的博客-CSDN博客  (此篇文章,主要参考write_wait,我们在中断处理发送流程中看到对此wakeup的操作)

linux 串口驱动相关推荐

  1. linux串口驱动分析

    linux串口驱动分析 硬件资源及描写叙述 s3c2440A 通用异步接收器和发送器(UART)提供了三个独立的异步串行 I/O(SIO)port,每一个port都能够在中断模式或 DMA 模式下操作 ...

  2. GPS NMEA 0183 4.10协议/GPS Linux串口驱动

      NMEA 0183是美国国家海洋电子协会(National Marine Electronics Association)为海用电子设备制定的标准格式.现在已经成为GPS导航设备统一的RTCM(R ...

  3. linux 串口驱动 理解,linux 串口驱动 理解

    linux 串口 驱动 理解 一.核心数据结构 串口驱动有3个核心数据结构,它们都定义在 1.uart_driver uart_driver包含了串口设备名.串口驱动名.主次设备号.串口控制台(可选) ...

  4. Linux串口驱动(2) - 线路规程

    1. 注册tty的ldisc ldisc全称 line discipline(线路规程),因为历史原因,tty属于一类设备,而串口设备只是其中一种,所以该模块负责将用户操作桥接到不同的tty驱动.从代 ...

  5. Linux串口驱动(3) - open详解

    1. 用户空间open的操作实现 串口设备是被注册为字符设备的,在注册过程中填充了struct file_operations tty_fops结构体,该结构体中的成员open.read.write等 ...

  6. linux串口驱动分析【转】

    转自:http://blog.csdn.net/hanmengaidudu/article/details/11946591 硬件资源及描述 s3c2440A 通用异步接收器和发送器(UART)提供了 ...

  7. linux 串口驱动(二)初始化 【转】

    转自:http://blog.chinaunix.net/uid-27717694-id-3493611.html 8250串口的初始化: (1)定义uart_driver.uart_ops.uart ...

  8. 正点原子linux串口驱动下载,「正点原子Linux连载」第六十三章Linux RS232/485/GPS驱动实验...

    1)实验平台:正点原子Linux开发板 2)摘自<正点原子I.MX6U嵌入式Linux驱动开发指南>关注官方微信号公众号,获取更多资料:正点原子 第六十三章Linux RS232/485/ ...

  9. xilinx linux 串口驱动

    串口是常用的外设,串口有很多电平标准,TTL.232.485 等等,它们的驱动程序都是一样的.在嵌入式Linux系统中,串口被看成终端设备(tty),包括 3 个结构体:uart_driver.uar ...

  10. linux串口驱动及应用程序,基于华邦W90P710处理器的Linux内核应用及串口驱动的实现-嵌入式系统-与非网...

    嵌入式Linux是一种很受欢迎的操作系统,具有开放源码.不存在黑箱技术.内核小.功能强大.运行稳定.效率高.易于定制裁减等特点[1],广泛应用于工控产品.很多工控产品需要和外部设备进行信息交换,而串口 ...

最新文章

  1. 测试CH340C的功能,制作MicroPython ESP8266,ESP32下载器
  2. 算法------最接近的三数之和
  3. linux c size_t ssize_t 简介
  4. 在domain中验证cron表达式
  5. 让latex写论文更方便的几个工具
  6. POJ 1320 Street Numbers 解佩尔方程
  7. java新建配置文件_使用Java输出字符流FileWriter创建配置文件
  8. 微软研发致胜策略读书笔记(转)
  9. 修改数据库端口为51433
  10. 微课|中学生可以这样学Python(例11.2):tkinter猜数游戏(1)
  11. 蓝桥杯省赛考点_如何评价2018第九届蓝桥杯省赛?
  12. 软件工程 -- 数据流图的画法
  13. 概率论与数理统计——卡方分布的期望与方差
  14. c语言实训报告 总结与展望,c语言实训报告总结范文四篇合集
  15. js中this指向的四种规则+ 箭头函数this指向
  16. Titanic 生存预测(上)
  17. socket 编程基本步骤
  18. 【自然语言处理】BERT GPT
  19. 硬盘详解与如何选购固态硬盘
  20. NewLife使用心得

热门文章

  1. 行政区划编码转换区域名工具类
  2. 华为手机邮箱发件服务器端口设置,华为手机设置-华为手机POP3设置
  3. 用yolov5训练kitti数据集
  4. javaweb框架学习开端
  5. 局域网计算机共享加密码,局域网文件共享设置密码的方法
  6. 5G协议学习(38.300-物理层)
  7. iOS下Safari自动化测试
  8. mac 编译mysql 源码_Mac上编译MySQL源码与安装
  9. CPU缓存侧信道攻击综述-Survey of CPU Cache-Based Side-Channel Attacks
  10. 提取unity3d游戏资源文件