ARM驱动学习之21_字符驱动

news2024/9/20 20:25:58

                              ARM驱动学习之21_字符驱动

操作步骤:

file_operations中的函数比较多,
选取用的比较多的函数简单介绍,
后
面的驱动教程中调用了对应的函数

• int (*open) (struct inode *, struct file *)
– 打开函数
• int (*release) (struct inode *, struct file *)
– 释放close函数
• long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long)
– io控制函数
• ssize_t (*read) (struct file *, char __user *, size_t, loff_t *)
– 读函数
• ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *)
– 写函数
• loff_t (*llseek) (struct file *, loff_t, int)
– 定位函数

1.修改文件名为char_driver并修改Makefile里面的文件。

定义函数如下:
/*打开操作*/
static int chardevnode_open(struct inode * inode,struct file * file){
    printk(KERN_EMERG "chardevnode_open is opened! \n");
    return 0;
}

/*关闭操作*/
static int chardevnode_release(struct inode *inode,struct file *file){
    printk(KERN_EMERG "chardevnode_release is release! \n");
    return 0;     
}

/*IO操作*/
static long chardevnode_ioctl (struct file *file, unsigned int cmd, unsigned long arg){
    printk(KERN_EMERG "chardevnode_ioctl is success! cmd is %d,arg is %d \n",cmd,arg);
    return 0;  
}

static ssize_t chardevnode_read (struct file *file , char __user *buf, size_t count, loff_t *f_ops){
    return 0; 
}

static ssize_t chardevnode_write (struct file *file , const char __user *buf, size_t count, loff_t *f_ops){
    return 0; 
}

static loff_t chardevnode_llseek (struct file *file , loff_t offset, int ence){
    return 0; 
}

2.在struct file_operations my_fops = {
    .owner = THIS_MODULE,
    .open = chardevnode_open,
    .release = chardevnode_release,
    .unlocked_ioctl = chardevnode_ioctl,
    .read = chardevnode_read,
    .write = chardevnode_write,
    .llseek = chardevnode_llseek,
};

2.修改invoke_hello.c文件:

1.将“invoke_hello.c”改为“invoke_char_driver.c”
在文件中添加如下内容:
char *hello_node0 = "/dev/chardevnode0";
char *hello_node1 = "/dev/chardevnode1";
2.修改函数名为hello_node0 和 hello_node1;
if((fd = open(hello_node0,O_RDWR|O_NDELAY)) < 0)
{
    printf();
}

close(fd);

编译应用命令如下
– arm-none-linux-gnueabi-gcc -o invoke_char_driver invoke_char_driver.c -static

代码,设备节点:

#include <linux/init.h>
/*包含初始化宏定义的头文件,代码中的module_init和module_exit在此文件中*/
#include <linux/module.h>
/*包含初始化加载模块的头文件,代码中的MODULE_LICENSE在此头文件中*/
/*定义module_param module_param_array的头文件*/
#include <linux/moduleparam.h>
/*定义module_param module_param_array中perm的头文件*/
#include <linux/stat.h>
/*字符设备函数*/
#include <linux/fs.h>
/*MDKDEV转换设备号数据类型宏定义*/
#include <linux/kdev_t.h>
/*定义字符设备的结构体*/
#include <linux/cdev.h>
/*分配内存空间函数头文件*/
#include <linux/slab.h>

#include <linux/device.h>


#define DEVICE_NAME "chardevnode"
#define DEVICE_MINOR_NUM 2
#define DEV_MAJOR 0
#define DEV_MINOR 0

#define REGDEV_SIZE 3000


MODULE_LICENSE("Dual BSD/GPL");
/*声明是开源的,没有内核版本限制*/
MODULE_AUTHOR("iTOPEET_dz");
/*声明作者*/

static int numdev_major = DEV_MAJOR ;//主设备号
static int numdev_minor = DEV_MINOR ;//次设备号

module_param(numdev_major,int,S_IRUSR);
module_param(numdev_minor,int,S_IRUSR);



