首页 > 其他分享 >四,多节点和内核接口开发

四,多节点和内核接口开发

时间:2024-10-15 21:48:11浏览次数:3  
标签:tmp struct 接口 内核 xydled gpio include buf 节点

一,多节点思想

1.什么是多节点

一个设备对应一个节点文件(设备文件)

2.多节点实现的方法

linux2.6的连续注册

class类的生成多个设备文件

3.一个LED灯的多节点的代码

#include "linux/kernel.h"
#include "linux/module.h"//基本必须头文件
#include "linux/fs.h"//申请设备号,内和操作结构体
#include "linux/cdev.h"//linux2.6开发头文件
#include "linux/of.h"//设备树接口相关头文件
#include "linux/of_gpio.h" //设备树 GPIO相关接口
#include "linux/gpio.h"//GPIO子系统头文件
#include "linux/platform_device.h"//平台设备总线头文件
dev_t *devnum;//首设备号
struct cdev *cdev;//linux2.6结构体
struct file_operations *ops;//内核文件操作集合
struct class *cls;//类结构体

//自定义LED灯信息结构体
struct xydled_info {
    int gpio_num;//gpio的编号
    enum of_gpio_flags active_flags;//GPIO有效电平
    char led_name[32];//存储led灯设备名
    struct xydled_info * next; //下一项
};
struct xydled_info * head; //头节点

int count=0;//LED灯数量

struct of_device_id xydled_table={
    .compatible = "xyd_led1",
};


struct platform_driver * platdrv;
/*
    你不管哪个LED灯被打开都会调用 这个open!

*/
int xydled_open(struct inode * inode, struct file * f)
{
    struct xydled_info *tmp =head;

    for(int i=0;i<count;i++) 
    {
        if(inode->i_rdev==*devnum+i)//LEDi看谁设备号相同
        {
            //操作第i灯
            gpio_set_value(tmp->gpio_num,!tmp->active_flags);

        }
            tmp=tmp->next;
    }
    return 0;
}

int xydled_close(struct inode * inode, struct file * f)
{
    struct xydled_info  *tmp  = head;
    for(int i=0;i<count;i++)
    {    
        if(inode->i_rdev==*devnum+i)//LEDi//看谁设备号相同
        {
            //操作第 i 灯
            gpio_set_value(tmp->gpio_num,tmp->active_flags);
        }
        tmp= tmp->next;
    }

    return 0;
}

//新入口
int xydled_probe(struct platform_device * devp)
{
    //1.获取所有GPIO信息
    struct xydled_info * tmp;
    while(1)
    {
        tmp = kzalloc(sizeof(struct xydled_info), GFP_KERNEL);//开辟一个结构体空间
        tmp->next = NULL;//链表下一项指向空
        //获取GPIO的有效电平和GPIO编号 存入到结构体信息里面
        tmp->gpio_num = of_get_named_gpio_flags(devp->dev.of_node,"led_gpio",count,&tmp->active_flags);
        if(tmp->gpio_num  < 0)//没有信息获取
        {
            kfree(tmp);//释放空间
            break;
        }
        sprintf(tmp->led_name,"xydled%d",count+1);
        if(count == 0)//这是我的第一个节点
        {
            head=tmp;//头节点即是第一个存信息节点
        }else //不是头节点
        {
            struct xydled_info  * tempp = head; 
            while(tempp->next!=NULL)
                tempp=tempp->next;//遍历尾节点
            tempp->next=tmp;//新节点接到尾节点
        }
        count ++;


    }


  

  //2: 注册GPIO引脚
    tmp = head;
    for(int i=0;i<count;i++)
    {
        gpio_request(tmp->gpio_num, tmp->led_name);//申请引脚
        gpio_direction_output(tmp->gpio_num,tmp->active_flags);//设置输出且设置初始电平无效状态
        tmp = tmp->next;
    }
    //3:多节点
    //3.1 申请设备号
    devnum = kzalloc(sizeof(dev_t), GFP_KERNEL);
    alloc_chrdev_region(devnum,0,count,"xydled");
    //3.2: linux2.6的结构体的初始化
    cdev = kzalloc(sizeof(struct cdev), GFP_KERNEL);
    ops  = kzalloc(sizeof(struct file_operations),GFP_KERNEL);
    ops->owner = THIS_MODULE;
    ops->open = xydled_open;
    ops->release = xydled_close;
    cdev_init(cdev,ops);
    //3.3:添加内核
    cdev_add(cdev,*devnum,count);//连续添加设备
    //3.4:生成一个类设备文件
    cls = class_create(THIS_MODULE,"xydled");
    //3.5: 创建设备节点
    tmp = head;
    for(int i=0;i<count;i++)
    {
        device_create(cls,NULL,*devnum + i,NULL,tmp->led_name);
        tmp = tmp->next;
    }
    return 0;
}

