解决一个驱动代码解耦合问题
之前解决的项目LCD设备兼容问题,在 a.c 文件里面定义了一个变量,然后在 b.c 里面使用 extern
声明引用这个变量,通过这种方法可以在b.c中使用在a.c 里面初始化的变量。
但是这中情况就会引起一个问题,就是驱动代码之间耦合了,这也违背了驱动代码 高内聚、低耦合的思想。
所以,这篇文章就是讨论解决这个问题的。
之前写的文章
1、先说说问题产生的本质
在 a.c 驱动文件中,我会根据 dts 文件的配置挂载一个platform 驱动,这个驱动获取dts文件的 gpio口信息,申请gpio口,并赋值给 g_lcm_power
变量。
代码如下
dts文件
panel: panel@0 {
compatible = "hx8279d";
gpio_lcd_pwr_en = <&pio 47 0>;
status = "okay";
};
驱动文件
static const struct of_device_id lcm_platform_of_match[] = {
{
.compatible = "hx8279d",
.data = 0,
}, {
/* sentinel */
}
};
MODULE_DEVICE_TABLE(of, platform_of_match);
static int lcm_platform_probe(struct platform_device *pdev)
{
const struct of_device_id *id;
enum of_gpio_flags flags;
int ret;
struct device_node *node = pdev->dev.of_node;
PRINTFx("[Kernel/LCM] lcm_platform_probe() enter\n");
id = of_match_node(lcm_platform_of_match, pdev->dev.of_node);
if (!id)
return -ENODEV;
g_lcm_power = of_get_named_gpio_flags(node, "gpio_lcd_pwr_en", 0, &flags);
if (!gpio_is_valid(g_lcm_power)) {
dev_err(&pdev->dev, "invalid en gpio%d\n", g_lcm_power);
}
ret = devm_gpio_request(&pdev->dev, g_lcm_power, "gpio_lcd_pwr_en");
if (ret) {
dev_err(&pdev->dev,
"failed to request GPIO%d for relay-en-gpio\n",
g_lcm_power);
return -EINVAL;
}
return 0;
}
static struct platform_driver lcm_driver = {
.probe = lcm_platform_probe,
.driver = {
.name = "hx8279d",
.owner = THIS_MODULE,
.of_match_table = lcm_platform_of_match,
},
};
static int __init lcm_init(void)
{
PRINTFx("[Kernel/LCM] lcm_init() probe enter\n");
/*
if (platform_driver_register(&lcm_driver)) {
PRINTFx("LCM: failed to register this driver!\n");
return -ENODEV;
}
*/
return 0;
}
static void __exit lcm_exit(void)
{
platform_driver_unregister(&lcm_driver);
}
late_initcall(lcm_init);
module_exit(lcm_exit);
MODULE_AUTHOR("mediatek");
MODULE_DESCRIPTION("LCM display subsystem driver");
MODULE_LICENSE("GPL");
a.c 文件 和 b.c 文件的只能执行一个lcm 驱动,具体执行哪个驱动是在lk判断硬件接了哪一个硬件模组,所以我们在实现驱动代码的时候,a.c驱动文件和b.c驱动文件都需要具备注册上述说的那个 power gpio代码,用来控制模组的电源。
我的解决办法是
在 a.c 驱动文件中,我会根据 dts 文件的配置挂载一个platform 驱动,这个驱动获取dts文件的 gpio口信息,申请gpio口,并赋值给 g_lcm_power
变量。
因为a.c的platform驱动我是默认每次开机都会加载。
在b.c驱动文件中,我使用 extern int g_lcm_power;
来声明这个变量,这样做之后,如果在lk识别到b.c的驱动,这个变量也可以正常使用。
2、什么是高内聚、低耦合?
这是之前写的一篇文章,我觉得解释的比较不错了。
3、如何解决这样的问题?
如何解决,也就是说我们要对驱动代码进行解耦合。
因为我们代码中就只对一个对GPIO口的控制,如果脱离DTS的注册,直接在驱动文件里面对这个GPIO口进行操作的话,理论上就可以解决耦合的问题了。
这部分可以去查一下下面这个函数
gpio_direction_output
测试看看如果在不申请的情况下是否可以使用。
第二种情况就还是使用dts来匹配
dts改成如下
panel: panel@0 {
/*compatible = "hx8279d";*/
gpio_lcd_pwr_en = <&pio 47 0>;
status = "okay";
};
在 a.c 和 b.c 驱动中,同时使用如下代码申请gpio口,linux的dts是一个很不错组织结构,也有很多函数来获取dts中的文件。
想研究dts的同学,可以看看这个目录下的内容,对大家调试非常有帮助。
static void lcm_init_power(void)
{
struct device_node *panel_nd;
int ret;
enum of_gpio_flags flags;
PRINTFx("[Kernel/LCM] lcm_init_power() enter\n");
/*查找整个dts文件,找到panel,前面是NULL就是让这个函数查找整个dts*/
panel_nd = of_find_node_by_name(NULL, "panel");
if(!panel_nd){
PRINTFx("Can't file panel_nd node\n");
return;
}
/*获取gpio_lcd_pwr_en属性信息*/
g_lcm_power = of_get_named_gpio_flags(panel_nd, "gpio_lcd_pwr_en", 0, &flags);
PRINTFx("1212121g_lcm_power=%d\n", g_lcm_power);
if (!gpio_is_valid(g_lcm_power)) {
PRINTFx("invalid en gpio%d\n", g_lcm_power);
return;
}
ret = gpio_request( g_lcm_power, "gpio_lcd_pwr_en");
if (ret) {
PRINTFx("failed to request GPIO%d for relay-en-gpio\n",g_lcm_power);
return;
}
PRINTFx("[Kernel/LCM] lcm_init_power() end\n");
return;
#ifndef BUILD_LK
PRINTFx("[Kernel/LCM] lcm_init() enter\n");
#endif
}