41

I am looking for an explanation of what happens in Linux when this key combination is pressed to change the current terminal. In particular, what software component intercepts this key combination and changes the terminal? Is it the kernel? If it is the kernel, could you provide the location of the source file which handles this?

Edit: I want to understand how this works in both a graphical (X11) and text-based environment.

direprobs
  • 974
user31765
  • 557
  • 1
    To clarify, are you pressing these keys while in X11 (that is, a graphical session) or on the text console? The answer is different. – derobert Feb 04 '13 at 22:04

1 Answers1

39

It is the kernel. Keep in mind the keyboard is hardware and everything that happens there passes through the kernel; in the case of VT switching, it handles the event completely itself and does not pass anything on to userspace (however, I believe there is an ioctl related means by which userspace programs can be notified of a switch occurring involving them and perhaps affect it, which X no doubt does).

The kernel has a keymap build into it; this can be modified while running with loadkeys, and viewed with dumpkeys:

[...]
keycode  59 = F1               F13              Console_13       F25             
        alt     keycode  59 = Console_1       
        control alt     keycode  59 = Console_1       
keycode  60 = F2               F14              Console_14       F26             
        alt     keycode  60 = Console_2       
        control alt     keycode  60 = Console_2       
keycode  61 = F3               F15              Console_15       F27             
        alt     keycode  61 = Console_3       
        control alt     keycode  61 = Console_3
[...]   

The kernel source contains a default keymap file which looks exactly like this; for 3.12.2 it's src/drivers/tty/vt/defkeymap.map. You'll also notice there is a corresponding defkeymap.c file (this can be generated with loadkeys --mktable). The handling is in keyboard.c (all these files are in the same directory) which calls set_console() from vt.c:

» grep set_console *.c
keyboard.c:     set_console(last_console);
keyboard.c:     set_console(i);
keyboard.c:     set_console(i);
keyboard.c:     set_console(value);
vt.c:int set_console(int nr)
vt_ioctl.c:                     set_console(arg);

I edited some hits out of that list; you can see the function signature on the second last line.

So these are the things involved in the switching. If you look at the sequence of calls, eventually you come back to kbd_event() in keyboard.c. This is registered as an event handler for the module:

(3.12.2 drivers/tty/vt/keyboard.c line 1473)

MODULE_DEVICE_TABLE(input, kbd_ids);

static struct input_handler kbd_handler = {
    .event      = kbd_event,   <--- function pointer HERE
    .match      = kbd_match,
    .connect    = kbd_connect,
    .disconnect = kbd_disconnect,
    .start      = kbd_start,
    .name       = "kbd",
    .id_table   = kbd_ids,
};  

int __init kbd_init(void)
{

[...]

    error = input_register_handler(&kbd_handler);           

Hence, kbd_event() should be called when something bubbles up from the actual hardware driver (probably something from drivers/hid/ or drivers/input/). However, you won't see it referred to as kbd_event outside of that file, since it is registered via a function pointer.

Some resources for scrutinizing the kernel

  • The Linux Cross Reference Identifier Search is a great tool.
  • The Interactive Linux Kernel Map is an interesting graphical front end to the cross reference tool.
  • There are a few historical archives of the massive Linux Kernel Mailing List (LKML), which goes back to at least 1995; some of them are not maintained and have broken search features, but the gmane one seems to work very well. People have asked a lot of questions on the mail list and it is a primary means of communication amongst the developers as well.
  • You can inject your own printk lines into the source as a simple means of tracing (not all of the standard C lib can be used in kernel code, including printf from stdio). printk stuff ends up in syslog.

Wolfgang Mauerer wrote a great big book on the 2.6 kernel, Professional Linux Kernel Architecture, which goes through a lot of the source. Greg Kroah-Hartman, one of the principle devs for the last decade, also has a lot of things kicking around.

goldilocks
  • 87,661
  • 30
  • 204
  • 262
  • 1
    Thanks, this is exactly what I was looking for. Can you elaborate on what happens earlier in the chain? How does the the code in keyboard.c get called when we press Ctrl + Alt + F1? keyboard.c is not the actual "keyboard driver", is it? – user31765 Feb 04 '13 at 22:32
  • 1
    No, I don't think so. It's all part of the tty driver, for which keyboard.c would be an event handler; the "keyboard driver" itself would be lower level -- there's bunches of them in drivers/input/keyboard/ for non-usb stuff. Usb stuff is standardized so there would only be one (probably involving drivers/hid/usbhid/usbkbd.c). I'm guessing that the keyboard driver is for producing a scancode that can be handed to vt/keyboard.c (see getkeycode() near the top of that). Documentation/input/input.txt has some (wonderfully ancient, lol) hints. – goldilocks Feb 04 '13 at 23:27
  • PS. Many of the kernel devs are on the on the linux kernel mail list (LKML) which is open to the public, and if you mind your P&Qs etc (http://www.tux.org/lkml/) it is worthwhile inquiring there...just make sure you set up a folder for it right away, there is a LOT of mail involved. – goldilocks Feb 04 '13 at 23:38
  • Upon inspecting the code more closely, there are only three non-obsolete functions in keyboard.c which call set_console: fn_lastcons(), fn_dec_console(), and fn_inc_console(). One for going to the last console and one for going to the right or the left. So I still don't understand how set_console() gets called when we press Ctrl+Alt+F. I assume we have to pass as a parameter to set_console() somewhere. I see that set_console() crops up in vt_ioctl.c too, but isn't that just for ioctl's from user space, e.g. from chvt? There are still some holes in my understanding. – user31765 Feb 05 '13 at 03:02
  • 1
    There's more potentially related stuff in drivers/hid. Also notice 'console_callback()' in vt.c, which can do the switch and is registered at the top via DECLARE_WORK. This relates to the scheduler: http://lxr.free-electrons.com/ident?i=DECLARE_WORK (that cross-reference tool can be fed from http://makelinux.net/kernel_map which you might find interesting); I'd assume that makes that function kind of a "main loop" for the vt. Obviously the missing link here is exactly how keyboard events get passed around. – goldilocks Feb 05 '13 at 15:11
  • OK, thanks for the hint about console_callback(). It looks like first in the call sequence is kbd_event() in keyboard.c which calls schedule_console_callback() and then console_callback() in vt.c gets called and from there we call change_console() to change the virtual terminal. Like you said, the missing link in this chain is how we end up at kbd_event() in keyboard.c. – user31765 Feb 05 '13 at 15:42
  • @user31765: I think see the missing link then -- I've added a few paragraphs at the end which hopefully wrap that up. – goldilocks Feb 05 '13 at 16:06