• 正文
    • 在mydevice.c源码的基础上进行添加,重命名为mydevice-auto.c
    • mydevice-auto.c完整示例源码
    • 编译
    • 编写测试应用源码device-auto_app.c
    • 测试
  • 相关推荐
申请入驻 产业图谱

飞凌嵌入式ElfBoard ELF 1板卡-

11小时前
160
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

例程代码路径:ELF 1开发板资料包3-例程源码3-2 驱动例程源码2_字符驱动mydevice-auto

上一节写的驱动加载后,需要手动使用mknod命令在/dev下创建设备节点,本节讲解如何让驱动自动在/dev目录下生成设备节点。

想要实现自动创建节点,首先需要创建设备类,然后创建设备节点并关联到设备类。

mydevice.c源码的基础上进行添加,重命名为mydevice-auto.c

(一)添加头文件

#include <linux/device.h>

(二)声明变量

static struct class *my_class;

static struct device *my_device;

(三)在mydevice_init(void)函数中创建类和设备节点

static int __init mydevice_init(void)

{

    int ret;

 

    // 在这里执行驱动程序的初始化操作

 

    // 注册字符设备驱动程序

    ret = alloc_chrdev_region(&dev_num,0,1,DEVICE_NAME);

    if (ret < 0) {

        printk(KERN_ALERT "Failed to allocate device number: %dn", ret);

        return ret;

}

   major=MAJOR(dev_num);   //获取主设备号

   minor=MINOR(dev_num);   //获取次设备号

printk(KERN_INFO "major number: %dn",major);

printk(KERN_INFO "minor number: %dn",minor);

 

my_cdev.owner = THIS_MODULE;

        cdev_init(&my_cdev,&fops);   //初始化字符设备结构体

        cdev_add(&my_cdev,dev_num,1);   //将字符设备添加到内核中

 

       // 创建设备类

    my_class = class_create(THIS_MODULE, "my_class");

    if (IS_ERR(my_class)) {

        pr_err("Failed to create classn");

        return PTR_ERR(my_class);

}

  // 创建设备节点并关联到设备类

    my_device = device_create(my_class, NULL, MKDEV(major, minor), NULL, DEVICE_NAME);

    if (IS_ERR(my_device)) {

        pr_err("Failed to create devicen");

        class_destroy(my_class);

        return PTR_ERR(my_device);

    }

           printk(KERN_INFO "Device registered successfully.n");

    return 0;

}

 

class_create()函数的原型:

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

owner:指向拥有该设备类的内核模块的指针。通常使用THIS_MODULE来指定当前驱动模块作为拥有者;

name:指定设备类的名称。该名称将用于在sysfs文件系统中创建对应的类目录;

class_create()函数返回一个指向新创建的设备类的struct class指针。如果创建失败,它将返回一个指向NULL的指针;

设备类的创建是设备驱动程序中重要的一步,它为设备提供了一个统一的命名空间和属性集合,并将相关设备节点组织在一起。创建设备类后,驱动程序可以使用device_create()函数创建设备节点,并将其关联到该设备类下。

device_create()函数的原型:

struct device *device_create(struct class *class, struct device *parent,

                             dev_t dev, void *drvdata, const char *fmt, ...);

class:指向设备节点所属的设备类的struct class指针;

parent:指向设备节点的父设备的struct device指针,如果没有父设备,则可以设置为NULL;

dev:指定设备节点的设备号,使用MKDEV(major, minor)来创建;

drvdata:指向与设备节点相关的私有数据的指针,可以将驱动程序的特定数据与设备节点关联起来;

fmt:设备节点名称的格式字符串,用于在sysfs文件系统中创建设备节点。可以使用类似"mydevice%d"的格式,并使用可变参数来指定设备节点名称的后缀;

device_create()函数返回一个指向新创建的设备节点的struct device指针。如果创建失败,它将返回一个指向NULL的指针;

设备节点的创建需要先创建一个设备类(使用class_create()函数),然后使用device_create()函数创建设备节点并将其关联到设备类下;

(四)mydevice_exit(void)函数中添加销毁设备节点和设备类

static void __exit mydevice_exit(void)

{

// 在这里执行驱动程序的清理操作

// 销毁设备节点

 device_destroy(my_class, MKDEV(major, minor));

// 销毁设备类

 class_destroy(my_class);

// 删除字符设备

    cdev_del(&my_cdev);

    // 注销字符设备驱动程序

    unregister_chrdev(0, DEVICE_NAME);

 

    printk(KERN_INFO "Device unregistered.n");

}

 

mydevice-auto.c完整示例源码

#include <linux/module.h>       // 包含模块相关函数的头文件

#include <linux/fs.h>           // 包含文件系统相关函数的头文件

#include <linux/uaccess.h>      // 包含用户空间数据访问函数的头文件

#include <linux/cdev.h>         //包含字符设备头文件

#include <linux/device.h>

#define DEVICE_NAME "mydevice"  // 设备名称

static dev_t dev_num;   //分配的设备号

struct  cdev my_cdev;          //字符设备指针

int major;  //主设备号

int minor;  //次设备号

static struct class *my_class;

static struct device *my_device;

 

static int device_open(struct inode *inode, struct file *file)

{

// 在这里处理设备打开的操作

printk(KERN_INFO "This is device_open.n");

    return 0;

}

 

