第 14 行调用 of_demo_controller_register 注册 demo controller 驱动,xlate 函数设置的都是 of_demo_simple_xlate, 这个函数完成对 user 传来的参数的处理 1. int of_demo_controller_registe

Similar documents
CC213

C++ 程式設計

Open topic Bellman-Ford算法与负环

CC213

untitled

ebook14-4

新・明解C言語入門編『索引』

Microsoft PowerPoint - Lecture7II.ppt

Fun Time (1) What happens in memory? 1 i n t i ; 2 s h o r t j ; 3 double k ; 4 char c = a ; 5 i = 3; j = 2; 6 k = i j ; H.-T. Lin (NTU CSIE) Referenc

概述

C C C The Most Beautiful Language and Most Dangerous Language in the Programming World! C 2 C C C 4 C Project 30 C Project 3 60 Project 40

新版 明解C++入門編

全国计算机技术与软件专业技术资格(水平)考试

Microsoft PowerPoint - string_kruse [兼容模式]

untitled

bingdian001.com

int *p int a 0x00C7 0x00C7 0x00C int I[2], *pi = &I[0]; pi++; char C[2], *pc = &C[0]; pc++; float F[2], *pf = &F[0]; pf++;

nb.PDF

FY.DOC

JavaIO.PDF

Microsoft Word - 01.DOC

