字符设备驱动第十七课----platform

device

1出处和定义:

<include/linux/platform_device.h>
struct platform_device {
    const char  *name;    //设备名,用于匹配
    int     id;           //设备ID
    struct device   dev;  //父设备
    u32     num_resources;//资源数
    struct resource *resource; //资源数组首地址
    ....
};
<include/linux/device.h>
struct device {
    void        *platform_data;         //平台特有数据,因具体设备不同而不同,用于设备私有属性的拓展
    struct device_node  *of_node;       //设备树上的节点
    void (*release)(struct device *dev);//释放函数
    ...
};

2.注册:

/*
* 功能:把设备添加到内核设备列表,遍历驱动列表,看是否能找到匹配的驱动,找到则回调驱动的探测函数
* 返回值:成功:0       失败:负数
*/
int platform_device_register(struct platform_device *);

3.卸载:

/*
* 功能:把设备从内核设备列表中删除,回调驱动的回收清理(卸载)函数
* 返回值:成功:0       失败:负数
*/
int platform_device_unregister(struct platform_device *);

工程实例

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>

#include <asm/current.h>
#include <linux/sched.h>

#include <linux/ioport.h>
#include <linux/platform_device.h>

#include "../private.h"
/*设备私有数据*/
static struct privatedata priv = {  
    .val = 0x12345678,
    .str = "hello world",
};

/*设备资源*/
struct resource res[] = {   
    [0] = {
        .start  = 0x10000000,
        .end    = 0x20000000-1,
        .flags  = IORESOURCE_MEM    //资源是一块io内存
    },
    //效果与上个元素一样,只是调用了一个宏包装了一下
    [1] = DEFINE_RES_MEM(0x20000000, 1024),//起始地址,大小
    [2] = {
        .start  = 10,
        .flags  = IORESOURCE_IRQ//资源是一个中断,中断号为10
    },
    [3] = DEFINE_RES_IRQ(11),//效果与上个元素一样,只是调用了一个宏包装了一下  
};

static void dev_release(struct device *dev)
{
    //get command and pid
    printk(KERN_INFO "(%s:pid=%d), %s : %s : %d - leave.\n",
        current->comm, current->pid, __FILE__, __func__, __LINE__);
}


/*定义一个platform设备*/
static struct platform_device demoobj = {
    .name   = "demo0",          //设备名
    .id = 0,                    //设备ID
    .dev    = {                 //设备父对象
        .platform_data = &priv,//私有数据,前面定义好的
        .release = dev_release,//回收清理函数
    },
    .num_resources  = ARRAY_SIZE(res),//资源个数(用了个宏求数组中元素个数)
    .resource   = res,         //资源数组,前面定义好的
};

#if 0
static int __init device_init(void)
{
    //get command and pid
    printk(KERN_INFO "(%s:pid=%d), %s : %s : %d - leave.\n",
        current->comm, current->pid, __FILE__, __func__, __LINE__);
    /* 注册:1.加入到设备列表中;2.寻找匹配的驱动 */
    return platform_device_register(&demoobj);
}

static void __exit device_exit(void)
{
    //get command and pid
    printk(KERN_INFO "(%s:pid=%d), %s : %s : %d - leave.\n",
        current->comm, current->pid, __FILE__, __func__, __LINE__);
    /*注销设备:1.从设备列表中删除*/
    platform_device_unregister(&demoobj);
}

module_init(device_init);
module_exit(device_exit);
#else
//3. register obj
module_platform_device(demoobj);//自己定义的一个宏,与上面的效果一样
#endif

MODULE_LICENSE("GPL");
MODULE_AUTHOR("xxg");
MODULE_DESCRIPTION("Demo for kernel module");

driver

1.定义与出处

<include/linux/platform_device.h>