//新出口
int xydled_remove(struct platform_device *devp)
{
    return 0;
}
//加载函数
static int __init xydled_init(void)
{
    platdrv = kzalloc(sizeof(struct platform_driver), GFP_KERNEL);//空间开辟
    platdrv->probe = xydled_probe;//新入口
    platdrv->remove = xydled_remove;//新出口
    platdrv->driver.of_match_table = &xydled_table;
    platdrv->driver.name = "xydled_driver";//驱动名
    return platform_driver_register(platdrv);//注册驱动层信息 主要是想匹配设备树信息
}

//卸载函数
static void __exit xydled_exit(void)
{


}
module_init(xydled_init);//加载函数的声明
module_exit(xydled_exit);//卸载函数的声明
MODULE_LICENSE("GPL");//开源协议的声明


 

二,内核接口的write和read

1.内核层和用户层之间的数据交换

如果要获取传感器的数据,我们需要设置传感器的工作模式,需要我们用户层和内核层做数据交换。从而学完read和write能够驱动内容更多。

2.内核read和write详解

函数原型:

ssize_t (*read) ( struct file * file, char __user * buf, size_t size, loff_t * offt );

ssize_t (*write) ( struct file * file, const char __user * buf, size_t size, loff_t * offt );

函数参数:

file: 内核所有的传参都是内核传递 调用这个函数的时候 就会传递内核的所带的信息 其中 file 就是内核的传参之一。

buf: 缓冲区。

如果是 read 的 buf,上层调用的 read(fd,buf,len) 就是上层传递的 buf,上层调用 read 本意是什么->读取内容!

读到传递 buf->内核层的 buf 所以说,内核层 read 的 buf 我们应该往里填充数据 内核层的 read 实际上在写 buf 数据->传递 上层了! 也就是上层的 read 数据来源于内核层的 read 的 buf! copy_to_user()->写入到内核层 buf->传递上层

如果你是 write 的 buf,上层调用 write(fd,buf,len) 上层本意->写入数据,数据在 buf。

最终 buf->内核层 实际上内核层的 write 在 读取上层传递过来的 buf(数据)

copy_from_user();->拷贝上层传递 buf 数据

size:

上层传递的数据的大小 read 代表上层期望读取数据长度

write 代表上层传递的数据的长度

offt:

一般开发字符设备无用,偏移量

3.按键的驱动

#include "linux/kernel.h"
#include "linux/module.h"//基本必须头文件
#include "linux/fs.h"//申请设备号,内和操作结构体
#include "linux/cdev.h"//linux2.6开发头文件
#include "linux/of.h"//设备树接口相关头文件
#include "linux/of_gpio.h" //设备树 GPIO相关接口
#include "linux/gpio.h"//GPIO子系统头文件
#include "linux/platform_device.h"//平台设备总线头文件
#include "linux/miscdevice.h"
#include "asm/uaccess.h"
#include "linux/uaccess.h"
enum of_gpio_flags key1_active; 
int key1_gpionum; 
struct miscdevice mymisc; 
struct file_operations ops;


int mykey_open(struct inode * inode, struct file * f)
{
    
    
    return 0;
}

int mykey_close(struct inode * inode, struct file * f)
{
    

    return 0;
}

ssize_t mykey_read(struct file * file, char __user * buf, size_t 
size, loff_t *ppos) 
{
    uint8_t value=0;
    //4.读取GPIO的值
    value=gpio_get_value(key1_gpionum);
    //把value的值拷贝给上层
    int ret=copy_to_user(buf,&value,1);
    ret=ret;
    return 0;

}
//新入口
int mykey_probe(struct platform_device * devp)
{
    //1.有设备树-》获取GPIO的信息

    key1_gpionum = of_get_named_gpio_flags(devp->dev.of_node,"xyd_gpios",0,&key1_active); 
    //2.申请GPIO
    gpio_request(key1_gpionum,"xydkey1");
    //3.引脚设置为 输入模式
    gpio_direction_input(key1_gpionum);

    ops.owner=THIS_MODULE;
    ops.open=mykey_open;
    ops.release=mykey_close;
    ops.read=mykey_read;


    mymisc.minor=255;
    mymisc.name="xydkey1";
    mymisc.fops=&ops;

    return misc_register(&mymisc);
}

//新出口
int mykey_remove(struct platform_device *devp)
{
    return 0;
}
struct platform_driver drv; 
struct of_device_id mykey_tale={ 
 .compatible = "xydkey", 
}; 


 