static struct file_operations gpio_ctl_fops={ ioctl: gpio_ctl_ioctl, open : gpio_open, release: gpio_release, ; #defineled1_on() (GPBDAT &= ~0x1) #def

概述

C PICC C++ C++ C C #include<pic.h> C static volatile unsigned char 0x01; static volatile unsigned char 0x02; static volatile unsigned cha

提问袁小兵:

python内存管理

软件测试(TA07)第一学期考试

Lorem ipsum dolor sit amet, consectetuer adipiscing elit

Important Notice SUNPLUS TECHNOLOGY CO. reserves the right to change this documentation without prior notice. Information provided by SUNPLUS TECHNOLO

C/C++ 语言 - 循环

nooog

Fuzzy Highlight.ppt

EK-STM32F

威 福 髮 藝 店 桃 園 市 蘆 竹 區 中 山 里 福 祿 一 街 48 號 地 下 一 樓 50,000 獨 資 李 依 純 105/04/06 府 經 登 字 第 號 宏 品 餐 飲 桃 園 市 桃 園 區 信 光 里 民

( CIP) /. :, ( ) ISBN TP CIP ( 2005) : : : : * : : 174 ( A ) : : ( 023) : ( 023)

INTRODUCTION TO COM.DOC

1 Framework.NET Framework Microsoft Windows.NET Framework.NET Framework NOTE.NET NET Framework.NET Framework 2.0 ( 3 ).NET Framework 2.0.NET F

《C语言程序设计》教材习题参考答案

四川省普通高等学校

6 C51 ANSI C Turbo C C51 Turbo C C51 C51 C51 C51 C51 C51 C51 C51 C C C51 C51 ANSI C MCS-51 C51 ANSI C C C51 bit Byte bit sbit

K301Q-D VRT中英文说明书141009

ebook15-C

无类继承.key

Microsoft Word - 把时间当作朋友(2011第3版)3.0.b.07.doc

SDK 概要 使用 Maven 的用户可以从 Maven 库中搜索 "odps-sdk" 获取不同版本的 Java SDK: 包名 odps-sdk-core odps-sdk-commons odps-sdk-udf odps-sdk-mapred odps-sdk-graph 描述 ODPS 基

在挑选合适的 SDK 的时候需要注意, 标准 windows 平台应用选择 FBX SDK VS2015,windows 应用商店和全平台通用的不用考虑 windows 全平台通用的应用是 windows10 新推出的功能, 可以打通 windows phone windows s

BOOL EnumWindows(WNDENUMPROC lparam); lpenumfunc, LPARAM (Native Interface) PowerBuilder PowerBuilder PBNI 2

2013 C 1 # include <stdio.h> 2 int main ( void ) 3 { 4 int cases, a, b, i; 5 scanf ("%d", & cases ); 6 for (i = 0;i < cases ;i ++) 7 { 8 scanf ("%d %d

Outline USB Application Requirements Variable Definition Communications Code for VB Code for Keil C Practice

chp6.ppt

科学计算的语言-FORTRAN95

chap07.key

c_cpp

Microsoft Word - 11.doc

untitled

EJB-Programming-4-cn.doc

地 理 志 鏡 止 煞, 來 達 到 安 宅 的 效 果 4. 門 神 符 紙 : 於 門 板 繪 製 門 神, 作 為 宅 第 的 守 護, 民 宅 所 使 用 的 門 神 題 材, 多 為 天 官 賜 福 或 文 武 官 員 符 紙 是 以 畫 了 符 咒 的 紙 懸 掛 室 內, 或 加 框

OOP with Java 通知 Project 4: 4 月 19 日晚 9 点

Improved Preimage Attacks on AES-like Hash Functions: Applications to Whirlpool and Grøstl

KillTest 质量更高 服务更好 学习资料 半年免费更新服务

untitled

《大话设计模式》第一章

C/C++语言 - 分支结构

01

(baking powder) 1 ( ) ( ) 1 10g g (two level design, D-optimal) 32 1/2 fraction Two Level Fractional Factorial Design D-Optimal D

Guide to Install SATA Hard Disks

untitled

ebook39-5

2013 C 1 #include <stdio.h> 2 int main(void) 3 { 4 int cases, i; 5 long long a, b; 6 scanf("%d", &cases); 7 for (i = 0; i < cases; i++) 8 { 9 scanf("%

C 1

穨control.PDF

C H A P T E R 7 Windows Vista Windows Vista Windows Vista FAT16 FAT32 NTFS NTFS New Technology File System NTFS

C语言的应用.PDF

MATLAB 1

C/C++语言 - C/C++数据

2 2 3 DLight CPU I/O DLight Oracle Solaris (DTrace) C/C++ Solaris DLight DTrace DLight DLight DLight C C++ Fortran CPU I/O DLight AM

untitled

UTI (Urinary Tract Infection) - Traditional Chinese

mvc

ebook39-6

untitled

untitled

Transcription:

作者 彭东林 pengdonglin137@163.com 平台 TQ2440 Linux 4.10.17 概述 上一篇大概介绍了一下 demo controller 的结构, 下面结合驱动分析 正文 一 demo controller 驱动 这里主要分析 probe 函数 demo_controller_probe: 1. static int demo_controller_probe(struct platform_device *pdev) 2. { 3. struct device *dev = &pdev >dev; 4. struct device_node *np = dev >of_node; 5. int ret = 0; 6. 7. dev_dbg(dev, "%s enter.\n", func ); 8. 9. if (!np) { 10. dev_err(dev, "of_node is NULL\n"); 11. return EINVAL; 12. } 13. 14. ret = of_demo_controller_register(np, of_demo_simple_xlate, dev); 15. if (ret < 0) { 16. dev_err(dev, "%s: register demo controller failed: %d\n", func, 17. return EINVAL; 18. } 19. 20. dev_info(dev, "register demo controller successfully.\n"); 21. 22. return ret; 23. }

第 14 行调用 of_demo_controller_register 注册 demo controller 驱动,xlate 函数设置的都是 of_demo_simple_xlate, 这个函数完成对 user 传来的参数的处理 1. int of_demo_controller_register(struct device_node *np, 2. int (*of_demo_xlate) 3. (struct of_phandle_args *, struct of_demo *), 4. void *data) 5. { 6. struct of_demo *ofdemo; 7. 8. if (!np!of_demo_xlate) { 9. pr_err("%s: not enough information provided\n", func ); 10. return EINVAL; 11. } 12. 13. if (!of_get_property(np, "demo controller", NULL)) { 14. pr_err("%s: can not register demo controller for %s.\n", 15. func, np >name); 16. return EINVAL; 17. } 18. 19. ofdemo = kzalloc(sizeof(*ofdemo), GFP_KERNEL); 20. if (!ofdemo) 21. return ENOMEM; 22. 23. ofdemo >of_node = np; 24. ofdemo >of_demo_xlate = of_demo_xlate; 25. ofdemo >of_demo_data = data; 26. 27. /* Now queue of_demo controller structure in list */ 28. mutex_lock(&of_demo_lock); 29. list_add_tail(&ofdemo >of_demo_controllers, &of_demo_list); 30. mutex_unlock(&of_demo_lock); 31. 32. return 0; 33. } 这个函数用 ofdemo 代表一个 demo controller 结构体, 然后进行初始化, 最后将其加入到全局链表 of_demo_list 中 二 demo user 驱动 还是从 demo_user_probe 开始, 在 demo_user_probe 中主要调用的就是 of_demo_request, 将 name 表示的要申请的 demo 资源传递给 demo controller, 然后返回处理以后的结果 1. int of_demo_request(struct device_node *np, const char *name) 2. { 3. struct of_phandle_args demo_spec;

4. struct of_demo *ofdemo; 5. int result; 6. int index; 7. 8. if (!np!name) { 9. pr_err("%s: not enough information provided\n", func ); 10. return EINVAL; 11. } 12. 13. index = of_property_match_string(np, "demo names", name); 14. if (index < 0) { 15. pr_err("%s: not match %s in demo names\n", func, name); 16. return ENODEV; 17. } 18. 19. if (of_parse_phandle_with_args(np, "demos", "#demo cells", index, 20. &demo_spec)) { 21. pr_err("%s: parse %s failed\n", func, name); 22. return ENODEV; 23. } 24. 25. mutex_lock(&of_demo_lock); 26. ofdemo = of_demo_find_controller(&demo_spec); 27. 28. if (ofdemo) { 29. result = ofdemo >of_demo_xlate(&demo_spec, ofdemo); 30. } else { 31. pr_warn("%s: can not find demo controller for %s\n", 32. func, name); 33. result = 1; 34. } 35. 36. mutex_unlock(&of_demo_lock); 37. 38. of_node_put(demo_spec.np); 39. 40. return result; 41. } 第 13 行的 of_property_match_string 完成的功能 : 解析 np 节点, 返回 name 表示的字符串在 "demonames" 属性值中的索引号 第 19 行调用 of_parse_phandle_with_args, 解析 np 节点的 "demos" 属性, 获得第 index 个字段, 存放到 demo_spec 中第 26 行调用 of_demo_find_controller 根据 demo_spec 中的 device_node 成员找到对应的 demo controller 第 29 行调用找到的 demo controller 的 of_demo_xlate 函数, 也就是 of_demo_simple_xlate, 对 demo_spec 的 args 成员中的参数进行处理, 然后返回处理以后的结果第 38 行释放前面的 demo controller 的 device_node, 因为在调用 of_parse_phandle_with_args 会 get 该 device node

三 详细分析 1 of_property_match_string 1. int of_property_match_string(const struct device_node *np, const char *propn 2. const char *string) 3. { 4. const struct property *prop = of_find_property(np, propname, NULL); 5. size_t l; 6. int i; 7. const char *p, *end; 8. 9. if (!prop) 10. return EINVAL; 11. if (!prop >value) 12. return ENODATA; 13. 14. p = prop >value; 15. end = p + prop >length; 16. 17. for (i = 0; p < end; i++, p += l) { 18. l = strnlen(p, end p) + 1; 19. if (p + l > end) 20. return EILSEQ; 21. pr_debug("comparing %s with %s\n", string, p); 22. if (strcmp(string, p) == 0) 23. return i; /* Found it; return index */ 24. } 25. return ENODATA; 26. } 第 4 行获得片 propname 属性的值第 14 行中 prop >value 指向的是存放属性值的占用的内存空间的起始地址第 15 行的 prop >length 指向的是属性值占用的内存空间的长度, 所以 end 指向的是属性值占用的内存地址空间的结尾地址第 18 行的 strnlen 函数搜索从 p 开始长度为 (end >p), 直到找到搜索到结尾或者 '\0', 所以该行的作用就是找到 propname 属性中的每一个字符串的长度, 字符串的首地址存放在 p 中, 字符串的长度存放在 l 中, 这样的话, 第 17 行的 p+=l, 此时 p 就指向下一个字符串的开头 第 22 行将找到的字符串 p 跟传入的 string 字符串比较, 如果不相等的话, 继续遍历下一个字符串 ; 如果相等的话, 表示找到了 string 指向的字符串, 然后返回 i, 也就是找到的字符串在属性值里的索引 2 of_parse_phandle_with_args 1. /** 2. * of_parse_phandle_with_args() Find a node pointed by phandle in a list 3. * @np: pointer to a device tree node containing a list

4. * @list_name: property name that contains a list 5. * @cells_name: property name that specifies phandles' arguments count 6. * @index: index of a phandle to parse out 7. * @out_args: optional pointer to output arguments structure (will be fill 8. * 9. * This function is useful to parse lists of phandles and their arguments. 10. * Returns 0 on success and fills out_args, on error returns appropriate 11. * errno value. 12. * 13. * Caller is responsible to call of_node_put() on the returned out_args >np 14. * pointer. 15. * 16. * Example: 17. * 18. * phandle1: node1 { 19. * #list cells = <2>; 20. * } 21. * 22. * phandle2: node2 { 23. * #list cells = <1>; 24. * } 25. * 26. * node3 { 27. * list = <&phandle1 1 2 &phandle2 3>; 28. * } 29. * 30. * To get a device_node of the `node2' node you may call this: 31. * of_parse_phandle_with_args(node3, "list", "#list cells", 1, &args); 32. */ 33. int of_parse_phandle_with_args(const struct device_node *np, const char *lis 34. const char *cells_name, int index, 35. struct of_phandle_args *out_args) 36. { 37. if (index < 0) 38. return EINVAL; 39. return of_parse_phandle_with_args(np, list_name, cells_name, 0, 40. index, out_args); 41. } 首先可以看看这个函数的注释, 基本就可以直到这个函数的目的了, 这个也是很核心的函数 1. static int of_parse_phandle_with_args(const struct device_node *np, 2. const char *list_name, 3. const char *cells_name, 4. int cell_count, int index, 5. struct of_phandle_args *out_args) 6. { 7. struct of_phandle_iterator it; 8. int rc, cur_index = 0; 9. 10. /* Loop over the phandles until all the requested entry is found */ 11. of_for_each_phandle(&it, rc, np, list_name, cells_name, cell_count) { 12. /*

13. * All of the error cases bail out of the loop, so at 14. * this point, the parsing is successful. If the requested 15. * index matches, then fill the out_args structure and return, 16. * or return ENOENT for an empty entry. 17. */ 18. rc = ENOENT; 19. if (cur_index == index) { 20. if (!it.phandle) 21. goto err; 22. 23. if (out_args) { 24. int c; 25. 26. c = of_phandle_iterator_args(&it, 27. out_args >args, 28. MAX_PHANDLE_ARGS); 29. out_args >np = it.node; 30. out_args >args_count = c; 31. } else { 32. of_node_put(it.node); 33. } 34. 35. /* Found it! return success */ 36. return 0; 37. } 38. 39. cur_index++; 40. } 41. 42. /* 43. * Unlock node before returning result; will be one of: 44. * ENOENT : index is for empty phandle 45. * EINVAL : parsing error on data 46. */ 47. 48. err: 49. of_node_put(it.node); 50. return rc; 51. } 第 11 40 行的循环会不断遍历 demos 属性的值, 直到循环次数跟传入的 index 相同, 也就是找到了 demos 属性中的第 index 项, 然后将解析出来的关于该项的信息存放到传入的 out_args 中, 其中 np 存放的是第 index 项引用的 demo controller 设备节点, 第 index 项的参数个数存放到 args_count 中, 具体的参数存放到 args 中这里需要看看 of_for_each_phandle 的定义 : 1. #define of_for_each_phandle(it, err, np, ln, cn, cc) \ 2. for (of_phandle_iterator_init((it), (np), (ln), (cn), (cc)),\ 3. err = of_phandle_iterator_next(it); \ 4. err == 0; \ 5. err = of_phandle_iterator_next(it))

这里涉及到两个函数 of_phandle_iterator_init 和 of_phandle_iterator_next. of_phandle_iterator_init: 1. int of_phandle_iterator_init(struct of_phandle_iterator *it, 2. const struct device_node *np, 3. const char *list_name, 4. const char *cells_name, 5. int cell_count) 6. { 7. const be32 *list; 8. int size; 9. 10. memset(it, 0, sizeof(*it)); 11. 12. list = of_get_property(np, list_name, &size); 13. if (!list) 14. return ENOENT; 15. 16. it >cells_name = cells_name; 17. it >cell_count = cell_count; 18. it >parent = np; 19. it >list_end = list + size / sizeof(*list); 20. it >phandle_end = list; 21. it >cur = list; 22. 23. return 0; 24. } 这里初始化了一个 it 变量, 下面会反复使用 : 第 12 行找到 demos 属性的属性值占用的内存空间的大小 size, 然后将该内存空间的首地址存放到 list 中第 16 行的 cells_name 指向的是 "#demo cells" 第 17 行的 cell_count 被初始化为 0 第 18 行 parent 指向 demo user 这个设备树节点的 device_node 第 19 行 list_end 指向 "demos" 属性值内存空间的结尾第 20 行的 phandle_end 指向 "demos" 属性值内存空间首地址第 21 行的 cur 初始化为 "demo" 属性值内存空间首地址 of_phandle_iterator_next: 1. int of_phandle_iterator_next(struct of_phandle_iterator *it) 2. { 3. uint32_t count = 0; 4. 5. if (it >node) { 6. of_node_put(it >node); 7. it >node = NULL; 8. } 9.

10. if (!it >cur it >phandle_end >= it >list_end) 11. return ENOENT; 12. 13. it >cur = it >phandle_end; 14. 15. /* If phandle is 0, then it is an empty entry with no arguments. */ 16. it >phandle = be32_to_cpup(it >cur++); 17. 18. if (it >phandle) { 19. 20. /* 21. * Find the provider node and parse the #* cells property to 22. * determine the argument length. 23. */ 24. it >node = of_find_node_by_phandle(it >phandle); 25. 26. if (it >cells_name) { 27. if (!it >node) { 28. pr_err("%s: could not find phandle\n", 29. it >parent >full_name); 30. goto err; 31. } 32. 33. if (of_property_read_u32(it >node, it >cells_name, 34. &count)) { 35. pr_err("%s: could not get %s for %s\n", 36. it >parent >full_name, 37. it >cells_name, 38. it >node >full_name); 39. goto err; 40. } 41. } else { 42. count = it >cell_count; 43. } 44. 45. /* 46. * Make sure that the arguments actually fit in the remaining 47. * property data length 48. */ 49. if (it >cur + count > it >list_end) { 50. pr_err("%s: arguments longer than property\n", 51. it >parent >full_name); 52. goto err; 53. } 54. } 55. 56. it >phandle_end = it >cur + count; 57. it >cur_count = count; 58. 59. return 0; 60. 61. err: 62. if (it >node) { 63. of_node_put(it >node);

64. it >node = NULL; 65. } 66. 67. return EINVAL; 68. } 第 5 行的 if 分支是为了释放上次循环中不符合条件的 demo controller 节点, 对于符合条件的 device node 节点的释放工作由调用者完成, 这个从函数的注释里看得很清楚第 10 行是判断是否遍历完成第 16 行 cur 指向的是每一个 entry 的第一个整数, 也就是该 entry 所引用的 demo controller 节点的 phandle 第 24 行根据 phandle 找到所引用的 demo controller 的 device_node 第 33 行获取该 demo controller 节点的 "#demo cells" 属性的值, 存放到 count 中, 也就是描述一个 demo 资源需要的参数的个数第 56 行,phandle_end 指向该 entry 占用的内存空间的结尾从这里我们知道了, 调用依次 of_phandle_iterator_next,it 的成员被赋值的情况如下 : cell name: "#demo cells" parent: demo user 的 device node list_end: "demos" 的属性值占用的内存空间的结尾 phandle_end: 当前 entry 的结尾地址 cur_count: 当前 entry 引用的 demo contoller 的 "#demo cells" 属性值 cur: 当前 entry 的首地址 在找到需要的 entry 后, 也就是 cur_index 跟 index 相等的时候, 会调用 int of_phandle_iterator_args 对 it 中的参数进行转存 of_phandle_iterator_args: 1. int of_phandle_iterator_args(struct of_phandle_iterator *it, 2. uint32_t *args, 3. int size) 4. { 5. int i, count; 6. 7. count = it >cur_count; 8. 9. if (WARN_ON(size < count)) 10. count = size; 11. 12. for (i = 0; i < count; i++) 13. args[i] = be32_to_cpup(it >cur++); 14. 15. return count; 16. } 第 13 行将当前 entry 中的需要传递给 demo controller 的参数存放到 args 中 第 14 行返回当前 entry 所引用的 demo controller 的 "#demo cells" 属性值

3 of_demo_find_controller 1. static struct of_demo *of_demo_find_controller(struct of_phandle_args *demo_ 2. { 3. struct of_demo *ofdemo; 4. 5. list_for_each_entry(ofdemo, &of_demo_list, of_demo_controllers) 6. if (ofdemo >of_node == demo_spec >np) 7. return ofdemo; 8. 9. pr_debug("%s: can't find demo controller %s\n", func, 10. demo_spec >np >full_name); 11. 12. return NULL; 13. } 这个函数很容易理解,demo_spec >np 存放的是找到的 entry 所引用的 demo controller 节点对应的 device_node, 然后遍历 of_demo_list, 找到之前注册的 demo controller 4 of_demo_simple_xlate 1. int of_demo_simple_xlate(struct of_phandle_args *demo_spec, 2. struct of_demo *ofdemo) 3. { 4. int count = demo_spec >args_count; 5. struct device *dev = ofdemo >of_demo_data; 6. int ret = 0; 7. 8. dev_dbg(dev, "%s enter, count: %d\n", func, count); 9. switch (count) 10. { 11. case 1: 12. pr_info("args[0]: %d\n", demo_spec >args[0]); 13. ret = demo_spec >args[0]; 14. break; 15. case 2: 16. pr_info("%d x %d =?\n", demo_spec >args[0], demo_spec >args[1]); 17. ret = demo_spec >args[0] * demo_spec >args[1]; 18. break; 19. case 3: 20. pr_info("%d + %d + %d =?\n", demo_spec >args[0], demo_spec >args[1] 21. ret = demo_spec >args[0] + demo_spec >args[1] + demo_spec >args[2]; 22. break; 23. default: 24. dev_err(dev, "args count %d is not supported.\n", count); 25. return EINVAL; 26. } 27. 28. return ret; 29. }

这个函数对从 entry 中解析到的参数进行处理 完