Linux驱动学习之内核接口和多节点设备

四盏灯:
原则上我们想要实现流水灯!
需要怎么做?
一个驱动 -> 生成一个设备文件!
一个设备文件怎么控制四个 LED 灯?
你有两种方法:
1 : 你写四个驱动 你就能生成四个 LED 灯!
四个驱动有什么特点没
除了引脚不一样 其他代码几乎都一样!
2 : 你写一个驱动 却生成四个设备文件!

一驱多设

前置

open和relase参数一样,如果说多个设备用一套open,close,我们该怎么确定是哪个灯呢,我们可以想到stm32 hal库串口中断,通过回调函数参数的值,判断是哪个串口 。

同理,对于多设备匹配一个open,我们可以也通过参数 inode-> r_dev 即通过设备号判断是那个设备。

由于inode结构体过于大,就只展示一小部分

驱动源码

cpp 复制代码
#include "linux/device.h"
#include "linux/export.h"
#include "linux/fs.h"
#include "linux/gpio.h"
#include "linux/mod_devicetable.h"
#include "linux/module.h"
#include "linux/of.h"
#include "linux/of_gpio.h"
#include "linux/platform_device.h"
#include "linux/cdev.h"
#include "linux/printk.h"
#include "linux/slab.h"



typedef struct g{
    uint32_t pin;
    char name[32];
    enum of_gpio_flags gpio_flag;
    struct g *next;
}GPIO;
GPIO head;
struct class * cls;
struct cdev * cdev;
static dev_t dev_num;
struct platform_device *node;
static int open (struct inode *inode, struct file *file)
{
    GPIO *p=&head;
    for(uint8_t i=0;i<of_gpio_named_count(node->dev.of_node,"led_pin");i++)
    {
        if(dev_num+i==inode->i_rdev)
        {
            gpio_set_value(p->next->pin,1);
        }
        p=p->next;
    }
    return 0;
}
static int close (struct inode *inode, struct file *file)
{
    GPIO *p=&head;
    for(uint8_t i=0;i<of_gpio_named_count(node->dev.of_node,"led_pin");i++)
    {
        if(dev_num+i==inode->i_rdev)
        {
            gpio_set_value(p->next->pin,0);
        }
        p=p->next;
    }
    return 0;
}
static struct file_operations fops={
    .owner=THIS_MODULE,
    .open=open,
    .release=close,

};
static	int probe(struct platform_device *d)
{
    node=d;
    head.next=NULL;
    printk("%d\r\n",of_gpio_named_count(d->dev.of_node,"led_pin"));
   for(int i=0;i<of_gpio_named_count(d->dev.of_node,"led_pin");i++)
   {
        GPIO *tem=kzalloc(sizeof(GPIO), GFP_KERNEL);
       tem->pin= of_get_named_gpio_flags(d->dev.of_node,"led_pin",i,&tem->gpio_flag);
        if(tem->gpio_flag==OF_GPIO_ACTIVE_LOW)
        {
            gpio_request(tem->pin,"led");
            gpio_direction_output(tem->pin,1);
        }
        else
        {
            gpio_request(tem->pin,"led");
            gpio_direction_output(tem->pin,0);
        }
        tem->next=head.next;
        head.next=tem;
        sprintf(tem->name,"led_%d",i);
   }
   printk("666\r\n");
    alloc_chrdev_region(&dev_num, 0,of_gpio_named_count(d->dev.of_node,"led_pin"), "led");
    cdev= cdev_alloc();
    cdev->ops=&fops;
    cdev_add(cdev,dev_num,of_gpio_named_count(d->dev.of_node,"led_pin"));
    cls= class_create(THIS_MODULE, "led");
    GPIO *p=&head;
    for(int i=0;i<of_gpio_named_count(d->dev.of_node,"led_pin");i++) {
    
        device_create(cls,NULL,dev_num+i,NULL,p->next->name);
        p=p->next;
    }
    return 0;
}
static	int remove(struct platform_device *d)
{
     
    printk(KERN_INFO "Goodbye, world!\n");
    return 0;
}

static struct of_device_id match={
    .compatible="led",
};
static struct platform_driver driver={
    .probe=probe,
    .remove=remove,
    .driver={
        .name="led",
        .of_match_table=&match,
    },
};

static int __init  start(void)
{
    platform_driver_register(&driver);
    printk("hahaha\r\n");
    return 0;
}
static void __exit stop(void)
{
    platform_driver_unregister(&driver);
    printk("gun\r\n");
}
module_init(start);
module_exit(stop);
MODULE_LICENSE("GPL");
相关推荐
一只小风华~14 分钟前
Vue Router 的三种历史模式详解
前端·javascript·vue.js·笔记·学习·前端框架·ecmascript
酌量1 小时前
路径平滑优化详解(二次规划): 数学建模与目标函数推导
经验分享·笔记·学习·机器人·自动驾驶
爱倒腾的老唐3 小时前
01、如何学习单片机
单片机·嵌入式硬件·学习
于小汐在咯9 小时前
词根学习笔记 | Agri系列
笔记·学习
霜绛9 小时前
Unity:Json笔记——Json文件格式、JsonUtlity序列化和反序列化
学习·unity·json·游戏引擎
我命由我1234511 小时前
Excel - Excel 列出一列中所有不重复数据
经验分享·学习·职场和发展·word·powerpoint·excel·职场发展
璞致电子11 小时前
fpga开发板ZYNQ 璞致 PZ7010/7020 邮票孔核心板简介-ZYNQ7000系列小系统学习板
linux·嵌入式硬件·学习·fpga开发·fpga·fpga开发板·xilinx开发板
Miki Makimura12 小时前
Reactor 模式实现:从 epoll 到高并发调试
运维·服务器·c++·学习
jiajixi13 小时前
go-swagger学习笔记
笔记·学习·golang
Mingze031414 小时前
C语言四大排序算法实战
c语言·数据结构·学习·算法·排序算法