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

news2024/11/18 21:52:32

一、框架回顾

在这里插入图片描述

二、编写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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AutoConfigurationPackages.Registrar.class源码阅读

类作用 &#xff5b;link ImportBeanDefinitionRegistrar&#xff5d;存储来自导入的基本包配置。 registerBeanDefinitions 作用&#xff1a; 根据导入的有Configuration注解的类给定的注释元数据注册bean定义。由于与&#xff5b;codeConfiguration&#xff5d;相关的生命周…

HarmonyOS开发:NodeJs脚本实现组件化动态切换

前言 上篇文章&#xff0c;我们使用NodeJs脚本完成了HarmonyOS项目的组件化运行&#xff0c;但是由于脚本是基于4.0.0.400版本的DevEco Studio开发的&#xff0c;可能在配置文件的修改上有些许差距&#xff0c;那么遇到这种情况怎么办&#xff0c;一种是再写一套针对性的脚本文…

谁能想到,字节2023校招起薪40w+

大家好&#xff0c;我是老原。 转眼2023也来到了年底&#xff0c;每年的校招季&#xff0c;都是大厂上演抢人大战的时机&#xff0c;公布薪资和“开奖”一样刺激。 就拿互联网新贵—字节跳动来说&#xff0c;按照字节15薪计算白菜第一年的总包都超过40W了&#xff0c;对比去年…

【Linux】VM及WindowsServer安装

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是Java方文山&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;推荐给大家我的专栏《微信小程序开发实战》。&#x1f3af;&#x1f3a…

电脑怎么共享屏幕?电脑屏幕共享软件分享!

如何控制某人的电脑屏幕&#xff1f; 有时我们可能需要远程控制某人的计算机屏幕&#xff0c;例如&#xff0c;为我们的客户提供远程支持&#xff0c;远程帮助朋友或家人解决计算机问题&#xff0c;或在家中与同事完成团队合作。那么&#xff0c;电脑怎么共享屏幕&#xff…

皮卡丘RCE靶场通关攻略

皮卡丘RCE靶场通关攻略 文章目录 皮卡丘RCE靶场通关攻略RCE(remote command/code execute)概述远程系统命令执行启动环境漏洞练习第一关exec "ping"第二关 exec "eval" RCE(remote command/code execute)概述 RCE漏洞&#xff0c;可以让攻击者直接向后台服…

java--do-while循环

1.do-while循环 2.do-while循环的特点 先执行后判断 3.三种循环的区别小结 1.for循环和while循环(先判断后执行)&#xff1b;do...while(先执行后判断) 2.for循环和while循环的执行流程是一模一样的&#xff0c;功能上无区别&#xff0c;for能做到的while也能做&#xff0c…

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

大纲 UDAF入参并非表中一行&#xff08;Row&#xff09;的集合计算每个人考了几门课计算每门课有几个人考试计算每个人的平均分计算每课的平均分计算每个人的最高分和最低分 入参是表中一行&#xff08;Row&#xff09;的集合计算每个人的最高分、最低分以及所属的课程计算每课…

rust学习

rust学习 String类型clone和copy结构体的内存分布for循环&#xff08;<font color red>important&#xff01;&#xff09;堆和栈数据结构vector panic模式匹配忽略模式的值绑定 方法和关联函数线程学习1.多线程的风险2.使用spawn创建线程等待子线程结束move 关键字强制…

主流大语言模型的技术细节

主流大语言模型的技术原理细节从预训练到微调https://mp.weixin.qq.com/s/P1enjLqH-UWNy7uaIviWRA 比较 LLaMA、ChatGLM、Falcon 等大语言模型的细节&#xff1a;tokenizer、位置编码、Layer Normalization、激活函数等。2. 大语言模型的分布式训练技术&#xff1a;数据并行、…

[论文阅读]MVF——基于 LiDAR 点云的 3D 目标检测的端到端多视图融合

