kernel(六)从根源解决 10 分钟后 LCD 黑屏

10 分钟后, LCD 黑屏, LCD 控制器已经被静止,这时如果触发一个中断, LCD 控制器又被使能,恢复显示。

drivers/tty/vt/vt.c

kernel(六)从根源解决 10 分钟后 LCD 黑屏_第1张图片
          blankinterval 决定了延迟多久后关闭 LCD 控制器,默认为 10 分钟,同时定义了一个 work,后面在定时器超时时会调用。将blankinterval 改为0则不会关闭LCD控制器。

       这里定义了一个定时器,指定超时调用函数为 blank_screen_t,在 con_init 初始化函数中对其设置了超时时间为 blankinterval

       定时器超时后调用函数 blank_screen_t
kernel(六)从根源解决 10 分钟后 LCD 黑屏_第2张图片

       这个函数中重新设置超时值为 blankinterval,并调度 console_work 执行, console_work 就会调用函数 console_callback

       在这里调用了 do_blank_screen 来关闭 LCD。
在 vt.c 中有一个 tty_operations 结构体
kernel(六)从根源解决 10 分钟后 LCD 黑屏_第3张图片

       这个函数跟我们平时见到的 file_operations 有点相似,我们可以在用户空间对/dev/tty1 调用 open、ioctl、 close,内核会分别调用到这里的 con_open、 vt_ioctl、 con_close
重点关注 vt_ioctl,其定义在 drivers/tty/vt/vt_ioctl.c
kernel(六)从根源解决 10 分钟后 LCD 黑屏_第4张图片

       如果用户空间传入的 cmd 为 TIOCLINUX,就会以 arg 参数调用 tioclinux,其定义在 vt.c 中
kernel(六)从根源解决 10 分钟后 LCD 黑屏_第5张图片

 这里只列出部分参数, 更多的请看源码。
当 arg 为 TIOCL_UNBLANKSCREEN 就会调用 unblank_screen 使能 LCD 控制器,
当 arg 为 TIOCL_BLANKSCREEN 就会调用 do_blank_screen(0)关闭 LCD 控制器,
现在在用户层已经可以打开或者关闭 LCD 控制器了。我们还需要在用户层修改那个间隔时间,或者
设置为 0,永不关闭 LCD 控制器。
当用户层对/dev/tty1 调用 write,内核就会调用 con_ops 的成员函数 con_write
kernel(六)从根源解决 10 分钟后 LCD 黑屏_第6张图片

这里调用了 do_con_write,它将传入的参数 buf 和 count 经过一系列的处理,得到 vc_data 结构体 vc,传给函数 do_con_trol

do_con_trol 根据传入的参数,调用 setterm_command

在 setterm_command 函数中根据参数选择设置 blankinterval 的值

这里关键是要构造用户空间传来的 buf,使得内核能够根据 buf 调用到上面的代码。
do_con_write 中对 buf 的处理过程以及后面那一连串的 switc……case,实在是太复杂了, 这里介绍一个命令 setterm,它是一个终端控制命令,它属于开源软件 util-linux,下载 util-linux-2.24.tar.gz,分析util-linux-2.24/term-utils/setterm.c,找到如下内容
kernel(六)从根源解决 10 分钟后 LCD 黑屏_第7张图片

下面编写一个控制程序 lcd_con.c,交叉编译后,拷贝到根文件系统

[root@$Louis210: /]# ./lcd_con on
[root@$Louis210: /]# ./lcd_con off
[root@$Louis210: /]# ./lcd_con on 1
[root@$Louis210: /]# ./lcd_con on 0
使能 LCD 控制器, LCD 恢复显示
关闭 LCD 控制器,黑屏
设置间隔时间为 1 分钟
设置永不关闭 LCD 控制器

lcd_con.c

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc, char **argv)
{
	int ret;
	int blank, interval;
	int fd;
	char buf[10];
	
	fd = open("/dev/tty1", O_RDWR);
	if (fd < 0)
	{
		perror("open");
		exit(1);
	}
	
	if (argc == 2)
	{
		if (strcmp(argv[1], "on") == 0)
		{
			blank = TIOCL_UNBLANKSCREEN;
			printf("unblank screen\n");
		}
		else
		{
			blank = TIOCL_BLANKSCREEN;
			printf("blank screen\n");
		}
		ret = ioctl(fd, TIOCLINUX, &blank);
		if (ret < 0)
		{
			perror("ioctl");
			close(fd);
			exit(1);
		}
		
	}
	else if (argc == 3)
	{
		interval = atoi(argv[2]);
		sprintf(buf, "\033[9;%d]", interval);
		ret = write(fd, buf, strlen(buf) + 1);
		if (ret < 0)
		{
			perror("write");
			close(fd);
			exit(1);
		}
	}
	else
	{
		printf("Usage:%s on [n]\n"
				"%s off", argv[0]);
	}
	
	close(fd);
	return 0;
}

你可能感兴趣的:(kernel,kernel)