struct reg_dev
{
    char *data;
    unsigned long size;
    struct cdev cdev;
};
struct reg_dev *my_devices;
static struct class * myclass;




/*打开操作*/
static int chardevnode_open(struct inode * inode,struct file * file){
    printk(KERN_EMERG "chardevnode_open is success! \n");
    return 0;
}

/*关闭操作*/
static int chardevnode_release(struct inode *inode,struct file *file){
    printk(KERN_EMERG "chardevnode_release is success! \n");
    return 0;     
}

/*IO操作*/
static long chardevnode_ioctl (struct file *file, unsigned int cmd, unsigned long arg){
    printk(KERN_EMERG "chardevnode_ioctl is success! cmd is %d,arg is %d \n",cmd,arg);
    return 0;  
}


ssize_t chardevnode_read (struct file *file , char __user *buf, size_t count, loff_t *f_ops){
    return 0; 
}

ssize_t chardevnode_write (struct file *file , const char __user *buf, size_t count, loff_t *f_ops){
    return 0; 
}

loff_t chardevnode_llseek (struct file *file , loff_t offset, int ence){
    return 0; 
}

struct file_operations my_fops = {
    .owner = THIS_MODULE,
	.open = chardevnode_open,
	.release = chardevnode_release,
	.unlocked_ioctl = chardevnode_ioctl,
	.read = chardevnode_read,
	.write = chardevnode_write,
	.llseek = chardevnode_llseek,
};



/*设备注册到系统*/
static void reg_init_cdev(struct reg_dev *dev,int index){
    int err;
    int devno = MKDEV(numdev_major,numdev_minor + index);
    /*数据初始化*/
    cdev_init(&dev -> cdev,&my_fops);
    dev -> cdev.owner = THIS_MODULE;
    dev -> cdev.ops = &my_fops;

    err = cdev_add(&dev -> cdev,devno,1);
    if(err){
        printk(KERN_EMERG "failed,cdev_add is %d ,index is %d\n",err,index);
    }
    else{
        printk(KERN_EMERG "cdev_add %d success\n",index);
		printk(KERN_EMERG "numdev_minor  is %d",numdev_minor);
    }

}

static int Ascdev_init(void)
{
	int ret = 0;
	int i = 0;
	
	printk(KERN_EMERG "numdev_major is %d!\n",numdev_major);
	printk(KERN_EMERG "numdev_minor is %d!\n",numdev_minor);
	
	dev_t num_dev;
	if(numdev_major){
		num_dev = MKDEV(numdev_major,numdev_minor);
		//宏命令,用于处理各种设备号相关的数据
		//设备注册
		ret = register_chrdev_region(num_dev,DEVICE_MINOR_NUM,DEVICE_NAME);
		if(ret < 0)
		{
			 printk(KERN_EMERG "register_chrdev_region req is %d is failed \n",num_dev );
			 
		}
		printk(KERN_EMERG "register_chrdev_region %d is success \n",numdev_major);	
	}
	else{
		ret = alloc_chrdev_region(&num_dev,numdev_minor,DEVICE_MINOR_NUM,DEVICE_NAME);
		if(ret < 0)
		{
			 printk(KERN_EMERG "alloc_chrdev_region req is %d is failed \n",num_dev );
			 return -1;
		}
		numdev_major = MAJOR(num_dev);//huoqu 
		printk(KERN_EMERG "numdev_major is %d \n",numdev_major);
	}

	myclass = class_create(THIS_MODULE,DEVICE_NAME);

	
	my_devices = kmalloc(DEVICE_MINOR_NUM * sizeof(struct reg_dev),GFP_KERNEL);	
	if(!my_devices){
		ret = -ENOMEM;
		goto fail;
	}	
	memset(my_devices,0,DEVICE_MINOR_NUM * sizeof(struct reg_dev));//初始化缓存为0;
	for(i = 0;i < DEVICE_MINOR_NUM;i ++){
    my_devices[i].data = kmalloc(REGDEV_SIZE,GFP_KERNEL);
    memset(my_devices[i].data,0,REGDEV_SIZE);
    reg_init_cdev(&my_devices[i],i);
	device_create(myclass,NULL,MKDEV(numdev_major,numdev_minor + i),NULL,DEVICE_NAME"%d",i);//这个 i 可以创建chardevnode0,chardevnode1		
	}
	
	printk(KERN_EMERG "Ascdev enter!\n");
	/*打印信息,KERN_EMERG表示紧急信息*/
	return 0;
	
fail:
    unregister_chrdev_region(MKDEV(numdev_major,numdev_minor),DEVICE_MINOR_NUM);
    printk(KERN_EMERG "kmalloc is fail\n");
    
    return ret;	
	
	
}

