编写虚拟UART驱动程序-框架

一、框架回顾

在这里插入图片描述

二、编写UART驱动要做的事

在这里插入图片描述

1.注册一个uart_driver
2. 对于每一个port,都会在设备树里面有一个节点
3. 设备树里的节点和platform_driver节点匹配
4. 当platform_dirver的probe函数被调用时,可以获得设备树里的信息,从而把每个串口设置成对应的uart_driver

三、虚拟的UART

在这里插入图片描述

为了做实验,我们还要创建一个虚拟文件:/proc/virt_uart_buf

  • 要发送数据给虚拟串口时,执行:echo "xxx" > /proc/virt_uart_buf
  • 要读取虚拟串口的数据时,执行:cat /proc/virt_uart_buf
    虚拟串口需要有接收中断(写入buff时),查看6ull的手册,第三章中断中,使用99是可157里面一样是保留的。
    在这里插入图片描述

编写代码的思路:
在platform_driver的probe函数里,需要设置uart_port(提供uart_ops),然后注册uart_port
uart_ops需要提供设置串口的信息,需要设置读数据,需要设置写输入的方法

四、编程

4.1 编写设备树

/ {
        virtual_uart: virtual_uart_100ask {
                compatible = "100ask,virtual_uart";
                interrupt-controller;
                #interrupt-cells = <2>;

                interrupt-parent = <&intc>;
                interrupts = <GIC_SPI 99 IRQ_TYPE_LEVEL_HGIH>;
        };
};

4.2 编写uart_driver

4.3 编写platform_driver

#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/serial_core.h>
#include <linux/sysrq.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/proc_fs.h>
#include <linux/tty_flip.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/fs.h>
#include <linux/uaccess.h>

static struct uart_port *virtual_port;
static struct proc_dir_entry *uart_proc_file;

#define BUF_LEN 1024
#define NEXT_PLACE(i) ((i+1)&0x3ff)
static unsigned char txbuf[1024];
static int tx_buf_r = 0;
static int tx_buf_w = 0;

static unsigned char rxbuf[1024];
//static int rx_buf_r = 0;
static int rx_buf_w = 0;

static struct uart_driver virtual_uart_drv = {
	.owner = THIS_MODULE,
	.driver_name = "VIRT_UART",
	.dev_name = "ttyVIRT",
	.major = 0,
	.minor = 0,
	.nr = 1,
};

/* circle buffer */
static int is_txbuf_empty(void)
{
	return tx_buf_r == tx_buf_w;
}

static int is_txbuf_full(void)
{
	return NEXT_PLACE(tx_buf_w) == tx_buf_r;
}

static int txbuf_put(unsigned char val)
{
	if(is_txbuf_full())
		return -1;
	txbuf[tx_buf_w] = val;
	tx_buf_w = NEXT_PLACE(tx_buf_w);
	return 0;
}

static int txbuf_get(unsigned char *pval)
{
	if(is_txbuf_empty())
		return -1;
	*pval =txbuf[tx_buf_r];
	tx_buf_r = NEXT_PLACE(tx_buf_r);
	return 0;
}

static int txbuf_count(void)
{
	if(tx_buf_w >= tx_buf_r)
		return tx_buf_w - tx_buf_r;
	else
		return BUF_LEN + tx_buf_w - tx_buf_r;
}

static ssize_t virtual_uart_buf_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
	int cnt = txbuf_count();
	int i;
	unsigned char val;

	cnt = (cnt > size)?size:cnt;

	for(i=0;i<cnt;i++) {
		int ret;
		txbuf_get(&val);
		ret = copy_to_user(buf+i, &val, 1);
	}

	return cnt;
}

static ssize_t virtual_uart_buf_write(struct file *file, const char __user *buf, size_t size, loff_t *off)
{
	rx_buf_w = copy_from_user(rxbuf, buf, size);

	irq_set_irqchip_state(virtual_port->irq, IRQCHIP_STATE_PENDING, 1);

	return size;
}

static const struct file_operations virtual_uart_buf_fops = {
	.read  = virtual_uart_buf_read,
	.write = virtual_uart_buf_write,
};

static unsigned int virtual_uart_tx_empty(struct uart_port *port)
{
	return 1;
}

