一、源码分析

从源码分析,这样我们才能精准定位到收发数据的程序位置

1、驱动是如何匹配设备树设备最后走到probe函数的

  以8250串口驱动为例子,如下图所示:
在这里插入图片描述

2、分析8250串口驱动,定位数据收发程序位置

  分析流程如下图所示:
在这里插入图片描述

二、源码修改补丁

commit 1eaa96393d8dc4c8de75e49195fe395a4d45803b
Author: dengjiawen <1411471554@qq.com>
Date:   Mon Feb 5 17:30:47 2024 +0800

    基于RK3288 Android7.1 RS485自动控制收发

diff --git a/kernel/build_bootimg.sh b/kernel/build_bootimg.sh
new file mode 100755
index 0000000000..47946e6c26
--- /dev/null
+++ b/kernel/build_bootimg.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+echo "Start build kernel"
+make ARCH=arm rockchip_defconfig && make ARCH=arm rk3288-evb-android-rk808-edp.img -j64 && cd ..
+if [ $? -eq 0 ]; then
+    echo "Build kernel ok!"
+    echo "start build bootimg"
+    rm -rf out/target/product/rk3288/kernel
+    rm -rf out/target/product/rk3288/boot.img
+    make bootimage -j48
+    ./mkimage.sh ota boot	
+else
+    echo "Build kernel failed!"
+    exit 1
+fi
\ No newline at end of file
diff --git a/kernel/arch/arm/boot/dts/rk3288.dtsi b/kernel/arch/arm/boot/dts/rk3288.dtsi
index 414cb4fbd2..7d2cbacb64 100644
--- a/kernel/arch/arm/boot/dts/rk3288.dtsi
+++ b/kernel/arch/arm/boot/dts/rk3288.dtsi
@@ -544,7 +544,7 @@
                clocks = <&cru SCLK_UART1>, <&cru PCLK_UART1>;
                clock-names = "baudclk", "apb_pclk";
                pinctrl-names = "default";
-               pinctrl-0 = <&uart1_xfer>;
+               pinctrl-0 = <&uart1_xfer &uart1_485>;
                status = "disabled";
        };
 
@@ -2302,6 +2302,10 @@
                        uart1_rts: uart1-rts {
                                rockchip,pins = <5 11 RK_FUNC_1 &pcfg_pull_none>;
                        };
+
+                       uart1_485: uart1-485 {
+                               rockchip,pins = <8 3 RK_FUNC_GPIO &pcfg_pull_none>;
+                       };
                };
diff --git a/kernel/arch/arm/boot/dts/rk3288-evb-android-rk808-edp.dts b/kernel/arch/arm/boot/dts/rk3288-evb-android-rk808-edp.dts
index ca37f35195..07b29ec59d 100644
--- a/kernel/arch/arm/boot/dts/rk3288-evb-android-rk808-edp.dts
+++ b/kernel/arch/arm/boot/dts/rk3288-evb-android-rk808-edp.dts
@@ -752,6 +751,7 @@
 
 &uart1 {
        status = "okay";
+       rs485-enable = <&gpio8 3 GPIO_ACTIVE_HIGH>;
 };

diff --git a/kernel/drivers/tty/serial/8250/8250_dw.c b/kernel/drivers/tty/serial/8250/8250_dw.c
index 1ebbe7c140..0201fbdc3d 100644
--- a/kernel/drivers/tty/serial/8250/8250_dw.c
+++ b/kernel/drivers/tty/serial/8250/8250_dw.c
@@ -32,6 +32,10 @@
 
 #include "8250.h"
 
+/* by huidu --- djw */
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+
 /* Offsets for the DesignWare specific registers */
 #define DW_UART_USR	0x1f /* UART Status Register */
 #define DW_UART_RFL	0x21 /* UART Receive Fifo Level Register */
@@ -406,6 +410,9 @@ static int dw8250_probe(struct platform_device *pdev)
 	int err;
 	u32 val;
 