static void Ascdev_exit(void)
{	
	int i;
	for(i = 0;i < DEVICE_MINOR_NUM;i++){
		cdev_del(&(my_devices[i].cdev));	
		device_destroy(myclass,MKDEV(numdev_major,numdev_minor + i));

	}
	
	class_destroy(myclass);
//	kfree(myclass);	
	unregister_chrdev_region(MKDEV(numdev_major,numdev_minor),DEVICE_MINOR_NUM);
	printk(KERN_EMERG "Ascdev exit!\n");
}


module_init(Ascdev_init);
/*初始化函数*/
module_exit(Ascdev_exit);
/*卸载函数*/

应用:

/*************************************************************************
> File Name: Invoke.c
> Author: 
> Mail: 
> Created Time: Fri 27 Sep 2019 10:51:55 PM CST
************************************************************************/

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>

int main(void)
{
	char * hello_node0 = "/dev/chardevnode0";
	char * hello_node1 = "/dev/chardevnode1";
	
    int fd; 
    if(fd = open(hello_node0,O_RDWR|O_NDELAY) < 0){
        printf("hello_node0 open %s is failed\r\n",hello_node0);
       }
   else{
        printf("hello_node0 open  %s is success\r\n",hello_node0);
		
    }
	close(fd);
    if(fd = open(hello_node1,O_RDWR|O_NDELAY) < 0){
        printf("hello_node1 open %s is failed\r\n",hello_node1);
       }
   else{
        printf("hello_node1 open  %s is success\r\n",hello_node1);
		
    }	
	close(fd);
    return 0;
}

运行结果:

[root@iTOP-4412]# ls
chardevicenode.ko   invoke_char_driver
[root@iTOP-4412]# insmod chardevicenode.ko                                                                     
[ 1951.543724] numdev_major is 0!
[ 1951.545312] numdev_minor is 0!
[ 1951.548335] numdev_major is 248 
[ 1951.553133] cdev_add 0 success
[ 1951.554733] numdev_minor  is 0
[ 1951.559293] cdev_add 1 success
[ 1951.561050] numdev_minor  is 0
[ 1951.565035] Ascdev enter!
[root@iTOP-4412]# ls /sys/class                                                                                
android_usb   gpsdrv        kovaplus      net           scsi_device   ump
arvo          graphics      lcd           power_supply  scsi_disk     usb_device
backlight     i2c-adapter   lirc          ppp           scsi_generic  video4linux
bdi           i2c-dev       mali          pyra          scsi_host
block         ieee80211     mdio_bus      rc            sound
bluetooth     input         mem           rc522         spi_master
chardevnode   kone          misc          regulator     switch
firmware      koneplus      mmc_host      rtc           tty
[root@iTOP-4412]# ls /dev/chardevnode*                                                                         
/dev/chardevnode0  /dev/chardevnode1
[root@iTOP-4412]# ./invoke_char_driver                                                                         
[ 2065.729172] chardevnode_open is success! 
[ 2065.732435] chardevnode_open is success! 
[ 2065.735821] chardevnode_release is success! 
[ 2065.740939] chardevnode_release is success! 
hello_node0 open  /dev/chardevnode0 is successhello_node1 open  /dev/chardevnode1 is success[root@iTOP-4412]# 
[root@iTOP-4412]# rmmod chardevicenode                                                                         
[ 2072.553457] Ascdev exit!

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

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