static void virtual_uart_start_tx(struct uart_port *port)
{
	struct circ_buf *xmit = &port->state->xmit;

	while(!uart_circ_empty(xmit) &&
			!uart_tx_stopped(port)) {

		/* save circ buffer into the txbuf */

		//txbuf[tx_buf_w++] = xmit->buf[xmit->tail];
		txbuf_put(xmit->buf[xmit->tail]);
		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE -1);
		port->icount.tx++;
	}

   if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
       uart_write_wakeup(port);
}

static void
virtual_uart_set_termios(struct uart_port *port, struct ktermios *termios,
             struct ktermios *old)
{
	return;
}

static int virtual_startup(struct uart_port *port)
{
	return 0;
}

static void virtual_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
}

static unsigned int virtual_get_mctrl(struct uart_port *port)
{
	return 0;
}

static void virtual_stop_tx(struct uart_port *port)
{
}

static void virtual_stop_rx(struct uart_port *port)
{
}

static void virtual_shutdown(struct uart_port *port)
{
}

static const char *virtual_type(struct uart_port *port)
{
	return "100ASK_VIRT_UART";
}

static const struct uart_ops  virtual_port_ops = {
    .tx_empty   = virtual_uart_tx_empty,
	.set_mctrl	= virtual_set_mctrl,
	.get_mctrl	= virtual_get_mctrl,
    .start_tx   = virtual_uart_start_tx,
	.stop_tx 	= virtual_stop_tx,
	.stop_rx	= virtual_stop_rx,
//	.enable_ms	= imx_enable_ms,
//	.break_ctl	= imx_break_ctl,
	.startup	= virtual_startup,
	.shutdown	= virtual_shutdown,
//	.flush_buffer	= imx_flush_buffer,
    .set_termios    = virtual_uart_set_termios,
	.type			= virtual_type,
//	.config_port	= imx_config_port,
//	.verify_port	= imx_verify_port,
};

static irqreturn_t virtual_uart_rxint(int irq, void *dev_id)
{
	struct uart_port *port = dev_id;
	unsigned long flags;
	int i;

	spin_lock_irqsave(&port->lock, flags);

	for(i=0;i<rx_buf_w;i++) {
		port->icount.rx++;

		tty_insert_flip_char(&port->state->port, rxbuf[i], TTY_NORMAL);
	}
	rx_buf_w = 0;

	spin_unlock_irqrestore(&port->lock, flags);
	tty_flip_buffer_push(&port->state->port);

	return IRQ_HANDLED;
}

static int virtual_uart_probe(struct platform_device *pdev)
{
	int rx_irq;
	int ret;

	uart_proc_file = proc_create("virtual_uart_buf", 0, NULL, &virtual_uart_buf_fops);

	virtual_port = devm_kzalloc(&pdev->dev, sizeof(struct uart_port), GFP_KERNEL);
	if(!virtual_port) {
		return -ENOMEM;
	}
	
	rx_irq = platform_get_irq(pdev, 0);
	ret = devm_request_irq(&pdev->dev, rx_irq, virtual_uart_rxint, 0,
			dev_name(&pdev->dev), virtual_port);


	virtual_port->dev = &pdev->dev;
	virtual_port->iotype = UPIO_MEM;
	virtual_port->irq = rx_irq;
	virtual_port->fifosize = 32;
	virtual_port->ops = &virtual_port_ops;
	virtual_port->flags = UPF_BOOT_AUTOCONF;

	return uart_add_one_port(&virtual_uart_drv, virtual_port);
}

static int virtual_uart_remove(struct platform_device *pdev)
{
	uart_remove_one_port(&virtual_uart_drv, virtual_port);
	proc_remove(uart_proc_file);
	return 0;
}

static const struct of_device_id virtual_uart_of_match[] = {
	{ .compatible = "100ask,virtual_uart", },
	{ },
};

static struct platform_driver virtual_uart_platform_drv = {
	.probe  = virtual_uart_probe,
	.remove = virtual_uart_remove,
	.driver = {
		.name = "virtual_uart",
		.of_match_table = of_match_ptr(virtual_uart_of_match),
	},
};

static int __init virtual_uart_init(void)
{
	int ret = uart_register_driver(&virtual_uart_drv);
	if(ret) return ret;

	ret = platform_driver_register(&virtual_uart_platform_drv);
	if(ret != 0)
		uart_unregister_driver(&virtual_uart_drv);

	return ret;
}

static void __exit virtual_uart_exit(void)
{
	platform_driver_unregister(&virtual_uart_platform_drv);
	uart_unregister_driver(&virtual_uart_drv);
}

