设备树下Led驱动实验-Led字符设备驱动代码框架的实现

一.  简介

上一篇文章学习了向设备树文件添加 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 目录及其下文件的原因在于,在3_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;
};

struct dtsled_dev dtsled;
/*打开设备函数 */
static int dtsled_open(struct inode * node, struct file * file)
{
//    file->private_data = &dtsled;
    return 0;
}

/*写数据函数*/
static ssize_t dtsled_write(struct file * file, const char __user * buf, size_t count, loff_t * opt)
{
//    struct dtsled_dev * led = (struct dtsled_dev*)(file->private_data);
    return 0;
}

/*关闭设备函数 */
static int dtsled_release(struct inode * node, struct file * file)
{
//    struct dtsled_dev* led = (struct dtsled_dev*)(file->private_data);
    return 0;
}

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

/*驱动入口函数 */
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);
        printk("dtsled.major: %d\n", dtsled.major);
        printk("dtsled.minor: %d\n", dtsled.minor);
    }
    if(ret < 0)
    {
        printk("apply_dev_numbers failed!\n");
        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)
    {
        printk("cdev-add failed!\n");
        goto cdev_add_failed;
    }

    /*3. 自动创建设备节点 */
    //创建类
    dtsled.class = class_create(THIS_MODULE, DEV_NAME);
    if (IS_ERR(dtsled.class)) {
        printk("class_create failed!\n");
		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)) {
        printk("device_create failed!\n");
		ret = PTR_ERR(dtsled.dev);
		goto auto_create_dev_failed;
	}

    return 0;

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");

三.  驱动代码编译

编译驱动代码,进入工程目录下,输入 "make" 命令进行编译:

wangtian@wangtian-virtual-machine:~/zhengdian_Linux/Linux_Drivers/5_dtsled.c$ make
make -C /home/wangtian/zhengdian_Linux/linux/kernel/linux-imx-rel_imx_4.1.15_2.1.0_ga M=/home/wangtian/zhengdian_Linux/Linux_Drivers/5_dtsled.c modules
make[1]: 进入目录“/home/wangtian/zhengdian_Linux/linux/kernel/linux-imx-rel_imx_4.1.15_2.1.0_ga”
  Building modules, stage 2.
  MODPOST 1 modules
make[1]: 离开目录“/home/wangtian/zhengdian_Linux/linux/kernel/linux-imx-rel_imx_4.1.15_2.1.0_ga”
wangtian@wangtian-virtual-machine:~/zhengdian_Linux/Linux_Drivers/5_dtsled.c$

可以看出,驱动代码已经编译通过。

下一篇进行驱动加载测试,确定目前实现的驱动框架可以正常运行。

  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值