MVF End-to-End Multi-View Fusion for 3D Object Detection in LiDAR Point Clouds 论文网址&#xff1a;MVF 论文代码&#xff1a; 简读论文 这篇论文提出了一个端到端的多视角融合(Multi-View Fusion, MVF)算法,用于在激光雷达点云中进行3D目标检测。论文的主要贡献有两个…

Flutter报错RenderBox was not laid out: RenderRepaintBoundary的解决方法

文章目录 报错问题分析问题原因 解决办法RenderBox was not laid out错误的常见原因常见原因解决方法 RenderRepaintBoundaryRenderRepaintBoundary用途 报错 RenderBox was not laid out: RenderRepaintBoundary#d4abf relayoutBoundaryup1 NEEDS-PAINT NEEDS-COMPOSITING-BI…

华为终端智能家居应用方案

PLC-IoT概述 华为智能PLC-IoT工业物联网系列通信模块是基于电力线宽带载波技术的产品&#xff0c;实现数据在电力线上双向、高速、稳定的传输&#xff0c;广泛适用于电力、交通、工业制造、智能家居等领域&#xff0c;PLC-IoT通信模块包含头端和尾端两种类型&#xff0c;头端配…

N-129基于springboot,vue学生宿舍管理系统

开发工具&#xff1a;IDEA 服务器&#xff1a;Tomcat9.0&#xff0c; jdk1.8 项目构建&#xff1a;maven 数据库&#xff1a;mysql5.7 系统分前后台&#xff0c;项目采用前后端分离 前端技术&#xff1a;vuevue-element-admin 服务端技术&#xff1a;springboot,mybatis…

基于 nodejs+vue旅游推荐系统 mysql

目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1 1.1背景及意义 1 1.2 国内外研究概况 1 1.3 研究的内容 1 第2章 相关技术 3 2.1 nodejs简介 4 2.2 express框架介绍 6 2.4 MySQL数据库 4 第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性&#xff1a;…

centos中安装Mysql8.0

其实和mysql5.7的安装差不多 1.root用户 2.更新密钥 rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2022 3.安装mysql yum库 rpm -Uvh https://dev.mysql.com/ get/mysql80-community-release-el7-2.noarch.rpm 4.通过上两步&#xff0c;我们就可以使用yum去安装…

基于单片机嵌入式的智能交通信号灯管理系统的设计与实现

项目介绍 有目共睹电子设备已经席卷了整个人类生活&#xff0c;他们不断改善着人们的起居住行&#xff0c;这也就促进了嵌入式人工智能的快速发展。 本课设模拟系统分为软硬件两部分组成。硬件部分是由两位8段数码管和LED灯构成的显示系统和控制电路等组成&#xff0c;能较好的…

二进制部署kubernetes集群的推荐方式

软件版本&#xff1a; 软件版本containerdv1.6.5etcdv3.5.0kubernetesv1.24.0 一、系统环境 1.1 环境准备 角色IP服务k8s-master01192.168.10.10etcd、containerd、kube-apiserver、kube-scheduler、kube-controller-manager、kubele、kube-proxyk8s-node01后续etcd、conta…

JavaScript笔记(本文中将JavaScript简写为JS)

JS对大小写敏感 JS代码块的作用域都是全局的 JS的数组只能使用数字作为下标 JS对浮点型数据的精确度很难确定 JS在定义数组元素以及对象&#xff0c;在最后不能添加逗号 JS 中&#xff0c;变量可以在使用后声明&#xff0c;也就是变量可以先使用再声明&#xff0c;但不适用于已…

航天航空VR科普展VR太空科技馆沉浸式遨游体验

10月21日至23日&#xff0c;为期三天的第11届中国(芜湖)科普产品博览交易会(以下简称“科博会”)圆满落下帷幕。展会期间&#xff0c;以中国科协党组书记、分管日常工作副主席、书记处第一书记贺军科&#xff0c;省委常委、副省长张红文&#xff0c;省人大常委会副主任、省科协…