linux-input.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
[parent not found: <35696980-2a55-c5c1-3fa9-eadf251dcdde@uniontech.com>]
* [PATCH] input&tty: Fix the keyboard led light display problem
@ 2021-10-15  8:37 lianzhi chang
  0 siblings, 0 replies; 19+ messages in thread
From: lianzhi chang @ 2021-10-15  8:37 UTC (permalink / raw)
  To: linux-kernel; +Cc: linux-input, lianzhi chang

Switching from the desktop environment to the tty environment,
the state of the keyboard led lights and the state of the keyboard
lock are inconsistent. This is because the attribute kb->kbdmode
of the tty bound in the desktop environment (xorg) is set to
VC_OFF, which causes the ledstate and kb->ledflagstate
values of the bound tty to always be 0, which causes the switch
from the desktop When to the tty environment, the LED light
status is inconsistent with the keyboard lock status.

Signed-off-by: lianzhi chang <changlianzhi@uniontech.com>
---
The latest changes:
(1) Move the definition of ledstate to the input module (/drivers/input/input.c), 
and set or get its value through the input_update_ledstate and input_get_ledstate 
functions.
(2) To update the ledstate reference in keyboard.c, you must first get the value 
through input_get_ledstate.
(3) Other necessary changes

 drivers/input/input.c     | 46 ++++++++++++++++++++++++++++++++++++++-
 drivers/tty/vt/keyboard.c | 19 ++++++++++++++--
 include/linux/input.h     |  3 +++
 3 files changed, 65 insertions(+), 3 deletions(-)

diff --git a/drivers/input/input.c b/drivers/input/input.c
index ccaeb2426385..8c0ef947ac34 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -37,6 +37,11 @@ static DEFINE_IDA(input_ida);
 static LIST_HEAD(input_dev_list);
 static LIST_HEAD(input_handler_list);
 
+#define VC_SCROLLOCK	0	/* scroll-lock mode */
+#define VC_NUMLOCK	1	/* numeric lock mode */
+#define VC_CAPSLOCK	2	/* capslock mode */
+static unsigned int ledstate = -1U;			/* undefined */
+
 /*
  * input_mutex protects access to both input_dev_list and input_handler_list.
  * This also causes input_[un]register_device and input_[un]register_handler
@@ -472,8 +477,12 @@ void input_inject_event(struct input_handle *handle,
 
 		rcu_read_lock();
 		grab = rcu_dereference(dev->grab);
-		if (!grab || grab == handle)
+		if (!grab || grab == handle) {
 			input_handle_event(dev, type, code, value);
+
+			if (type == EV_LED && code <= LED_SCROLLL)
+				input_update_ledstate(code, value);
+		}
 		rcu_read_unlock();
 
 		spin_unlock_irqrestore(&dev->event_lock, flags);
@@ -481,6 +490,41 @@ void input_inject_event(struct input_handle *handle,
 }
 EXPORT_SYMBOL(input_inject_event);
 
+void input_update_ledstate(unsigned int flag, unsigned int value)
+{
+	unsigned int bit;
+
+	switch (flag) {
+	case LED_NUML:
+		bit = VC_NUMLOCK;
+		break;
+	case LED_CAPSL:
+		bit = VC_CAPSLOCK;
+		break;
+	case LED_SCROLLL:
+		bit = VC_SCROLLOCK;
+		break;
+	default:
+		WARN_ON_ONCE(1);
+		return;
+	}
+
+	if (ledstate == -1U)
+		ledstate = 0;
+
+	if (value)
+		ledstate |= BIT(bit);
+	else
+		ledstate &= ~BIT(bit);
+}
+EXPORT_SYMBOL(input_update_ledstate);
+
+unsigned int input_get_ledstate(void)
+{
+	return ledstate;
+}
+EXPORT_SYMBOL(input_get_ledstate);
+
 /**
  * input_alloc_absinfo - allocates array of input_absinfo structs
  * @dev: the input device emitting absolute events
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index c7fbbcdcc346..0cfccb1d7992 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -151,7 +151,6 @@ static bool rep;			/* flag telling character repeat */
 
 static int shift_state = 0;
 
-static unsigned int ledstate = -1U;			/* undefined */
 static unsigned char ledioctl;
 
 /*
@@ -1021,10 +1020,14 @@ struct kbd_led_trigger {
 
 static int kbd_led_trigger_activate(struct led_classdev *cdev)
 {
+	unsigned int ledstate;
+
 	struct kbd_led_trigger *trigger =
 		container_of(cdev->trigger, struct kbd_led_trigger, trigger);
 
 	tasklet_disable(&keyboard_tasklet);
+
+	ledstate = input_get_ledstate();
 	if (ledstate != -1U)
 		led_trigger_event(&trigger->trigger,
 				  ledstate & trigger->mask ?
@@ -1137,6 +1140,10 @@ static void kbd_init_leds(void)
  */
 static unsigned char getledstate(void)
 {
+	unsigned int ledstate;
+
+	ledstate = input_get_ledstate();
+
 	return ledstate & 0xff;
 }
 
