Skip to content
Permalink
Browse files
tty: Fix the keyboard led light display problem
Use the "ctrl+alt+Fn" key combination to switch the system from tty to
desktop or switch the system from desktop to tty. After the switch is
completed, it is found that the state of the keyboard lock is
inconsistent with the state of the keyboard Led light.The reasons are
as follows:

* The desktop environment (Xorg and other services) is bound to a tty
  (assuming it is tty1), and the kb->kbdmode attribute value of tty1
  will be set to VC_OFF. According to the current code logic, in the
  desktop environment, the values of ledstate and kb->ledflagstate
  of tty1 will not be modified anymore, so they are always 0.

* When switching between each tty, the final value of ledstate set by
  the previous tty is compared with the kb->ledflagstate value of the
  current tty to determine whether to set the state of the keyboard
  light. The process of switching between desktop and tty is also the
  process of switching between tty1 and other ttys. There are two
  situations:

  - (1) In the desktop environment, tty1 will not set the ledstate,
  which will cause when switching from the desktop to other ttys,
  if the desktop lights up the keyboard's led, after the switch is
  completed, the keyboard's led light will always be on;

  - (2) When switching from another tty to the desktop, this
  mechanism will trigger tty1 to set the led state. If other tty
  lights up the led of the keyboard before switching to the desktop,
  the led will be forcibly turned off. This situation should
  be avoided.

* Current patch explanation:When VT is switched,the keyboard LED
  status will be set to the current tty saved value;the value of
  kb->kbdledctl can be used to confirm whether the current VT
  can change the status of the keyboard led light;kb->kbdledctl
  is a new addition,you can use ioctl get or set.

Signed-off-by: lianzhi chang <changlianzhi@uniontech.com>
Suggested-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
  • Loading branch information
lianzhi chang authored and intel-lab-lkp committed Dec 13, 2021
1 parent f5bced9 commit 8cc658e5dd82e5d70fa3ac9dace8fe62eaed325f
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 1 deletion.
@@ -153,6 +153,7 @@ static int shift_state = 0;

static unsigned int ledstate = -1U; /* undefined */
static unsigned char ledioctl;
static bool vt_switch;

/*
* Notifier list for console keyboard events
@@ -414,6 +415,12 @@ void vt_set_leds_compute_shiftstate(void)
{
unsigned long flags;

/*
* When switching VT,according to the value of vt_switch,
* judge whether it is necessary to force the keyboard light
* state to be issued.
*/
vt_switch = true;
set_leds();

spin_lock_irqsave(&kbd_event_lock, flags);
@@ -1247,14 +1254,24 @@ void vt_kbd_con_stop(unsigned int console)
*/
static void kbd_bh(struct tasklet_struct *unused)
{
struct kbd_struct *kb;
unsigned int leds;
unsigned long flags;

kb = kbd_table + fg_console;
if (kb->kbdledctl == VC_LEDCTL_OFF)
return;

spin_lock_irqsave(&led_lock, flags);
leds = getleds();
leds |= (unsigned int)kbd->lockstate << 8;
spin_unlock_irqrestore(&led_lock, flags);

if (vt_switch) {
ledstate = ~leds;
vt_switch = false;
}

if (leds != ledstate) {
kbd_propagate_led_state(ledstate, leds);
ledstate = leds;
@@ -1857,6 +1874,35 @@ int vt_do_kdskbmode(unsigned int console, unsigned int arg)
return ret;
}

/**
* vt_do_kdskbledctl - set whether VT can control led
* @console: the console to use
* @arg: the requested mode
*
* Whether to allow the current vt to change the
* keyboard light
*/
int vt_do_kdskbledctl(unsigned int console, unsigned int arg)
{
struct kbd_struct *kb = &kbd_table[console];
unsigned long flags;
int ret = 0;

spin_lock_irqsave(&kbd_event_lock, flags);
switch (arg) {
case K_LEDCTL_ON:
kb->kbdledctl = VC_LEDCTL_ON;
break;
case K_LEDCTL_OFF:
kb->kbdledctl = VC_LEDCTL_OFF;
break;
default:
ret = -EINVAL;
}
spin_unlock_irqrestore(&kbd_event_lock, flags);
return ret;
}

/**
* vt_do_kdskbmeta - set keyboard meta state
* @console: the console to use
@@ -2157,6 +2203,21 @@ int vt_do_kdgkbmode(unsigned int console)
}
}

int vt_do_kdgkbledctl(unsigned int console)
{
struct kbd_struct *kb = &kbd_table[console];

/* This is a spot read so needs no locking */
switch (kb->kbdledctl) {
case VC_LEDCTL_ON:
return K_LEDCTL_ON;
case VC_LEDCTL_OFF:
return K_LEDCTL_OFF;
default:
return K_LEDCTL_ON;
}
}

