linux GPIO子系統核心原始碼追蹤
提到GPIO 子系統,我們先來追蹤下GPIO 子系統的介面函式是如何新增到核心中的?
初次追蹤GPIO 子系統原始碼,邏輯有點亂,後續再次梳理;但有1點已經很明確:GPIO 子系統初始化 裝置的gpio PIN引腳,已有初步的瞭解和認識;
核心編譯時,已將GPIO 子系統編譯進核心,所以驅動程式若想要要使用GPIO 子系統介面函式,只需按編寫驅動程式一般步驟、GPIO 子系統介面函式呼叫順序,進行初始化即可。
參考部落格:https://blog.csdn.net/kuangzuxiaoN/article/details/55517931,在此表示感謝
【01】首先檢視那些 gpio 檔案被編譯進核心
ls -l /linux-3.5/drivers/gpio/*.o,
"/linux-3.5/drivers/gpio/gpio-samsung.c"
【02】 core_initcall() 函式的入口呼叫函式
在該檔案中,找到 core_initcall() 函式的入口呼叫函式;
3264 core_initcall(samsung_gpiolib_init); 3265 3266 int s3c_gpio_cfgpin(unsigned int pin, unsigned int config) 3267 { 3268 struct samsung_gpio_chip *chip = samsung_gpiolib_getchip(pin); 3269 unsigned long flags;
【03】檢視函式 samsung_gpiolib_init()
檢視函式 samsung_gpiolib_init(),找到 exynos4412 的gpio初始化的位置;
2972 /* TODO: cleanup soc_is_* */ 2973 static __init int samsung_gpiolib_init(void) 2974 { 2975 struct samsung_gpio_chip *chip; 2976 int i, nr_chips; 2977 #if defined(CONFIG_ARCH_EXYNOS4) || defined(CONFIG_SOC_EXYNOS5250) 2978 void __iomem *gpio_base1, *gpio_base2, *gpio_base3, *gpio_base4; 2979 #endif 2980 int group = 0; 2981 2982 samsung_gpiolib_set_cfg(samsung_gpio_cfgs, ARRAY_SIZE(samsung_gpio_cfg s)); 2983 2984 if (soc_is_s3c24xx()) { 2985 s3c24xx_gpiolib_add_chips(s3c24xx_gpios, 2986 ARRAY_SIZE(s3c24xx_gpios), S3C24XX_VA_GPIO); 2987 } else if (soc_is_s3c64xx()) { 2988 samsung_gpiolib_add_2bit_chips(s3c64xx_gpios_2bit, 。。。。。。 // 【如下為 exynos4x21 的初始化位置:soc_is_exynos4412()】 。。。。。。 // 【chip = chip_p = exynos4x12_gpios_1;】 3044 } else if (soc_is_exynos4210() || soc_is_exynos4212() || 3045 soc_is_exynos4412()) { 3046 #ifdef CONFIG_ARCH_EXYNOS4 3047 struct samsung_gpio_chip *chip_p; 3048 int offset = 0; 3049 int group1 = 0; 3050 3051 /* gpio part1 */ 3052 gpio_base1 = ioremap(EXYNOS4_PA_GPIO1, SZ_4K); 3053 if (gpio_base1 == NULL) { 3054 pr_err("unable to ioremap for gpio_base1\n"); 3055 goto err_ioremap1; 3056 } 3057 3058 if (soc_is_exynos4210()) { 3059 chip = chip_p = exynos4210_gpios_1; 3060 nr_chips = ARRAY_SIZE(exynos4210_gpios_1); 3061 } else { // 【chip = chip_p = exynos4x12_gpios_1;】 3062 chip = chip_p = exynos4x12_gpios_1; 3063 nr_chips = ARRAY_SIZE(exynos4x12_gpios_1); 3064 } 3065 3066 for (i = 0; i < nr_chips; i++, chip++) { 3067 if (!chip->config) { 3068 chip->config = &exynos_gpio_cfg; 3069 if (chip->group) 3070 group = chip->group; 3071 chip->group = group++; 3072 } 3073 3074 if (chip->base) 3075 offset = (u32)chip->base; 3076 chip->base = gpio_base1 + offset; 3077 offset += 0x20; 3078 3079 exynos_gpiolib_attach_ofnode(chip, EXYNOS4_PA_GPIO1, 0); 3080 } 3081 samsung_gpiolib_add_4bit_chips(chip_p, nr_chips, gpio_base1); 3082 group1 = group; 3083 3084 /* gpio part2 */ 3085 gpio_base2 = ioremap(EXYNOS4_PA_GPIO2, SZ_4K); 3086 if (gpio_base2 == NULL) { 3087 pr_err("unable to ioremap for gpio_base2\n"); 3088 goto err_ioremap2; 3089 } 3090 3091 if (soc_is_exynos4210()) { 3092 chip = chip_p = exynos4210_gpios_2; 3093 nr_chips = ARRAY_SIZE(exynos4210_gpios_2); 3094 } else { 3095 chip = chip_p = exynos4x12_gpios_2; 3096 nr_chips = ARRAY_SIZE(exynos4x12_gpios_2); 3097 } 3098 3099 offset = 0; 。。。。。。
【04】找到EXYNOS4412開發平臺的程式碼邏輯
samsung_gpiolib_init() 函式定義了三星EXYNOS系列不同產品的GPIO,我的開發平臺是EXYNOS4412,因此只看這部分就行了,如下所示:
3058 if (soc_is_exynos4210()) {
3059 chip = chip_p = exynos4210_gpios_1;
3060 nr_chips = ARRAY_SIZE(exynos4210_gpios_1);
3061 } else {
3062 chip = chip_p = exynos4x12_gpios_1;
3063 nr_chips = ARRAY_SIZE(exynos4x12_gpios_1);
3064 }
【05】exynos4x12_gpios_1[]; 陣列的定義
注意:chip = chip_p = exynos4x12_gpios_1; 這個結構體,跳轉到exynos4x12_gpios_1定義的地方;
其在核心原始碼目錄下./drivers/gpio/gpio-exynos4.c中:
2229 static struct samsung_gpio_chip exynos4x12_gpios_1[] = {
2230 {
2231 .chip = {
2232 .base = EXYNOS4_GPA0(0),
2233 .ngpio = EXYNOS4_GPIO_A0_NR,
2234 .label = "GPA0",
2235 },
2236 }, {
。。。。。。
。。。。。。
2552 }, {
2553 .base = (void *)0x260,
2554 .chip = {
2555 .base = EXYNOS4X12_GPM0(0),
2556 .ngpio = EXYNOS4X12_GPIO_M0_NR,
2557 .label = "GPM0",
2558 },
2559 }, {
2560 .chip = {
2561 .base = EXYNOS4X12_GPM1(0),
2562 .ngpio = EXYNOS4X12_GPIO_M1_NR,
2563 .label = "GPM1",
2564 },
2565 }, {
2566 .chip = {
2567 .base = EXYNOS4X12_GPM2(0),
2568 .ngpio = EXYNOS4X12_GPIO_M2_NR,
2569 .label = "GPM2",
2570 },
2571 }, {
2572 .chip = {
2573 .base = EXYNOS4X12_GPM3(0),
2574 .ngpio = EXYNOS4X12_GPIO_M3_NR,
2575 .label = "GPM3",
2576 },
2577 }, {
2578 .chip = {
2579 .base = EXYNOS4X12_GPM4(0),
2580 .ngpio = EXYNOS4X12_GPIO_M4_NR,
2581 .label = "GPM4",
2582 },
2583 }, {
2584 .base = (void *)0xC00,
2585 .config = &samsung_gpio_cfgs[9],
。。。。。。
。。。。。。
2611 }, {
2612 .config = &samsung_gpio_cfgs[9],
2613 .irq_base = IRQ_EINT(24),
2614 .chip = {
2615 .base = EXYNOS4_GPX3(0),
2616 .ngpio = EXYNOS4_GPIO_X3_NR,
2617 .label = "GPX3",
2618 .to_irq = samsung_gpiolib_to_irq,
2619 },
2620 },
2621 };
【06】samsung_gpio_chip結構體的定義
先來看這個結構體的定義:samsung_gpio_chip
42 /**
43 * struct samsung_gpio_chip - wrapper for specific implementation of gpio
44 * @chip: The chip structure to be exported via gpiolib.
45 * @base: The base pointer to the gpio configuration registers.
46 * @group: The group register number for gpio interrupt support.
47 * @irq_base: The base irq number.
48 * @config: special function and pull-resistor control information.
49 * @lock: Lock for exclusive access to this gpio bank.
50 * @pm_save: Save information for suspend/resume support.
51 *
52 * This wrapper provides the necessary information for the Samsung
53 * specific gpios being registered with gpiolib.
54 *
55 * The lock protects each gpio bank from multiple access of the shared
56 * configuration registers, or from reading of data whilst another thread
57 * is writing to the register set.
58 *
59 * Each chip has its own lock to avoid any contention between different
60 * CPU cores trying to get one lock for different GPIO banks, where each
61 * bank of GPIO has its own register space and configuration registers.
62 */
63 struct samsung_gpio_chip {
64 struct gpio_chip chip;
65 struct samsung_gpio_cfg *config;
66 struct samsung_gpio_pm *pm;
67 void __iomem *base;
68 int irq_base;
69 int group;
70 spinlock_t lock;
71 #ifdef CONFIG_PM
72 u32 pm_save[5];
73 #endif
74 };
【07】結構體成員 chip結構體gpio_chip的定義
再來看其結構體成員 chip結構體:gpio_chip,如下所示,定義了gpio 操作的大部分函式,比如:
"/linux-3.5/include/asm-generic/gpio.h",檔案中,比較常用的如下:
int (*request)(struct gpio_chip *chip,
int (*direction_input)(struct gpio_chip *chip,
int (*direction_output)(struct gpio_chip *chip,
int (*get)(struct gpio_chip *chip,
int (*set_debounce)(struct gpio_chip *chip,
92 struct gpio_chip {
93 const char *label;
94 struct device *dev;
95 struct module *owner;
96
97 int (*request)(struct gpio_chip *chip,
98 unsigned offset);
99 void (*free)(struct gpio_chip *chip,
100 unsigned offset);
101
102 int (*direction_input)(struct gpio_chip *chip,
103 unsigned offset);
104 int (*get)(struct gpio_chip *chip,
105 unsigned offset);
106 int (*direction_output)(struct gpio_chip *chip,
107 unsigned offset, int value);
108 int (*set_debounce)(struct gpio_chip *chip,
109 unsigned offset, unsigned debounce);
110
111 void (*set)(struct gpio_chip *chip,
112 unsigned offset, int value);
113
114 int (*to_irq)(struct gpio_chip *chip,
115 unsigned offset);
116
117 void (*dbg_show)(struct seq_file *s,
118 struct gpio_chip *chip);
119 int base;
120 u16 ngpio;
121 const char *const *names;
122 unsigned can_sleep:1;
123 unsigned exported:1;
124
125 #if defined(CONFIG_OF_GPIO)
126 /*
127 * If CONFIG_OF is enabled, then all GPIO controllers described in the
128 * device tree automatically may have an OF translation
129 */
130 struct device_node *of_node;
131 int of_gpio_n_cells;
132 int (*of_xlate)(struct gpio_chip *gc,
133 const struct of_phandle_args *gpiospec, u32 *flags);
134 #endif
135 };
【08】再來看exynos4x12_gpios_1[]陣列元素
在這裡我們再回到前面結構體陣列中的元素chip中的成員:GPM4,剛好對應 LED0——4;
分析基地址的數值: .base = EXYNOS4X12_GPM4(0), // 巨集定義
2552 }, {
2553 .base = (void *)0x260,
2554 .chip = {
2555 .base = EXYNOS4X12_GPM0(0),
2556 .ngpio = EXYNOS4X12_GPIO_M0_NR,
2557 .label = "GPM0",
2558 },
2559 }, {
......
2577 }, {
2578 .chip = {
2579 .base = EXYNOS4X12_GPM4(0), // 巨集定義
2580 .ngpio = EXYNOS4X12_GPIO_M4_NR,
2581 .label = "GPM4",
2582 },
2583 }, {
EXYNOS4X12_GPM4(0)的定義如下:
"/linux-3.5/arch/arm/mach-exynos/include/mach/gpio.h"
注意:如下巨集,把每個 GPIO 地址做了一下封裝,根據巨集名字就指導操作那個GPIO;
149 #define EXYNOS4X12_GPM0(_nr) (EXYNOS4X12_GPIO_M0_START + (_nr))
150 #define EXYNOS4X12_GPM1(_nr) (EXYNOS4X12_GPIO_M1_START + (_nr))
151 #define EXYNOS4X12_GPM2(_nr) (EXYNOS4X12_GPIO_M2_START + (_nr))
152 #define EXYNOS4X12_GPM3(_nr) (EXYNOS4X12_GPIO_M3_START + (_nr))
153 #define EXYNOS4X12_GPM4(_nr) (EXYNOS4X12_GPIO_M4_START + (_nr)) // 巨集定義
154
155 #define EXYNOS4_GPX0(_nr) (EXYNOS4_GPIO_X0_START + (_nr))
EXYNOS4X12_GPIO_M4_START,的定義為如下 exynos4_gpio_number 列舉型別的元素:
69 /* EXYNOS4 GPIO bank numbers */
70
71 enum exynos4_gpio_number {
72 EXYNOS4_GPIO_A0_START = 0,
73 EXYNOS4_GPIO_A1_START = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_A0),
74 EXYNOS4_GPIO_B_START = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_A1),
......
89 EXYNOS4X12_GPIO_M3_START = EXYNOS_GPIO_NEXT(EXYNOS4X12_GPIO_M2),
90 EXYNOS4X12_GPIO_M4_START = EXYNOS_GPIO_NEXT(EXYNOS4X12_GPIO_M3), // 巨集定義
91
92 EXYNOS4_GPIO_F0_START = EXYNOS_GPIO_NEXT(EXYNOS4X12_GPIO_M4),
......
115 EXYNOS4_GPIO_Y6_START = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_Y5),
116 EXYNOS4_GPIO_Z_START = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_Y6),
117 };
再到 EXYNOS_GPIO_NEXT() 的定義處:
15 /* Macro for EXYNOS GPIO numbering */
16
17 #define EXYNOS_GPIO_NEXT(__gpio) \
18 ((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 1)
// 注意:##連線符號是把傳遞過來的引數當成字串進行代替
根據以上可知: .base = EXYNOS4X12_GPM4(0),的結果:
因為:
#define EXYNOS4X12_GPM4(_nr) (EXYNOS4X12_GPIO_M4_START + (_nr)) // 巨集定義
EXYNOS4X12_GPIO_M4_START = EXYNOS_GPIO_NEXT(EXYNOS4X12_GPIO_M3),
#define EXYNOS_GPIO_NEXT(__gpio) \
((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 1)
所以,最終:
====》EXYNOS4X12_GPM4(0)
= EXYNOS_GPIO_NEXT(EXYNOS4X12_GPIO_M3) + 0;
= ((EXYNOS4X12_GPIO_M3_START) + (EXYNOS4X12_GPIO_M3_NR) + CONFIG_S3C_GPIO_SPACE + 1) + 0;
即,很顯然, EXYNOS4X12_GPM4(0) 就是:從GPM3的首地址 + GPM3個數 + GPM4的offset就是當前GPM4的IO偏移量;
所以這樣一步一步傳遞,可以得出GPM4的地址。
計算方法可參見:https://blog.csdn.net/s762888517/article/details/9143381
即:89 EXYNOS4X12_GPIO_M3_START = EXYNOS_GPIO_NEXT(EXYNOS4X12_GPIO_M2), 該地址可一直向前查詢呼叫,最終可追溯到記憶體中 表示GPIO的最小地址;
53 #define EXYNOS4X12_GPIO_M3_NR (8)
CONFIG_S3C_GPIO_SPACE 巨集定義,其值是0
【注意】
#define EXYNOS4X12_GPIO_M3_NR (8) 含義是:
其對應GPM3CON控制暫存器,其中可以用作為GPIO分別是GPM3CON[7:0]共8個GPIO。
50 #define EXYNOS4X12_GPIO_M0_NR (8)
51 #define EXYNOS4X12_GPIO_M1_NR (7)
52 #define EXYNOS4X12_GPIO_M2_NR (5) //其對應GPM2CON控制暫存器,其中可以用作為GPIO分別是GPM3CON[4:0]共5個GPIO。
53 #define EXYNOS4X12_GPIO_M3_NR (8)
54 #define EXYNOS4X12_GPIO_M4_NR (8)
【09】GPIO底層的呼叫過程:
接下來再看一下GPIO底層的呼叫過程:
./arch/arm/plat-samsung/include/plat/gpio-cfg.h中定義了這幾個函式
1)/*GPIO引腳功能配置*/
70 /* Defines for generic pin configurations */
71 #define S3C_GPIO_INPUT (S3C_GPIO_SPECIAL(0))
72 #define S3C_GPIO_OUTPUT (S3C_GPIO_SPECIAL(1))
73 #define S3C_GPIO_SFN(x) (S3C_GPIO_SPECIAL(x))
74
75 #define samsung_gpio_is_cfg_special(_cfg) \
76 (((_cfg) & S3C_GPIO_SPECIAL_MARK) == S3C_GPIO_SPECIAL_MARK)
77
78 /**
79 * s3c_gpio_cfgpin() - Change the GPIO function of a pin.
80 * @pin pin The pin number to configure.
81 * @to to The configuration for the pin's function.
82 *
83 * Configure which function is actually connected to the external
84 * pin, such as an gpio input, output or some form of special function
85 * connected to an internal peripheral block.
86 *
87 * The @to parameter can be one of the generic S3C_GPIO_INPUT, S3C_GPIO_OUTPUT
88 * or S3C_GPIO_SFN() to indicate one of the possible values that the helper
89 * will then generate the correct bit mask and shift for the configuration.
......
94 * for (gpio = start; gpio < end; gpio++)
95 * s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
......
100 */
101 extern int s3c_gpio_cfgpin(unsigned int pin, unsigned int to);
s3c_gpio_cfgpin() 函式實現原型:
/linux-3.5/drivers/gpio/gpio-samsung.c
3266 int s3c_gpio_cfgpin(unsigned int pin, unsigned int config)
3267 {
3268 struct samsung_gpio_chip *chip = samsung_gpiolib_getchip(pin);
3269 unsigned long flags;
3270 int offset;
3271 int ret;
3272
3273 if (!chip)
3274 return -EINVAL;
3275
3276 offset = pin - chip->chip.base;
3277
3278 samsung_gpio_lock(chip, flags);
3279 ret = samsung_gpio_do_setcfg(chip, offset, config);
3280 samsung_gpio_unlock(chip, flags);
3281
3282 return ret;
3283 }
3284 EXPORT_SYMBOL(s3c_gpio_cfgpin);
2)/*操作GPIO子系統常用的介面函式*/
在核心原始碼目錄下./include/linux/gpio.h中定義了這幾個函式:
87 static inline bool gpio_is_valid(int number)
88 {
89 return false;
90 }
91
92 static inline int gpio_request(unsigned gpio, const char *label)
93 {
94 return -ENOSYS;
95 }
96
......
103 static inline int gpio_request_one(unsigned gpio,
104 unsigned long flags, const char *label)
105 {
106 return -ENOSYS;
107 }
108
......
114
115 static inline int gpio_request_array(const struct gpio *array, size_t num)
116 {
117 return -ENOSYS;
118 }
119
120 static inline void gpio_free(unsigned gpio)
121 {
122 might_sleep();
123
124 /* GPIO can never have been requested */
125 WARN_ON(1);
126 }
127
......
135
136 static inline void gpio_free_array(const struct gpio *array, size_t num)
137 {
138 might_sleep();
139
140 /* GPIO can never have been requested */
141 WARN_ON(1);
142 }
143
144 static inline int gpio_direction_input(unsigned gpio)
145 {
146 return -ENOSYS;
147 }
148
149 static inline int gpio_direction_output(unsigned gpio, int value)
150 {
151 return -ENOSYS;
152 }
......
179 static inline int gpio_get_value_cansleep(unsigned gpio)
180 {
181 /* GPIO can never have been requested or set as {in,out}put */
182 WARN_ON(1);
183 return 0;
184 }
185
186 static inline void gpio_set_value_cansleep(unsigned gpio, int value)
187 {
188 /* GPIO can never have been requested or set as output */
189 WARN_ON(1);
190 }
191
192 static inline int gpio_export(unsigned gpio, bool direction_may_change)
193 {
194 /* GPIO can never have been requested or set as {in,out}put */
195 WARN_ON(1);
196 return -EINVAL;
197 }
......
220 static inline int gpio_to_irq(unsigned gpio)
221 {
222 /* GPIO can never have been requested or set as input */
223 WARN_ON(1);
224 return -EINVAL;
225 }
226
227 static inline int irq_to_gpio(unsigned irq)
228 {
229 /* irq can never have been returned from gpio_to_irq() */
230 WARN_ON(1);
231 return -EINVAL;
232 }
3)GPIO子系統————驅動初始化一般步驟:
在驅動初始化時,直接呼叫這幾個相關的函式就可以了,
首先,申請GPIO資源,呼叫gpio_request函式;
其次,配置GPIO引腳模式:輸入、輸出還是作其它用,呼叫s3c_gpio_cfgpin函式,這個函式的第二引數選擇S3C_GPIO_INPUT、S3C_GPIO_OUTPUT、S3C_GPIO_SFN(x)三者之一就可以了;
然後,在應用層直接下發操作命令,比如使用ioctl命令進行操作裝置檔案,則核心解析命令碼,再去操作GPIO實現功能;
最後,解除安裝驅動時,記得釋放申請的GPIO,有始有終,這時呼叫gpio_free函式,一個簡單的IO控制就可以這樣完成。
---------------------借鑑部落格:在此表示感謝!!!
作者:kuangzuxiaoN
來源:CSDN
原文:https://blog.csdn.net/kuangzuxiaoN/article/details/55517931
版權宣告:本文為博主原創文章,轉載請附上博文連結!
【遺留問題】
比如:EXYNOS4_GPA1(0),現在只是暫且認為EXYNOS4_GPA1(0)最終指的地址,就是 GPA1_CON暫存器的首地址,還沒真正推算出來。
計算最前面兩個:
1)計算地址:.base = EXYNOS4X12_GPA0(0),
121 #define EXYNOS4_GPA0(_nr) (EXYNOS4_GPIO_A0_START + (_nr))
71 enum exynos4_gpio_number {
72 EXYNOS4_GPIO_A0_START = 0,
所以:EXYNOS4X12_GPA0(0)
= (EXYNOS4_GPIO_A0_START + (_nr))
= 0 + 0 = 0;
2)計算地址:EXYNOS4_GPA1(0)
22 #define EXYNOS4_GPA1(_nr) (EXYNOS4_GPIO_A1_START + (_nr))
71 enum exynos4_gpio_number {
72 EXYNOS4_GPIO_A0_START = 0,
73 EXYNOS4_GPIO_A1_START = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_A0),
22 #define EXYNOS4_GPIO_A0_NR (8)
所以:
#define EXYNOS_GPIO_NEXT(__gpio) \
((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 1)
==》EXYNOS4_GPA1(0)
= (EXYNOS4_GPIO_A1_START + (_nr))
= (EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_A0) + 0);
= (((EXYNOS4_GPIO_A0_START) + (EXYNOS4_GPIO_A0_NR) + CONFIG_S3C_GPIO_SPACE + 1) + 0)
(GPA0首地址 + GPA0個數 + 0 + 1) + GPA0的offset)
= 0 + 8 + 1 + 0
= 9
71 enum exynos4_gpio_number {
72 EXYNOS4_GPIO_A0_START = 0,
73 EXYNOS4_GPIO_A1_START = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_A0),
17 #define EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_A0) \
18 ((EXYNOS4_GPIO_A0_START) + (EXYNOS4_GPIO_A0_NR) + CONFIG_S3C_GPIO_SPACE + 1)
本文GPIO子系統程式碼追蹤,參考如下部落格文章,在此表示感謝,寫的不錯,贊一個。
https://blog.csdn.net/kuangzuxiaoN/article/details/55517931?locationNum=2&fps=1
42 #ifdef CONFIG_GENERIC_GPIO
43
44 #ifdef CONFIG_ARCH_HAVE_CUSTOM_GPIO_H
45 #include <asm/gpio.h>
46 #else
47
48 #include <asm-generic/gpio.h>
標頭檔案區別:
https://blog.csdn.net/lk07828/article/details/44245577?locationNum=10