Linux设备驱动---字符设备驱动接口函数

内核提供了三个函数来注册一组字符设备编号,这三个函数分别是 register_chrdev_region()alloc_chrdev_region()register_chrdev()

 

一、register_chrdev和unregister_chrdev

在Linux2.6内核以前注册字符设备的函数接口是register_chrdev,注销字符设备接口函数是unregister_chrdev.

register_chrdev()---老版本字符设备注册函数

static inline int register_chrdev(unsigned int major, const char *name, const struct file_opertations * fops)

参数

说明

Major

表示设备编号。major=0,则表示采用系统动态分配的主设备号;不为0,则表示静态注册

Name

表示设备名字

Fops

在内核内部与驱动设备挂钩

返回值:

major值为0,正常注册后,返回分配的主设备号。如果分配失败,返回 EBUSY 的负值(-EBUSY)。major值若大于linux/major.h(2.4内核)中声明的最大值(#define MAX_CHRDEV255),则返回EINVAL 的负值(-EINVAL)。

指定major值后,若该设备号已被占用,返回EBUSY的负值(-EBUSY)。若正常注册,则返回0值。

 

unregister_chrdev() --- 老版本字符设备注销函数

功能:注销设备

原型:

#include <linux.fs.h>

int unregister_chrdev (unsigned int major, const char *name)

说明:

注销设备驱动程序的内核函数

major主设备号

name设备文件

返回值:

major值若大于linux/major.h(2.4内核)中声明的最大值 (#define MAX_CHRDEV255),返回 EINVAL的负值(-EINVAL)。指定了major的值后,若将要注销的major值并不是注册的设备驱动程序,返回EINVAL的负值(-EINVAL)。正常注销则返回0值。

 

二、register_chrdev_region(静态注册)

新接口注册字符设备驱动需要两步:

step1:注册/分配主次设备号

step2:注册字符驱动设备

<linux/fs.h>

int register_chrdev_region(dev_t first, unsigned int count, char *name);

参数说明:

参数

说明

first

要分配的设备编号范围的初始值,这组连续设备号的起始设备号,相当于register_chrdefv()中主设备号

count

连续编号范围,是这组设备号的大小(也就是次设备号个数)

name

编号相关的设备名称,(proc/devices);本组设备的驱动名称

 

三、alloc_chrdev_region(动态注册)

<linux/fs.h>

int alloc_chrdev_region(dev_t *dev,unisgned baseminor,unsigned count,const char*name)

参数说明:

参数

说明

dev

系统分配所得的设备号。可以用MAJOR和MINOR将主次设备号打印查看

baseminor

次设备号的基准,从第几个设备号开始分配

count

次设备号的个数

name

驱动的名字

返回值:分配成功,返回设备号的第一个参数;分配错误,返回小于零的参数

 

cdev结构体

cdev是一个结构体,里面的成员来共同帮助我们注册驱动到内核中,表达字符设备的,将这个struct cdev结构体进行填充,主要填充的内容就是

struct cdev {

struct kobject kobj;

struct module *owner;//填充时,值要为 THIS_MODULE,表示模块

const struct file_operations *ops;//这个file_operations结构体,注册驱动的关键,要填充成这个结构体变量

struct list_head list;

dev_t dev;//设备号,主设备号+次设备号

unsigned int count;//次设备号个数

};

cdev结构体中ops变量让file_operations结构体变量成为cdev的成员,这个结构体会被cdev_add函数向内核注册cdev结构体。

cdev结构体,可以用很多函数来操作他。

如:

cdev_alloc:让内核为这个结构体分配内存的

cdev_init:将struct cdev类型的结构体变量和file_operations结构体进行绑定的

cdev_add:向内核里面添加一个驱动,注册驱动

cdev_del:从内核中注销掉一个驱动。注销驱动

 

设备号

(1)dev_t类型(包括了主设备号和次设备号  不同的内核中定义不一样有的是16位次设备号和16位主设备号构成  有的是20为次设备号12位主设备号 )

(2)MKDEV、MAJOR、MINOR三个宏

MKDEV:  是用来将主设备号和次设备号,转换成一个主次设备号的。(设备号)

MAJOR:   从设备号里面提取出来主设备号的。

MINOR宏:从设备号中提取出来次设备号的。

 

关于设备文件的创建

刚开始写Linux设备驱动程序的时候,很多时候都是利用mknod命令手动创建设备节点,实际上Linux内核为我们提供了一组函数,可以用来在模块加载的时候自动在/dev目录下创建相应设备节点,并在卸载模块时删除该节点,当然前提条件是用户空间移植了udev。

内核中定义了struct class结构体,顾名思义,一个struct class结构体类型变量对应一个类, 内核同时提供了class_create(…)函数,可以用它来创建一个类,这个类存放于sysfs下面,一旦创建好了这个类,再调用 device_create(…)函数来在/dev目录下创建相应的设备节点。这样,加载模块的时候,用户空间中的udev会自动响应 device_create(…)函数,去/sysfs下寻找对应的类从而创建设备节点。

注意,在2.6较早的内核版本中,device_create(…)函数名称不同,是class_device_create(…),所以在新的内核中编译以前的模块程序有时会报错,就是因为函数名称不同,而且里面的参数设置也有一些变化。

       struct class和device_create(…) 以及device_create(…)都定义在/include/linux/device.h中,使用的时候一定要包含这个头文件,否则编译器会报错。

class_create()

struct class *class_create(struct module *owner, const char *name);

owner    指向拥有这个struct类的模块的指针

name     指向该类名称的字符串指针

 

device_create()

  struct device *device_create(struct class *class, struct device *parent, dev_t devt, const char *fmt, ...)

第一个参数指定所要创建的设备所从属的类

第二个参数是这个设备的父设备,如果没有就指定为NULL

第三个参数是设备号

第四个参数是设备名称

第五个参数是从设备号

 

猜你喜欢

转载自blog.csdn.net/weixin_42445727/article/details/89086008
今日推荐