• Linux驱动调试:增加文件节点属性


    在调试linux驱动的时候,经常需要用户层和内核态进行交互,比较常用的方法是ioctl和文件节点,这里介绍一下在设备驱动增加文件节点的常见方法。

    (1)module_param方式

    可以在驱动使用函数module_param来设置参数,本意就是设置加载驱动的时候可以传入哪些参数,代码示例如下:

    1. static int debug;
    2. module_param(debug, int, 0644);
    3. MODULE_PARM_DESC(debug, "debug level (0-3)");

    设置上述参数之后,会在对应的module下面生成文件节点,例如lt6911uxc:

    /sys/module/lt6911uxc/parameters/debug
    

    (2)proc文件节点

    可以在/proc/目录下生成对应的文件节点,示例如下:

    1. void lt7911uxc_init_procfs(struct lt7911uxc *lt7911uxc)
    2. {
    3. struct proc_dir_entry *parent;
    4. struct device *dev = <7911uxc->i2c_client->dev;
    5. g_lt7911uxc = lt7911uxc;
    6. g_lt7911uxc->crc = LT7911UXC_CRC;
    7. parent = proc_mkdir("lt7911uxc", NULL);
    8. if (!parent) {
    9. dev_err(dev, "lt7911uxc init procfs mkdir fail!");
    10. return;
    11. }
    12. proc_create("crc-set", S_IWUSR | S_IWGRP, parent, &set_crc_fops);
    13. dev_info(dev, "-- lt7911uxc_init_procfs --");
    14. }
    15. static ssize_t lt7911uxc_crc_write(struct file *file, const char __user *buffer,
    16. size_t count, loff_t *pos)
    17. {
    18. u8 data[3]= { 0xff };
    19. const size_t size = sizeof(data);
    20. struct device *dev = &g_lt7911uxc->i2c_client->dev;
    21. unsigned long val;
    22. dev_info(dev, "-- lt7911uxc crc write start --\n");
    23. if (count > size)
    24. return -EINVAL;
    25. if (copy_from_user(data, buffer, count))
    26. return -EFAULT;
    27. val = simple_strtoul(data, NULL, 16);
    28. g_lt7911uxc->crc = val;
    29. dev_info(dev, "-- lt7911uxc_crc_write: %x --", g_lt7911uxc->crc);
    30. return count;
    31. }
    32. static ssize_t lt7911uxc_crc_read(struct file *fd,
    33. char __user *buf_, size_t size, loff_t *offset)
    34. {
    35. u16 ver = 0;
    36. u8 out[7] = {0};// one byte max value in hex is "255".
    37. ssize_t len = 0;
    38. ver = g_lt7911uxc->crc;
    39. len = sizeof(out) - *offset;
    40. if (len < 0)
    41. len = 0;
    42. snprintf(out, sizeof(out), "%x\n", ver);
    43. if (copy_to_user(buf_, out, len) ) {
    44. pr_err("copy to user failed");
    45. return -EFAULT;
    46. }
    47. *offset += len;
    48. pr_info("-- fw_version_read --, len: %zd\n", len);
    49. return len;
    50. }
    51. static const struct proc_ops set_crc_fops = {
    52. .proc_write = lt7911uxc_crc_write,
    53. .proc_read = lt7911uxc_crc_read,
    54. };

    通过函数proc_mkdir在/proc/目录下创建一个目录,通过proc_create函数创建文件节点,再实现对应的节点的读写函数即可。

    例如上述例子,可以通过如下命令操作:

    1. cat /proc/lt7911uxc/crc-set
    2. echo 1 > /proc/lt7911uxc/crc-set

    (3)class文件节点

    创建class文件节点。如下示例,在sys/class的目录下创建max96714的目录,在max96714目录下再创建max96714_state目录,后面生成的属性都会在这个目录下。

    1. static int max96714_create_class_attr(struct max96714 *max96714)
    2. {
    3. int ret = 0;
    4. struct device *dev = &max96714->client->dev;
    5. max96714->class = class_create(THIS_MODULE, "max96714");
    6. if (IS_ERR(max96714->class)) {
    7. ret = -ENOMEM;
    8. dev_err(dev, "failed to create max96714 class!\n");
    9. return ret;
    10. }
    11. max96714->classdev = device_create_with_groups(max96714->class, dev,
    12. MKDEV(0, 0), max96714,
    13. max96714_groups, "max96714_state");
    14. if (IS_ERR(max96714->classdev)) {
    15. ret = PTR_ERR(max96714->classdev);
    16. dev_err(dev, "Failed to create device\n");
    17. goto err;
    18. }
    19. ret = devm_add_action_or_reset(dev, max96714_unregister_class_device, max96714);
    20. if (ret)
    21. dev_err(dev, "device unregister max96714 class failed!\n");
    22. return ret;
    23. err:
    24. class_destroy(max96714->class);
    25. return ret;
    26. }
    27. static void max96714_remove_class_attr(struct max96714 *max96714)
    28. {
    29. class_destroy(max96714->class);
    30. }
    1. static void max96714_unregister_class_device(void *data)
    2. {
    3. struct max96714 *max96714 = data;
    4. struct device *dev = max96714->classdev;
    5. device_unregister(dev);
    6. }
    7. static ssize_t mcu_rise_show(struct device *dev,
    8. struct device_attribute *attr, char *buf)
    9. {
    10. struct max96714 *max96714 = dev_get_drvdata(dev);
    11. u8 checksum = 0;
    12. int ret;
    13. u8 rise_val = 0;
    14. ...
    15. return snprintf(buf, PAGE_SIZE, "%x\n", rise_val);
    16. }
    17. static ssize_t mcu_rise_store(struct device *dev,
    18. struct device_attribute *attr,
    19. const char *buf, size_t count)
    20. {
    21. struct max96714 *max96714 = dev_get_drvdata(dev);
    22. uint8_t value, value_l;
    23. u8 checksum = 0;
    24. int ret;
    25. if (!max96714)
    26. return -EINVAL;
    27. sscanf(buf, "%d %d", &value, &value_l);
    28. ...
    29. return count;
    30. }
    31. static DEVICE_ATTR_RW(mcu_rise);
    32. static struct attribute *max96714_attrs[] = {
    33. &dev_attr_mcu_rise.attr,
    34. NULL
    35. };
    36. ATTRIBUTE_GROUPS(max96714);

    (4)其他方式

    其他的创建方式还有sysfs_create_files,device_create_file等方式,这里不再赘述。

  • 相关阅读:
    【附源码】Python计算机毕业设计团结里小区疫情防控系统
    坚鹏:中国邮政储蓄银行金融科技前沿技术发展与应用场景第4期
    Hadoop 3.2.4 集群搭建详细图文教程
    JavaScript 中关于 ?? 和 || 的区别和相似性
    MongoDB-1入门介绍
    css3实现无缝滚动,鼠标经过暂停
    Python正则表达式
    SQLServer连接表
    OpenCV读取输入图像的指定区域到输出图像的指定区域
    大数据Flink(七十三):SQL的滚动窗口(TUMBLE)
  • 原文地址:https://blog.csdn.net/qq_34341546/article/details/133687101