相关文章

uniapp H5 打开地图 并选中标记点

uniapp H5 打开地图 并选中标记点 先上代码 //打开地图 显示景区位置openMap() {// 支付宝// #ifdef MP-ALIPAYmy.openLocation({longitude: Number(this.detailObj.longitude), // 经度latitude: Number(this.detailObj.latitude), // 纬度name: this.detailObj.scenicName, …

C++速通LeetCode中等第10题-轮转数组(四种方法)

方法一&#xff1a;巧用deque双向队列容器 class Solution { public:void rotate(vector<int>& nums, int k) {deque<int> q;int tmp;if(nums.size() > 1){for(auto num:nums) q.push_back(num);for(int i 0;i < k;i){tmp q.back();q.pop_back();q.pu…

dgl库安装

此篇文章继续上一篇pytorch已经安装成功的情况 &#xff08;python3.9&#xff0c;pytorch2.2.2&#xff0c;cuda11.8&#xff09; 上一篇pytorch安装教学链接 选择与之匹配的版本 输入下方代码进行测试 import dgl.data dataset dgl.data.CoraGraphDataset() print(‘Numb…

24 小时不关机的挂机云电脑,还能这么玩?

云电脑技术为我们提供了无限可能。特别是对于游戏爱好者&#xff0c;挂机云电脑不仅解决了传统电脑的局限性&#xff0c;还带来了更为便利的游戏体验。除此之外云电脑还有什么其他玩法呢&#xff1f; 01 挂机云电脑的优势 首先要知道&#xff0c;什么是挂机云电脑&#xff1f…

局域网变压器市场价值

2024 年全球局域网变压器市场价值为 3.056 亿美元&#xff0c;预计到 2030 年将达到 4.426 亿美元&#xff0c;2024-2030 年的复合年增长率为 5.4%。 局域网变压器市场包括用于改变电信号电压或格式的产品&#xff0c;以改善和简化局域网 (LAN) 上的数据传输。这些变压器对于保…

【JavaScript】数据结构之链表(双指针、滑动窗口)

什么是链表&#xff1f; 多个元素存储的列表链表中的元素在内存中不是顺序存储的&#xff0c;而是通过“next”指针联系在一起的&#xff0c;这个“next”可以自定义。JS中的原型链原理就是链表结构&#xff0c;是通过__proto__指针联系在一起的。 双指针形式 对撞指针&am…

分布式事务一致性:本地消息表设计与实践

概念 本地消息表是一种常见的解决分布式事务问题的方法。其核心思想是将分布式事务拆分成本地事务来处理&#xff0c;通过消息队列来保证各个本地事务的最终一致性。 实现步骤 创建本地消息表&#xff1a;在数据库中创建一个本地消息表&#xff0c;用于存储待发送的消息以及消…

【图像检索】基于灰度共生矩的纹理图像检索,matlab实现

博主简介&#xff1a;matlab图像代码项目合作&#xff08;扣扣&#xff1a;3249726188&#xff09; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 本次案例是基于灰度共生矩的纹理图像检索&#xff0c;用matlab实现。 一、案例背景和算法介绍 …

从“群聊”到“一单到底”,天润融通工单系统助力品牌服务升级

“您好&#xff0c;我在xx店买的酸奶出现了质量问题&#xff0c;怎么处理&#xff1f;” “你们xx门店的服务态度怎么那么差啊&#xff0c;我要投诉&#xff01;” “您好&#xff0c;xx店的微波炉总是坏的&#xff0c;店员根本不管&#xff01;” 这些耳熟能详的抱怨&#…

【qt】一个WPS项目了解qt界面设计的基本套路

项目功能演示: 放心食用!最后有完整代码. 超级详细,期待您的一个点赞❥(^_-) 一览全局: WPS项目目录 一.创建项目二.导入资源三.ui设计四.字号选择框初始化五.滚动条初始化六.添加自定义文本类七.初始化action状态八.新建文档九.打开文件十.保存与另存为十一.打印/打印预览十…

