19_编写console驱动#

编写console驱动#

  • 参考代码

    • Linux 4.9.88

      kernel/printk.c
      include/linux/kernel.h
      kernel/printk/internal.h
      drivers/tty/serial/imx.c
      
    • Linux 5.4

      kernel/printk.c
      include/linux/kernel.h
      kernel/printk/printk_safe.c
      drivers/tty/serial/stm32-usart.
      
  • 本节视频配套源码在GIT仓库里,目录如下

    doc_and_source_for_drivers\IMX6ULL\source\09_UART\
    	08_virtual_uart_driver_console
    
    doc_and_source_for_drivers\STM32MP157\source\A7\09_UART\
    	08_virtual_uart_driver_console
    

1. 回顾printk的使用#

image-20210813175952791

2. console结构体分析#

include\linux\console.h:

struct console {
	char	name[16];  // name为"ttyXXX",在cmdline中用"console=ttyXXX0"来匹配
    
    // 输出函数
	void	(*write)(struct console *, const char *, unsigned);
    
	int	    (*read)(struct console *, char *, unsigned);
    
    // APP访问/dev/console时通过这个函数来确定是哪个(index)设备
    // 举例:
    // a. cmdline中"console=ttymxc1"
    // b. 则注册对应的console驱动时:console->index = 1
    // c. APP访问/dev/console时调用"console->device"来返回这个index
	struct  tty_driver *(*device)(struct console *co, int *index);
    
	void	(*unblank)(void);
    
    // 设置函数, 可设为NULL
	int	    (*setup)(struct console *, char *);
    
    // 匹配函数, 可设为NULL
	int	    (*match)(struct console *, char *name, int idx, char *options); 
    
	short	flags;
    
    // 哪个设备用作console: 
    // a. 可以设置为-1, 表示由cmdline=ttyVIRT0确定
    // b. 也可以直接指定
	short	index;
    
    // 常用: CON_PRINTBUFFER
	int	    cflag;
	void	*data;
	struct	 console *next;
};

3. 编写console驱动#

/*
 * Interrupts are disabled on entering
 */
static void virt_uart_console_write(struct console *co, const char *s, unsigned int count)
{
	int i;
	for (i = 0; i < count; i++)
		if (txbuf_put(s[i]) != 0)
			return;
}

static struct console virt_uart_console = {
	.name		= "ttyVIRT",
	.write		= virt_uart_console_write,
	.device		= uart_console_device,
	.flags		= CON_PRINTBUFFER,
	.index		= -1,
};

static struct uart_driver virt_uart_drv = {
	.owner          = THIS_MODULE,
	.driver_name    = "VIRT_UART",
	.dev_name       = "ttyVIRT",
	.major          = 0,
	.minor          = 0,
	.nr             = 1,
	.cons           = virt_uart_console,
};

4. 上机实验#

4.1 设置工具链#

1. STM32MP157#
export ARCH=arm
export CROSS_COMPILE=arm-buildroot-linux-gnueabihf-
export PATH=$PATH:/home/book/100ask_stm32mp157_pro-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin
2. IMX6ULL#
export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-
export PATH=$PATH:/home/book/100ask_imx6ull-sdk/ToolChain/gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf/bin

4.2 编译驱动#

4.3 修改cmdline#

1. IMX6ULL#
在uboot执行:
setenv mmcargs setenv bootargs console=${console},${baudrate} root=${mmcroot} console=ttyVIRT0
boot

启动linux后确认:
cat /proc/cmdline

安装驱动程序:
echo "7 4 1 7" > /proc/sys/kernel/printk
insmod virtual_uart.ko
cat /proc/consoles  /* 确认有没有ttyVIRT0 */

cat /proc/virt_uart_buf  /* 查看信息 */

echo hello > /dev/console
cat /proc/virt_uart_buf  /* 查看信息 */
2. STM32MP157#
mount /dev/mmcblk2p2 /boot

修改/boot/mmc0_extlinux/和/boot/mmc1_extlinux下的配置文件,
配置文件里的"APPEND"表示cmdline信息,
在"APPEND"行末" console=ttyVIRT0",
在三个"APPEND"语句中都添加


启动linux后确认:
cat /proc/cmdline

安装驱动程序:
insmod virtual_uart.ko
cat /proc/consoles  /* 确认有没有ttyVIRT0 */

cat /proc/virt_uart_buf  /* 查看信息 */

echo hello > /dev/console
cat /proc/virt_uart_buf  /* 查看信息 */