Bootstrap

解析设备树(dts)的接口函数

文章索引:

1.解析设备树的接口函数

2.一个无关话题:零长度数组

3.Enableauto repeat feature of Linux input subsystem


************************1.解析设备树的接口函数********************



static inline int of_property_read_u8(const struct device_node *np,const char *propname,u8 *out_value) 

static inline int of_property_read_u16(const struct device_node *np,const char *propname,u8 *out_value) 

static inline int of_property_read_u32(const struct device_node *np,const char *propname,u8 *out_value) 

从设备结点np中读取属性名为propname,类型为81632位的属性值,并放入out_values。实际上这里调用的就是sz1XXX_array函数。

 

intof_property_read_u32_index(conststruct device_node *np,const char*propname,u32 index, u32 *out_value)

从设备结点np中读取属性名为propname的属性值中第indexu32数值给out_value

 

intof_property_read_u64(conststructdevice_node *np, const char *propname,u64 *out_value)

从设备结点np中读取属性名为propname,类型为64位的属性值,并放入out_values

 

intof_property_read_string(structdevice_node *np, const char *propname,const char**out_string)

从设备结点np中读取属性名为propname的字符串型属性值

 

intof_property_read_string_index(structdevice_node *np, const char *propname,intindex, const char **output)

从设备结点np中读取属性名为propname的字符串型属性值数组中的第index个字符串

 

intof_property_count_strings(structdevice_node *np, const char *propname)

从设备结点np中读取属性名为propname的字符串型属性值的个数

 

unsignedint irq_of_parse_and_map(structdevice_node *dev, int index)

从设备节点dev中读取第indexirq

 

int of_irq_to_resource(structdevice_node *dev, int index, struct resource *r)

从设备节点dev中读取第indexirq号,并填充一个irq资源结构体

 

int of_irq_count(structdevice_node *dev)

获取设备节点devirq个数



staticinline boolof_property_read_bool(conststruct device_node *np,const char *propname);

如果设备结点np含有propname属性,则返回true,否则返回false。一般用于检查空属性是否存在。

 

structproperty*of_find_property(conststruct device_node *np,const char *name,int *lenp)

根据name参数,在指定的设备结点np中查找匹配的property,并返回这个property

 

constvoid * of_get_property(conststruct device_node *np, const char *name,int *lenp)

根据name参数,在指定的设备结点np中查找匹配的property,并返回这个property的属性值



structdevice_node* of_get_parent(conststruct device_node *node)

获得node节点的父节点的devicenode



int of_device_is_compatible(conststruct device_node *device,const char *compat);

判断设备结点devicecompatible属性是否包含compat指定的字符串



of_allnodes中查找信息:

structdevice_node*of_find_node_by_path(constchar *path)
根据路径参数,在全局链表of_allnodes中,查找匹配的device_node



structdevice_node*of_find_node_by_name(structdevice_node *from,const char*name)
则根据name在全局链表of_allnodes中查找匹配的device_node,from=NULL表示从头开始查找



structdevice_node*of_find_node_by_type(structdevice_node *from,const char *type)

根据设备类型在全局链表of_allnodes中查找匹配的device_node



structdevice_node *of_find_compatible_node(structdevice_node *from, const char*type, const char*compatible);

根据compatible的属性值在全局链表of_allnodes中查找匹配的device_node,大多数情况下,fromtypeNULL

 

structdevice_node*of_find_node_with_property(structdevice_node *from,const char *prop_name)

根据节点属性的name在全局链表of_allnodes中查找匹配的device_node

 

structdevice_node*of_find_node_by_phandle(phandlehandle)

根据phandle在全局链表of_allnodes中查找匹配的device_node

 

杂:

void__iomem*of_iomap(struct device_node*node, int index);

通过设备结点直接进行设备内存区间的ioremap()index是内存段的索引。若设备结点的reg属性有多段,可通过index标示要ioremap的是哪一段,只有1段的情况,index0

 

unsignedlong __initof_get_flat_dt_root(void)

用来查找在dtb中的根节点,好像返回的都是0



intof_alias_get_id(struct device_node*np, const char *stem)

获取节点np对应的aliasid

 

structdevice_node*of_node_get(structdevice_node *node)

voidof_node_put(struct device_node *node)

