LED模板驱动程序的改造:总线设备驱动模型

简介: LED模板驱动程序的改造:总线设备驱动模型

LED模板驱动程序的改造:总线设备驱动模型

1.原来LED分层分离的思想

aa5560865dfb418f816b6ed6c4a7c9fd.png

2.现在要根据总线设备驱动模型实现的框架

f76024de3bbf4f108f603b1ccc2b80de.png


实现的代码

准备从开始调用led_drv开始一步一步的分析

leddrv.h

#ifndef _LEDDRV_H
#define _LEDDRV_H
#include "led_opr.h"
void led_class_create_device(int minor);
void led_class_destroy_device(int minor);
void register_led_operations(struct led_operations *opr);
#endif /* _LEDDRV_H */

这里声明了3个外部函数,创建设备号,销毁设备号,获得led_operations结构体。

leddrv.c

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include "led_opr.h"
/* 1. 确定主设备号                                                                 */
static int major = 0;
static struct class *led_class;
struct led_operations *p_led_opr;
#define MIN(a, b) (a < b ? a : b)
void led_class_create_device(int minor)
{
  device_create(led_class, NULL, MKDEV(major, minor), NULL, "100ask_led%d", minor); /* /dev/100ask_led0,1,... */
}
void led_class_destroy_device(int minor)
{
  device_destroy(led_class, MKDEV(major, minor));
}
void register_led_operations(struct led_operations *opr)
{
  p_led_opr = opr;
}
EXPORT_SYMBOL(led_class_create_device);
EXPORT_SYMBOL(led_class_destroy_device);
EXPORT_SYMBOL(register_led_operations);
/* 3. 实现对应的open/read/write等函数,填入file_operations结构体              */
static ssize_t led_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{
  printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
  return 0;
}
/* write(fd, &val, 1); */
static ssize_t led_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
  int err;
  char status;
  struct inode *inode = file_inode(file);
  int minor = iminor(inode);
  printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
  err = copy_from_user(&status, buf, 1);
  /* 根据次设备号和status控制LED */
  p_led_opr->ctl(minor, status);
  return 1;
}
static int led_drv_open (struct inode *node, struct file *file)
{
  int minor = iminor(node);
  printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
  /* 根据次设备号初始化LED */
  p_led_opr->init(minor);
  return 0;
}
static int led_drv_close (struct inode *node, struct file *file)
{
  printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
  return 0;
}
/* 2. 定义自己的file_operations结构体                                              */
static struct file_operations led_drv = {
  .owner   = THIS_MODULE,
  .open    = led_drv_open,
  .read    = led_drv_read,
  .write   = led_drv_write,
  .release = led_drv_close,
};
/* 4. 把file_operations结构体告诉内核:注册驱动程序                                */
/* 5. 谁来注册驱动程序啊?得有一个入口函数:安装驱动程序时,就会去调用这个入口函数 */
static int __init led_init(void)
{
  int err;
  printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
  major = register_chrdev(0, "100ask_led", &led_drv);  /* /dev/led */
  led_class = class_create(THIS_MODULE, "100ask_led_class");
  err = PTR_ERR(led_class);
  if (IS_ERR(led_class)) {
    printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    unregister_chrdev(major, "led");
    return -1;
  }
  return 0;
}
/* 6. 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数           */
static void __exit led_exit(void)
{
  printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
  class_destroy(led_class);
  unregister_chrdev(major, "100ask_led");
}
/* 7. 其他完善:提供设备信息,自动创建设备节点                                     */
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");

leddrv.c程序实现了创建设备,销毁设备,获得led_operations结构体这三个函数,并将注册字符结构体file_operations,并实现file_operations结构体open,read,write,close四个函数。这里在open和write里面调用了p_led_opr这个led_operations结构体。这个opr通过register_led_operations这个函数在chip_demo_gpio.c里面进行调用。将chip_demo_gpio里面的led_operations结构体传递个leddrv.c里面。

EXPORT_SYMBOL()将一个函数声明为外部程序也可以调用这个函数。


led_opr.h

#ifndef _LED_OPR_H
#define _LED_OPR_H
struct led_operations {
  int (*init) (int which); /* 初始化LED, which-哪个LED */       
  int (*ctl) (int which, char status); /* 控制LED, which-哪个LED, status:1-亮,0-灭 */
};
struct led_operations *get_board_led_opr(void);
#endif

在这个函数内部实现的是led_operations结构体,和get_board_led_opr函数

