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

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

操作步骤:

cpp 复制代码
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文件:

cpp 复制代码
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

代码,设备节点:

cpp 复制代码
#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);
/*卸载函数*/

应用:

cpp 复制代码
/*************************************************************************
> 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!
相关推荐
西岸行者4 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意4 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码4 天前
嵌入式学习路线
学习
毛小茛4 天前
计算机系统概论——校验码
学习
babe小鑫4 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms4 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下4 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。4 天前
2026.2.25监控学习
学习
im_AMBER4 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J4 天前
从“Hello World“ 开始 C++
c语言·c++·学习