Linux字符设备open函数中获取平台设备私有数据的方法
Linux平台驱动与字符驱动数据传递问题解答
核心问题解决方法
你的架构思路合理,核心问题是未正确从字符设备open函数中获取通过device_create传入的私有数据。以下是具体解决步骤:
1. 添加设备匹配函数
在leds.c中新增用于通过次设备号查找对应struct device的匹配函数:
static int match_minor(struct device *dev, void *data) { int target_minor = *(int *)data; return MINOR(dev->devt) == target_minor; }
2. 修改led_open函数获取私有数据
更新leds.c中的led_open函数,实现私有数据的获取与初始化调用:
static int led_open(struct inode *inode, struct file *filp) { int err, minor; struct device *dev; struct drv_priv *priv; if (!inode || !filp) return -EINVAL; if (!alpha_led_ops.inited || !alpha_led_ops.alpha_led_init) return -ENODEV; minor = MINOR(inode->i_rdev); // 通过次设备号查找对应设备结构 dev = class_find_device(led_class, NULL, &minor, match_minor); if (!dev) return -ENODEV; // 获取关联的私有数据 priv = dev_get_drvdata(dev); if (!priv) { put_device(dev); return -EINVAL; } // 执行LED GPIO初始化 err = alpha_led_ops.alpha_led_init(priv); if (err) { put_device(dev); return err; } // 将私有数据保存到file结构,方便后续读写/ioctl操作 filp->private_data = priv; put_device(dev); return 0; }
架构优化建议
- 合并驱动模块:无需将平台驱动与字符驱动拆分为两个独立模块,通常平台驱动内部直接注册字符设备即可,减少模块间依赖,数据传递更直接。
- 调整初始化时机:
alpha_led_init更适合在probe阶段执行(设备匹配成功后立即初始化GPIO),而非等到用户空间打开设备时。这样可以避免重复初始化,也更符合驱动初始化的设计逻辑。
修改后的probe函数示例:
static int alpha_led_probe(struct platform_device *pdev) { int err, gpio; const char *status = NULL; struct drv_priv *priv = NULL; struct device_node *np = pdev->dev.of_node; if (!np) return -EINVAL; err = of_property_read_string(np, "status", &status); if (err || strcmp(status, "okay") != 0) return -EINVAL; gpio = of_get_named_gpio(np, "led-gpio", 0); if (gpio < 0) return gpio; priv = devm_kzalloc(&pdev->dev, sizeof(struct drv_priv), GFP_KERNEL); if (!priv) return -ENOMEM; platform_set_drvdata(pdev, priv); priv->led_gpio = gpio; // 直接在probe阶段完成GPIO初始化 err = alpha_led_init(priv); if (err) return err; return create_led_device_node(led_count++, np->name, priv); }
此时led_open函数只需做基础检查:
static int led_open(struct inode *inode, struct file *filp) { int minor; struct device *dev; struct drv_priv *priv; if (!inode || !filp) return -EINVAL; minor = MINOR(inode->i_rdev); dev = class_find_device(led_class, NULL, &minor, match_minor); if (!dev) return -ENODEV; priv = dev_get_drvdata(dev); if (!priv) { put_device(dev); return -EINVAL; } filp->private_data = priv; put_device(dev); return 0; }
原代码其他注意点
alpha_led_remove函数中gpio_free的调用逻辑正确,需保留。- 全局变量
led_count在多设备热插拔场景下可能导致次设备号冲突,建议改用动态分配方式管理。
内容的提问来源于stack exchange,提问作者candylife9
相关产品推荐
相关产品推荐