devicenode计数增加/减少



conststruct of_device_id*of_match_node(conststruct of_device_id *matches,const struct device_node*node)

matches数组中of_device_id结构的nametypedevicenodecompatibletype匹配,返回匹配度最高的of_device_id结构



platform_deviceresource相关:

intof_address_to_resource(structdevice_node *dev, int index,struct resource *r)

根据设备节点devreg属性值,填充资源结构体rIndex参数指明了使用reg属性中第几个属性值,一般设置为0,表示第一个。



structplatform_device*of_device_alloc(structdevice_node *np,const char *bus_id,struct device *parent)

根据devicenodebus_id以及父节点创建该设备的platform_device结构,同时会初始化它的resource成员。

 

intof_platform_bus_probe(structdevice_node *root,const struct of_device_id *matches,struct device*parent)

遍历of_allnodes中的节点挂接到of_platform_bus_type总线上,由于此时of_platform_bus_type总线上还没有驱动,所以此时不进行匹配

 

intof_platform_populate(structdevice_node *root,const struct of_device_id *matches,const structof_dev_auxdata *lookup,struct device *parent)

遍历of_allnodes中的所有节点,生成并初始化所以节点的platform_device结构



structplatform_device*of_find_device_by_node(structdevice_node *np)

根据device_node查找返回该设备对应的platform_device结构



***************************************************************************


×××××××××××××××2.一个无关话题:零长度数组××××××××××××××××××××

零长度数组的英文原名为Arraysof Length Zero,是GNUC的规范,主要用途是用来作为结构体的最后一个成员,然后用它来访问此结构体对象之后的一段内存(通常是动态分配的内存)。什么意思呢?

structdevres为例,node变量的长度为3个指针的长度,而structdevres的长度也是3个指针的长度。而data只是一个标记,当有人分配了大于3个指针长度的空间并把它转换为structdevres类型的变量后,我们就可以通过data来访问多出来的memory。也就是说,有了零长度数组datastructdevres结构的长度可以不定,完全依赖于你分配的空间的大小。有什么用呢?

以本文的应用场景为例,多出来的、可通过data访问的空间,正是具体的deviceresource所占的空间。资源的类型不同,占用的空间的多少也不同,但devres模块的主要功能又是释放资源所占的资源。这是就是零长度数组的功能之一,因为整个memory空间是连续的,因此可以通过释devres指针,释放所有的空间,包括data所指的那片不定长度的、具体资源所用的空间。

零长度数组(data[0]),在不同的C版本中,有不同的实现方案,包括1长度数组(data[1])和不定长度数组(data[],本文所描述就是这一种),具体可参考GCC的规范:

https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html

××××××××××××××××3按键重复机制×××××××××××××××××××××××××

/*Enable auto repeatfeature of Linux input subsystem */



EV_REPinput_repeat_key,键盘重复,GPIO键盘

要实现的效果:类似桌面打开记事本,按下键盘后有输入,按住按键不放的话就连续输入。

环境:嵌入式Linux系统,键盘有GPIO扫描实现,模拟成标准键盘,界面用QT4LineEdit显示。

键盘的驱动我就不多说了,参考input/keyboardomap方面代码即可;QT里面继承keyPressEvent()即可判断按下的是哪个键。

要注意的有一些,说说心得:

1、键盘要注意防抖动

2、如果确认有键盘就input_report_key(&va->kb_dev,key_got,1);然后重复扫描,这一步很重要,重复扫描的时间要小于33ms。为什么?看下input.c就知道了,input.cinput_repeat_key会隔rep[REP_PERIOD]调用一次,但是如果我们在驱动里释放了按键,则input_repeat_key不会再调用(此函数前面有判断)。

因此扫描的时间一定要少于rep[REP_PERIOD],不这样做的话,就会出现你本来想按一次按键,结果多了几个尾巴。

例如,你确认按键后200ms再开始扫描是否还按下,则input_repeat_key已经调用好几次了,所以多了几个尾巴,这样就不是只按下一次键盘了。

3、千万不要因手按键盘的重复时间的固定思路迷惑了程序的编写。只要驱动指定了EV_REP,则驱动上层会自动启动上述的timer,本驱动只要判断按键是否抬起然后input_report_key(x,x,0);即可!

*******************************************************************************


;