//加载函数
static int __init mykey_init(void)
{
    drv.probe=mykey_probe;
    drv.remove=mykey_remove;
    drv.driver.name="mykey_driver";
    drv.driver.of_match_table=&mykey_tale;

    return platform_driver_register(&drv);
}

//卸载函数
static void __exit mykey_exit(void)
{


}
module_init(mykey_init);//加载函数的声明
module_exit(mykey_exit);//卸载函数的声明
MODULE_LICENSE("GPL");//开源协议的声明


标签:tmp,struct,接口,内核,xydled,gpio,include,buf,节点
From: https://blog.csdn.net/hcc_v/article/details/142964708

相关文章

  • 集合Collection接口中的成员方法
    一、Collection集合的介绍:1.Collection是一个接口,List,Set是继承Collection接口的子接口2.当我们使用Collection的方法的时候,由于是一个接口不能直接new对象,可以通过其具体实现的子类来进行调用二、Collection的基本方法(6)1.booleanadd(Ee),可以传任意一个类型的元素进去2......
  • 【Shiro】8.后端服务接口注释
    通过给接口服务方法添加注解可以实现权限校检,可以加在控制器方法上,也可以加在业务方法上,一般加在控制器方法上。@RequiresAuthentication验证用户登录,等同于方法subject.isAuthenticated()@RequiresUser验证用户是否被记忆;登录认证成功subject.isAuthenticated()为true......
  • vue+wangEditor编辑器,上传图片请求后台接口
    来吧,先给大家看一下,是否是你想要的简单轻便编辑器的效果。父组件:<EditorView:content="value"@change="grtUrl"/><script>importEditorViewfrom"@/components/EditorView";exportdefault{components:{EditorView}},dat......
  • AXI4-Lite 接口
    AXI4-Lite接口简介信号握手机制AXI4-Lite与AXI4-Full的区别Xilinx官方源码生成注:axi4-lite源码文件及testbench的task文件见附件!简介AXI4-Lite是AMBAAXI4协议的一个简化版本,专为简单的控制寄存器访问和不需要完整AXI4协议复杂性的场景而设计。它提......
  • AXI4-Full 接口
    AXI4-Full接口简介信号全局信号(GlobalSignals)写地址通道信号(WriteAddressChannelSignals)写数据通道信号(WriteDataChannelSignals)写响应通道信号(WriteResponseChannelSignals)读地址通道信号(ReadAddressChannelSignals)读数据通道信号(ReadDataChannelSigna......
  • 双十一将近,如何解决API接口调用数据超量及报错问题?
    随着双十一的临近,电商平台的API接口面临着巨大的挑战,尤其是在数据超量和报错问题上。以下是一些解决方案和最佳实践,可以帮助你一站式解决这些问题。1.性能测试在大促期间,如双十一,流量会大幅增长,因此进行性能测试是必要的。性能测试包括负载测试、基线测试、冒烟测试、浸泡......
  • 智能AI对话绘画二合一源码系统 内置所有大模型的接口 带完整的安装代码包以及搭建部署
    系统概述人工智能技术的飞速发展,越来越多的创新应用正在改变着我们的生活。本文将向大家介绍一款集成了智能对话与创意绘画功能的开源项目——“智能AI对话绘画二合一源码系统”。它不仅融合了最新的自然语言处理(NLP)和计算机视觉技术,还为开发者提供了从零开始构建自己专属AI服......
  • 在K8S中,Pod 如何实现对节点的资源控制?
    在Kubernetes中,Pod是可以被调度到集群中任何节点上的最小部署单元。Pod通过资源请求(requests)和资源限制(limits)来实现对节点资源的控制。这些资源控制机制确保了容器能够获得它们所需的资源,同时防止它们消耗过多资源,影响节点上其他容器或Pod的运行。以下是Pod实现对节点资......
  • 在K8S中,Worker节点加入集群的全过程?
    在Kubernetes(K8S)中,Worker节点加入集群的全过程涉及多个步骤,包括准备环境、配置网络、生成令牌、执行加入命令以及验证集群状态等。以下是详细的步骤说明:1.准备Worker节点环境检查系统要求:确保Worker节点的操作系统和硬件配置满足Kubernetes的最低要求。检查并安装必要的依......
  • 身份证实名认证API集成-二要素实名认证-实名认证接口-身份认证
    身份证实名认证接口是当下互联网服务用于验证用户真实身份的重要手段之一。在互联网金融、电子商务、社交网络等众多领域中,实名认证可以帮助平台更好的了解和服务在线用户,以做到防范欺诈行为的发生,保障交易资金与信息安全,该接口功能一般由第三方平台(如翔云、阿里云)来提供。......