/**
* vt_do_kdgkbmeta - report meta status
* @console: console to report
@@ -405,6 +405,18 @@ static int vt_k_ioctl(struct tty_struct *tty, unsigned int cmd,
case KDGKBMODE:
return put_user(vt_do_kdgkbmode(console), (int __user *)arg);

case KDSKBLEDCTL:
if (!perm)
return -EPERM;
ret = vt_do_kdskbledctl(console, arg);
if (ret)
return ret;
tty_ldisc_flush(tty);
break;

case KDGKBLEDCTL:
return put_user(vt_do_kdgkbledctl(console), (int __user *)arg);

/* this could be folded into KDSKBMODE, but for compatibility
reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */
case KDSKBMETA:
@@ -32,6 +32,10 @@ struct kbd_struct {
#define VC_CTRLRLOCK KG_CTRLR /* ctrlr lock mode */
unsigned char slockstate; /* for `sticky' Shift, Ctrl, etc. */

unsigned char kbdledctl:1/* Whether to allow to control the led of the keyboard */
#define VC_LEDCTL_ON 0 /* VT can set the keyboard light */
#define VC_LEDCTL_OFF 1 /* Prohibit VT to set the keyboard light */

unsigned char ledmode:1;
#define LED_SHOW_FLAGS 0 /* traditional state */
#define LED_SHOW_IOCTL 1 /* only change leds upon ioctl */
@@ -149,6 +149,7 @@ void hide_boot_cursor(bool hide);
/* keyboard provided interfaces */
int vt_do_diacrit(unsigned int cmd, void __user *up, int eperm);
int vt_do_kdskbmode(unsigned int console, unsigned int arg);
int vt_do_kdskbledctl(unsigned int console, unsigned int arg);
int vt_do_kdskbmeta(unsigned int console, unsigned int arg);
int vt_do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc,
int perm);
@@ -157,6 +158,7 @@ int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm,
int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm);
int vt_do_kdskled(unsigned int console, int cmd, unsigned long arg, int perm);
int vt_do_kdgkbmode(unsigned int console);
int vt_do_kdgkbledctl(unsigned int console);
int vt_do_kdgkbmeta(unsigned int console);
void vt_reset_unicode(unsigned int console);
int vt_get_shift_state(void);
@@ -86,6 +86,11 @@ struct unimapinit {
#define KDGKBMODE 0x4B44 /* gets current keyboard mode */
#define KDSKBMODE 0x4B45 /* sets current keyboard mode */

#define K_LEDCTL_ON 0x00
#define K_LEDCTL_OFF 0x01
#define KDGKBLEDCTL 0x4B73 /* set whether to allow control of keyboard lights */
#define KDSKBLEDCTL 0x4B74 /* get whether the keyboard light is currently allowed to be set */

#define K_METABIT 0x03
#define K_ESCPREFIX 0x04
#define KDGKBMETA 0x4B62 /* gets meta key handling mode */
@@ -179,6 +184,6 @@ struct console_font {

/* note: 0x4B00-0x4B4E all have had a value at some time;
don't reuse for the time being */
/* note: 0x4B60-0x4B6D, 0x4B70-0x4B72 used above */
/* note: 0x4B60-0x4B6D, 0x4B70-0x4B74 used above */

#endif /* _UAPI_LINUX_KD_H */

0 comments on commit 8cc658e

Please sign in to comment.