static int device_release(struct inode *inode, struct file *file)

{

// 在这里处理设备关闭的操作

printk(KERN_INFO "This is device_release.n");

 

    return 0;

}

 

static ssize_t device_read(struct file *file, char __user *buffer, size_t length, loff_t *offset)

{

// 在这里处理设备读取的操作

printk(KERN_INFO "This is device_read.n");

    return 0;

}

 

static ssize_t device_write(struct file *file, const char __user *buffer, size_t length, loff_t *offset)

{

// 在这里处理设备写入的操作

printk(KERN_INFO "This is device_write.n");

    return 0;

}

 

static struct file_operations fops = {

    .owner = THIS_MODULE,

    .open = device_open,

    .release = device_release,

    .read = device_read,

    .write = device_write,

};

 

static int __init mydevice_init(void)

{

    int ret;

 

    // 在这里执行驱动程序的初始化操作

 

    // 注册字符设备驱动程序

    ret = alloc_chrdev_region(&dev_num,0,1,DEVICE_NAME);

    if (ret < 0) {

        printk(KERN_ALERT "Failed to allocate device number: %dn", ret);

        return ret;

}

   major=MAJOR(dev_num);   //获取主设备号

   minor=MINOR(dev_num);   //获取次设备号

printk(KERN_INFO "major number: %dn",major);

printk(KERN_INFO "minor number: %dn",minor);

 

my_cdev.owner = THIS_MODULE;

        cdev_init(&my_cdev,&fops);   //初始化字符设备结构体

        cdev_add(&my_cdev,dev_num,1);   //将字符设备添加到内核中

 

       // 创建设备类

    my_class = class_create(THIS_MODULE, "my_class");

    if (IS_ERR(my_class)) {

        pr_err("Failed to create classn");

        return PTR_ERR(my_class);

}

  // 创建设备节点并关联到设备类

    my_device = device_create(my_class, NULL, MKDEV(major, minor), NULL, DEVICE_NAME);

    if (IS_ERR(my_device)) {

        pr_err("Failed to create devicen");

        class_destroy(my_class);

        return PTR_ERR(my_device);

    }

           printk(KERN_INFO "Device registered successfully.n");

    return 0;

}

 

static void __exit mydevice_exit(void)

{

// 在这里执行驱动程序的清理操作

// 销毁设备节点

 device_destroy(my_class, MKDEV(major, minor));

// 销毁设备类

 class_destroy(my_class);

// 删除字符设备

    cdev_del(&my_cdev);

    // 注销字符设备驱动程序

    unregister_chrdev(0, DEVICE_NAME);

 

    printk(KERN_INFO "Device unregistered.n");

}

 

module_init(mydevice_init);

module_exit(mydevice_exit);

 

MODULE_LICENSE("GPL");      // 指定模块的许可证信息

MODULE_AUTHOR("Your Name"); // 指定模块的作者信息

MODULE_DESCRIPTION("A simple character device driver"); // 指定模块的描述信息

编译

Makefile文件如下:

 . /opt/fsl-imx-x11/4.1.15-2.0.0/environment-setup-cortexa7hf-neon-poky-linux-gnueabi

elf@ubuntu:~/work/test/02_字符驱动/mydevice-auto$ make

将生成的mydevice.ko文件拷贝到开发板中。

编写测试应用源码device-auto_app.c

驱动中已经给应用层提供了open、read、write的接口,接下来应用层就可以进行相应的系统调用。

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <sys/ioctl.h>

#include <errno.h>

#include <fcntl.h>

 

#define DEV_NAME "/dev/my_device"

 

int main(int argc, char *argv[])

{

int reg;

int fd = 0;

int dat = 0;

 

 fd = open (DEV_NAME, O_RDWR);

 if (fd < 0) {

 perror("Open "DEV_NAME" Failed!n");

 exit(1);

 }

 

 reg = read(fd, &dat, 1);

 if (reg<0) {

 perror("read "DEV_NAME" Failed!n");

 exit(1);

}

 

 dat = 0;

 reg = write(fd, &dat, 1);

 if (reg<0) {

 perror("write "DEV_NAME" Failed!n");

 exit(1);

 }

 close(fd);

 return 0;

 }

设置环境变量:

 . /opt/fsl-imx-x11/4.1.15-2.0.0/environment-setup-cortexa7hf-neon-poky-linux-gnueabi

编译,将生成的device-auto_app文件拷贝到开发板中:

elf@ubuntu:~/work/test/02_字符驱动/device-auto_app$ $CC device-auto_app.c -o device-auto_app

测试

root@ELF1:~# insmod mydevice-auto.ko

major number: 245

minor number: 0

Device registered successfully.

root@ELF1:~# ls /dev/my_device

/dev/my_device

root@ELF1:~# ./device-auto_app

This is device_open.

This is device_read.

This is device_write.

This is device_release.

root@ELF1:~# rmmod mydevice-auto.ko

Device unregistered.

可以看出在使用insmod加载驱动后,在/dev下就生成了my_device节点,使用device_app测试正常。

点赞
收藏
评论
分享
加入交流群
举报

相关推荐

登录即可解锁
  • 海量技术文章
  • 设计资源下载
  • 产业链客户资源
  • 写文章/发需求
立即登录