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

一、字符设备驱动

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 查看消息

相关推荐
xiaoshuaishuai87 小时前
C# 接入 OpenClaw
windows·visualstudio·c#
嵌入式吴彦祖9 小时前
Luckfox Pico Ultra W WIFI
linux·嵌入式硬件
gihigo199814 小时前
嵌入式幼儿园刷卡系统 (C#实现)
c#
ipod74114 小时前
电子电路的元器件
单片机·嵌入式硬件
qq_4542450314 小时前
通用引用管理框架
数据结构·架构·c#
清风66666614 小时前
基于单片机的脉搏与呼吸监测报警设备设计与实现
单片机·嵌入式硬件·毕业设计·课程设计·期末大作业
aq553560014 小时前
三大编程语言深度对比:C# vs 易语言 vs 汇编
开发语言·汇编·c#
光泽雨14 小时前
c# 文件编译的过程
开发语言·c#
zxy284722530114 小时前
使用正运动的仿真软件C#
c#·仿真·运动控制·正运动·无硬件
foundbug99915 小时前
STM32 内部温度传感器测量程序(标准库函数版)
stm32·单片机·嵌入式硬件·算法