10 分钟后, LCD 黑屏, LCD 控制器已经被静止,这时如果触发一个中断, LCD 控制器又被使能,恢复显示。
drivers/tty/vt/vt.c
blankinterval 决定了延迟多久后关闭 LCD 控制器,默认为 10 分钟,同时定义了一个 work,后面在定时器超时时会调用。将blankinterval 改为0则不会关闭LCD控制器。
这里定义了一个定时器,指定超时调用函数为 blank_screen_t,在 con_init 初始化函数中对其设置了超时时间为 blankinterval
定时器超时后调用函数 blank_screen_t
这个函数中重新设置超时值为 blankinterval,并调度 console_work 执行, console_work 就会调用函数 console_callback
在这里调用了 do_blank_screen 来关闭 LCD。
在 vt.c 中有一个 tty_operations 结构体
这个函数跟我们平时见到的 file_operations 有点相似,我们可以在用户空间对/dev/tty1 调用 open、ioctl、 close,内核会分别调用到这里的 con_open、 vt_ioctl、 con_close
重点关注 vt_ioctl,其定义在 drivers/tty/vt/vt_ioctl.c
如果用户空间传入的 cmd 为 TIOCLINUX,就会以 arg 参数调用 tioclinux,其定义在 vt.c 中
这里只列出部分参数, 更多的请看源码。
当 arg 为 TIOCL_UNBLANKSCREEN 就会调用 unblank_screen 使能 LCD 控制器,
当 arg 为 TIOCL_BLANKSCREEN 就会调用 do_blank_screen(0)关闭 LCD 控制器,
现在在用户层已经可以打开或者关闭 LCD 控制器了。我们还需要在用户层修改那个间隔时间,或者
设置为 0,永不关闭 LCD 控制器。
当用户层对/dev/tty1 调用 write,内核就会调用 con_ops 的成员函数 con_write
这里调用了 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,找到如下内容
下面编写一个控制程序 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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/time.h>
#include <netdb.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <stdbool.h>
#include <linux/tiocl.h>
#include <asm-generic/ioctls.h>
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;
}