内核接口和多节点设备

admin2024-08-25  10

1:内核接口

int (*open) (struct inode *, struct file *);

内核层的open 和 内核层release的参数是一致

内核层的open是可以被上层多几次调用且可以被多个文件绑定!

        四个设备原则上可以用一个内核层的open

        上层打开四个文件就会产生四次调用 内核层的open

        因为设备文件不同 -> 在内核层调用 open带来内核传参也会不同!

对应的参数:

struct inode
{

      dev_t  i_rdev;

}

struct file
{

       void * private_data;//私有数据

}

2:内核接口的read和write

ssize_t(*read)(

    struct file *f,

    char __user *buf,

    size_t size,

    loff_t * offt

);
ssize_t (*write)(struct file *, char __user *, size_t, loff_t *);

3:多节点设备LED灯

#include "linux/kernel.h"
#include "linux/module.h"
#include "linux/of.h"
#include "linux/cdev.h"
#include "linux/fs.h"
#include "linux/gpio.h"
#include "linux/of_gpio.h"
#include "linux/device/class.h"
#include "linux/device.h"
#include "linux/platform_device.h"
#include "linux/miscdevice.h"
struct xydled_info_s{
    int gpio_num;//GPIO 编号
    enum of_gpio_flags gpio_flag;//GPIO_有效电平
    char name[32];//GIPO 的 LED 灯对应的设备文件名
    struct xydled_info_s * next;
};
struct xydled_info_s * head = NULL;//信息结构体头指针
int xydled_count = 0;//代表当前寻找到 LED 灯数量
dev_t devnum_base;//存储申请的首设备号
struct class * cls;//类结构体
struct cdev * cdev;//Linux2.6 的核心结构体
struct file_operations * ops;//内核文件操作集合
struct device_node * node;//设备树节点
int xyd_led_open(struct inode * inod, struct file * fil)
{
    //多个设备文件 共用了 一个内核层 open
    struct xydled_info_s * tmpp = head;
    int value;
    for(int i=0;i<xydled_count;i++)
    {
        if(inod->i_rdev == devnum_base +i )
        {
            if(tmpp->gpio_flag == OF_GPIO_ACTIVE_LOW)
            value = 0;
            gpio_set_value(tmpp->gpio_num,value);
            break;//最佳优化
        }
        tmpp=tmpp->next;
    }
    return 0;
}
int xyd_led_close(struct inode * inod, struct file * fil)
{
    struct xydled_info_s * tmpp = head;
    int value;
    for(int i=0;i<xydled_count;i++)
    {
        if(inod->i_rdev == devnum_base +i )
        {
            if(tmpp->gpio_flag == OF_GPIO_ACTIVE_LOW)
            {
                value = 0;
                gpio_set_value(tmpp->gpio_num,!value);
                break;//最佳优化
            }
            tmpp=tmpp->next;
        }
    }
    return 0;
}
//新入口
int xyd_led_probe(struct platform_device * dev)
{
    //1: 先取 Get 到 设备树节点
    node = dev->dev.of_node;
    //2:先去判断当前设备树状态
    const char * tmp;
    of_property_read_string(node,"status",&tmp);
    if(strcmp(tmp,"okay"))
    {
        printk("IS ERROR!\r\n");
        return -EINVAL;
    }
    //3:获取 GPIO 的信息: GPIO 编号 和 有效电平
    while(1)
    {
        //3.1: 创建了 我自己的结构体 空间
        struct xydled_info_s * tmpp = kzalloc(sizeof(struct
        xydled_info_s),GFP_KERNEL);
        if(tmpp == NULL)
        return -EIO;
        //3.2: 获取 GPIO 的信息
        tmpp->gpio_num = of_get_named_gpio(node,"xyd
        gpios",xydled_count);
        if(tmpp->gpio_num < 0)
        {
            //失败空间没有必要存在 ->释放
            kfree(tmpp);
            break;
        }
    //3.3:获取有效电平
      of_get_named_gpio_flags(node,"xyd
     gpios",xydled_count,&tmpp->gpio_flag);
    //3.4:封装设备文件名字
    sprintf(tmpp->name,"xyd_led_%d",xydled_count);
    //printf("确定有一个引脚成功获取了");
    //3.5:初始化当前这个 GPIO
    gpio_request(tmpp->gpio_num,tmpp->name);
    if(tmpp->gpio_flag == OF_GPIO_ACTIVE_LOW)
        gpio_direction_output(tmpp->gpio_num,1);
    else
        gpio_direction_output(tmpp->gpio_num,0);
    //3.6:创建 GPIO 信息链表的关系
    if(xydled_count == 0)
    {
        head = tmpp;
        tmpp ->next = NULL;
    }else
    {
        //找到最后一链表尾部
        struct xydled_info_s * tempp = head;
        while(tempp->next !=NULL)
        tempp=tempp->next;
        tempp->next = tmpp;
        tmpp->next = NULL;
    }
    //3.7: 数量标志 底加
    xydled_count++;
}
    //4:申请设备号
    alloc_chrdev_region(&devnum_base,0,xydled_count,"xyd_led");
    //5: 初始化 Linux2.6 的 核心结构体
    cdev = kzalloc(sizeof(struct cdev), GFP_KERNEL);
    ops = kzalloc(sizeof(struct file_operations), GFP_KERNEL);
    ops->owner = THIS_MODULE;
    ops->open = xyd_led_open;
    ops->release = xyd_led_close;
    cdev_init(cdev,ops);
    //6:往内核添加/注册设备
    cdev_add(cdev,devnum_base,xydled_count);
    /*
    我现在连续添加了多个设备-> xydled_count
    这些设备 共用一个 cdev 即代表共用了 cdev->ops
    共用了 open close!!!!
    */
    //7:创建 类结构体
    cls = class_create(THIS_MODULE, "xyd_led");
    //8: 根据数量创建设备文件
    struct xydled_info_s * xydtmp = head;
    for(int i =0;i<xydled_count;i++)
    {
        device_create(cls,NULL,devnum_base+i,NULL,xydtmp->name);
        xydtmp= xydtmp->next;
    }
    return 0;
}
//新出口
int xyd_led_remove(struct platform_device * dev)
{
    //我不喜欢写卸载!
    return 0;
}
struct of_device_id xyd_id_table[]={
    {.compatible = "xyd_led",},
};
struct platform_driver drv={
    .probe = xyd_led_probe,//新入口
    .remove= xyd_led_remove,//新出口
    .driver ={
    .name = "xyd_led",
    .of_match_table =xyd_id_table,//匹配名字
    },
};
static int __init myxyd_led_init(void)
{
    return platform_driver_register(&drv);
}
//卸载函数
static void __exit myxyd_led_exit(void)
{
    platform_driver_unregister(&drv);
}
    module_init(myxyd_led_init);
    module_exit(myxyd_led_exit);
    MODULE_LICENSE("GPL");
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明原文出处。如若内容造成侵权/违法违规/事实不符,请联系SD编程学习网:675289112@qq.com进行投诉反馈,一经查实,立即删除!