1. There are per-tty keyboard flags: each VC has its own NumLock, CapsLock, ScrollLock. By default these keyboard flags are shown in the LEDs. The usual way to change them is by pressing the corresponding key. (Side remark: pressing the NumLock key when in application key mode will not change the NumLock status, but produce an escape sequence. If you want the NumLock key to always change the Numlock status, bind it to Bare_Num_Lock.)
2. Next, there are per-tty default keyboard flags, to initialize the keyboard flags when a reset occurs. Thus if you want NumLock on all the time, that is possible. The usual way to change them is by `
setleds -D ...'.
3. There is the possibility that the leds do not reflect the keyboard flags, but something else.
3A. This something else can be three bits somewhere in the kernel - which can be used if you want to monitor some hardware or software status bit(s). If you want this, edit the kernel source to call
3B. This something else can also be whatever some user program wants to show in the LEDs. Thus, people who like such things can make nice patterns of lights. If you want this, use the KDSETLED ioctl.
This latter use is not per-tty, but the choice between former and latter use is per-tty.
Summarizing: Each tty has a flag
kbd->ledmode. If this has the value LED_SHOW_FLAGS then the keyboard flags (NumLock etc.) of that tty are shown. If this has the value LED_SHOW_MEM then three selected memory addresses are shown. If this has the value LED_SHOW_IOCTL then the leds show whatever value was last assigned to them using the KDSETLED ioctl.
One may add that X uses ioctl's to set the LEDs, but fails to reset its VT when it exits, so after using X there may be one VT that is not in the default LED_SHOW_FLAGS state. This can be fixed by doing `
setleds -L' on that VT. See setleds(1).