module_init(virtual_uart_init);
module_exit(virtual_uart_exit);
MODULE_LICENSE("GPL");

4.4 实现uart_ops

4.5 实现/proc/virt_uart_buf

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/105445.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Vue3 封装 element-plus 图标选择器

一、实现效果 效果一&#xff1a; 效果二&#xff1a; 效果一的这个是把全部的icon图标都让它显示出来&#xff0c;让我们自己选择说选图标 二、效果一实现步骤 2.1. 全局注册 icon 组件 // main.ts import App from ./App.vue; import { createApp } from vue; import * a…

代码随想录算法训练营第2天| 977有序数组的平方、209长度最小的子数组。

JAVA代码编写 977. 有序数组的平方 给你一个按 非递减顺序 排序的整数数组 nums&#xff0c;返回 每个数字的平方 组成的新数组&#xff0c;要求也按 非递减顺序 排序。 示例 1&#xff1a; 输入&#xff1a;nums [-4,-1,0,3,10] 输出&#xff1a;[0,1,9,16,100] 解释&…

PDF编辑工具Acrobat Pro DC 2023中文

Acrobat Pro DC 2023是一款全面、高效的PDF编辑和管理软件。它提供了丰富的PDF编辑功能&#xff0c;如创建、编辑、合并、分割、压缩、旋转、裁剪等&#xff0c;让用户可以轻松处理各种PDF文档。同时&#xff0c;该软件还具有智能的PDF处理技术&#xff0c;可以自动识别和修复P…

中国铁路线路数据,分为高速铁路和普通铁路,有shp格式和xlsx格式,免费下载

数据地址&#xff1a; 中国铁路线路数据https://www.xcitybox.com/datamarketview/#/Productpage?id274 基本信息. 数据名称: 中国铁路线路数据 数据格式: ShpXlsx 数据时间: 2018年 数据几何类型: 线 数据坐标系: WGS84坐标系 数据来源&#xff1a;网络公开数据 数据…

Java 使用 poi 和 aspose 实现 word 模板数据写入并转换 pdf 增加水印

本项目所有源码和依赖资源都在文章顶部链接&#xff0c;有需要可以下载使用 1. 需求描述 从指定位置读取一个 word 模板获取业务数据并写入该 word 模板&#xff0c;生成新的 word 文档将新生成的 word 文档转换为 pdf 格式对 pdf 文档添加水印 2. 效果预览 word 模板 带水印的…

openpnp - SlotSchultzFeeder source code bugfix

文章目录 openpnp - SlotSchultzFeeder source code bugfix概述笔记openpnp源码调试环境排查思路开git分支查到的问题 - 1查到的问题 - 2查到的问题 - 3针对以上问题进行的逻辑修正D:\my_openpnp\openpnp_github\src\main\java\org\openpnp\machine\reference\driver\wizards\G…

Spark On Hive原理和配置

目录 一、Spark On Hive原理 &#xff08;1&#xff09;为什么要让Spark On Hive&#xff1f; 二、MySQL安装配置&#xff08;root用户&#xff09; &#xff08;1&#xff09;安装MySQL &#xff08;2&#xff09;启动MySQL设置开机启动 &#xff08;3&#xff09;修改MySQL…

用 Rust 和 cURL 库制作一个有趣的爬虫

目录 一、介绍 二、准备工作 三、代码实现 四、解析 HTML 并提取特定元素示例 总结 本文将介绍如何使用 Rust 编程语言和 cURL 库制作一个有趣的网络爬虫。我们将通过实例代码来展示如何抓取网页内容、处理数据和解析 HTML 结构。同时&#xff0c;还将探讨爬虫技术的原理、…

YOLOv5 添加 OTA,并使用 coco、CrowdHuman数据集进行训练。

YOLO-OTA 第一步&#xff1a;拉取 YOLOv5 的代码第二步&#xff1a;添加 ComputeLossOTA 函数第二步&#xff1a;修改 train 和 val 中损失函数为 ComputeLossOTA 函数1、在 train.py 中 首先添加 ComputeLossOTA 库。2、在 train.py 修改初始化的损失函数3、在 train.py 修改一…

ChatGPT 与 Python Echarts 完成热力图实例

