Linux内核API cdev_del

函数cdev_del()用于从Linux内核系统中移除cdev结构体变量所描述的字符设备,函数执行之后,输入参数所代表的字符设备将不可用。

cdev_del文件包含

#include <linux/cdev.h>

cdev_del函数定义

在内核源码中的位置:linux-3.19.3/fs/char_dev.c

函数定义格式:

void cdev_del(struct cdev *)

cdev_del输入参数说明

  • 函数cdev_del()的输入参数代表将要从Linux内核系统中删除的字符设备描述符,此结构体的定义及详细信息请读者参考极客笔记中函数cdev_alloc()的返回参数说明部分。

cdev_del返回参数说明

  • 函数cdev_del()的返回值是void类型的变量,即不返回任何值。

cdev_del实例解析

编写测试文件:cdev_add_del.c

头文件引用、全局变量定义及相关函数声明:

/*头文件引用*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/vmalloc.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>

MODULE_LICENSE("GPL");

/*宏定义及全局变量定义*/
#define MEM_MALLOC_SIZE    4096                       //缓冲区大小
#define MEM_MAJOR       245                           //主设备号
#define MEM_MINOR          0                          //次设备号
char *mem_spvm;                                      //缓冲区指针,指向内存区
struct cdev *mem_cdev;                               //设备对象指针
struct class *mem_class;                             //设备类指针

static int  __init  cdev_add_del_init(void);          //模块加载函数声明
static void  __exit  cdev_add_del_exit(void);         //模块卸载函数声明
static int mem_open(struct inode *ind, struct file *filp);     //设备打开函数声明
static int mem_release(struct inode *ind, struct file *filp); //设备关闭函数声明

/*设备读函数声明*/
static ssize_t mem_read(struct file *filp, char __user *buf, size_t size, loff_t *fpos);

/*设备写函数声明*/
static ssize_t mem_write(struct file *filp, const char __user *buf, size_t size,loff_t *fpos);

/*定义设备驱动文件结构体*/
struct file_operations mem_fops =
{
    .open = mem_open,                               //打开设备函数
    .release = mem_release,                         //关闭设备函数
    .read = mem_read,                               //读设备数据函数
    .write = mem_write,                             //向设备写数据函数
};

模块加载函数定义:

int __init cdev_add_del_init (void)
{
    int res;
    printk("into the cdev_add_del_init\n");
    int devno = MKDEV(MEM_MAJOR, MEM_MINOR);        //创建设备号,主设备号与次设备号
    mem_spvm = (char *)vmalloc(MEM_MALLOC_SIZE); //开辟内存缓冲区
    if (mem_spvm == NULL)
        printk("vmalloc failed! \n");
    else
        printk("vmalloc successfully! addr=0x%x\n", (unsigned int)mem_spvm);
    mem_cdev = cdev_alloc();                       //动态分配一个新的字符设备对象
    if (mem_cdev == NULL)
    {
        printk("cdev_alloc failed! \n");
        return 0;
    }
    cdev_init(mem_cdev, &mem_fops);                 //初始化字符设备对象
    mem_cdev->owner = THIS_MODULE;                  //初始化设备持有者
    res = cdev_add(mem_cdev, devno, 1);             //将字符设备加入内核系统
    if (res)
    {
        cdev_del(mem_cdev);                         //添加失败,删除设备驱动
        mem_cdev = NULL;                            //添加失败,释放缓冲区
        printk("cdev add Error\n");
    }
    else
    {
        printk("cdev add OK\n");
    }
    printk("out the cdev_add_del_init\n");
    return 0;
}

模块退出函数定义:

void __exit cdev_add_del_exit (void)
{
    printk("into cdev_add_del_exit\n");
    if (mem_cdev ! = NULL)
        cdev_del(mem_cdev);                         //从内核中将设备删除
    printk("cdev del OK\n");
    if (mem_spvm ! = NULL)
        vfree(mem_spvm);                            //释放缓冲区空间
    printk("vfree ok! \n");
    printk("out cdev_add_del_exit\n");
}

相关函数定义:

/*设备打开函数定义*/
int mem_open(struct inode *ind, struct file *filp)
{
    printk("open vmalloc space\n");
    try_module_get(THIS_MODULE);                  //模块引用计数器自加
    printk("open vmalloc space success\n");
    return 0;
}