@@ -1248,16 +1255,21 @@ void vt_kbd_con_stop(unsigned int console)
 static void kbd_bh(struct tasklet_struct *unused)
 {
 	unsigned int leds;
+	unsigned int ledstate;
 	unsigned long flags;
+	struct kbd_struct *kb = kbd_table + fg_console;
+
+	if (kb->kbdmode == VC_OFF)
+		return;
 
 	spin_lock_irqsave(&led_lock, flags);
 	leds = getleds();
+	ledstate = input_get_ledstate();
 	leds |= (unsigned int)kbd->lockstate << 8;
 	spin_unlock_irqrestore(&led_lock, flags);
 
 	if (leds != ledstate) {
 		kbd_propagate_led_state(ledstate, leds);
-		ledstate = leds;
 	}
 }
 
@@ -1604,8 +1616,11 @@ static void kbd_disconnect(struct input_handle *handle)
  */
 static void kbd_start(struct input_handle *handle)
 {
+	unsigned int ledstate;
+
 	tasklet_disable(&keyboard_tasklet);
 
+	ledstate = input_get_ledstate();
 	if (ledstate != -1U)
 		kbd_update_leds_helper(handle, &ledstate);
 
diff --git a/include/linux/input.h b/include/linux/input.h
index 0354b298d874..0e0ba53a9cc7 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -420,6 +420,9 @@ ktime_t *input_get_timestamp(struct input_dev *dev);
 void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value);
 void input_inject_event(struct input_handle *handle, unsigned int type, unsigned int code, int value);
 