热力图是一种数据可视化方式&#xff0c;它通过颜色的变化来表示数据的差异和分布。以下是使用热力图的一些作用和好处&#xff1a; 数据可视化&#xff1a;热力图可以将复杂的数据集转化为更直观、更易理解的形式。这对于很多人来说&#xff0c;尤其是那些没有深入统计学或数…

YouTrack 中如何设置邮件通知

在 YouTrack 中&#xff0c;默认是不会邮件通知的。 你可以为你的账号设置邮件通知。 设置的方法为单击用户属性&#xff0c;然后在弹出的小窗口中选择属性选项。 设置邮件通知 在通知 Tab 页面中&#xff0c;选择发送邮件的方式&#xff0c;默认这个选项是不选择的。 用户…

IDEA 断点高阶

一、按钮介绍 1.1 补充 返回断点处&#xff1a; 设置debug配置&#xff1a; 二、增加/切换debugger视图 三、window快捷键 所在行处&#xff1a; CtrlF8断点属性编辑&#xff1a; CtrlShiftF8 四、一些常用的高级功能 4.1 查看对象内存-Attach memory agent 1.勾选Atta…

vscode下ssh免密登录linux服务器

vscode使用ssh免密登录linux 1、安装SSH插件2、生成密钥3、linux安装ssh服务4、linux下配置公钥5、vscode远程登录 注&#xff1a;测试环境为window10Ubuntu1804/Ubuntu2204 1、安装SSH插件 扩展->搜索SSH->点击install进行安装&#xff0c;如下图所示&#xff1a; 2、…

非小米笔记本小米妙享中心安装最新教程 3.2.0.464 兼容所有Windows系统

小米妙享中心 3.2.0.464 版本帮助 : 支持音频流转、屏幕镜像、屏幕拓展、键鼠拓展、无线耳机、小米互传 目录 小米妙享中心 3.2.0.464 版本帮助 : 1.常规教程使用安装包方式安装失败 或者 1.1安装失败可使用大佬的加载补丁方法解决 补充卸载残留 1.2 截图存档 2. 本教程…

原生JavaScript实现的SPA单页应用(hash路由)

什么叫做SPA单页应用 单页Web应用 &#xff08;single page web application&#xff0c;SPA&#xff09; &#xff0c;就是只有一张Web页面的应用&#xff0c;是加载单个HTML 页面并在用户与应用程序交互时动态更新该页面的Web应用程序。 单页应用的说法是在JavaScript和AJA…

每日一练——返回链表的中间结点

&#x1d649;&#x1d65e;&#x1d658;&#x1d65a;!!&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦ &#x1f44f;&#x1f3fb;‧✧̣̥̇:Solitary-walk ⸝⋆ ━━━┓ - 个性标签 - &#xff1a;来于“云”的“羽球人”。…

Nginx 的配置文件(负载均衡,反向代理)

Nginx可以配置代理多台服务器&#xff0c;当一台服务器宕机之后&#xff0c;仍能保持系统可用。 cmd查找端口是否使用&#xff1a;netstat -ano Nginx出现403 forbidden #解决办法&#xff1a;修改web目录的读写权限&#xff0c;或者是把nginx的启动用户改成目录的所属用户&…

0基础学习PyFlink——用户自定义函数之UDF

大纲 标量函数入参并非表中一行&#xff08;Row&#xff09;入参是表中一行&#xff08;Row&#xff09;alias PyFlink中关于用户定义方法有&#xff1a; UDF&#xff1a;用户自定义函数。UDTF&#xff1a;用户自定义表值函数。UDAF&#xff1a;用户自定义聚合函数。UDTAF&…

Go学习第十章——文件操作,Json和测试

Go文件操作&#xff0c;Json和测试 1 文件1.1 基本介绍1.2 读取的基本操作1.3 写入的基本操作1.4 使用案例(三个) 2 Go语言的Json使用2.1 序列化案例2.2 反序列化案例 3 单元测试3.1 先看个需求3.2 快速入门3.3 入门总结 1 文件 1.1 基本介绍 文件在程序中是以流的形式来操作…

使用Jenkins触发gitlab的webhook

满足条件&#xff1a; 首先手动构建可以完成构建 例如&#xff1a; 打开项目点击配置 在“Build Triggers”栏勾选&#xff0c;Build when a change is pushed to GitLab. GitLab webhook &#xff1b;如下 复制URL链接&#xff0c;我的链接是&#xff1a;http://192.168.44…