字符设备驱动开发-注册-设备文件创建

发布时间:2023年12月22日

一、字符设备驱动

linux系统中一切皆文件

1、应用层:??APP1??APP2??...

fd?=?open("led驱动的文件",O_RDWR);

read(fd);

write();

close();

2、内核层:??

对灯写一个驱动

?led_driver.c

?driver_open();

?driver_read();

?driver_write();??

?driver_close();

struct?file_operations

?{

int?(*open)?(struct?inode?*,?struct?file?*);???

ssize_t?(*read)?(struct?file?*,?char?__user?*,?size_t,?loff_t?*);

ssize_t?(*write)?(struct?file?*,?const?char?__user?*,?size_t,?loff_t?*);???????

int?(*release)?(struct?inode?*,?struct?file?*);//(close)

}

cdev:

设备号1???????????设备号2?????????????设备号n

设备驱动1?????设备驱动2????....??? 设备驱动n

设备号:32位,无符号数字

高12位???:主设备号?:区分哪一类设备

低20位???:次设备号?:区分同类中哪一个设备

3、硬件层:??LED???uart??ADC??PWM

每个驱动里面都有对应的file_operations

1)open的过程:

open打开文件,这个文件与底层的驱动的设备号有关系,

通过设备号访问设备驱动中的struct?file_operations里面的open函数。

2)read的过程:

open函数会有一个返回值,文件描述符fd,read函数通过fd

找到驱动中的struct?file_operations里面的read函数。

Led驱动:字符设备???步骤:
  1. 注册字符设备驱动?-?得到一个字符设备驱动的框架,并且得到设备号
  2. 确定操作的硬件设备?-?led灯(初始化灯)
  3. 初始化灯(先建立灯实际物理地址和虚拟地址之间的映射)-?
  4. 基于操作系统开发,操作虚拟内存,
  5. 用户空间数据拷贝到内核空间数据的交互(用户使用的时候,驱动才会被真正运行,涉及数据交互)
  6. 在应用层创建一个设备文件(设备节点)
?file_operations?操作方法结构体

struct?file_operations

?{

int?(*open)?(struct?inode?*,?struct?file?*);???

ssize_t?(*read)?(struct?file?*,?char?__user?*,?size_t,?loff_t?*);

ssize_t?(*write)?(struct?file?*,?const?char?__user?*,?size_t,?loff_t?*);???????

int?(*release)?(struct?inode?*,?struct?file?*);//(close)

}

二、字符设备驱动的注册

1、注册一个字符设备驱动register_chrdev

int register_chrdev(unsigned?int?major, const char *name, const struct?file_operations?*fops)
功能:注册一个字符设备驱动
参数:
	@major:主设备号??
			??:如果你填写的值大于0,它认为这个就是主设备号
			??:如果你填写的值为0,操作系统给你分配一个主设备号
	@name :名字	cat?/proc/devices?
    @fops :操作方法结构体
返回值:major>0 ,成功返回0,失败返回错误码(负数)?vi?-t?EIO
		major=0,成功主设备号,失败返回错误码(负数)		??

当注册一个字符设备驱动的时候。

如果成功的话,当你使用cat?/proc/devices?命令查看的时候可以看到系统自动分配的主设备号和这个名字

2、注销一个字符设备驱动

void unregister_chrdev(unsigned?int?major, const char *name)
	功能:注销一个字符设备驱动
	参数:
		@major:主设备号
		@name:名字
	返回值:无

三、手动创建设备文件?mknod

sudo?mknod?led?(路径是任意)?c/b??主设备号???次设备号

sudo?rf?led?删除的时候记得加-rf

1、设备驱动程序

#include?<linux/module.h>
#include?<linux/init.h>
#include?<linux/printk.h>
#include?<linux/fs.h>

#define?NAME?"chrdev_devled"

int?major?= 0; //保存主设备号
//?open?read?write?release?初始化
int myopen(struct inode *node, struct file *file_t)
{
    printk("%s?%s?%d\n", __FILE__, __func__, __LINE__);
    return 0;
}
ssize_t myread(struct file *file_t, char?__user?*ubuf, size_t?n, loff_t *off_t)
{
    printk("%s?%s?%d\n", __FILE__, __func__, __LINE__);
    return 0;
}
ssize_t mywrite(struct file *file_t, const char?__user?*ubuf, size_t?n, loff_t *off_t)
{
    printk("%s?%s?%d\n", __FILE__, __func__, __LINE__);
    return 0;
}
int myclose(struct inode *node, struct file *file_t)
{
    printk("%s?%s?%d\n", __FILE__, __func__, __LINE__);
    return 0;
}
struct file_operations?fops?= {
    .open?=?myopen,
    .read?=?myread,
    .write?=?mywrite,
    .release?=?myclose,
};
//入口函数
static int?__init?chrdev_init(void)
{
    printk("%s?%s?%d\n", __FILE__, __func__, __LINE__);
    //注册字符设备驱动:?主设备号?驱动名?结构体
????major=register_chrdev(major,?NAME, &fops);
    //容错判断
    if(major?< 0)
    {
        printk("chrdev_register?err.\n");
        return -EINVAL;
    }
    return 0;
}
//出口函数
static void?__exit?chrdev_exit(void)
{
    printk(KERN_ERR?"%s?%s?%d\n", __FILE__, __func__, __LINE__);
    //注销字符设备驱动
    unregister_chrdev(major,?NAME);
}
module_init(chrdev_init);//入口
module_exit(chrdev_exit);//出口
MODULE_LICENSE("GPL");//协议

2、应用层读取程序

#include?<sys/types.h>
#include?<sys/stat.h>
#include?<fcntl.h>
#include?<unistd.h>
#include?<sys/ioctl.h>
 
#include?<stdio.h>
 
 
int?main(int?argc,char?*argv[])
{
????int?fd?= -1;
????char?buf[32] = "";
    if(argc?< 2)
    {
????????printf("请输入要打开的文件\n");
        return 1;
    }
 
????fd?=?open(argv[1],O_RDWR);
    if(fd?< 0)
    {
????????printf("open?%s?failed\n",argv[1]);
        return 2;
    }
????read(fd,buf,sizeof(buf));
????write(fd,buf,sizeof(buf));
????read(fd,buf,sizeof(buf));
????write(fd,buf,sizeof(buf));
????printf("buf=%s\n",buf);
????close(fd);
????fd?= -1;
    return 0;
}

3、操作步骤:

--make?驱动文件

--insmod?安装驱动

--cat?/proc/devicse?查看设备号

--sudo?mknod?led?c?244?0?创建设备文件(设备节点)

--dmesg?查看消息

--sudo?dmesg?-C删除消息?

--sudo?gcc?app.c?编译应用层读取文件

--./app?.led读取

--led--dmesg?查看消息

文章来源:https://blog.csdn.net/m0_74937538/article/details/135144873
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。