# gpio 对linux c app里面的一个gpio操作云里雾里半天,是时候好好理理了。 * https://www.kernel.org/doc/Documentation/gpio/sysfs.txt * https://www.kernel.org/doc/Documentation/gpio/gpio-legacy.txt 主要是这gpio number是如何同pin number 一一对应的。 ```shell 256 root@mxj-zbcs-310:#tree /sys/class/gpio . |-- export |-- gpio120 -> ../../devices/soc.0/1c20800.pinctrl/gpio/gpio120 |-- gpio228 -> ../../devices/soc.0/1c20800.pinctrl/gpio/gpio228 |-- gpio229 -> ../../devices/soc.0/1c20800.pinctrl/gpio/gpio229 |-- gpio232 -> ../../devices/soc.0/1c20800.pinctrl/gpio/gpio232 |-- gpio32 -> ../../devices/soc.0/1c20800.pinctrl/gpio/gpio32 |-- gpio33 -> ../../devices/soc.0/1c20800.pinctrl/gpio/gpio33 |-- gpio359 -> ../../devices/soc.0/1f02c00.pinctrl/gpio/gpio359 |-- gpio64 -> ../../devices/soc.0/1c20800.pinctrl/gpio/gpio64 |-- gpiochip0 -> ../../devices/soc.0/1c20800.pinctrl/gpio/gpiochip0 |-- gpiochip1024 -> ../../devices/soc.0/pinctrl.1/gpio/gpiochip1024 |-- gpiochip352 -> ../../devices/soc.0/1f02c00.pinctrl/gpio/gpiochip352 `-- unexport ``` 奇怪,今天发现`sys/class/gpio` 下面的gpio没有了。只剩下`gpiochip`了。原来需要在应用export 对应io number。 ```shell fd = open("/sys/class/gpio/export", O_WRONLY); len = snprintf(buffer, sizeof(buffer), "%d", pin); if (write(fd, buffer, len) < 0) { } ``` 这里的`export`和`unport`以及之后对 io number value的`read write` 操作都是在`gpiolibc` 上实现的。 ```c snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/value", pin); fd = open(path, O_WRONLY); if (fd < 0) { } if (write(fd, &values_str[value == 0 ? 0 : 1], 1) < 0) { } ``` 接下来需要理一理`gpiolibc` 的实现,`gpiolibc` 所有操作都是基于`gpio_desc *desc` 变量。改变量通过`gpio_desc` 结构体定义这里的数组。数组索引就对应我们这里的io number。 ```c static struct gpio_desc gpio_desc[ARCH_NR_GPIOS]; ``` 这个结构体的实现主要是是通过`gpio_chip`来操作的,例如`gpiod_set_value` 是通过`gpio_desc` 获取到`gpio_chip` 然后在通过`gpio_chip->set()` 实现IO的读写。 ```c static void gpiod_set_value(struct gpio_desc *desc, int value) { struct gpio_chip *chip; if (!desc) return; chip = desc->chip; /* Should be using gpio_set_value_cansleep() */ WARN_ON(chip->can_sleep); trace_gpio_value(desc_to_gpio(desc), 0, value); if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) _gpio_set_open_drain_value(desc, value); else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) _gpio_set_open_source_value(desc, value); else chip->set(chip, gpio_chip_hwgpio(desc), value); } ``` 所以对于`gpio_chip` 的初始化就很重要了。然而我并没有找。 ```c static inline u32 sunxi_data_reg(u16 pin) { u8 bank = pin / PINS_PER_BANK; u32 offset = bank * BANK_MEM_SIZE; offset += DATA_REGS_OFFSET; offset += pin % PINS_PER_BANK / DATA_PINS_PER_REG * 0x04; return round_down(offset, 4); } #define PINS_PER_BANK 32 //其中 PINS_PER_BANK 为32 ``` 对于如上计算的`bank` `1-7`依次对应 `PB-PH`。 `8` 对应`PL` ![](http://docs.leconiot.com/lib/exe/fetch.php?media=jaysnote:images:cpux_port.png) ![](http://docs.leconiot.com/lib/exe/fetch.php?media=jaysnote:images:cpux_port_l.png) >Page.396 3.21. Port Controller(CPUx-PORT) `pin % PINS_PER_BANK` 对于Port 尾号,例如pin=32,对应 `PB0` ```c #define IO_NUMBER_CARD_READER0 228 //!< PH4 (IC-D0_L) 读卡器信号0 #define IO_NUMBER_CARD_READER1 229 //!< PH5 (IC-D1_L) 读卡器信号1 #define IO_NUMBER_DOOR_CTRL 33 //!< PB1 (Core_OPEN)门禁控制 #define IO_NUMBER_DOOR_CHECK 64 //!< PC0 (button)按键选择(非门控制) #define IO_NUMBER_USER_KEY 32 //!< PB0 (Userkey)用户按键 #define IO_NUMBER_A64_SHUTDOWN 359 //!< PL7 (Core_SHUTDOWN) 用MCU 控制 A64 软件开关机 #define IO_NUMBER_BODY_RADAR 232 //!< PH8 (Body_Sensor)人体雷达 #define IO_NUMBER_A64_SENSE //!< PH4 (Core_SENSE) 未知功能 ``` shell 脚本转换 ```shell num2name(){ local num=$1 local h=$[$num/32] local l=$[$num%32] local H=$(echo -e `printf '\\\x%02x' $[0x41+h]`) echo P$H$l } name2num(){ local name=$1 name=${name#P} local H=${name:0:1} local l=${name:1} local h=$[`printf '%d' \'$H`-0x41] echo $[h*32+l] } ```