• Linux内核中ideapad-laptop.c文件全解析5


    接前一篇文章《Linux内核中ideapad-laptop.c文件全解析4》,链接为:

    Linux内核中ideapad-laptop.c文件全解析4_蓝天居士的博客-CSDN博客

    上一回详细分析了ideapad_sysfs_init,这一回详细分析ideapad_debugfs_init。

    • ideapad_debugfs_init

    ideapad_debugfs_init在同文件(drivers/platform/x86/ideapad-laptop.c)中实现,代码如下:

    1. static void ideapad_debugfs_init(struct ideapad_private *priv)
    2. {
    3. struct dentry *dir;
    4. dir = debugfs_create_dir("ideapad", NULL);
    5. priv->debug = dir;
    6. debugfs_create_file("cfg", 0444, dir, priv, &debugfs_cfg_fops);
    7. debugfs_create_file("status", 0444, dir, priv, &debugfs_status_fops);
    8. }
    9. static void ideapad_debugfs_exit(struct ideapad_private *priv)
    10. {
    11. debugfs_remove_recursive(priv->debug);
    12. priv->debug = NULL;
    13. }

    debugfs_create_dir函数的声明在include/linux/debugfs.h中: 

    struct dentry *debugfs_create_dir(const char *name, struct dentry *parent);

    debugfs_create_dir函数在指定的父目录下创建一个名为name的目录。如果parent为NULL,则将在debugfs根目录中创建该目录。成功时,返回值是一个struct dentry指针,可用于在目录中创建文件(并在最后清理它)。 ERR_PTR(-ERROR) 返回值表示出现问题;如果返回 ERR_PTR(-ENODEV),这表明内核是在没有debugfs支持的情况下构建的,并且任何功能都将不起作用。

    debugfs_create_file函数的声明同样在include/linux/debugfs.h中:

    1. struct dentry *debugfs_create_file(const char *name, umode_t mode,
    2. struct dentry *parent, void *data,
    3. const struct file_operations *fops);

    debugfs_create_file函数在debugfs目录中创建文件。参数name是要创建的文件的名称,mode描述文件应具有的访问权限,parent表示应保存文件的目录,数据将存储在生成的inode结构的i_private字段中,fops是一组实现文件行为的文件操作。至少应该提供read()和/或write()操作;其它的可以根据需要加入。同样,返回值将是指向已创建文件的 dentry 指针,错误时为 ERR_PTR(-ERROR),如果缺少debugfs支持,则返回 ERR_PTR(-ENODEV)。

     这里假设按照一般情况,将debugfs挂载到/sys/kernel/debug/路径下,命令如下:

    sudo mount -t debugfs none /sys/kernel/debug

    则ideapad_debugfs_init函数的实际作用是,在/sys/kernel/debug/下创建了ideapad文件夹,其中包含了cfg文件和status文件。

    回到ideapad_debugfs_init函数

    1. static void ideapad_debugfs_init(struct ideapad_private *priv)
    2. {
    3. struct dentry *dir;
    4. dir = debugfs_create_dir("ideapad", NULL);
    5. priv->debug = dir;
    6. debugfs_create_file("cfg", 0444, dir, priv, &debugfs_cfg_fops);
    7. debugfs_create_file("status", 0444, dir, priv, &debugfs_status_fops);
    8. }
    9. static void ideapad_debugfs_exit(struct ideapad_private *priv)
    10. {
    11. debugfs_remove_recursive(priv->debug);
    12. priv->debug = NULL;
    13. }

    debugfs_cfg_fops和debugfs_status_fops的定义直接搜索是搜不到的,因为使用了字符串拼接。在include/linux/seq.h中:

    1. #define DEFINE_SHOW_ATTRIBUTE(__name) \
    2. static int __name ## _open(struct inode *inode, struct file *file) \
    3. { \
    4. return single_open(file, __name ## _show, inode->i_private); \
    5. } \
    6. \
    7. static const struct file_operations __name ## _fops = { \
    8. .owner = THIS_MODULE, \
    9. .open = __name ## _open, \
    10. .read = seq_read, \
    11. .llseek = seq_lseek, \
    12. .release = single_release, \
    13. }

    因此,将DEFINE_SHOW_ATTRIBUTE(debugfs_status)展开来,具体内容为:

    1. static int __debugfs_status_open(struct inode *inode, struct file *file)
    2. {
    3. rerurn single_open(file, debugfs_status_show, inode->i_private);
    4. }
    5. static const struct file_operations debugfs_status_fops = {
    6. .owner = THIS_MODULE,
    7. .open = debugfs_status_open,
    8. .read = seq_read,
    9. .llseek = seq_lseek,
    10. .release = single_release,
    11. }

    debugfs_status_show函数的代码如下:

    1. static int debugfs_status_show(struct seq_file *s, void *data)
    2. {
    3. struct ideapad_private *priv = s->private;
    4. unsigned long value;
    5. if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL_MAX, &value))
    6. seq_printf(s, "Backlight max: %lu\n", value);
    7. if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL, &value))
    8. seq_printf(s, "Backlight now: %lu\n", value);
    9. if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL_POWER, &value))
    10. seq_printf(s, "BL power value: %s (%lu)\n", value ? "on" : "off", value);
    11. seq_puts(s, "=====================\n");
    12. if (!read_ec_data(priv->adev->handle, VPCCMD_R_RF, &value))
    13. seq_printf(s, "Radio status: %s (%lu)\n", value ? "on" : "off", value);
    14. if (!read_ec_data(priv->adev->handle, VPCCMD_R_WIFI, &value))
    15. seq_printf(s, "Wifi status: %s (%lu)\n", value ? "on" : "off", value);
    16. if (!read_ec_data(priv->adev->handle, VPCCMD_R_BT, &value))
    17. seq_printf(s, "BT status: %s (%lu)\n", value ? "on" : "off", value);
    18. if (!read_ec_data(priv->adev->handle, VPCCMD_R_3G, &value))
    19. seq_printf(s, "3G status: %s (%lu)\n", value ? "on" : "off", value);
    20. seq_puts(s, "=====================\n");
    21. if (!read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &value))
    22. seq_printf(s, "Touchpad status: %s (%lu)\n", value ? "on" : "off", value);
    23. if (!read_ec_data(priv->adev->handle, VPCCMD_R_CAMERA, &value))
    24. seq_printf(s, "Camera status: %s (%lu)\n", value ? "on" : "off", value);
    25. seq_puts(s, "=====================\n");
    26. if (!eval_gbmd(priv->adev->handle, &value))
    27. seq_printf(s, "GBMD: %#010lx\n", value);
    28. if (!eval_hals(priv->adev->handle, &value))
    29. seq_printf(s, "HALS: %#010lx\n", value);
    30. return 0;
    31. }

    将DEFINE_SHOW_ATTRIBUTE(debugfs_cfg)展开来,具体内容为: 

    1. static int __debugfs_cfg_open(struct inode *inode, struct file *file)
    2. {
    3. rerurn single_open(file, debugfs_cfg_show, inode->i_private);
    4. }
    5. static const struct file_operations debugfs_cfg_fops = {
    6. .owner = THIS_MODULE,
    7. .open = debugfs_cfg_open,
    8. .read = seq_read,
    9. .llseek = seq_lseek,
    10. .release = single_release,
    11. }

     debugfs_cfg_show函数的代码如下:

    1. static int debugfs_cfg_show(struct seq_file *s, void *data)
    2. {
    3. struct ideapad_private *priv = s->private;
    4. seq_printf(s, "_CFG: %#010lx\n\n", priv->cfg);
    5. seq_puts(s, "Capabilities:");
    6. if (test_bit(CFG_CAP_BT_BIT, &priv->cfg))
    7. seq_puts(s, " bluetooth");
    8. if (test_bit(CFG_CAP_3G_BIT, &priv->cfg))
    9. seq_puts(s, " 3G");
    10. if (test_bit(CFG_CAP_WIFI_BIT, &priv->cfg))
    11. seq_puts(s, " wifi");
    12. if (test_bit(CFG_CAP_CAM_BIT, &priv->cfg))
    13. seq_puts(s, " camera");
    14. if (test_bit(CFG_CAP_TOUCHPAD_BIT, &priv->cfg))
    15. seq_puts(s, " touchpad");
    16. seq_puts(s, "\n");
    17. seq_puts(s, "Graphics: ");
    18. switch (priv->cfg & 0x700) {
    19. case 0x100:
    20. seq_puts(s, "Intel");
    21. break;
    22. case 0x200:
    23. seq_puts(s, "ATI");
    24. break;
    25. case 0x300:
    26. seq_puts(s, "Nvidia");
    27. break;
    28. case 0x400:
    29. seq_puts(s, "Intel and ATI");
    30. break;
    31. case 0x500:
    32. seq_puts(s, "Intel and Nvidia");
    33. break;
    34. }
    35. seq_puts(s, "\n");
    36. return 0;
    37. }

    和sysfs一样,其中用到的接口函数在单独一个会目中详细分析。

    至此,ideapad-laptop.c中debugfs部分的代码就全部分析完了。

  • 相关阅读:
    写论文有哪些注意事项呢?
    HTML静态网页成品作业(HTML+CSS)——非遗昆曲介绍设计制作(1个页面)
    vue3学习(九)--- keep-alive缓存组件
    3.5 动态定位shellcode
    Unity与C#
    “沉迷”学习,神奇的“峰终定律”
    测试外包服务 | 从人员外包到测试工具、测试平台,提供全方位的测试解决方案~
    12.0、C语言——实用调试技巧
    docker部署frp穿透内网
    只需100GB内存,让Falcon 180B在你的电脑上起飞
  • 原文地址:https://blog.csdn.net/phmatthaus/article/details/128078328