+void input_update_ledstate(unsigned int flag, unsigned int value);
+unsigned int input_get_ledstate(void);
+
 static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)
 {
 	input_event(dev, EV_KEY, code, !!value);
-- 
2.20.1




^ permalink raw reply	[flat|nested] 19+ messages in thread
[parent not found: <61693925.1c69fb81.a058.27f2SMTPIN_ADDED_BROKEN@mx.google.com>]
* [PATCH] input&tty: Fix the keyboard led light display problem
@ 2021-10-15  6:45 lianzhi chang
  2021-10-15  6:52 ` Greg KH
  0 siblings, 1 reply; 19+ messages in thread
From: lianzhi chang @ 2021-10-15  6:45 UTC (permalink / raw)
  To: linux-kernel
  Cc: dmitry.torokhov, gregkh, jirislaby, andriy.shevchenko,
	linux-input, 282827961, lianzhi chang

Switching from the desktop environment to the tty environment,
the state of the keyboard led lights and the state of the keyboard
lock are inconsistent. This is because the attribute kb->kbdmode
of the tty bound in the desktop environment (xorg) is set to
VC_OFF, which causes the ledstate and kb->ledflagstate
values of the bound tty to always be 0, which causes the switch
from the desktop When to the tty environment, the LED light
status is inconsistent with the keyboard lock status.

Signed-off-by: lianzhi chang <changlianzhi@uniontech.com>
---
 drivers/input/input.c     | 46 ++++++++++++++++++++++++++++++++++++++-
 drivers/tty/vt/keyboard.c | 19 ++++++++++++++--
 include/linux/input.h     |  3 +++
 3 files changed, 65 insertions(+), 3 deletions(-)

diff --git a/drivers/input/input.c b/drivers/input/input.c
index ccaeb2426385..8c0ef947ac34 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -37,6 +37,11 @@ static DEFINE_IDA(input_ida);
 static LIST_HEAD(input_dev_list);
 static LIST_HEAD(input_handler_list);
 
+#define VC_SCROLLOCK	0	/* scroll-lock mode */
+#define VC_NUMLOCK	1	/* numeric lock mode */
+#define VC_CAPSLOCK	2	/* capslock mode */
+static unsigned int ledstate = -1U;			/* undefined */
+
 /*
  * input_mutex protects access to both input_dev_list and input_handler_list.
  * This also causes input_[un]register_device and input_[un]register_handler
@@ -472,8 +477,12 @@ void input_inject_event(struct input_handle *handle,
 
 		rcu_read_lock();
 		grab = rcu_dereference(dev->grab);
-		if (!grab || grab == handle)
+		if (!grab || grab == handle) {
 			input_handle_event(dev, type, code, value);
+
+			if (type == EV_LED && code <= LED_SCROLLL)
+				input_update_ledstate(code, value);
+		}
 		rcu_read_unlock();
 
 		spin_unlock_irqrestore(&dev->event_lock, flags);
@@ -481,6 +490,41 @@ void input_inject_event(struct input_handle *handle,
 }
 EXPORT_SYMBOL(input_inject_event);
 
+void input_update_ledstate(unsigned int flag, unsigned int value)
+{
+	unsigned int bit;
+
+	switch (flag) {
+	case LED_NUML:
+		bit = VC_NUMLOCK;
+		break;
+	case LED_CAPSL:
+		bit = VC_CAPSLOCK;
+		break;
+	case LED_SCROLLL:
+		bit = VC_SCROLLOCK;
+		break;
+	default:
+		WARN_ON_ONCE(1);
+		return;
+	}
+
+	if (ledstate == -1U)
+		ledstate = 0;
+
+	if (value)
+		ledstate |= BIT(bit);
+	else
+		ledstate &= ~BIT(bit);
+}
+EXPORT_SYMBOL(input_update_ledstate);
+
+unsigned int input_get_ledstate(void)
+{
+	return ledstate;
+}
+EXPORT_SYMBOL(input_get_ledstate);
+
 /**
  * input_alloc_absinfo - allocates array of input_absinfo structs
  * @dev: the input device emitting absolute events
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index c7fbbcdcc346..0cfccb1d7992 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -151,7 +151,6 @@ static bool rep;			/* flag telling character repeat */
 
 static int shift_state = 0;
 
-static unsigned int ledstate = -1U;			/* undefined */
 static unsigned char ledioctl;
 
 /*
@@ -1021,10 +1020,14 @@ struct kbd_led_trigger {
 
 static int kbd_led_trigger_activate(struct led_classdev *cdev)
 {
+	unsigned int ledstate;
+
 	struct kbd_led_trigger *trigger =
 		container_of(cdev->trigger, struct kbd_led_trigger, trigger);
 
 	tasklet_disable(&keyboard_tasklet);
+
+	ledstate = input_get_ledstate();
 	if (ledstate != -1U)
 		led_trigger_event(&trigger->trigger,
 				  ledstate & trigger->mask ?
@@ -1137,6 +1140,10 @@ static void kbd_init_leds(void)
  */
 static unsigned char getledstate(void)
 {
+	unsigned int ledstate;
+
+	ledstate = input_get_ledstate();
+
 	return ledstate & 0xff;
 }
 
@@ -1248,16 +1255,21 @@ void vt_kbd_con_stop(unsigned int console)
 static void kbd_bh(struct tasklet_struct *unused)
 {
 	unsigned int leds;
+	unsigned int ledstate;
 	unsigned long flags;
+	struct kbd_struct *kb = kbd_table + fg_console;
+
+	if (kb->kbdmode == VC_OFF)
+		return;
 
 	spin_lock_irqsave(&led_lock, flags);
 	leds = getleds();
+	ledstate = input_get_ledstate();
 	leds |= (unsigned int)kbd->lockstate << 8;
 	spin_unlock_irqrestore(&led_lock, flags);
 
 	if (leds != ledstate) {
 		kbd_propagate_led_state(ledstate, leds);
-		ledstate = leds;
 	}
 }
 
@@ -1604,8 +1616,11 @@ static void kbd_disconnect(struct input_handle *handle)
  */
 static void kbd_start(struct input_handle *handle)
 {
+	unsigned int ledstate;
+
 	tasklet_disable(&keyboard_tasklet);
 
+	ledstate = input_get_ledstate();
 	if (ledstate != -1U)
 		kbd_update_leds_helper(handle, &ledstate);
 
diff --git a/include/linux/input.h b/include/linux/input.h
index 0354b298d874..0e0ba53a9cc7 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -420,6 +420,9 @@ ktime_t *input_get_timestamp(struct input_dev *dev);
 void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value);
 void input_inject_event(struct input_handle *handle, unsigned int type, unsigned int code, int value);
 
+void input_update_ledstate(unsigned int flag, unsigned int value);
+unsigned int input_get_ledstate(void);
+
 static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)
 {
 	input_event(dev, EV_KEY, code, !!value);
-- 
2.20.1




^ permalink raw reply	[flat|nested] 19+ messages in thread
* [PATCH] input&tty: Fix the keyboard led light display problem
@ 2021-10-15  1:20 lianzhi chang
  0 siblings, 0 replies; 19+ messages in thread
From: lianzhi chang @ 2021-10-15  1:20 UTC (permalink / raw)
  To: linux-kernel; +Cc: linux-input, lianzhi chang

Switching from the desktop environment to the tty environment,
the state of the keyboard led lights and the state of the keyboard
lock are inconsistent. This is because the attribute kb->kbdmode
of the tty bound in the desktop environment (xorg) is set to
VC_OFF, which causes the ledstate and kb->ledflagstate
values of the bound tty to always be 0, which causes the switch
from the desktop When to the tty environment, the LED light
status is inconsistent with the keyboard lock status.

Signed-off-by: lianzhi chang <changlianzhi@uniontech.com>
---
 drivers/input/input.c     |  7 ++++++-
 drivers/tty/vt/keyboard.c | 30 +++++++++++++++++++++++++++++-
 include/linux/kbd_kern.h  |  2 ++
 3 files changed, 37 insertions(+), 2 deletions(-)

diff --git a/drivers/input/input.c b/drivers/input/input.c
index ccaeb2426385..43c09700bf68 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -25,6 +25,7 @@
 #include <linux/rcupdate.h>
 #include "input-compat.h"
 #include "input-poller.h"
+#include <linux/kbd_kern.h>
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
 MODULE_DESCRIPTION("Input core");
@@ -472,8 +473,12 @@ void input_inject_event(struct input_handle *handle,
 
 		rcu_read_lock();
 		grab = rcu_dereference(dev->grab);
-		if (!grab || grab == handle)
+		if (!grab || grab == handle) {
 			input_handle_event(dev, type, code, value);
+
+			if (type == EV_LED && code < LED_SCROLLL)
+				update_value_ledstate(code, value);
+		}
 		rcu_read_unlock();
 
 		spin_unlock_irqrestore(&dev->event_lock, flags);
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index c7fbbcdcc346..0240915cdfef 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -1140,6 +1140,31 @@ static unsigned char getledstate(void)
 	return ledstate & 0xff;
 }
 
+void update_value_ledstate(unsigned int flag, unsigned int value)
+{
+	unsigned int bit;
+
+	switch (flag) {
+	case LED_NUML:
+		bit = VC_NUMLOCK;
+		break;
+	case LED_CAPSL:
+		bit = VC_CAPSLOCK;
+		break;
+	case LED_SCROLLL:
+		bit = VC_SCROLLOCK;
+		break;
+	default:
+		WARN_ON_ONCE(1);
+		return;
+	}
+
+	if (value)
+		ledstate |= BIT(bit);
+	else
+		ledstate &= ~BIT(bit);
+}
+
 void setledstate(struct kbd_struct *kb, unsigned int led)
 {
         unsigned long flags;
@@ -1249,6 +1274,10 @@ static void kbd_bh(struct tasklet_struct *unused)
 {
 	unsigned int leds;
 	unsigned long flags;
+	struct kbd_struct *kb = kbd_table + fg_console;
+
+	if (kb->kbdmode == VC_OFF)
+		return;
 
 	spin_lock_irqsave(&led_lock, flags);
 	leds = getleds();
@@ -1257,7 +1286,6 @@ static void kbd_bh(struct tasklet_struct *unused)
 
 	if (leds != ledstate) {
 		kbd_propagate_led_state(ledstate, leds);
-		ledstate = leds;
 	}
 }
 
diff --git a/include/linux/kbd_kern.h b/include/linux/kbd_kern.h
index c40811d79769..36a3402658e6 100644
--- a/include/linux/kbd_kern.h
+++ b/include/linux/kbd_kern.h
@@ -62,6 +62,8 @@ extern int kbd_init(void);
 
 extern void setledstate(struct kbd_struct *kbd, unsigned int led);
 
+extern void update_value_ledstate(int flag, int value);
+
 extern int do_poke_blanked_console;
 
 extern void (*kbd_ledfunc)(unsigned int led);
-- 
2.20.1

Dear friends, because the email I send to linux-kernel@vger.kernel.org 
will always fail many times, in order not to harass you, the latest 
information may not be synchronized with you. For the previous problem, 
I will resend it again. And respond to the previous questions:

@Jiri Slaby <jirislaby@kernel.org>
(1)
> +            if (type == EV_LED && code < 3)
>
> 3 is a magic constant. In fact, you mean "code <= LED_SCROLLL", right?

> > Yes, that's it.I have corrected it.
(2)
>   +void update_value_ledstate(int flag, int value)
>
> Why is the int signed?

> >I will correct it, it's my mistake

(3)
> +{
> +    if (ledstate == -1U)
> +        ledstate = 0;
> +
> +    if (flag == LED_NUML) {
> +        ledstate &= ~(1 << 1);

> ledstate &= ~BIT(VC_NUMLOCK);
>
> +        ledstate |= value << 1;
>
>What ensures that value is 0 or 1 here?

> >The original code here is like this, there is no guarantee that the
> >value passed down is 0 or 1, I need to think about how to do it!

(4)
> What about something like this (maybe ifs would be shorter, dunno, try
> it):
> unsigned int bit;
>
> switch (flag) {
> case LED_NUML:
>   bit = VC_NUMLOCK;
>   break;
> case LED_CAPSL:
>   bit = VC_CAPSLOCK;
>   break;
> case LED_SCROLLL:
>   bit = VC_SCROLLOCK;
>   break;
> default:
>   WARN_ON_ONCE(1);
>   return;
> }
>
> if (value)
>   ledstate |= BIT(bit);
> else
>   ledstate &= ~BIT(BIT);

>>This way the intention is clearer, I also considered how to optimize
>>here, your code is better than mine!

(5)
> Can you explain why (not to me, to the commit log)?
>
>       spin_lock_irqsave(&led_lock, flags);
>       leds = getleds();
> @@ -1257,7 +1278,6 @@ static void kbd_bh(struct tasklet_struct *unused)
>         if (leds != ledstate) {
>           kbd_propagate_led_state(ledstate, leds);
> -        ledstate = leds;
>
> The same here. Why this doesn't break the current behaviour.

>>Assuming that the desktop environment (xorg) occupies tty1,
>> kb->kbdmode of tty1 will be set to VC_OFF. According to the code logic
>> before modification, problems will occur:
>>1) The ledstate and kb->ledflagstate in the tty1 environment are
>always 0 and will not be modified.
>>2) At this time, if ledstate is not 0 in the tty2 environment,
>>switch from tty2 to tty1 (desktop environment). According to the code
>> logic of kbd_event (tasklet_schedule(&keyboard_tasklet), the code
>> execution enters the kbd_bh() function, at this time tty1 Will go to
>> set the keyboard state to 0. At this time, the keyboard setting state
>> of xorg may not be like this.


@Andy Shevchenko<andriy.shevchenko@linux.intel.com>
(1)
> + if (value)
> + ledstate |= BIT(bit);
> + else
> + ledstate &= ~BIT(BIT);

>NIH assign_bit().

>On top of that, what is BIT as parameter does in the else branch? Have you
>compiled this?

>>This is an error and has been corrected.
(2)
>  extern void setledstate(struct kbd_struct *kbd, unsigned int led);

>

>Not sure if wee need this blank line, since both functions are from the same
>(functional) group.

> +extern void update_value_ledstate(int flag, int value);

>>I don't understand what you mean here. Isn't there a blank line between all function declarations?

(3)
> + unsigned int bit;
unsigned long bit;
(see below why)
>>Why is unsigned long bit??

@Dmitry Torokhov <dmitry.torokhov@gmail.com> 
>No, we should not be putting hooks for tty/vt directly into input core.
>The code in drivers/tty/vt/keyboard.c is getting all relevant input
>events and should be able to keep the led state synchronized. Please
>keep all the changes localized there.

>>Although driver/tty/vt/keyboard.c is acquiring all related input events, 
>>the related operations of the input_inject_event function should be passed to 
>>the keyboard driver, right? After input_inject_event is completed, can 
>>kbd_event still get the corresponding change event?

>>I think it is possible to put the ledstate variable and the update_value_ledstate function into the input module, and add a new function for keyboard.c to call (for example: get_kbd_ledstate), so that keyboard.c can get the value of ledstate. Is this okay?

---
Thank you very much for your hard work!!
lianzhi chang



^ permalink raw reply	[flat|nested] 19+ messages in thread
* [PATCH] input&tty: Fix the keyboard led light display problem
@ 2021-10-14  8:53 lianzhi chang
       [not found] ` <616827d8.1c69fb81.75aa0.eea0SMTPIN_ADDED_BROKEN@mx.google.com>
  0 siblings, 1 reply; 19+ messages in thread
From: lianzhi chang @ 2021-10-14  8:53 UTC (permalink / raw)
  To: linux-kernel; +Cc: linux-input, lianzhi chang

Switching from the desktop environment to the tty environment,
the state of the keyboard led lights and the state of the keyboard
lock are inconsistent. This is because the attribute kb->kbdmode
of the tty bound in the desktop environment (xorg) is set to
VC_OFF, which causes the ledstate and kb->ledflagstate
values of the bound tty to always be 0, which causes the switch
from the desktop When to the tty environment, the LED light
status is inconsistent with the keyboard lock status.

Signed-off-by: lianzhi chang <changlianzhi@uniontech.com>
---
 drivers/input/input.c     |  7 ++++++-
 drivers/tty/vt/keyboard.c | 30 +++++++++++++++++++++++++++++-
 include/linux/kbd_kern.h  |  2 ++
 3 files changed, 37 insertions(+), 2 deletions(-)

diff --git a/drivers/input/input.c b/drivers/input/input.c
index ccaeb2426385..43c09700bf68 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -25,6 +25,7 @@
 #include <linux/rcupdate.h>
 #include "input-compat.h"
 #include "input-poller.h"
+#include <linux/kbd_kern.h>
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
 MODULE_DESCRIPTION("Input core");
@@ -472,8 +473,12 @@ void input_inject_event(struct input_handle *handle,
 
 		rcu_read_lock();
 		grab = rcu_dereference(dev->grab);
-		if (!grab || grab == handle)
+		if (!grab || grab == handle) {
 			input_handle_event(dev, type, code, value);
+
+			if (type == EV_LED && code < LED_SCROLLL)
+				update_value_ledstate(code, value);
+		}
 		rcu_read_unlock();
 
 		spin_unlock_irqrestore(&dev->event_lock, flags);
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index c7fbbcdcc346..0240915cdfef 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -1140,6 +1140,31 @@ static unsigned char getledstate(void)
 	return ledstate & 0xff;
 }
 
+void update_value_ledstate(unsigned int flag, unsigned int value)
+{
+	unsigned int bit;
+
+	switch (flag) {
+	case LED_NUML:
+		bit = VC_NUMLOCK;
+		break;
+	case LED_CAPSL:
+		bit = VC_CAPSLOCK;
+		break;
+	case LED_SCROLLL:
+		bit = VC_SCROLLOCK;
+		break;
+	default:
+		WARN_ON_ONCE(1);
+		return;
+	}
+
+	if (value)
+		ledstate |= BIT(bit);
+	else
+		ledstate &= ~BIT(bit);
+}
+
 void setledstate(struct kbd_struct *kb, unsigned int led)
 {
         unsigned long flags;
@@ -1249,6 +1274,10 @@ static void kbd_bh(struct tasklet_struct *unused)
 {
 	unsigned int leds;
 	unsigned long flags;
+	struct kbd_struct *kb = kbd_table + fg_console;
+
+	if (kb->kbdmode == VC_OFF)
+		return;
 
 	spin_lock_irqsave(&led_lock, flags);
 	leds = getleds();
@@ -1257,7 +1286,6 @@ static void kbd_bh(struct tasklet_struct *unused)
 
 	if (leds != ledstate) {
 		kbd_propagate_led_state(ledstate, leds);
-		ledstate = leds;
 	}
 }
 
diff --git a/include/linux/kbd_kern.h b/include/linux/kbd_kern.h
index c40811d79769..36a3402658e6 100644
--- a/include/linux/kbd_kern.h
+++ b/include/linux/kbd_kern.h
@@ -62,6 +62,8 @@ extern int kbd_init(void);
 
 extern void setledstate(struct kbd_struct *kbd, unsigned int led);
 
+extern void update_value_ledstate(int flag, int value);
+
 extern int do_poke_blanked_console;
 
 extern void (*kbd_ledfunc)(unsigned int led);
-- 
2.20.1




^ permalink raw reply	[flat|nested] 19+ messages in thread
[parent not found: <20211014071627.23256-1-changlianzhi@uniontech.com>]
* [PATCH] input&tty: Fix the keyboard led light display problem
@ 2021-10-14  7:20 lianzhi chang
  0 siblings, 0 replies; 19+ messages in thread
From: lianzhi chang @ 2021-10-14  7:20 UTC (permalink / raw)
  To: linux-kernel; +Cc: linux-input, lianzhi chang

Switching from the desktop environment to the tty environment,
the state of the keyboard led lights and the state of the keyboard
lock are inconsistent. This is because the attribute kb->kbdmode
of the tty bound in the desktop environment (xorg) is set to
VC_OFF, which causes the ledstate and kb->ledflagstate
values of the bound tty to always be 0, which causes the switch
from the desktop When to the tty environment, the LED light
status is inconsistent with the keyboard lock status.

Signed-off-by: lianzhi chang <changlianzhi@uniontech.com>
---
 drivers/input/input.c     |  7 ++++++-
 drivers/tty/vt/keyboard.c | 30 +++++++++++++++++++++++++++++-
 include/linux/kbd_kern.h  |  2 ++
 3 files changed, 37 insertions(+), 2 deletions(-)

diff --git a/drivers/input/input.c b/drivers/input/input.c
index ccaeb2426385..43c09700bf68 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -25,6 +25,7 @@
 #include <linux/rcupdate.h>
 #include "input-compat.h"
 #include "input-poller.h"
+#include <linux/kbd_kern.h>
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
 MODULE_DESCRIPTION("Input core");
@@ -472,8 +473,12 @@ void input_inject_event(struct input_handle *handle,
 
 		rcu_read_lock();
 		grab = rcu_dereference(dev->grab);
-		if (!grab || grab == handle)
+		if (!grab || grab == handle) {
 			input_handle_event(dev, type, code, value);
+
+			if (type == EV_LED && code < LED_SCROLLL)
+				update_value_ledstate(code, value);
+		}
 		rcu_read_unlock();
 
 		spin_unlock_irqrestore(&dev->event_lock, flags);
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index c7fbbcdcc346..f612ed5c647f 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -1140,6 +1140,31 @@ static unsigned char getledstate(void)
 	return ledstate & 0xff;
 }
 
+void update_value_ledstate(unsigned int flag, unsigned int value)
+{
+	unsigned int bit;
+
+	switch (flag) {
+	case LED_NUML:
+		bit = VC_NUMLOCK;
+		break;
+	case LED_CAPSL:
+		bit = VC_CAPSLOCK;
+		break;
+	case LED_SCROLLL:
+		bit = VC_SCROLLOCK;
+		break;
+	default:
+		WARN_ON_ONCE(1);
+		return;
+	}
+
+	if (value)
+		ledstate |= BIT(bit);
+	else
+		ledstate &= ~BIT(BIT);
+}
+
 void setledstate(struct kbd_struct *kb, unsigned int led)
 {
         unsigned long flags;
@@ -1249,6 +1274,10 @@ static void kbd_bh(struct tasklet_struct *unused)
 {
 	unsigned int leds;
 	unsigned long flags;
+	struct kbd_struct *kb = kbd_table + fg_console;
+
+	if (kb->kbdmode == VC_OFF)
+		return;
 
 	spin_lock_irqsave(&led_lock, flags);
 	leds = getleds();
@@ -1257,7 +1286,6 @@ static void kbd_bh(struct tasklet_struct *unused)
 
 	if (leds != ledstate) {
 		kbd_propagate_led_state(ledstate, leds);
-		ledstate = leds;
 	}
 }
 
diff --git a/include/linux/kbd_kern.h b/include/linux/kbd_kern.h
index c40811d79769..36a3402658e6 100644
--- a/include/linux/kbd_kern.h
+++ b/include/linux/kbd_kern.h
@@ -62,6 +62,8 @@ extern int kbd_init(void);
 
 extern void setledstate(struct kbd_struct *kbd, unsigned int led);
 
+extern void update_value_ledstate(int flag, int value);
+
 extern int do_poke_blanked_console;
 
 extern void (*kbd_ledfunc)(unsigned int led);
-- 
2.20.1




^ permalink raw reply	[flat|nested] 19+ messages in thread
[parent not found: <20211014040508.8367-1-changlianzhi@uniontech.com>]
[parent not found: <20211014030836.30612-1-changlianzhi@uniontech.com>]
* [PATCH] input&tty: Fix the keyboard led light display problem
@ 2021-10-14  4:06 lianzhi chang
  0 siblings, 0 replies; 19+ messages in thread
From: lianzhi chang @ 2021-10-14  4:06 UTC (permalink / raw)
  To: linux-kernel; +Cc: linux-input, 282827961, lianzhi chang

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 3122 bytes --]

Switching from the desktop environment to the tty environment,
the state of the keyboard led lights and the state of the keyboard
lock are inconsistent. This is because the attribute kb->kbdmode
of the tty bound in the desktop environment (xorg) is set to
VC_OFF, which causes the ledstate and kb->ledflagstate
values of the bound tty to always be 0, which causes the switch
from the desktop When to the tty environment, the LED light
status is inconsistent with the keyboard lock status.

Signed-off-by: lianzhi chang <changlianzhi@uniontech.com>
---
 drivers/input/input.c     |  7 ++++++-
 drivers/tty/vt/keyboard.c | 22 +++++++++++++++++++++-
 include/linux/kbd_kern.h  |  2 ++
 3 files changed, 29 insertions(+), 2 deletions(-)

diff --git a/drivers/input/input.c b/drivers/input/input.c
index ccaeb2426385..41f6186a9cc4 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -25,6 +25,7 @@
 #include <linux/rcupdate.h>
 #include "input-compat.h"
 #include "input-poller.h"
+#include <linux/kbd_kern.h>
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
 MODULE_DESCRIPTION("Input core");
@@ -472,8 +473,12 @@ void input_inject_event(struct input_handle *handle,
 
 		rcu_read_lock();
 		grab = rcu_dereference(dev->grab);
-		if (!grab || grab == handle)
+		if (!grab || grab == handle) {
 			input_handle_event(dev, type, code, value);
+
+			if (type == EV_LED && code < 3)
+				update_value_ledstate(code, value);
+		}
 		rcu_read_unlock();
 
 		spin_unlock_irqrestore(&dev->event_lock, flags);
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index c7fbbcdcc346..005fa5cf2a67 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -1140,6 +1140,23 @@ static unsigned char getledstate(void)
 	return ledstate & 0xff;
 }
 
+void update_value_ledstate(int flag, int value)
+{
+	if (ledstate == -1U)
+		ledstate = 0;
+
+	if (flag == LED_NUML) {
+		ledstate &= ~(1 << 1);
+		ledstate |= value << 1;
+	} else if (flag == LED_CAPSL) {
+		ledstate &= ~(1 << 2);
+		ledstate |= value << 2;
+	} else if (flag == LED_SCROLLL) {
+		ledstate &= ~(1 << 0);
+		ledstate |= value << 0;
+	}
+}
+
 void setledstate(struct kbd_struct *kb, unsigned int led)
 {
         unsigned long flags;
@@ -1249,6 +1266,10 @@ static void kbd_bh(struct tasklet_struct *unused)
 {
 	unsigned int leds;
 	unsigned long flags;
+	struct kbd_struct *kb = kbd_table + fg_console;
+
+	if (kb->kbdmode == VC_OFF)
+		return;
 
 	spin_lock_irqsave(&led_lock, flags);
 	leds = getleds();
@@ -1257,7 +1278,6 @@ static void kbd_bh(struct tasklet_struct *unused)
 
 	if (leds != ledstate) {
 		kbd_propagate_led_state(ledstate, leds);
-		ledstate = leds;
 	}
 }
 
diff --git a/include/linux/kbd_kern.h b/include/linux/kbd_kern.h
index c40811d79769..36a3402658e6 100644
--- a/include/linux/kbd_kern.h
+++ b/include/linux/kbd_kern.h
@@ -62,6 +62,8 @@ extern int kbd_init(void);
 
 extern void setledstate(struct kbd_struct *kbd, unsigned int led);
 
+extern void update_value_ledstate(int flag, int value);
+
 extern int do_poke_blanked_console;
 
 extern void (*kbd_ledfunc)(unsigned int led);
-- 
2.20.1


\v¸\x12

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2021-10-15 10:16 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <20211015083613.7429-1-changlianzhi@uniontech.com>
2021-10-15  8:41 ` [PATCH] input&tty: Fix the keyboard led light display problem Greg KH
     [not found]   ` <616942b2.1c69fb81.dfbff.25afSMTPIN_ADDED_BROKEN@mx.google.com>
2021-10-15 10:16     ` Greg KH
     [not found] <35696980-2a55-c5c1-3fa9-eadf251dcdde@uniontech.com>
2021-10-15 13:06 ` Andy Shevchenko
2021-10-15  8:37 lianzhi chang
     [not found] <61693925.1c69fb81.a058.27f2SMTPIN_ADDED_BROKEN@mx.google.com>
2021-10-15  8:25 ` Greg KH
  -- strict thread matches above, loose matches on Subject: below --
2021-10-15  6:45 lianzhi chang
2021-10-15  6:52 ` Greg KH
     [not found]   ` <616934f3.1c69fb81.59ff6.49d9SMTPIN_ADDED_BROKEN@mx.google.com>
2021-10-15  8:04     ` Greg KH
2021-10-15  1:20 lianzhi chang
2021-10-14  8:53 lianzhi chang
     [not found] ` <616827d8.1c69fb81.75aa0.eea0SMTPIN_ADDED_BROKEN@mx.google.com>
2021-10-14 13:21   ` gregkh
     [not found] <20211014071627.23256-1-changlianzhi@uniontech.com>
2021-10-14  7:34 ` Greg KH
2021-10-14 15:13 ` Andy Shevchenko
2021-10-14 14:55   ` Jiri Slaby
2021-10-14 18:20 ` Dmitry Torokhov
2021-10-14  7:20 lianzhi chang
     [not found] <20211014040508.8367-1-changlianzhi@uniontech.com>
2021-10-14  4:12 ` Jiri Slaby
     [not found] <20211014030836.30612-1-changlianzhi@uniontech.com>
2021-10-14  4:12 ` Jiri Slaby
2021-10-14  4:06 lianzhi chang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).