解決一個(gè)驅(qū)動(dòng)代碼解耦合問(wèn)題
之前解決的項(xiàng)目LCD設(shè)備兼容問(wèn)題,在 a.c 文件里面定義了一個(gè)變量,然后在 b.c 里面使用 extern聲明引用這個(gè)變量,通過(guò)這種方法可以在b.c中使用在a.c 里面初始化的變量。

但是這中情況就會(huì)引起一個(gè)問(wèn)題,就是驅(qū)動(dòng)代碼之間耦合了,這也違背了驅(qū)動(dòng)代碼 高內(nèi)聚、低耦合的思想。
所以,這篇文章就是討論解決這個(gè)問(wèn)題的。
之前寫(xiě)的文章
1、先說(shuō)說(shuō)問(wèn)題產(chǎn)生的本質(zhì)
在 a.c 驅(qū)動(dòng)文件中,我會(huì)根據(jù) dts 文件的配置掛載一個(gè)platform 驅(qū)動(dòng),這個(gè)驅(qū)動(dòng)獲取dts文件的 gpio口信息,申請(qǐng)gpio口,并賦值給 g_lcm_power變量。
代碼如下
dts文件
?panel:?panel@0?{
??compatible?=?"hx8279d";
??gpio_lcd_pwr_en?=?<&pio?47?0>;
??status?=?"okay";
?};
驅(qū)動(dòng)文件
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 文件的只能執(zhí)行一個(gè)lcm 驅(qū)動(dòng),具體執(zhí)行哪個(gè)驅(qū)動(dòng)是在lk判斷硬件接了哪一個(gè)硬件模組,所以我們?cè)趯?shí)現(xiàn)驅(qū)動(dòng)代碼的時(shí)候,a.c驅(qū)動(dòng)文件和b.c驅(qū)動(dòng)文件都需要具備注冊(cè)上述說(shuō)的那個(gè) power gpio代碼,用來(lái)控制模組的電源。
我的解決辦法是
在 a.c 驅(qū)動(dòng)文件中,我會(huì)根據(jù) dts 文件的配置掛載一個(gè)platform 驅(qū)動(dòng),這個(gè)驅(qū)動(dòng)獲取dts文件的 gpio口信息,申請(qǐng)gpio口,并賦值給 g_lcm_power變量。
因?yàn)閍.c的platform驅(qū)動(dòng)我是默認(rèn)每次開(kāi)機(jī)都會(huì)加載。
在b.c驅(qū)動(dòng)文件中,我使用 extern int g_lcm_power;來(lái)聲明這個(gè)變量,這樣做之后,如果在lk識(shí)別到b.c的驅(qū)動(dòng),這個(gè)變量也可以正常使用。
2、什么是高內(nèi)聚、低耦合?
這是之前寫(xiě)的一篇文章,我覺(jué)得解釋的比較不錯(cuò)了。
3、如何解決這樣的問(wèn)題?
如何解決,也就是說(shuō)我們要對(duì)驅(qū)動(dòng)代碼進(jìn)行解耦合。
因?yàn)槲覀兇a中就只對(duì)一個(gè)對(duì)GPIO口的控制,如果脫離DTS的注冊(cè),直接在驅(qū)動(dòng)文件里面對(duì)這個(gè)GPIO口進(jìn)行操作的話(huà),理論上就可以解決耦合的問(wèn)題了。
這部分可以去查一下下面這個(gè)函數(shù)
gpio_direction_output
測(cè)試看看如果在不申請(qǐng)的情況下是否可以使用。
第二種情況就還是使用dts來(lái)匹配
dts改成如下
?panel:?panel@0?{
??/*compatible?=?"hx8279d";*/
??gpio_lcd_pwr_en?=?<&pio?47?0>;
??status?=?"okay";
?};
在 a.c 和 b.c 驅(qū)動(dòng)中,同時(shí)使用如下代碼申請(qǐng)gpio口,linux的dts是一個(gè)很不錯(cuò)組織結(jié)構(gòu),也有很多函數(shù)來(lái)獲取dts中的文件。
想研究dts的同學(xué),可以看看這個(gè)目錄下的內(nèi)容,對(duì)大家調(diào)試非常有幫助。

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");
????/*查找整個(gè)dts文件,找到panel,前面是NULL就是讓這個(gè)函數(shù)查找整個(gè)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
}


