设备树下Led驱动实验-Led驱动代码框架搭建

发布时间:2024年01月17日

一.? 简介

上一篇文章学习了向设备树文件添加 Led设备节点信息。经过测试,开发板上电后系统上可以看到Led灯的设备节点。文章地址如下:

设备树下Led驱动实验-向设备树文件添加Led设备节点-CSDN博客

本文继续进行Led 驱动开发实验,具体学习 LED驱动代码框架的搭建。

?二.? 设备树下Led驱动代码框架搭建

1.? 创建 vscode工程

这里我所存放的驱动实验代码在? ubuntu系统下的如下目录:

/home/wangtian/zhengdian_Linux/Linux_Drivers

打开 ubuntu系统,进入如上目录,创建 工程目录 5_dtsled:

mkdir 5_dtsled

进入 5_dtsled目录下,将前面实验 3_newchrled工程中 .vscode目录及其下文件拷贝到该工程下:

wangtian@wangtian-virtual-machine:~/zhengdian_Linux/Linux_Drivers$ cd 5_dtsled.c/
angtian@wangtian-virtual-machine:~/zhengdian_Linux/Linux_Drivers/5_dtsled.c$ sudo cp ../3_newchrled/.vscode/ ./ -rf

注意: 拷贝.vscode.目录及其下文件的原因在于,在newchrled工程中的 .vscode目录下文件,设置了 驱动程序可能会调用到的 Linux内核源码的路径(NXP官方)。

拷贝 Makefile文件

将前面实验 3_newchrled工程中Makefile拷贝到该工程下,操作如下:

wangtian@wangtian-virtual-machine:~/zhengdian_Linux/Linux_Drivers/5_dtsled.c$ sudo cp ../3_newchrled/Makefile ./ -f

更改 Makefile文件的目标文件名,更改为如下:

obj-m := dtsled.o

创建 dtsled.c文件:

wangtian@wangtian-virtual-machine:~/zhengdian_Linux/Linux_Drivers/5_dtsled.c$ touch dtsled.c

2.? Led驱动框架代码搭建

将 3_newchrled工程中 newchrled.c文件中头文件拷贝到 dtsled.c中:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/cdev.h>
#include <linux/device.h>

接下来再重新编写一次,Led驱动框架代码(代码实现其实与 3_newchrled工程的驱动框架是一样的)。这里重新写一次以熟悉框架流程。

dtsled.c 文件中的驱动框架代码实现如下:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/cdev.h>
#include <linux/device.h>

#define DEV_NAME   "alpha_led" 
#define DEV_CNT    1 

//Led设备结构体
struct dtsled_dev {
    dev_t devid; //设备号(主+次设备号)
    int major;   //主设备号
    int minor;   //次设备号
    struct cdev cdev;
    struct class* class;
    struct device * dev;
};

const struct file_operations dtsled_fops = {
    .owner = THIS_MODULE,   
    // .open = dtsled.open,
    // .write = dtsled_write,
    // .release = dtsled_release,
};

struct dtsled_dev dtsled;

/*驱动入口函数 */
static int __init dtsled_init(void)
{
    int ret = 0;
    dtsled.major = 0;


    /*1. 申请设备号 */
    if(dtsled.major) //给定设备号
    {
        dtsled.devid = MKDEV(dtsled.major, 0);
        ret = register_chrdev_region(dtsled.devid, DEV_CNT, DEV_NAME);
    }
    else //向内核申请设备号
    {
        ret = alloc_chrdev_region(&dtsled.devid, 0, DEV_CNT, DEV_NAME);
        dtsled.major = MAJOR(dtsled.devid);
        dtsled.minor = MINOR(dtsled.devid);
    }
    if(ret < 0)
    {
        goto apply_devid_failed;        
    }

    /*2. 添加字符设备 */
    dtsled.cdev.owner = THIS_MODULE;
    cdev_init(&dtsled.cdev, &dtsled_fops);
    ret = cdev_add(&dtsled.cdev, dtsled.devid, DEV_CNT);
    if(ret < 0)
    {
        goto cdev_add_failed;
    }

    return 0;

    /*3. 自动创建设备节点 */
    //创建类
    dtsled.class = class_create(THIS_MODULE, DEV_NAME);
    if (IS_ERR(dtsled.class)) {
		ret = PTR_ERR(dtsled.class);
		goto auto_class_create_failed;
	}
    //创建设备 
    dtsled.dev = device_create(dtsled.class, NULL, dtsled.devid, NULL, DEV_NAME);
    if (IS_ERR(dtsled.dev)) {
		ret = PTR_ERR(dtsled.dev);
		goto auto_create_dev_failed;
	}


auto_create_dev_failed:
    class_destroy(dtsled.class);
auto_class_create_failed:
    cdev_del(&dtsled.cdev);
cdev_add_failed:
    unregister_chrdev_region(dtsled.devid, DEV_CNT);
apply_devid_failed:
    return ret;
}

/*驱动出口函数 */
static void __exit dtsled_exit(void)
{
    /*1.删除字符设备 */
    cdev_del(&dtsled.cdev);
    /*2.注销设备号 */
    unregister_chrdev_region(dtsled.devid, DEV_CNT);
    /*3. 摧毁设备 */
    device_destroy(dtsled.class, dtsled.devid);
    /*4. 摧毁类*/
    class_destroy(dtsled.class);
}

/*模块入口与出口*/
module_init(dtsled_init);
module_exit(dtsled_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("LingXiaoZhan");

文章来源:https://blog.csdn.net/wojiaxiaohuang2014/article/details/135625059
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。