MySQL高阶1867-最大数量高于平均水平的订单

目录 题目 准备数据 分析数据 题目 您正在运行一个电子商务网站&#xff0c;该网站正在寻找不平衡的订单。不平衡订单的订单最大数量严格大于每个订单&#xff08;包括订单本身&#xff09;的平均数量。 订单的平均数量计算为&#xff08;订单中所有产品的总数量&#xff…

visionpro脚本

visionproToolBlock的脚本的优先级优于工具连线的优先级&#xff0c;一般是照着脚本的执行顺序进行执行对应的工具&#xff0c;最常用的是C#的高级脚本&#xff0c;C#的脚本如下分为5部分。 第一部分&#xff1a;主要是一些库的引用&#xff0c;对于有些类型不知道库的时候&…

14_Python面向对象

面向过程与面向对象 在编程范式&#xff08;programming paradigms&#xff09;中&#xff0c;面向过程&#xff08;Procedural Programming&#xff09;和面向对象&#xff08;Object-Oriented Programming&#xff0c;简称OOP&#xff09;是两种主要的编程风格。 Python是一…

【医学半监督】置信度指导遮蔽学习的半监督医学图像分割

摘要: 半监督学习(Semi-supervised learning)旨在利用少数标记数据和多数未标记数据训练出高性能模型。现有方法大多采用预测任务机制,在一致性或伪标签的约束下获得精确的分割图,但该机制通常无法克服确认偏差。针对这一问题,本文提出了一种用于半监督医学图像分割的新…

(十六)Ubuntu 20.04 下搭建PX4+MATLAB 仿真环境(HITL)

在文章&#xff08;十五&#xff09;Ubuntu 20.04 下搭建PX4MATLAB 仿真环境我们学习了如何配置仿真环境&#xff0c;在本节&#xff0c;主要进行HITL的仿真环境搭建。 根据&#xff08;十五&#xff09;Ubuntu 20.04 下搭建PX4MATLAB 仿真环境完成配置到如下界面&#xff1a;…

志邦家居CIO吴俊涛谈转型:天润融通如何赋能家居行业未来

根据国家统计局、住建部等各部门综合数据显示&#xff0c;2024年国内泛家居全渠道销售额在预计将超过4.7万亿元&#xff0c;并且在存量房需求释放与智能家居品类创新的推动下&#xff0c;预计2027年将突破5.3万亿元&#xff0c;展现出强劲的增长弹性。 然而&#xff0c;家居行…

【matlab】将程序打包为exe文件(matlab r2023a为例)

文章目录 一、安装运行时环境1.1 安装1.2 简介 二、打包三、打包文件为什么很大 一、安装运行时环境 使用 Application Compiler 来将程序打包为exe&#xff0c;相当于你使用C编译器把C语言编译成可执行程序。 在matlab菜单栏–App下面可以看到Application Compiler。 或者在…

mybatisplus逻辑删除

逻辑删除配置 mybatis-plus:global-config:db-config:logic-delete-field: deletedlogic-not-delete-value:0logic-delete-value:1 查询语句也会自动加上where isdeleted0

FedOV

3 FEDOV: ONE-SHOT FEDERATED OPEN-SET VOTING FRAMEWORK 3.1 PROBLEM STATEMENT 假设有个客户端及其本地数据集。我们的目标是在服务器的帮助下&#xff0c;在不交换原始数据的情况下&#xff0c;训练一个优秀的机器学习模型 。此外&#xff0c;每个客户端只允许与服务器进行…

Linux 删除文件不释放空间问题处理

背景&#xff1a; 服务器磁盘空间已经达到100%&#xff0c;删除存放日志路径下的文件后&#xff0c;发现空间并未释放&#xff01; 原因&#xff1a;在linux系统中&#xff0c;通过rm删除文件将会从文件系统的文件夹结构上解除链接(unlink)然后删除&#xff0c;然而假设文件是被…