struct platform_driver {
    int (*probe)(struct platform_device *);     //探测函数
    int (*remove)(struct platform_device *);    //驱动卸载时调用
    void (*shutdown)(struct platform_device *); //关机时调用
    int (*suspend)(struct platform_device *, pm_message_t state); //休眠时调用
    int (*resume)(struct platform_device *);  //唤醒时调用
    struct device_driver driver;               // 父对象
    const struct platform_device_id *id_table; //id表,若有多份platform设备信息(用C写的),则用ID区分他们,把他们放一个id表中管理起来
    bool prevent_deferred_probe;
};
struct device_driver {
    const char      *name;      //设备名,若一个驱动只对应一个设备则通过该域来匹配
    struct driver_private *p; //驱动私有数据
    const struct of_device_id   *of_match_table;//用于匹配设备树中的设备的ID表
    ...
};
<include/linux/mod_devicetable.h>

struct of_device_id {
    char    name[32];
    char    type[32];
    char    compatible[128];      //设备树中的compatible属性
    const void *data;             //私有数据
};

2.设备匹配表申明:

/*
* 功能:
* 类型:  of:设备树写的设备信息     platform (i2c):C语言写的设备信息
*/
MODULE_DEVICE_TABLE(类型,id表)

3.注册:

/*
* 功能:1.将驱动添加到内核的驱动列表中
*      2.匹配设备列表,若匹配成功则回调设备的探测函数
* 输入参数:struct platform_driver:驱动句柄
* 返回值:成功:0   失败:负数
*/
int platform_driver_register(struct platform_driver *);

4.注销:

/*
* 功能:1.将驱动从驱动列表中删除
*      2.回调设备的卸载函数
* 输入参数:struct platform_driver:驱动句柄
* 返回值:none
*/
void platform_driver_unregister(struct platform_driver *);

工程实例

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>

#include <asm/current.h>
#include <linux/sched.h>

#include <linux/ioport.h>
#include <linux/platform_device.h>

#include "../private.h"
/*探测函数*/
static int demo_probe(struct platform_device *pdev)
{
    printk(KERN_INFO "%s : %s : %d - entry.\n", __FILE__, __func__, __LINE__);
    return 0;
}

static int demo_remove(struct platform_device *pdev)
{
    printk(KERN_INFO "%s : %s : %d - leave.\n", __FILE__, __func__, __LINE__);
    return 0;
}

/*设备匹配表*/
static struct platform_device_id tbl[] = {
    {"demo0"},
    {"demo1"},
    {},
};
MODULE_DEVICE_TABLE(platform, tbl);//告诉内核匹配表是谁,在设备树中还是在C代码中

//1. alloc obj
static struct platform_driver drv = {
    .probe  = demo_probe, //探测函数
    .remove = demo_remove,//卸载函数

    .driver = {         //驱动
        .name = "demo",//驱动名
    },

    .id_table = tbl,//ID匹配时将会用到的匹配表
};

#if 1
static int __init drv_init(void)
{
    //get command and pid
    printk(KERN_INFO "(%s:pid=%d), %s : %s : %d - entry.\n",
        current->comm, current->pid, __FILE__, __func__, __LINE__);
    /*驱动注册:1.将驱动添加到驱动列表中;
                2.从设备列表中匹配设备,匹配成功则调用探测函数*/
    return platform_driver_register(&drv);
}
static void __exit drv_exit(void)
{
    //get command and pid
    printk(KERN_INFO "(%s:pid=%d), %s : %s : %d - leave.\n",
        current->comm, current->pid, __FILE__, __func__, __LINE__);
/*驱动注销:1.将驱动从驱动列表中删除;
            2.回调驱动的卸载函数*/
    platform_driver_unregister(&drv);
}
module_init(drv_init);
module_exit(drv_exit);
#else
//3. register obj
module_platform_driver(drv);//与上面一样,只是用自定义的宏包装了一下
#endif

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Farsight");
MODULE_DESCRIPTION("Demo for kernel module");
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xxgui1992

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值