chip_demo_gpio.c

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/platform_device.h>
#include "led_opr.h"
#include "leddrv.h"
#include "led_resource.h"
static int g_ledpins[100];
static int g_ledcnt = 0;
static int board_demo_led_init (int which) /* 初始化LED, which-哪个LED */       
{   
    //printk("%s %s line %d, led %d\n", __FILE__, __FUNCTION__, __LINE__, which);
    printk("init gpio: group %d, pin %d\n", GROUP(g_ledpins[which]), PIN(g_ledpins[which]));
    switch(GROUP(g_ledpins[which]))
    {
        case 0:
        {
            printk("init pin of group 0 ...\n");
            break;
        }
        case 1:
        {
            printk("init pin of group 1 ...\n");
            break;
        }
        case 2:
        {
            printk("init pin of group 2 ...\n");
            break;
        }
        case 3:
        {
            printk("init pin of group 3 ...\n");
            break;
        }
    }
    return 0;
}
static int board_demo_led_ctl (int which, char status) /* 控制LED, which-哪个LED, status:1-亮,0-灭 */
{
    //printk("%s %s line %d, led %d, %s\n", __FILE__, __FUNCTION__, __LINE__, which, status ? "on" : "off");
    printk("set led %s: group %d, pin %d\n", status ? "on" : "off", GROUP(g_ledpins[which]), PIN(g_ledpins[which]));
    switch(GROUP(g_ledpins[which]))
    {
        case 0:
        {
            printk("set pin of group 0 ...\n");
            break;
        }
        case 1:
        {
            printk("set pin of group 1 ...\n");
            break;
        }
        case 2:
        {
            printk("set pin of group 2 ...\n");
            break;
        }
        case 3:
        {
            printk("set pin of group 3 ...\n");
            break;
        }
    }
    return 0;
}
static struct led_operations board_demo_led_opr = {
    .init = board_demo_led_init,
    .ctl  = board_demo_led_ctl,
};
struct led_operations *get_board_led_opr(void)
{
    return &board_demo_led_opr;
}
static int chip_demo_gpio_probe(struct platform_device *pdev)
{
    struct resource *res;
    int i = 0;
    while (1)
    {
        res = platform_get_resource(pdev, IORESOURCE_IRQ, i++);
        if (!res)
            break;
        g_ledpins[g_ledcnt] = res->start;
        led_class_create_device(g_ledcnt);
        g_ledcnt++;
    }
    return 0;
}
static int chip_demo_gpio_remove(struct platform_device *pdev)
{
    struct resource *res;
    int i = 0;
    while (1)
    {
        res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
        if (!res)
            break;
        led_class_destroy_device(i);
        i++;
        g_ledcnt--;
    }
    return 0;
}
static struct platform_driver chip_demo_gpio_driver = {
    .probe      = chip_demo_gpio_probe,
    .remove     = chip_demo_gpio_remove,
    .driver     = {
        .name   = "100ask_led",
    },
};
static int __init chip_demo_gpio_drv_init(void)
{
    int err;
    err = platform_driver_register(&chip_demo_gpio_driver); 
    register_led_operations(&board_demo_led_opr);
    return 0;
}
static void __exit lchip_demo_gpio_drv_exit(void)
{
    platform_driver_unregister(&chip_demo_gpio_driver);
}
module_init(chip_demo_gpio_drv_init);
module_exit(lchip_demo_gpio_drv_exit);
MODULE_LICENSE("GPL");

主要实现了总线设备驱动模型的platform_driver_register,驱动函数,并往总线设备上面进行注册。并实现了设备驱动上面的初始化操作。也实现了led_operations结构体并实现了其内部函数的操作(对应引脚应该执行什么操作)。

led_resource.h

#ifndef _LED_RESOURCE_H
#define _LED_RESOURCE_H
/* GPIO3_0 */
/* bit[31:16] = group */
/* bit[15:0]  = which pin */
#define GROUP(x) (x>>16)
#define PIN(x)   (x&0xFFFF)
#define GROUP_PIN(g,p) ((g<<16) | (p))
#endif

实现了GROUP,PIN,GROUP_PIN等宏定义

