以一个实际例子来学习Linux驱动程序开发之“设备类”的相关知识【利用设备类实现对同一设备类下的多个LED灯实现点亮或关闭】

前言

对于一个设备的驱动程序来说,其实上层用户主要看到的、用到的就是设备文件和设备类,当然用得最多的是设备文件,虽然设备类用得不多,但也是每一个设备注册实例化时必须要用到的东西,本篇博文就以一个简单的例子说明设备类的功能。

设备类的本质

所谓设备类,本质上就是“物以类聚,人以群分”思想的体现,它允许每个设备有一个自己的所属类,说白了就是所属分组,假如某几个设备的所属类是相同的,那么我们就能对这些设备进行一些统一的操作。

下面以一个实际例子看下设备类在Linux嵌入式驱动开发中是如何被定义和使用的。

例子的问题背景和源码

假设我们有 3 个 LED 灯设备(功能相似),它们共享一个驱动程序,每个设备可以独立地开关操作。设备类可以在以下方面帮助实现分组管理:

  • 在Linux的 /sys/class/ 目录中,将这些设备归类到一个统一的类目录下。
  • 通过类属性实现对所有设备的统一操作,比如一键控制所有 LED 的开关。

我们这里就利用设备类的概念来一键控制所有 LED 的开关。

源码如下:

#include <linux/module.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/cdev.h>

#define LED_COUNT 3  // 三个 LED 设备

static struct class *led_class;
static struct cdev led_cdev;
static dev_t dev;
static int led_status[LED_COUNT];  // 每个 LED 的状态(0: 关,1: 开)

// 模拟控制 LED 的硬件操作
static void led_control(int index, int status)
{
   
    printk(KERN_INFO "LED %d is now %s\n", index, status ? "ON" : "OFF");
    led_status[index] = status;
}

// 打开设备的回调函数
static int led_open(struct inode *inode, struct file *file)
{
   
    int minor = iminor(inode);  // 获取设备次设备号
    printk(KERN_INFO "LED device %d opened\n", minor);
    return 0;
}

// 写入设备数据的回调函数
static ssize_t led_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
   
    int minor = iminor(file_inode(file));  // 获取次设备号
    int status;

    // 模拟接收用户的控制命令,'1' 为开,'0' 为关
    if (copy_from_user(&status, buf, sizeof(int)))
        return -EFAULT;

    if (status != 0 && status != 1)
        return -EINVAL;

    // 控制对应的 LED
    led_control(minor, status);
    return sizeof(int);
}

// 文件操作结构体
static const struct file_operations led_fops = {
   
    .owner = THIS_MODULE,
    .open = led_open,
    .write = led_write,
};

// 统一控制所有 LED 的类属性
static ssize_t led_all_control_store(struct class *cls, struct class_attribute *attr, const char *buf, size_t count)
{
   
    int status, i;

    if (kstrtoint(buf, 10, &status) || (status != 0 && status != 1))
        return -EINVAL;

    for (i = 0; i < LED_COUNT; i++)
        led_control(i, status);

    return count;
}

// 定义类属性
CLASS_ATTR_WO(led_all_control);

// 模块初始化函数
static int __init led_init(void)
{
   
    int ret, i;

    // 分配主设备号和次设备号范围
    ret = alloc_chrdev_region(&dev, 0, LED_COUNT, "led");
    if (ret < 0) {
   
        printk(KERN_ERR "Failed to allocate device numbers\n");
        return ret;
    }

    // 初始化 cdev 并注册
    cdev_init(&led_cdev, &led_fops);
    ret = cdev_add(&led_cdev, dev, LED_COUNT);
    if (ret < 0) {
   
        printk(KERN_ERR "Failed to add cdev\n");
        unregister_chrdev_region(dev, LED_COUNT);
        return ret;
    }

    // 创建设备类
    led_class = class_create(THIS_MODULE, "led_class");
    if (IS_ERR(led_class)) {
   
        printk(KERN_ERR "Failed to create class\n");
        cdev_del(&led_cdev);
        unregister_chrdev_region(dev, LED_COUNT);
        return PTR_ERR(led_class);
    }

    // 添加类属性
    ret 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值