Linux2.6设备驱动开发

一:Linux2.6驱动设备开发的特点

1:首先是属于字符型设备注册的方法之一

这种开发接口是在Linux2.6引入的,之前的版本不支持这种开发方式,也是目前最标准的开发方式。

2:Linux2.6的设备开发

不再去限制设备号,与其对应的就是需要去申请可用的设备号。

3:Linux2.6注册完毕设备且成功之后并不会生成设备文件

对于这种情况有两种方法:

通过指令手动生成

通过内核其他接口函数生成

4:Linux2.6与杂项的区别

杂项:

优点:简单

缺点:没有分类。能注册的设备有限

Linux2.6:

有点:主设备号不限制。2^12个主设备号,设备分类;2^20个次设备号

缺点:函数流程相对于杂项复杂

总结:Linux2.6相对于杂项而言复杂,Linux2.6设备号范围比杂项大。

二:Linux2.6 驱动开发架构

1、先去申请设备号->alloc_chrdev_region();

2、初始化Linux2.6核心结构体 cdev->cdev_init();

3、添加注册设备->cdev_add

4、生成一个与之相对应的设备文件:class_create device_create

总结:在使用Linux2.6驱动时的开发步骤,需要先申请设备号,然后进行初始化,然后添加注册的设备,最后生成设备文件。

三:linux2.6驱动开发接口

现在进入到具体的开发流程

1:如何在内核中申请一个可以用的设备号

头文件:

cpp 复制代码
#include "linux/fs.h"

对应的接口函数:

cpp 复制代码
int alloc_chrdev_region(
        dev_t *dev, //uint32_t类型数字,也就是申请的设备号
        unsigned baseminor,//申请的起始次设备号
        unsigned count,//连续申请的设备数量
	    const char *name)//任意填写名字

函数功能:向内核申请目前可以用的设备号,可以申请多个设备号

函数返回值:

成功返回0,失败返回非0

释放设备号接口:

cpp 复制代码
void unregister_chrdev_region(
    dev_t from, //填写的申请的首设备号
    unsigned count//释放几个信号
)

2:linux2.6的设备注册

头文件:

cpp 复制代码
#include "linux/cdev.h"

初始化函数:

cpp 复制代码
void cdev_init(
    struct cdev *cdev, //要初始化的cdev核心结构体
    const struct file_operations *fops//与cdev做绑定,注册的设备都会用此内核接口
)

动态开辟空间的方法:kzalloc();

添加函数:

cpp 复制代码
int cdev_add(
    struct cdev *p, //cdev核心结构体
    dev_t dev, //要注册的设备的首设备号
    unsigned count//要注册的设备的数量
    )

删除函数:

cpp 复制代码
void cdev_del(
    struct cdev *p//核心结构体
)

3:设备文件的生成

手动生成:

cpp 复制代码
mknod /dev/led c 234(主设备号) 0(次设备号)

自动生成:

内核接口:

想要生成设备文件必须先创建类结构体->class

cpp 复制代码
struct class * cls = class_create(THIS_MODULE,"led_class");

销毁一个类:

cpp 复制代码
class_destroy(struct class * cls)
cpp 复制代码
有了类结构体你就可以创建设备文件了
        struct device *device_create(
        struct class *class,
        struct device *parent,
        dev_t devt,
        void *drvdata,
        const char *fmt, ...
) *
class:
    刚才得到的类结构体
*parent:
    设备的父设备->没有父设备->NULL
*devt
    设备的设备号
*drvdata
    创建设备附带的私有数据->NULL
*fmt,...:
    跟 printf 一样的
直接当作字符串传递也是一样的
他就是你创建设备文件的名字!

如何销毁一个设备文件:

cpp 复制代码
void device_destroy(struct class *class, dev_t devt)
class:
    类结构体
devt:
    设备号

4:事例:linux2.6下的LED驱动

cpp 复制代码
#include"linux/fs.h"
#include"linux/module.h"
#include"linux/kernel.h"
#include"linux/cdev.h"
#include"linux/gpio.h"
#include"device.h"

dev_t  mydevnum;//设备号
struct cdev mycdev;//Cdev核心结构体
struct file_operations ops;//内核层的文件操集合结构体
struct class * cls;//类设备文件结构体
//开灯回调函数

int led_on (struct inode *i, struct file *f)
{
	gpio_set_value(21,1);
	gpio_set_value(22,0);
	return 0;
}
//关灯回调函数
int led_off (struct inode *i, struct file *f)
{
	gpio_set_value(21,0);
	gpio_set_value(22,1);
	return 0;
}
//入口函数
static int __init myled_init(void)
{
	//申请设备号
	int ret = alloc_chrdev_region(&mydevnum,0,1,"myled");
	if(ret < 0)
	{
		return -EINVAL;//加载失败
	}
	printk("主设备:%d\t\t次设备:%d\r\n",mydevnum>>20,mydevnum&0xFFFFF);
	//初始化Linux2.6 cdev结构体
	
	ops.owner = THIS_MODULE;
	ops.open = led_on;
	ops.release =led_off;
	cdev_init(&mycdev,&ops);
	//添加cdev设备
	cdev_add(&mycdev,mydevnum,1);
	//生成一个类设备文件
	cls=class_create(THIS_MODULE, "led_class");
	//创建设备文件
	device_create(cls,NULL,mydevnum,NULL,"led");
	//初始化硬件
	gpio_request(21,"led1");
	gpio_request(22,"led2");
	gpio_direction_output(21,0);
	gpio_direction_output(22,0);
	
	return 0;
}
//出口函数
static void __exit myled_exit(void)
{
	//卸载程序只有一个原则 ->倒序
	gpio_free(21);
	gpio_free(22);
	device_destroy(cls,mydevnum);
	class_destroy(cls);
	cdev_del(&mycdev);
	unregister_chrdev_region(mydevnum,1);
}
module_init(myled_init);
module_exit(myled_exit);
MODULE_LICENSE("GPL");
相关推荐
嵌入(师)19 小时前
嵌入式驱动开发详解1(系统调用)
驱动开发
昵称p20 小时前
杂项驱动开发
驱动开发·gpio子系统·杂项驱动开发
7yewh1 天前
嵌入式硬件杂谈(四)-高速板PCB设计 高速信号全面讲解 蛇形线 等长线 差分对 阻抗对
驱动开发·嵌入式硬件·mcu·物联网·硬件工程·pcb工艺·精益工程
lishing62 天前
Linux驱动开发(9):pinctrl子系统和gpio子系统--led实验
linux·运维·驱动开发
lishing62 天前
Linux驱动开发(7):使用设备树实现RGB 灯驱动
linux·驱动开发
TeYiToKu2 天前
笔记整理—linux驱动开发部分(13)块设备
linux·c语言·驱动开发·笔记·嵌入式硬件·arm
网易独家音乐人Mike Zhou2 天前
【Linux驱动开发】irq中断配置API及中断应用 阻塞休眠和非阻塞的驱动操作
linux·c语言·驱动开发·stm32·单片机·mcu·iot
believe、悠闲2 天前
GetVolumeInformation函数使用记录
c++·windows·驱动开发
不怕犯错,就怕不做2 天前
修复kernel编译栈帧大小异常问题error: the frame size of 1928 bytes is larger than 1024 bytes
linux·arm开发·驱动开发
bigbig猩猩2 天前
Gin 框架中的表单处理与数据绑定
驱动开发·gin