board_A_led.c

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/platform_device.h>
#include "led_resource.h"
static void led_dev_release(struct device *dev)
{
}
static struct resource resources[] = {
        {
                .start = GROUP_PIN(3,1),
                .flags = IORESOURCE_IRQ,
                .name = "100ask_led_pin",
        },
        {
                .start = GROUP_PIN(5,8),
                .flags = IORESOURCE_IRQ,
                .name = "100ask_led_pin",
        },
};
static struct platform_device board_A_led_dev = {
        .name = "100ask_led",
        .num_resources = ARRAY_SIZE(resources),
        .resource = resources,
        .dev = {
                .release = led_dev_release,
         },
};
static int __init led_dev_init(void)
{
    int err;
    err = platform_device_register(&board_A_led_dev);   
    return 0;
}
static void __exit led_dev_exit(void)
{
    platform_device_unregister(&board_A_led_dev);
}
module_init(led_dev_init);
module_exit(led_dev_exit);
MODULE_LICENSE("GPL");

这里实现了总线设备驱动模型的设备注册。并定义了platform_device 和实现resource的资源定义。

目录
相关文章
|
C++
Qt 父子对象的关系
Qt 父子对象的关系
333 0
|
安全 程序员 编译器
【实战经验】17个C++编程常见错误及其解决方案
想必不少程序员都有类似的经历:辛苦敲完项目代码,内心满是对作品品质的自信,然而当静态扫描工具登场时,却揭示出诸多隐藏的警告问题。为了让自己的编程之路更加顺畅,也为了持续精进技艺,我想借此机会汇总分享那些常被我们无意间忽视却又导致警告的编程小细节,以此作为对未来的自我警示和提升。
1348 94
|
8月前
|
网络协议 安全 应用服务中间件
云服务器怎么开启被关闭的端口?手把手教你开启端口
在使用云服务器时,若发现某些服务无法访问,可能是端口被关闭。本文介绍了端口关闭的原因、检查方法及开启步骤。原因包括初始设置限制、防火墙规则和外部网络策略;可通过netstat或ss命令检查端口状态,用ufw、iptables或firewalld调整防火墙规则。最后提供了解决常见问题的建议,确保端口正常开放并可供外网访问。
1539 9
|
Shell Docker Python
Dockerfile中的CMD和ENTRYPOINT
**Dockerfile 中的 `CMD` 和 `ENTRYPOINT` 用于设定容器启动行为。`CMD` 提供默认命令,可被 `docker run` 覆盖;`ENTRYPOINT` 设置不可变的入口点,其参数与 `CMD` 结合使用。两者皆有两种语法格式:数组和字符串。`ENTRYPOINT` 与 `CMD` 结合允许用户覆盖默认参数,但若需替换 `ENTRYPOINT`,需使用 `--entrypoint`。**
519 0
|
Oracle 关系型数据库 数据库
关系型数据库Oracle执行RMAN脚本
【7月更文挑战第22天】
412 2
|
监控 搜索推荐 数据挖掘
ERP系统中的客户关系管理与客户满意度调查解析
【7月更文挑战第25天】 ERP系统中的客户关系管理与客户满意度调查解析
749 1
|
消息中间件 数据可视化 Java
SpringBoot3集成Kafka
SpringBoot3集成KafkaKafka是一个开源的分布式事件流平台,常被用于高性能数据管道、流分析、数据集成和关键任务应用,基于Zookeeper协调的处理平台,也是一种消息系统,具有更好的吞吐量、内置分区、复制和容错。
1193 0
|
算法 Linux 调度
深度解析:Linux内核的进程调度机制
【4月更文挑战第12天】 在多任务操作系统如Linux中,进程调度机制是系统的核心组成部分之一,它决定了处理器资源如何分配给多个竞争的进程。本文深入探讨了Linux内核中的进程调度策略和相关算法,包括其设计哲学、实现原理及对系统性能的影响。通过分析进程调度器的工作原理,我们能够理解操作系统如何平衡效率、公平性和响应性,进而优化系统表现和用户体验。
|
机器学习/深度学习 人工智能 算法
构建未来:AI驱动的自适应网络安全防御系统
【5月更文挑战第11天】在数字时代的风口浪尖,网络安全问题日益凸显。传统的安全防御手段在应对不断进化的网络威胁时显得力不从心。本文提出了一个基于人工智能技术的自适应网络安全防御系统框架,旨在通过实时分析、学习和预测网络行为,自动调整防御策略以抵御未知攻击。系统采用先进的机器学习算法和大数据分析技术,能够在保持高效性能的同时,最小化误报率。文章详细阐述了系统的设计理念、关键技术组件以及预期效果,为网络安全的未来发展方向提供新思路。
|
移动开发 JavaScript 小程序
uView Icon 图标
uView Icon 图标
332 2