控制台驱动

Linux 内核有两种通用类型的控制台驱动程序。第一种类型在启动过程中由内核分配给所有虚拟控制台。这种类型将被称为“系统驱动程序”,并且只允许存在一个系统驱动程序。系统驱动程序是持久的,并且永远不能卸载,尽管它可能会变为非活动状态。

第二种类型必须显式加载和卸载。本文档将此称为“模块化驱动程序”。多个模块化驱动程序可以随时共存,每个驱动程序都与其他驱动程序(包括系统驱动程序)共享控制台。但是,模块化驱动程序无法接管当前由另一个模块化驱动程序占用的控制台。(例外:调用 do_take_over_console() 的驱动程序将成功接管,而不管占用控制台的驱动程序类型。)它们只能接管由系统驱动程序占用的控制台。同样,如果模块化驱动程序被控制台释放,则系统驱动程序将接管。

从程序员的角度来看,模块化驱动程序必须调用

do_take_over_console() - load and bind driver to console layer
give_up_console() - unload driver; it will only work if driver
                    is fully unbound

在较新的内核中,以下内容也可用

do_register_con_driver()
do_unregister_con_driver()

如果启用了 sysfs,则可以检查 /sys/class/vtconsole 的内容。这显示了系统当前注册的控制台后端,它们被命名为 vtcon<n>,其中 <n> 是一个从 0 到 15 的整数。因此

ls /sys/class/vtconsole
.  ..  vtcon0  vtcon1

/sys/class/vtconsole 中的每个目录都有 3 个文件

ls /sys/class/vtconsole/vtcon0
.  ..  bind  name  uevent

这些文件表示什么?

  1. bind - 这是一个读/写文件。它显示驱动程序的状态(如果读取),或者在写入时充当将驱动程序绑定或取消绑定到虚拟控制台的作用。可能的值为

    0
    • 表示驱动程序未绑定,如果 echo,则命令驱动程序取消绑定

    1
    • 表示驱动程序已绑定,如果 echo,则命令驱动程序绑定

  2. name - 只读文件。以这种格式显示驱动程序的名称

    cat /sys/class/vtconsole/vtcon0/name
    (S) VGA+
    
        '(S)' stands for a (S)ystem driver, i.e., it cannot be directly
        commanded to bind or unbind
    
        'VGA+' is the name of the driver
    
    cat /sys/class/vtconsole/vtcon1/name
    (M) frame buffer device
    
        In this case, '(M)' stands for a (M)odular driver, one that can be
        directly commanded to bind or unbind.
    
  3. uevent - 忽略此文件

取消绑定时,首先分离模块化驱动程序,然后系统驱动程序接管该驱动程序腾出的控制台。另一方面,绑定会将驱动程序绑定到当前由系统驱动程序占用的控制台。

注意 1

必须在 Kconfig 中选择绑定和取消绑定。它在下面

Device Drivers ->
    Character devices ->
            Support for binding and unbinding console drivers
注意 2

如果任何虚拟控制台处于 KD_GRAPHICS 模式,则绑定或取消绑定将不会成功。将控制台设置为 KD_GRAPHICS 的应用程序的一个示例是 X。

此功能有多有用?这对控制台驱动程序开发人员非常有用。通过从控制台层取消绑定驱动程序,可以卸载驱动程序、进行更改、重新编译、重新加载和重新绑定驱动程序,而无需重新启动内核。对于可能想要从帧缓冲控制台切换到 VGA 控制台以及反之亦然的普通用户,此功能也使之成为可能。(注意注意注意:请阅读 Documentation/fb 下的 fbcon.txt 以获取更多详细信息。)

开发人员的注意事项

do_take_over_console() 现在分解为

do_register_con_driver()
do_bind_con_driver() - private function

give_up_console() 是 do_unregister_con_driver() 的包装器,并且驱动程序必须完全取消绑定,此调用才能成功。con_is_bound() 将检查驱动程序是否绑定。

控制台驱动程序编写指南

为了使与控制台的绑定和取消绑定正常工作,控制台驱动程序必须遵循以下准则

  1. 除系统驱动程序外,所有驱动程序都必须调用 do_register_con_driver() 或 do_take_over_console()。do_register_con_driver() 只会将驱动程序添加到控制台的内部列表中。它不会接管控制台。顾名思义,do_take_over_console() 也会接管(或绑定到)控制台。

  2. 在 con->con_init() 期间分配的所有资源必须在 con->con_deinit() 中释放。

  3. 在 con->con_startup() 中分配的所有资源必须在先前绑定的驱动程序变为未绑定时释放。控制台层没有对 con->con_startup() 的补充调用,因此驱动程序有责任检查何时可以合法释放这些资源。在 con->con_deinit() 中调用 con_is_bound() 会有所帮助。如果调用返回 false(),则释放资源是安全的。必须确保这种平衡,因为当收到将驱动程序重新绑定到控制台的请求时,可以再次调用 con->con_startup()。

  4. 在驱动程序退出时,确保驱动程序完全未绑定。如果满足条件,则驱动程序必须调用 do_unregister_con_driver() 或 give_up_console()。

  5. do_unregister_con_driver() 也可以在使驱动程序无法处理控制台请求的条件下调用。这可能会发生在突然失去所有驱动程序的帧缓冲控制台上。

当前的控制台驱动程序仍然应该可以正常工作,但是绑定和取消绑定它们可能会导致问题。通过最少的修复,可以使这些驱动程序正常工作。

Antonino Daplas <adaplas@pol.net>