您的位置:首页 > 其它

字符设备驱动第四课----自动生成设备

2016-12-05 12:45 239 查看

【概述】

前面的时候我们要在应用程序中使用我们自己写的内核模块要做以下步骤:


1.insmod

2.mknod /dev/demo1 c 250 0

3.在运用程序中调用open(“/dev/demo1”,O_RDWR)打开我们自己创建的设备

现在问题来了,难道每次使用设备都要让用户(写运用程序的人)自己去创建设备吗?这显然不好,所以本节课就要解决“在驱动中自动创建设备”这个问题。


【涉及到的内核接口函数】

1.创建一个类

其实质是个目录,将同一类设备(共用同一个驱动程序的设备)归纳到其目录下,目录下是具体的设备。


/*
* 功能: 创建一个目录
* 输入参数: owner:THIS_MODULE
*          name:目录名
* 返回值: 成功:返回对象指针 失败:错误码
*/
struct class *class_create(owner, name)


2.创建一个设备:

跟手动敲mknod命令效果一样


<driver/base/core.h>
/*
* 功能:创建一个设备
* 输入参数:struct class *:所属对象,上一步创建的对象
*         struct device *parent:父设备
*         dev_t:将要创建的设备
*         void *drvdata:驱动传入的一些数据
*         const char *fmt:路径
* 返回值:成功:返回所创建的设备 失败:返回错误码
*/
struct device *device_create(struct class *class, struct device *parent,dev_t devt, void *drvdata, const char *fmt, ...)


3.销毁一个设备:

跟手动敲rmnod命令效果一样


<drivers/base/core.c>
/*
* 功能: 销毁指定设备
* 输入参数:struct class:所属类的指针
*         dev_t:设备号
* 返回值: none
*/
void device_destroy(struct class *class, dev_t devt)


4.销毁一个类:

<drivers/base/driver.h>
/*
* 功能: 销毁一个类
* 输入参数:struct class *:类指针
* 返回值:none
*/
void class_destroy(struct class *cls);


【工程实例】

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/errno.h>

#include <asm/current.h>
#include <linux/sched.h>

#include <linux/device.h>
static struct class *cls = NULL;

static int major = 0;
static int minor = 0;
const  int count = 6;

#define DEVNAME "demo"

static struct cdev *demop = NULL;

//打开设备
static int demo_open(struct inode *inode, struct file *filp)
{
//get command and pid
printk(KERN_INFO "(%s:pid=%d), %s : %s : %d\n",
current->comm, current->pid, __FILE__, __func__, __LINE__);
//get major and minor from inode
printk(KERN_INFO "(major=%d, minor=%d), %s : %s : %d\n",
imajor(inode), iminor(inode), __FILE__, __func__, __LINE__);

return 0;
}

//关闭设备
static int demo_release(struct inode *inode, struct file *filp)
{
//get command and pid
printk(KERN_INFO "(%s:pid=%d), %s : %s : %d\n",
current->comm, current->pid, __FILE__, __func__, __LINE__);
//get major and minor from inode
printk(KERN_INFO "(major=%d, minor=%d), %s : %s : %d\n",
imajor(inode), iminor(inode), __FILE__, __func__, __LINE__);

return 0;
}

//读设备
//ssize_t read(int fd, void *buf, size_t count)
static ssize_t demo_read(struct file *filp, char __user *buf, size_t size, loff_t *offset)
{
struct inode *inode = filp->f_path.dentry->d_inode;
//get command and pid
printk(KERN_INFO "(%s:pid=%d), %s : %s : %d\n",
current->comm, current->pid, __FILE__, __func__, __LINE__);
//get major and minor from inode
printk(KERN_INFO "(major=%d, minor=%d), %s : %s : %d\n",
imajor(inode), iminor(inode), __FILE__, __func__, __LINE__);

return 0;
}

//写设备
static ssize_t demo_write(struct file *filp, const char __user *buf, size_t size, loff_t *offset)
{
struct inode *inode = filp->f_path.dentry->d_inode;
//get command and pid
printk(KERN_INFO "(%s:pid=%d), %s : %s : %d\n",
current->comm, current->pid, __FILE__, __func__, __LINE__);
//get major and minor from inode
printk(KERN_INFO "(major=%d, minor=%d), %s : %s : %d\n",
imajor(inode), iminor(inode), __FILE__, __func__, __LINE__);

return 0;
}

static struct file_operations fops = {
.owner  = THIS_MODULE,
.open   = demo_open,
.release= demo_release,
.read   = demo_read,
.write  = demo_write,
};

static int __init demo_init(void)
{
dev_t devnum;
int ret, i;

struct device *devp = NULL;

//get command and pid
printk(KERN_INFO "(%s:pid=%d), %s : %s : %d\n",
current->comm, current->pid, __FILE__, __func__, __LINE__);

//1. alloc cdev obj
demop = cdev_alloc();
if(NULL == demop){
return -ENOMEM;
}

//2. init cdev obj
cdev_init(demop, &fops);

ret = alloc_chrdev_region(&devnum, minor, count, DEVNAME);
if(ret){
goto ERR_STEP;
}
major = MAJOR(devnum);

//3. register cdev obj
ret = cdev_add(demop, devnum, count);
if(ret){
goto ERR_STEP1;
}

cls = class_create(THIS_MODULE, DEVNAME);
if(IS_ERR(cls)){
ret = PTR_ERR(cls);
goto ERR_STEP1;
}

for(i = minor; i < (count+minor); i++){
devp = device_create(cls, NULL, MKDEV(major, i), NULL, "%s%d", DEVNAME, i);
if(IS_ERR(devp)){
ret = PTR_ERR(devp);
goto ERR_STEP2;
}
}

//get command and pid
printk(KERN_INFO "(%s:pid=%d), %s : %s : %d - ok.\n",
current->comm, current->pid, __FILE__, __func__, __LINE__);
return 0;

ERR_STEP2:
for(--i; i >= minor; i--){
device_destroy(cls, MKDEV(major, i));
}
class_destroy(cls);

ERR_STEP1:
unregister_chrdev_region(devnum, count);

ERR_STEP:
cdev_del(demop);

//get command and pid
printk(KERN_INFO "(%s:pid=%d), %s : %s : %d - fail.\n",
current->comm, current->pid, __FILE__, __func__, __LINE__);
return ret;
}

static void __exit demo_exit(void)
{
int i;
//get command and pid
printk(KERN_INFO "(%s:pid=%d), %s : %s : %d - leave.\n",
current->comm, current->pid, __FILE__, __func__, __LINE__);

for(i=minor; i < (count+minor); i++){
device_destroy(cls, MKDEV(major, i));
}
class_destroy(cls);

unregister_chrdev_region(MKDEV(major, minor), count);

cdev_del(demop);
}

module_init(demo_init);
module_exit(demo_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Farsight");
MODULE_DESCRIPTION("Demo for kernel module");
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: