linux-驱动学习(自用)

如同开始学C的部分,对于驱动的学习我们有必要记忆一些固定的东西

#include <linux/...> 包含相关的文件

这里要有两个相对必要的头文件

#include <linux/moudle.h>

#include <linux/init.h>

对应的函数

module_init(x);//这是个宏                                 __initcall(x);

module_exit(x);//这是个宏                                __exitcall(x);

MOULE_LICENSE(_license);//这是个宏         MODULE_INFO(license, _license)

MODULE_INFO(license, _license)                  MODULE_INFO(license, _license)

MODULE_INFO(license, _license)                  MODULE_INFO(tag, info)

MODULE_INFO(tag, info)                                 __MODULE_INFO(tag, tag, info)

__MODULE_INFO(tag, tag, info)                      __MODULE_INFO(tag, name, info)

__MODULE_INFO(tag, name, info)             

 static const char __UNIQUE_ID(name)[]             \    

__used __attribute__((section(".modinfo") , unused, aligned(1)))     \       

=__MODULE_INFO_PREFIX   __stringify(tag) "=" info               

...太多了   

杂项设备

注意:1>注册杂项设备(misc_register)

        2>根据misc_register函数要的参数创建结构体,

        3>创建的结构体根据需要赋予初值

        4>杂项主设备号默认为10,minor(次设备号),name 节点名, fops 文件相关操作的结构体

  platform

        1>注册paltform设备        (platform_driver_register(drv)     

        platform_driver_register(drv)     __platform_driver_register(drv, THIS_MODULE)

        __platform_driver_register(drv, THIS_MODULE)        

        int __platform_driver_register(struct platform_driver *drv,struct module *owner)

        因此drv 要传一个        struct platform_driver *类型的

        或者传一个 struct platform_driver 类型的地址

        2>注销paltform设备    void platform_driver_unregister(struct platform_driver * drv) 

        参数和注册相同

        3.struct platform_driver  drv 结构体

    struct platform_driver

{

    //probe函数指针 与设备树匹配会调用其指向的函数

    int (*probe)(struct platform_device *);       

    int (*remove)(struct platform_device *);      //remove函数指针

    void (*shutdown)(struct platform_device *);       

    int (*suspend)(struct platform_device *, pm_message_t state);

    int (*resume)(struct platform_device *);

    struct device_driver driver;    //该项重点    

    /#/ id_table 对应 platform 方法的匹配项,一般都用设备树有空可以了解一波

    const struct platform_device_id * id_table;       

    bool prevent_deferred_probe;

};  

       4.   struct device_driver

struct device_driver

{

    const char      *name;                //在/sys/bus下创建目录的名字    

    struct bus_type     *bus;            //什么总线类型?

    struct module       *owner;        //那个模块?

    const char      *mod_name;  /* used for built-in modules */

    bool suppress_bind_attrs;   /* disables bind/unbind via sysfs */

    enum probe_type probe_type;

    const struct of_device_id   *of_match_table; //该项重点 

    const struct acpi_device_id *acpi_match_table;

    int (*probe) (struct device *dev);

    int (*remove) (struct device *dev);

    void (*shutdown) (struct device *dev);

    int (*suspend) (struct device *dev, pm_message_t state);

    int (*resume) (struct device *dev);

    const struct attribute_group **groups;

    const struct attribute_group **dev_groups;

    const struct dev_pm_ops *pm;

    void (*coredump) (struct device *dev);

    struct driver_private *p;

};

        5.struct of_device_id 

struct of_device_id

{

    char    name[32];        

    char    type[32];          

    char    compatible[128];   //平台总线匹配项 对应设备树的compatible  

    const void *data;        

};

                                        

        6.  struct platform_driver int (*probe)(struct platform_device *) 指向的 prob函数中获取平台资源

相关内容

//平台总线

struct resource *platform_get_resource(struct platform_device *dev, \

unsigned int type, unsigned int num)

platform_device跟platform_driver的匹配

按照顺序有一个成功即完成匹配过程

a. 比较 platform_dev.driver_override 和 platform_driver.drv->name
b. 比较 platform_dev.dev.of_node的compatible属性 和 platform_driver.drv->of_match_table
c. 比较 platform_dev.name 和 platform_driver.id_table
d. 比较 platform_dev.name 和 platform_driver.drv->name

//设备树       

 内核函数of_platform_default_populate_init, 遍历device_node树, 生成platform_device

 设备树转换为platform        dts -> dtb -> device_node -> platform_device

1.处理device_node

of.h               // 提供设备树的一般处理函数

of_property_read_u32(读取某个属性的u32值)

of_get_child_count(获取某个device_node的子节点数)


of_address.h       // 地址相关的函数

of_get_address(获得reg属性中的addr, size值)


of_match_device(从matches数组中取出与当前设备最匹配的一项)
of_dma.h           // 设备树中DMA相关属性的函数
of_gpio.h          // GPIO相关的函数
of_graph.h         // GPU相关驱动中用到的函数, 从设备树中获得GPU信息
of_iommu.h         // 很少用到
of_irq.h           // 中断相关的函数
of_mdio.h          // MDIO (Ethernet PHY) API
of_net.h           // OF helpers for network devices. 
of_pci.h           // PCI相关函数
of_pdt.h           // 很少用到
of_reserved_mem.h  // reserved_mem的相关函数

2.处理 platform_device
of_platform.h      // 把device_node转换为platform_device时用到的函数
of_device_alloc(根据device_node分配设置platform_device)
of_find_device_by_node (根据device_node查找到platform_device)
of_platform_bus_probe (处理device_node及它的子节点)

of_device.h        // 设备相关的函数

of_match_device

设备树匹配操作

//找节点

of_find_compatible_node        根据设备树的compatible属性找节点

struct device_node * of_find_compatible_node

(struct device_node *from, const char *type, const char *compat);

of_find_node_by_phandle       根据phandle找到节点

struct device_node* of_find_node_by_phandle(phandle handle);

传入NULL表示从根节点开始寻找
dts文件被编译为dtb文件时,每一个节点都有一个数字ID,这些数字ID彼此不同。可以使用数字ID来找到device_node。这些数字ID就是phandle

//找属性

const void *of_get_property(const struct device_node *np, const char *name, int *lenp)

根据名字找到节点的属性,并且返回它的值

参数np表示节点,我们要在这个节点中找到名为name的属性,然后返回它的值
lenp用来保存这个属性的长度,即它的值的长度

 of_property_count_elems_of_size

根据名字找到节点的属性,确定它的值有多少个元素(elem)

//读取数据

 a.读某个整数u32/u64

int of_property_read_u32_index(const struct device_node *np, const char *propname, u32 index, u32 *out_value);

在设备树中,节点大概是这样:
xxx_node {
name2 = <0x50000000  0x60000000>;
};
调用of_property_read_u32 (np, “name2”, 1, &val)时,val将得到值0x0x60000000

 b.读数组

int of_property_read_variable_u8_array(const struct device_node *np, const char *propname, u8 *out_values, size_t sz_min, size_t sz_max);


int of_property_read_variable_u16_array(const struct device_node *np, const char *propname, u16 *out_values, size_t sz_min, size_t sz_max);


int of_property_read_variable_u32_array(const struct device_node *np, const char *propname, u32 *out_values, size_t sz_min, size_t sz_max);


int of_property_read_variable_u64_array(const struct device_node *np, const char *propname, u64 *out_values, size_t sz_min, size_t sz_max);

在设备树中,节点大概是这样:
xxx_node {
name2 = <0x50000012  0x60000034>;
};
上述例子中属性name2的值,长度为8
调用of_property_read_variable_u8_array (np, “name2”, out_values, 1, 10)时,out_values中将会保存这8个字节: 0x12,0x00,0x00,0x50,0x34,0x00,0x00,0x60


调用of_property_read_variable_u16_array (np, “name2”, out_values, 1, 10)时,out_values中将会保存这4个16位数值: 0x0012, 0x5000,0x0034,0x6000


总之,这些函数要么能取到全部的数值,要么一个数值都取不到
如果值的长度在sz_min和sz_max之间,就返回全部的数值;否则一个数值都不返回

 c.读字符串

 int of_property_read_string(const struct device_node *np, const char *propname, const   char **out_string);
 返回节点np的属性(名为propname)的值,(*out_string)指向这个值,把它当作字符串

                     

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值