+	/* by huidu --- djw */
+	int ret = 0;
+
 	if (!regs) {
 		dev_err(&pdev->dev, "no registers defined\n");
 		return -EINVAL;
@@ -445,6 +452,27 @@ static int dw8250_probe(struct platform_device *pdev)
 	data->uart_16550_compatible = device_property_read_bool(p->dev,
 						"snps,uart-16550-compatible");
 
+	/* by huidu --- djw */
+	uart.port.rs485.rs485_nd = p->dev->of_node;
+	uart.port.rs485.rs485_dir_gpio = of_get_named_gpio(uart.port.rs485.rs485_nd, "rs485-enable", 0);
+	if(!gpio_is_valid(uart.port.rs485.rs485_dir_gpio)) {
+		dev_err(p->dev, "invalid rs485 gpio %d\n", uart.port.rs485.rs485_dir_gpio);
+	} else {
+       ret = devm_gpio_request(p->dev, uart.port.rs485.rs485_dir_gpio, "rs485_enable");
+		if (ret) {
+			dev_err(p->dev, "failed to request GPIO%d for rs485 gpio\n", uart.port.rs485.rs485_dir_gpio);
+			return -EINVAL;
+       }
+       gpio_direction_output(uart.port.rs485.rs485_dir_gpio, 0);	//低电平为接收模式
+		gpio_set_value(uart.port.rs485.rs485_dir_gpio, 0);
+	}
+
 	err = device_property_read_u32(p->dev, "reg-shift", &val);
 	if (!err)
 		p->regshift = val;
diff --git a/kernel/drivers/tty/serial/8250/8250_port.c b/kernel/drivers/tty/serial/8250/8250_port.c
index 14665c09d2..7aa38c7cf2 100644
--- a/kernel/drivers/tty/serial/8250/8250_port.c
+++ b/kernel/drivers/tty/serial/8250/8250_port.c
@@ -43,6 +43,9 @@
 
 #include "8250.h"
 
+/* by huidu --- djw */
+#include <linux/of_gpio.h>
+
 /*
  * Debugging.
  */
@@ -1473,6 +1476,11 @@ void serial8250_tx_chars(struct uart_8250_port *up)
 	struct circ_buf *xmit = &port->state->xmit;
 	int count;
 
+	/* by huidu --- djw */
+	int lsr = 0; // 用于获取状态
+
 	if (port->x_char) {
 		serial_out(up, UART_TX, port->x_char);
 		port->icount.tx++;
@@ -1488,6 +1496,10 @@ void serial8250_tx_chars(struct uart_8250_port *up)
 		return;
 	}
 
+	/* by huidu --- djw */
+	printk("%s Set the rs485 to send mode\n", __LINE__);
+	gpio_set_value(up->port.rs485.rs485_dir_gpio, 1);
+
 	count = up->tx_loadsz;
 	do {
 		serial_out(up, UART_TX, xmit->buf[xmit->tail]);
@@ -1512,8 +1524,17 @@ void serial8250_tx_chars(struct uart_8250_port *up)
 	 * HW can go idle. So we get here once again with empty FIFO and disable
 	 * the interrupt and RPM in __stop_tx()
 	 */
-	if (uart_circ_empty(xmit) && !(up->capabilities & UART_CAP_RPM))
+	if (uart_circ_empty(xmit) && !(up->capabilities & UART_CAP_RPM)) {
 		__stop_tx(up);
+
+		/* by huidu --- djw */
+		do {
+			mdelay(3);
+			lsr = serial_in(up, UART_LSR);	//获取8250的线路状态寄存器
+		} while( !(lsr&UART_LSR_TEMT) );	//判断是否发送缓冲区是否为空
+		printk("%s Set the rs485 to receive mode\n", __LINE__);
+		gpio_set_value(up->port.rs485.rs485_dir_gpio, 0);	//设置为低电平
+	}
 }
 EXPORT_SYMBOL_GPL(serial8250_tx_chars);
 
diff --git a/kernel/include/uapi/linux/serial.h b/kernel/include/uapi/linux/serial.h
index 25331f9faa..75080340dc 100644
--- a/kernel/include/uapi/linux/serial.h
+++ b/kernel/include/uapi/linux/serial.h
@@ -125,6 +125,10 @@ struct serial_rs485 {
 	__u32	delay_rts_after_send;	/* Delay after send (milliseconds) */
 	__u32	padding[5];		/* Memory is cheap, new structs
 					   are a royal PITA .. */
+
+	/* by huidu --- djw */
+	struct device_node	*rs485_nd;
+	int	rs485_dir_gpio;
 };
 
 #endif /* _UAPI_LINUX_SERIAL_H */

上面的补丁是有点瑕疵的,只针对单个RS485自控有用,下面我提供两种可以满足配置多个RS485自控的补丁
补丁一:

diff --git a/kernel/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10.dts b/kernel/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10.dts
index 7906621ea62..f92785583d9 100755
--- a/kernel/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10.dts
+++ b/kernel/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10.dts
@@ -6,24 +6,40 @@
 
 #include "rk3568-evb1-ddr4-v10.dtsi"
 #include "rk3568-android.dtsi"
+
+&uart4 {
+	status = "okay";
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart4m1_xfer>;
+	pinctrl-1 = <&uart4_rs485_pinctrl>;
+	uart-rs485-gpios = <&gpio0 RK_PB7 GPIO_ACTIVE_HIGH>;	//led
+};
+
 &uart7{
     status ="okay";
     pinctrl-name = "default";
     pinctrl-0 = <&uart7m1_xfer>;
+	pinctrl-1 = <&uart7_rs485_pinctrl>;
+	uart-rs485-gpios = <&gpio0 RK_PC6 GPIO_ACTIVE_HIGH>;
 };
 
 &pinctrl{
+	uart4_rs485{
+		uart4_rs485_pinctrl:uart4-rs485-pinctrl {
+			rockchip,pins = <0 RK_PB7 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+	uart7_rs485{
+		uart7_rs485_pinctrl:uart7-rs485-pinctrl {
+			rockchip,pins = <0 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>;
 		};
 	};
 };
\ No newline at end of file
diff --git a/kernel/drivers/tty/serial/8250/8250_core.c b/kernel/drivers/tty/serial/8250/8250_core.c
index 4e1d450ffd5..a81e490ee8b 100644
--- a/kernel/drivers/tty/serial/8250/8250_core.c
+++ b/kernel/drivers/tty/serial/8250/8250_core.c
@@ -1010,6 +1010,13 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
 		uart->port.rs485_config	= up->port.rs485_config;
 		uart->port.rs485	= up->port.rs485;
 		uart->dma		= up->dma;
+
+		/* 获取uart rs485新定义的变量值 */
+		uart->port.uart_rs485_gpio = up->port.uart_rs485_gpio;
+		uart->port.rs485_gpio_uart_tx_value = up->port.rs485_gpio_uart_tx_value;
+		uart->port.uartx_node = up->port.uartx_node;
+		uart->port.uart_name = up->port.uart_name;
+
 #ifdef CONFIG_ARCH_ROCKCHIP
 		uart->port.line		= up->port.line;
 #endif
@@ -1022,7 +1029,7 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
 
 		if (up->port.flags & UPF_FIXED_TYPE)
 			uart->port.type = up->port.type;
-
+		/* 设置私有属性 */
 		serial8250_set_defaults(uart);
 
 		/* Possibly override default I/O functions.  */
diff --git a/kernel/drivers/tty/serial/8250/8250_dw.c b/kernel/drivers/tty/serial/8250/8250_dw.c
index 735420b3da4..5297d606049 100644
--- a/kernel/drivers/tty/serial/8250/8250_dw.c
+++ b/kernel/drivers/tty/serial/8250/8250_dw.c
@@ -29,6 +29,10 @@
 
 #include "8250.h"
 
+/* by djw */
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+
 /* Offsets for the DesignWare specific registers */
 #define DW_UART_USR	0x1f /* UART Status Register */
 #define DW_UART_DLF	0xc0 /* Divisor Latch Fraction Register */
@@ -633,6 +637,23 @@ static int dw8250_probe(struct platform_device *pdev)
 		data->enable_wakeup = 0;
 #endif
 
+	/* by djw */
+	p->uartx_node = dev->of_node;	//uartx节点
+	p->uart_name = "uart-rs485-gpios";
+
+	p->uart_rs485_gpio = of_get_named_gpio_flags(p->uartx_node, p->uart_name, 0, &p->rs485_gpio_uart_tx_value);	//获取flag是该属性第三个参赛, HIGH:0; LOW:1
+	if (!gpio_is_valid(p->uart_rs485_gpio)) {
+		dev_err(dev, "djw: %s invalid rs485 gpio%d\n", p->uart_name, p->uart_rs485_gpio);
+	} else {
+		err = devm_gpio_request(dev, p->uart_rs485_gpio, p->uart_name);
+		if(err) {
+			dev_err(p->dev, "djw: failed to request gpio%d for rs485 gpio\n", p->uart_rs485_gpio);
+		} else {
+			gpio_direction_output(p->uart_rs485_gpio, p->rs485_gpio_uart_tx_value);	//低电平为接收模式
+		}
+		printk("djw: %s gpio%d=%d, tx value is %d\n", p->uart_name, p->uart_rs485_gpio, gpio_get_value(p->uart_rs485_gpio), !p->rs485_gpio_uart_tx_value);
+	}
+
 	/* Always ask for fixed clock rate from a property. */
 	device_property_read_u32(dev, "clock-frequency", &p->uartclk);
 
@@ -694,6 +715,7 @@ static int dw8250_probe(struct platform_device *pdev)
 		uart.dma = &data->dma;
 	}
 
+	/* 这里是将&uart这个结构体变量的值获取到,然后注册到私有属性中 */
 	data->line = serial8250_register_8250_port(&uart);
 	if (data->line < 0) {
 		err = data->line;
diff --git a/kernel/drivers/tty/serial/8250/8250_port.c b/kernel/drivers/tty/serial/8250/8250_port.c
index 99d52647908..661669208c7 100644
--- a/kernel/drivers/tty/serial/8250/8250_port.c
+++ b/kernel/drivers/tty/serial/8250/8250_port.c
@@ -40,6 +40,9 @@
 
 #include "8250.h"
 
+/* by djw */
+#include <linux/of_gpio.h>
+
 /*
  * These are definitions for the Exar XR17V35X and XR17(C|D)15X
  */
@@ -1782,6 +1785,9 @@ void serial8250_tx_chars(struct uart_8250_port *up)
 	struct circ_buf *xmit = &port->state->xmit;
 	int count;
 
+	/* by djw */
+	int lsr_reg = 0;
+
 	if (port->x_char) {
 		serial_out(up, UART_TX, port->x_char);
 		port->icount.tx++;
@@ -1797,6 +1803,10 @@ void serial8250_tx_chars(struct uart_8250_port *up)
 		return;
 	}
 
+	/* by djw */
+	printk("djw: Set the rs485 gpio%d to send mode\n", port->uart_rs485_gpio);
+	gpio_set_value(port->uart_rs485_gpio, !port->rs485_gpio_uart_tx_value);
+
 	count = up->tx_loadsz;
 	do {
 		serial_out(up, UART_TX, xmit->buf[xmit->tail]);
@@ -1821,8 +1831,17 @@ void serial8250_tx_chars(struct uart_8250_port *up)
 	 * HW can go idle. So we get here once again with empty FIFO and disable
 	 * the interrupt and RPM in __stop_tx()
 	 */
-	if (uart_circ_empty(xmit) && !(up->capabilities & UART_CAP_RPM))
+	if (uart_circ_empty(xmit) && !(up->capabilities & UART_CAP_RPM)) {
 		__stop_tx(up);
+
+		/* by djw */
+		do {
+			udelay(10);
+			lsr_reg = serial_in(up, UART_LSR);	//获取8250的线路状态寄存器
+		} while( !(lsr_reg & UART_LSR_TEMT) );	//判断是否发送缓冲区是否为空
+		printk("djw: Set the rs485 gpio%d to receive mode\n", port->uart_rs485_gpio);
+		gpio_set_value(port->uart_rs485_gpio, port->rs485_gpio_uart_tx_value);
+	}
 }
 EXPORT_SYMBOL_GPL(serial8250_tx_chars);
 
diff --git a/kernel/include/linux/serial_core.h b/kernel/include/linux/serial_core.h
index 3460b15a260..99edc38f013 100644
--- a/kernel/include/linux/serial_core.h
+++ b/kernel/include/linux/serial_core.h
@@ -31,6 +31,10 @@
 #include <linux/sysrq.h>
 #include <uapi/linux/serial_core.h>
 
+/* by djw */
+#include <linux/of_gpio.h>
+
+
 #ifdef CONFIG_SERIAL_CORE_CONSOLE
 #define uart_console(port) \
 	((port)->cons && (port)->cons->index == (port)->line)
@@ -262,6 +266,12 @@ struct uart_port {
 	const struct attribute_group **tty_groups;	/* all attributes (serial core use only) */
 	struct serial_rs485     rs485;
 	void			*private_data;		/* generic platform data pointer */
+
+	/* by djw */
+	int					uart_rs485_gpio;
+	enum of_gpio_flags	rs485_gpio_uart_tx_value;	//保存gpio属性第三个参数
+	struct device_node 	*uartx_node;				//uartx节点
+	char				*uart_name;
 };
 
 static inline int serial_port_in(struct uart_port *up, int offset)

补丁二:

diff --git a/kernel/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10.dts b/kernel/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10.dts
index 7906621ea62..f92785583d9 100755
--- a/kernel/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10.dts
+++ b/kernel/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10.dts
@@ -6,24 +6,40 @@
 
 #include "rk3568-evb1-ddr4-v10.dtsi"
 #include "rk3568-android.dtsi"
+
+&uart4 {
+	status = "okay";
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart4m1_xfer>;
+	pinctrl-1 = <&uart4_rs485_pinctrl>;
+	uart-rs485-gpios = <&gpio0 RK_PB7 GPIO_ACTIVE_HIGH>;	//led
+};
+
 &uart7{
     status ="okay";
     pinctrl-name = "default";
     pinctrl-0 = <&uart7m1_xfer>;
+	pinctrl-1 = <&uart7_rs485_pinctrl>;
+	uart-rs485-gpios = <&gpio0 RK_PC6 GPIO_ACTIVE_HIGH>;
 };
 
 &pinctrl{
-	rk_485{
-		rk_485_gpio:rk-485-gpio {
-			rockchip,pins = <3 13 RK_FUNC_GPIO &pcfg_pull_none>;
+	uart4_rs485{
+		uart4_rs485_pinctrl:uart4-rs485-pinctrl {
+			rockchip,pins = <0 RK_PB7 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+	uart7_rs485{
+		uart7_rs485_pinctrl:uart7-rs485-pinctrl {
+			rockchip,pins = <0 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>;
 		};
 	};
 };
\ No newline at end of file
diff --git a/kernel/drivers/tty/serial/8250/8250_core.c b/kernel/drivers/tty/serial/8250/8250_core.c
index 4e1d450ffd5..a81e490ee8b 100644
--- a/kernel/drivers/tty/serial/8250/8250_core.c
+++ b/kernel/drivers/tty/serial/8250/8250_core.c
@@ -1010,6 +1010,13 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
 		uart->port.rs485_config	= up->port.rs485_config;
 		uart->port.rs485	= up->port.rs485;
 		uart->dma		= up->dma;
+
+		/* 获取uart rs485新定义的变量值 */
+		uart->port.uart_rs485_gpio = up->port.uart_rs485_gpio;
+		uart->port.rs485_gpio_uart_tx_value = up->port.rs485_gpio_uart_tx_value;
+		uart->port.uartx_node = up->port.uartx_node;
+		uart->port.uart_name = up->port.uart_name;
+
 #ifdef CONFIG_ARCH_ROCKCHIP
 		uart->port.line		= up->port.line;
 #endif
@@ -1022,7 +1029,7 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
 
 		if (up->port.flags & UPF_FIXED_TYPE)
 			uart->port.type = up->port.type;
-
+		/* 设置私有属性 */
 		serial8250_set_defaults(uart);
 
 		/* Possibly override default I/O functions.  */
diff --git a/kernel/drivers/tty/serial/8250/8250_dw.c b/kernel/drivers/tty/serial/8250/8250_dw.c
index 735420b3da4..1d1cca1cf2e 100644
--- a/kernel/drivers/tty/serial/8250/8250_dw.c
+++ b/kernel/drivers/tty/serial/8250/8250_dw.c
@@ -29,6 +29,10 @@
 
 #include "8250.h"
 
+/* by djw */
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+
 /* Offsets for the DesignWare specific registers */
 #define DW_UART_USR	0x1f /* UART Status Register */
 #define DW_UART_DLF	0xc0 /* Divisor Latch Fraction Register */
@@ -548,6 +552,10 @@ static int dw8250_probe(struct platform_device *pdev)
 	int err;
 	u32 val;
 
+	/* by djw */
+	u32 uart_rs485_gpios_array[3] = {0};
+	char uart_rs485_gpios_name[50] = {0};
+
 	if (!regs) {
 		dev_err(dev, "no registers defined\n");
 		return -EINVAL;
@@ -633,6 +641,32 @@ static int dw8250_probe(struct platform_device *pdev)
 		data->enable_wakeup = 0;
 #endif
 
+	/* by djw */
+	p->uartx_node = dev->of_node;	//uartx节点
+	p->uart_name = "uart-rs485";
+
+	snprintf(uart_rs485_gpios_name, sizeof(uart_rs485_gpios_name), "%s-gpios", p->uart_name);
+    if (of_property_read_u32_array(p->uartx_node, uart_rs485_gpios_name, uart_rs485_gpios_array, 3) == 0) {
+		printk("djw: uart_rs485_gpios_array[0]=%d, uart_rs485_gpios_array[1]=%d, uart_rs485_gpios_array[2]=%d\n", uart_rs485_gpios_array[0], uart_rs485_gpios_array[1], uart_rs485_gpios_array[2]);
+        /* GPIO_ACTIVE_HIGH=0, GPIO_ACTIVE_LOW=1 */
+		if (uart_rs485_gpios_array[2] == 0) {
+            p->rs485_gpio_uart_tx_value = 1;
+			p->uart_rs485_gpio = devm_gpiod_get(dev, p->uart_name, GPIOD_OUT_LOW);	//默认接收模式
+			if (IS_ERR(p->uart_rs485_gpio)) {
+				dev_err(dev, "djw: failed to request reset GPIO: %d\n", PTR_ERR(p->uart_rs485_gpio));
+			}			
+        } else if (uart_rs485_gpios_array[2] == 1) {
+            p->rs485_gpio_uart_tx_value = 0;
+			p->uart_rs485_gpio = devm_gpiod_get(dev, p->uart_name, GPIOD_OUT_HIGH);
+			if (IS_ERR(p->uart_rs485_gpio)) {
+				dev_err(dev, "djw: failed to request reset GPIO: %d\n", PTR_ERR(p->uart_rs485_gpio));
+			}			
+        }  
+    } else {  
+        dev_err(dev, "djw: Failed to read uart-rs485-gpios property\n");  
+    }
+	printk("djw: rs485 gpio value = %d, rs485 tx value is %d\n", gpiod_get_value(p->uart_rs485_gpio), p->rs485_gpio_uart_tx_value);
+
 	/* Always ask for fixed clock rate from a property. */
 	device_property_read_u32(dev, "clock-frequency", &p->uartclk);
 
@@ -694,6 +728,7 @@ static int dw8250_probe(struct platform_device *pdev)
 		uart.dma = &data->dma;
 	}
 
+	/* 这里是将&uart这个结构体变量的值获取到,然后注册到私有属性中 */
 	data->line = serial8250_register_8250_port(&uart);
 	if (data->line < 0) {
 		err = data->line;
diff --git a/kernel/drivers/tty/serial/8250/8250_port.c b/kernel/drivers/tty/serial/8250/8250_port.c
index 99d52647908..dec213dfb7d 100644
--- a/kernel/drivers/tty/serial/8250/8250_port.c
+++ b/kernel/drivers/tty/serial/8250/8250_port.c
@@ -40,6 +40,9 @@
 
 #include "8250.h"
 
+/* by djw */
+#include <linux/of_gpio.h>
+
 /*
  * These are definitions for the Exar XR17V35X and XR17(C|D)15X
  */
@@ -1782,6 +1785,9 @@ void serial8250_tx_chars(struct uart_8250_port *up)
 	struct circ_buf *xmit = &port->state->xmit;
 	int count;
 
+	/* by djw */
+	int lsr_reg = 0;
+
 	if (port->x_char) {
 		serial_out(up, UART_TX, port->x_char);
 		port->icount.tx++;
@@ -1797,6 +1803,10 @@ void serial8250_tx_chars(struct uart_8250_port *up)
 		return;
 	}
 
+	/* by djw */
+	printk("djw: Set the rs485 gpio%d to send mode\n", port->uart_rs485_gpio);
+	gpiod_set_value(port->uart_rs485_gpio, port->rs485_gpio_uart_tx_value);
+
 	count = up->tx_loadsz;
 	do {
 		serial_out(up, UART_TX, xmit->buf[xmit->tail]);
@@ -1821,8 +1831,17 @@ void serial8250_tx_chars(struct uart_8250_port *up)
 	 * HW can go idle. So we get here once again with empty FIFO and disable
 	 * the interrupt and RPM in __stop_tx()
 	 */
-	if (uart_circ_empty(xmit) && !(up->capabilities & UART_CAP_RPM))
+	if (uart_circ_empty(xmit) && !(up->capabilities & UART_CAP_RPM)) {
 		__stop_tx(up);
+
+		/* by djw */
+		do {
+			udelay(10);
+			lsr_reg = serial_in(up, UART_LSR);	//获取8250的线路状态寄存器
+		} while( !(lsr_reg & UART_LSR_TEMT) );	//判断是否发送缓冲区是否为空
+		printk("djw: Set the rs485 gpio%d to receive mode\n", port->uart_rs485_gpio);
+		gpiod_set_value(port->uart_rs485_gpio, !port->rs485_gpio_uart_tx_value);
+	}
 }
 EXPORT_SYMBOL_GPL(serial8250_tx_chars);
 
diff --git a/kernel/include/linux/serial_core.h b/kernel/include/linux/serial_core.h
index 3460b15a260..9d19a233999 100644
--- a/kernel/include/linux/serial_core.h
+++ b/kernel/include/linux/serial_core.h
@@ -31,6 +31,10 @@
 #include <linux/sysrq.h>
 #include <uapi/linux/serial_core.h>
 
+/* by djw */
+#include <linux/of_gpio.h>
+
+
 #ifdef CONFIG_SERIAL_CORE_CONSOLE
 #define uart_console(port) \
 	((port)->cons && (port)->cons->index == (port)->line)
@@ -262,6 +266,12 @@ struct uart_port {
 	const struct attribute_group **tty_groups;	/* all attributes (serial core use only) */
 	struct serial_rs485     rs485;
 	void			*private_data;		/* generic platform data pointer */
+
+	/* by djw */
+	struct gpio_desc 	*uart_rs485_gpio;
+	int					rs485_gpio_uart_tx_value;	//保存gpio属性第三个参数
+	struct device_node 	*uartx_node;				//uartx节点
+	char				*uart_name;
 };
 
 static inline int serial_port_in(struct uart_port *up, int offset)

三、驱动程序分析技巧

例如我需要分析dw8250_probe这个函数的调用,可以添加dump_stack函数进行打印所有函数的调用,如下图所示:
在这里插入图片描述
在这里插入图片描述
日志的显示的函数调用顺序是从下往上的。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