/*设备读函数定义*/
ssize_t mem_read(struct file *filp, char *buf, size_t size, loff_t *lofp)
{
    int res = -1;
    char *tmp;
    printk("copy data to the user space\n");
    tmp = mem_spvm;
    if (size > MEM_MALLOC_SIZE)                   //判断读取数据的大小
        size = MEM_MALLOC_SIZE;
    if (tmp ! = NULL)
        res = copy_to_user(buf, tmp, size);       //将内核输入写入用户空间
    if (res == 0)
    {
        printk("copy data success and the data is:%s\n", tmp);    //显示读取的数据
        return size;
    }
    else
    {
        printk("copy data fail to the user space\n");
        return 0;
    }
}

/*设备写函数定义*/
ssize_t mem_write(struct file *filp, const char *buf, size_t size, loff_t *lofp)
{
    int res = -1;
    char *tmp;
    printk("read data from the user space\n");
    tmp = mem_spvm;
    if (size > MEM_MALLOC_SIZE)                    //判断输入数据的大小
        size = MEM_MALLOC_SIZE;
    if (tmp ! = NULL)
        res = copy_from_user(tmp, buf, size);      //将用户输入数据写入内核空间
    if (res == 0)
    {
        printk("read data success and the data is:%s\n", tmp);    //显示写入的数据
        return size;
    }
    else
    {
        printk("read data from user space fail\n");
        return 0;
    }
}

/*设备关闭函数定义*/
int mem_release(struct inode *ind, struct file *filp)
{
    printk("close vmalloc space\n");
    module_put(THIS_MODULE);                       //模块引用计数器自减
    printk("close vmalloc space success\n");
    return 0;
}

模块加载、退出函数调用:

module_init(cdev_add_del_init);                   //模块加载
module_exit(cdev_add_del_exit);                   //模块卸载

用户态测试函数:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <linux/fcntl.h>
int main(int argc, char **argv)
{
    int fd, cnt;
    char buf[256];
    printf("char device testing.\n");
    fd = open("/dev/my_char_dev", O_RDWR);      //打开字符设备
    if (fd == 0)
    {
        printf("the char dev file cannot be opened.\n");
        return 1;
    }
    printf("input the data for kernel: ");
    scanf("%s", buf);                                //输入数据
    cnt = write(fd, buf, 256);                       //将输入数据写入设备
    if (cnt == 0)
        printf("Write Error! \n");
    cnt = read(fd, buf, 256);                        //从设备中读取数据
    if (cnt > 0)
        printf("read data from kernel is: %s\n", buf);
    else
        printf("read data error\n");
    close(fd);                                       //关闭设备
    printf("close the char dev file and test over\n");
    return 0;
}

实例运行结果及分析

首先编译模块,执行命令insmod cdev_add_del.ko插入内核模块,然后输入命令dmesg -c查看模块插入结果,会出现如图A所示的结果。

Linux内核API cdev_del

此时要想测试此设备的可用性需要使用命令mknod为此设备创建设备文件,输入命令创建设备文件:mknod /dev/my_char_dev c 245 0,然后执行命令ls /dev查看当前系统的设备文件,出现如图B所示的结果。

Linux内核API cdev_del

用gcc编译器编译用户驱动测试文件,运行编译之后的可执行文件,出现如图C所示的结果。

Linux内核API cdev_del

用户测试程序执行完之后,输入命令dmesg -c,出现如图D所示的结果。

Linux内核API cdev_del

删除内核模块,执行命令rmmod cdev_add_del.ko,然后输入命令dmesg -c,出现如图E所示的信息。

Linux内核API cdev_del

为了说明此时设备被删除了,重新执行用户测试程序,出现如图F所示的结果。

Linux内核API cdev_del

结果分析:

由图A可以判断字符设备添加成功,函数cdev_add()作用得以说明。图C和图D的显示信息进一步说明了字符设备的添加是成功的。图B的操作是为了创建设备文件,保证用户态驱动测试程序的正常执行。图E的输出信息及图F的结果共同说明了函数cdev_del()能够从Linux内核系统中删除字符设备,当字符设备被删除时,对设备的访问将失败。

赞(0)
未经允许不得转载:极客笔记 » Linux内核API cdev_del
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址