linux-input.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] HID: apple: fix up the F6 key on the Omoton KB066 keyboard
@ 2024-10-01  5:51 Alex Henrie
  2025-01-17  6:12 ` [PATCH resend] " Alex Henrie
  0 siblings, 1 reply; 24+ messages in thread
From: Alex Henrie @ 2024-10-01  5:51 UTC (permalink / raw)
  To: linux-input, jkosina; +Cc: Alex Henrie

The Omoton KB066 is an Apple A1255 keyboard clone (HID product code
05ac:022c). On both keyboards, the F6 key becomes Num Lock when the Fn
key is held. But unlike its Apple exemplar, when the Omoton's F6 key is
pressed without Fn, it sends the usage code 0xC0301 from the reserved
section of the consumer page instead of the standard F6 usage code
0x7003F from the keyboard page. The nonstandard code is translated to
KEY_UNKNOWN and becomes useless on Linux. The Omoton KB066 is a pretty
popular keyboard, judging from its 28,932 reviews on Amazon at time of
writing, so let's account for its quirk to make it more usable.

By the way, it would be nice if we could automatically set fnmode to 0
for Omoton keyboards because they handle the Fn key internally and the
kernel's Fn key handling creates undesirable side effects such as making
F1 and F2 always Brightness Up and Brightness Down in fnmode=1 (the
default) or always F1 and F2 in fnmode=2. Unfortunately I don't think
there's a way to identify Bluetooth keyboards more specifically than the
HID product code which is obviously inaccurate. Users of Omoton
keyboards will just have to set fnmode to 0 manually to get full Fn key
functionality.

Signed-off-by: Alex Henrie <alexhenrie24@gmail.com>
---
 drivers/hid/hid-apple.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index 7e1ae2a2bcc2..9767d17941d0 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -545,6 +545,9 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
 		}
 	}
 
+	if (usage->hid == 0xc0301) /* Omoton KB066 quirk */
+		code = KEY_F6;
+
 	if (usage->code != code) {
 		input_event_with_scancode(input, usage->type, code, usage->hid, value);
 
-- 
2.46.2


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

* [PATCH resend] HID: apple: fix up the F6 key on the Omoton KB066 keyboard
  2024-10-01  5:51 [PATCH] HID: apple: fix up the F6 key on the Omoton KB066 keyboard Alex Henrie
@ 2025-01-17  6:12 ` Alex Henrie
  2025-02-03 21:57   ` Jiri Kosina
                     ` (2 more replies)
  0 siblings, 3 replies; 24+ messages in thread
From: Alex Henrie @ 2025-01-17  6:12 UTC (permalink / raw)
  To: linux-input, jkosina, benjamin.tissoires; +Cc: Alex Henrie

The Omoton KB066 is an Apple A1255 keyboard clone (HID product code
05ac:022c). On both keyboards, the F6 key becomes Num Lock when the Fn
key is held. But unlike its Apple exemplar, when the Omoton's F6 key is
pressed without Fn, it sends the usage code 0xC0301 from the reserved
section of the consumer page instead of the standard F6 usage code
0x7003F from the keyboard page. The nonstandard code is translated to
KEY_UNKNOWN and becomes useless on Linux. The Omoton KB066 is a pretty
popular keyboard, judging from its 29,058 reviews on Amazon at time of
writing, so let's account for its quirk to make it more usable.

By the way, it would be nice if we could automatically set fnmode to 0
for Omoton keyboards because they handle the Fn key internally and the
kernel's Fn key handling creates undesirable side effects such as making
F1 and F2 always Brightness Up and Brightness Down in fnmode=1 (the
default) or always F1 and F2 in fnmode=2. Unfortunately I don't think
there's a way to identify Bluetooth keyboards more specifically than the
HID product code which is obviously inaccurate. Users of Omoton
keyboards will just have to set fnmode to 0 manually to get full Fn key
functionality.

Signed-off-by: Alex Henrie <alexhenrie24@gmail.com>
---
 drivers/hid/hid-apple.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index 7e1ae2a2bcc2..9767d17941d0 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -545,6 +545,9 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
 		}
 	}
 
+	if (usage->hid == 0xc0301) /* Omoton KB066 quirk */
+		code = KEY_F6;
+
 	if (usage->code != code) {
 		input_event_with_scancode(input, usage->type, code, usage->hid, value);
 
-- 
2.48.1


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

* Re: [PATCH resend] HID: apple: fix up the F6 key on the Omoton KB066 keyboard
  2025-01-17  6:12 ` [PATCH resend] " Alex Henrie
@ 2025-02-03 21:57   ` Jiri Kosina
  2025-02-05  3:02     ` Alex Henrie
  2025-02-07 13:07   ` Jiri Kosina
  2025-02-12 17:36   ` Aditya Garg
  2 siblings, 1 reply; 24+ messages in thread
From: Jiri Kosina @ 2025-02-03 21:57 UTC (permalink / raw)
  To: Alex Henrie; +Cc: linux-input, benjamin.tissoires

On Thu, 16 Jan 2025, Alex Henrie wrote:

> The Omoton KB066 is an Apple A1255 keyboard clone (HID product code
> 05ac:022c). On both keyboards, the F6 key becomes Num Lock when the Fn
> key is held. But unlike its Apple exemplar, when the Omoton's F6 key is
> pressed without Fn, it sends the usage code 0xC0301 from the reserved
> section of the consumer page instead of the standard F6 usage code
> 0x7003F from the keyboard page. The nonstandard code is translated to
> KEY_UNKNOWN and becomes useless on Linux. The Omoton KB066 is a pretty
> popular keyboard, judging from its 29,058 reviews on Amazon at time of
> writing, so let's account for its quirk to make it more usable.
> 
> By the way, it would be nice if we could automatically set fnmode to 0
> for Omoton keyboards because they handle the Fn key internally and the
> kernel's Fn key handling creates undesirable side effects such as making
> F1 and F2 always Brightness Up and Brightness Down in fnmode=1 (the
> default) or always F1 and F2 in fnmode=2. Unfortunately I don't think
> there's a way to identify Bluetooth keyboards more specifically than the
> HID product code which is obviously inaccurate. Users of Omoton
> keyboards will just have to set fnmode to 0 manually to get full Fn key
> functionality.
> 
> Signed-off-by: Alex Henrie <alexhenrie24@gmail.com>
> ---
>  drivers/hid/hid-apple.c | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
> index 7e1ae2a2bcc2..9767d17941d0 100644
> --- a/drivers/hid/hid-apple.c
> +++ b/drivers/hid/hid-apple.c
> @@ -545,6 +545,9 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
>  		}
>  	}
>  
> +	if (usage->hid == 0xc0301) /* Omoton KB066 quirk */
> +		code = KEY_F6;
> +

Sorry, it's not clear to me from the changelog why it's not possible to 
make this quirk apply only in case we're known to have 0x5ac/0x022c 
device. Is this VID/PID shared with other, differently-behaving devices?

Thanks,

-- 
Jiri Kosina
SUSE Labs


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

* Re: [PATCH resend] HID: apple: fix up the F6 key on the Omoton KB066 keyboard
  2025-02-03 21:57   ` Jiri Kosina
@ 2025-02-05  3:02     ` Alex Henrie
  0 siblings, 0 replies; 24+ messages in thread
From: Alex Henrie @ 2025-02-05  3:02 UTC (permalink / raw)
  To: Jiri Kosina; +Cc: linux-input, benjamin.tissoires

On Mon, Feb 3, 2025 at 2:57 PM Jiri Kosina <jikos@kernel.org> wrote:
>
> On Thu, 16 Jan 2025, Alex Henrie wrote:

> > diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
> > index 7e1ae2a2bcc2..9767d17941d0 100644
> > --- a/drivers/hid/hid-apple.c
> > +++ b/drivers/hid/hid-apple.c
> > @@ -545,6 +545,9 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
> >               }
> >       }
> >
> > +     if (usage->hid == 0xc0301) /* Omoton KB066 quirk */
> > +             code = KEY_F6;
> > +
>
> Sorry, it's not clear to me from the changelog why it's not possible to
> make this quirk apply only in case we're known to have 0x5ac/0x022c
> device. Is this VID/PID shared with other, differently-behaving devices?

The real Apple A1255 and the Omoton KB066 are both 05ac:022c. The
hid-apple driver is only used for devices that have VID 05ac, so
there's no need to check the VID again. We could restrict the quirk to
PID 022c only, but if the keyboard emits the reserved code 0xC0301,
it's surely an Omoton KB066 because no other keyboard uses that code.
What would be the advantage to adding a PID check?

-Alex

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

* Re: [PATCH resend] HID: apple: fix up the F6 key on the Omoton KB066 keyboard
  2025-01-17  6:12 ` [PATCH resend] " Alex Henrie
  2025-02-03 21:57   ` Jiri Kosina
@ 2025-02-07 13:07   ` Jiri Kosina
  2025-02-12 17:36   ` Aditya Garg
  2 siblings, 0 replies; 24+ messages in thread
From: Jiri Kosina @ 2025-02-07 13:07 UTC (permalink / raw)
  To: Alex Henrie; +Cc: linux-input, benjamin.tissoires

On Thu, 16 Jan 2025, Alex Henrie wrote:

> The Omoton KB066 is an Apple A1255 keyboard clone (HID product code
> 05ac:022c). On both keyboards, the F6 key becomes Num Lock when the Fn
> key is held. But unlike its Apple exemplar, when the Omoton's F6 key is
> pressed without Fn, it sends the usage code 0xC0301 from the reserved
> section of the consumer page instead of the standard F6 usage code
> 0x7003F from the keyboard page. The nonstandard code is translated to
> KEY_UNKNOWN and becomes useless on Linux. The Omoton KB066 is a pretty
> popular keyboard, judging from its 29,058 reviews on Amazon at time of
> writing, so let's account for its quirk to make it more usable.
> 
> By the way, it would be nice if we could automatically set fnmode to 0
> for Omoton keyboards because they handle the Fn key internally and the
> kernel's Fn key handling creates undesirable side effects such as making
> F1 and F2 always Brightness Up and Brightness Down in fnmode=1 (the
> default) or always F1 and F2 in fnmode=2. Unfortunately I don't think
> there's a way to identify Bluetooth keyboards more specifically than the
> HID product code which is obviously inaccurate. Users of Omoton
> keyboards will just have to set fnmode to 0 manually to get full Fn key
> functionality.
> 
> Signed-off-by: Alex Henrie <alexhenrie24@gmail.com>

Now applied to hid.git#for-6.14/upstream-fixes, thanks.

-- 
Jiri Kosina
SUSE Labs


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

* Re: [PATCH resend] HID: apple: fix up the F6 key on the Omoton KB066 keyboard
  2025-01-17  6:12 ` [PATCH resend] " Alex Henrie
  2025-02-03 21:57   ` Jiri Kosina
  2025-02-07 13:07   ` Jiri Kosina
@ 2025-02-12 17:36   ` Aditya Garg
  2025-02-12 17:43     ` Aditya Garg
  2 siblings, 1 reply; 24+ messages in thread
From: Aditya Garg @ 2025-02-12 17:36 UTC (permalink / raw)
  To: Alex Henrie
  Cc: linux-input@vger.kernel.org, jkosina@suse.cz,
	benjamin.tissoires@redhat.com

Hi Alex

> On 17 Jan 2025, at 11:42 AM, Alex Henrie <alexhenrie24@gmail.com> wrote:
> 
> The Omoton KB066 is an Apple A1255 keyboard clone (HID product code
> 05ac:022c). On both keyboards, the F6 key becomes Num Lock when the Fn
> key is held. But unlike its Apple exemplar, when the Omoton's F6 key is
> pressed without Fn, it sends the usage code 0xC0301 from the reserved
> section of the consumer page instead of the standard F6 usage code
> 0x7003F from the keyboard page. The nonstandard code is translated to
> KEY_UNKNOWN and becomes useless on Linux. The Omoton KB066 is a pretty
> popular keyboard, judging from its 29,058 reviews on Amazon at time of
> writing, so let's account for its quirk to make it more usable.
> 
> By the way, it would be nice if we could automatically set fnmode to 0
> for Omoton keyboards because they handle the Fn key internally and the
> kernel's Fn key handling creates undesirable side effects such as making
> F1 and F2 always Brightness Up and Brightness Down in fnmode=1 (the
> default) or always F1 and F2 in fnmode=2. Unfortunately I don't think
> there's a way to identify Bluetooth keyboards more specifically than the
> HID product code which is obviously inaccurate. Users of Omoton
> keyboards will just have to set fnmode to 0 manually to get full Fn key
> functionality.

Regarding the the fnmode=0 thing, could you test this patch:

-->8—
From e2b2ef3f579800f11ee293fb45838a4004ccaf23 Mon Sep 17 00:00:00 2001
From: Aditya Garg <gargaditya08@live.com>
Date: Wed, 12 Feb 2025 22:57:58 +0530
Subject: [PATCH] HID: apple: Add quirk to disable fn key on some non-apple
 keyboards

---
 drivers/hid/hid-apple.c | 54 +++++++++++++++++++++++++++++------------
 1 file changed, 39 insertions(+), 15 deletions(-)

diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index 49812a76b..9d4cbe636 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -42,6 +42,7 @@
 #define APPLE_BACKLIGHT_CTL	BIT(10)
 #define APPLE_IS_NON_APPLE	BIT(11)
 #define APPLE_MAGIC_BACKLIGHT	BIT(12)
+#define APPLE_DISABLE_FN	BIT(13)
 
 #define APPLE_FLAG_FKEY		0x01
 
@@ -89,6 +90,19 @@ struct apple_sc_backlight {
 	struct hid_device *hdev;
 };
 
+struct apple_backlight_config_report {
+	u8 report_id;
+	u8 version;
+	u16 backlight_off, backlight_on_min, backlight_on_max;
+};
+
+struct apple_backlight_set_report {
+	u8 report_id;
+	u8 version;
+	u16 backlight;
+	u16 rate;
+};
+
 struct apple_magic_backlight {
 	struct led_classdev cdev;
 	struct hid_report *brightness;
@@ -152,20 +166,6 @@ static const struct apple_key_translation magic_keyboard_2015_fn_keys[] = {
 	{ }
 };
 
-struct apple_backlight_config_report {
-	u8 report_id;
-	u8 version;
-	u16 backlight_off, backlight_on_min, backlight_on_max;
-};
-
-struct apple_backlight_set_report {
-	u8 report_id;
-	u8 version;
-	u16 backlight;
-	u16 rate;
-};
-
-
 static const struct apple_key_translation apple2021_fn_keys[] = {
 	{ KEY_BACKSPACE, KEY_DELETE },
 	{ KEY_ENTER,	KEY_INSERT },
@@ -364,6 +364,10 @@ static const struct apple_non_apple_keyboard non_apple_keyboards[] = {
 	{ "WKB603" },
 };
 
+static const struct apple_non_apple_keyboard non_apple_keyboards_disable_fn[] = {
+	{ "Omoton" },
+};
+
 static bool apple_is_non_apple_keyboard(struct hid_device *hdev)
 {
 	int i;
@@ -378,6 +382,20 @@ static bool apple_is_non_apple_keyboard(struct hid_device *hdev)
 	return false;
 }
 
+static bool apple_disable_fn_key(struct hid_device *hdev)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(non_apple_keyboards_disable_fn); i++) {
+		char *non_apple = non_apple_keyboards_disable_fn[i].name;
+
+		if (strncmp(hdev->name, non_apple, strlen(non_apple)) == 0)
+			return true;
+	}
+
+	return false;
+}
+
 static inline void apple_setup_key_translation(struct input_dev *input,
 		const struct apple_key_translation *table)
 {
@@ -419,7 +437,8 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
 	unsigned int real_fnmode;
 
 	if (fnmode == 3) {
-		real_fnmode = (asc->quirks & APPLE_IS_NON_APPLE) ? 2 : 1;
+		real_fnmode = (asc->quirks & APPLE_DISABLE_FN) ? 0 :
+			      ((asc->quirks & APPLE_IS_NON_APPLE) ? 2 : 1);
 	} else {
 		real_fnmode = fnmode;
 	}
@@ -738,6 +757,11 @@ static int apple_input_configured(struct hid_device *hdev,
 		asc->quirks |= APPLE_IS_NON_APPLE;
 	}
 
+	if (apple_disable_fn_key(hdev)) {
+		hid_info(hdev, "Disable fn key quirk detected; fnmode=0 behaviour will be followed by default\n");
+		asc->quirks |= APPLE_DISABLE_FN;
+	}
+
 	return 0;
 }
 
-- 
2.39.5 (Apple Git-154)



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

* Re: [PATCH resend] HID: apple: fix up the F6 key on the Omoton KB066 keyboard
  2025-02-12 17:36   ` Aditya Garg
@ 2025-02-12 17:43     ` Aditya Garg
  2025-02-16  1:08       ` Alex Henrie
  0 siblings, 1 reply; 24+ messages in thread
From: Aditya Garg @ 2025-02-12 17:43 UTC (permalink / raw)
  To: Alex Henrie
  Cc: linux-input@vger.kernel.org, jkosina@suse.cz,
	benjamin.tissoires@redhat.com



> On 12 Feb 2025, at 11:06 PM, Aditya Garg <gargaditya08@live.com> wrote:
> 
> Hi Alex
> 
>> On 17 Jan 2025, at 11:42 AM, Alex Henrie <alexhenrie24@gmail.com> wrote:
>> 
>> The Omoton KB066 is an Apple A1255 keyboard clone (HID product code
>> 05ac:022c). On both keyboards, the F6 key becomes Num Lock when the Fn
>> key is held. But unlike its Apple exemplar, when the Omoton's F6 key is
>> pressed without Fn, it sends the usage code 0xC0301 from the reserved
>> section of the consumer page instead of the standard F6 usage code
>> 0x7003F from the keyboard page. The nonstandard code is translated to
>> KEY_UNKNOWN and becomes useless on Linux. The Omoton KB066 is a pretty
>> popular keyboard, judging from its 29,058 reviews on Amazon at time of
>> writing, so let's account for its quirk to make it more usable.
>> 
>> By the way, it would be nice if we could automatically set fnmode to 0
>> for Omoton keyboards because they handle the Fn key internally and the
>> kernel's Fn key handling creates undesirable side effects such as making
>> F1 and F2 always Brightness Up and Brightness Down in fnmode=1 (the
>> default) or always F1 and F2 in fnmode=2. Unfortunately I don't think
>> there's a way to identify Bluetooth keyboards more specifically than the
>> HID product code which is obviously inaccurate. Users of Omoton
>> keyboards will just have to set fnmode to 0 manually to get full Fn key
>> functionality.
> 
> Regarding the the fnmode=0 thing, could you test this patch:
> 
> -->8—
> From e2b2ef3f579800f11ee293fb45838a4004ccaf23 Mon Sep 17 00:00:00 2001
> From: Aditya Garg <gargaditya08@live.com>
> Date: Wed, 12 Feb 2025 22:57:58 +0530
> Subject: [PATCH] HID: apple: Add quirk to disable fn key on some non-apple
> keyboards
> 
> ---
> drivers/hid/hid-apple.c | 54 +++++++++++++++++++++++++++++------------
> 1 file changed, 39 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
> index 49812a76b..9d4cbe636 100644
> --- a/drivers/hid/hid-apple.c
> +++ b/drivers/hid/hid-apple.c
> @@ -42,6 +42,7 @@
> #define APPLE_BACKLIGHT_CTL BIT(10)
> #define APPLE_IS_NON_APPLE BIT(11)
> #define APPLE_MAGIC_BACKLIGHT BIT(12)
> +#define APPLE_DISABLE_FN BIT(13)
> 
> #define APPLE_FLAG_FKEY 0x01
> 
> @@ -89,6 +90,19 @@ struct apple_sc_backlight {
> struct hid_device *hdev;
> };
> 
> +struct apple_backlight_config_report {
> + u8 report_id;
> + u8 version;
> + u16 backlight_off, backlight_on_min, backlight_on_max;
> +};
> +
> +struct apple_backlight_set_report {
> + u8 report_id;
> + u8 version;
> + u16 backlight;
> + u16 rate;
> +};
> +
> struct apple_magic_backlight {
> struct led_classdev cdev;
> struct hid_report *brightness;
> @@ -152,20 +166,6 @@ static const struct apple_key_translation magic_keyboard_2015_fn_keys[] = {
> { }
> };
> 
> -struct apple_backlight_config_report {
> - u8 report_id;
> - u8 version;
> - u16 backlight_off, backlight_on_min, backlight_on_max;
> -};
> -
> -struct apple_backlight_set_report {
> - u8 report_id;
> - u8 version;
> - u16 backlight;
> - u16 rate;
> -};
> -
> -
> static const struct apple_key_translation apple2021_fn_keys[] = {
> { KEY_BACKSPACE, KEY_DELETE },
> { KEY_ENTER, KEY_INSERT },
> @@ -364,6 +364,10 @@ static const struct apple_non_apple_keyboard non_apple_keyboards[] = {
> { "WKB603" },
> };
> 
> +static const struct apple_non_apple_keyboard non_apple_keyboards_disable_fn[] = {
> + { "Omoton" },

You could try replacing Omoton with OMOTON as well here if it does not work. Alternatively, you could try logging hdev->name for this device and put it in this table to get the correct name.

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

* Re: [PATCH resend] HID: apple: fix up the F6 key on the Omoton KB066 keyboard
  2025-02-12 17:43     ` Aditya Garg
@ 2025-02-16  1:08       ` Alex Henrie
  2025-02-16  6:06         ` Aditya Garg
  0 siblings, 1 reply; 24+ messages in thread
From: Alex Henrie @ 2025-02-16  1:08 UTC (permalink / raw)
  To: Aditya Garg
  Cc: linux-input@vger.kernel.org, jkosina@suse.cz,
	benjamin.tissoires@redhat.com

On Wed, Feb 12, 2025 at 10:44 AM Aditya Garg <gargaditya08@live.com> wrote:

> > On 12 Feb 2025, at 11:06 PM, Aditya Garg <gargaditya08@live.com> wrote:

> >> On 17 Jan 2025, at 11:42 AM, Alex Henrie <alexhenrie24@gmail.com> wrote:
> >>
> >> The Omoton KB066 is an Apple A1255 keyboard clone (HID product code
> >> 05ac:022c). On both keyboards, the F6 key becomes Num Lock when the Fn
> >> key is held. But unlike its Apple exemplar, when the Omoton's F6 key is
> >> pressed without Fn, it sends the usage code 0xC0301 from the reserved
> >> section of the consumer page instead of the standard F6 usage code
> >> 0x7003F from the keyboard page. The nonstandard code is translated to
> >> KEY_UNKNOWN and becomes useless on Linux. The Omoton KB066 is a pretty
> >> popular keyboard, judging from its 29,058 reviews on Amazon at time of
> >> writing, so let's account for its quirk to make it more usable.
> >>
> >> By the way, it would be nice if we could automatically set fnmode to 0
> >> for Omoton keyboards because they handle the Fn key internally and the
> >> kernel's Fn key handling creates undesirable side effects such as making
> >> F1 and F2 always Brightness Up and Brightness Down in fnmode=1 (the
> >> default) or always F1 and F2 in fnmode=2. Unfortunately I don't think
> >> there's a way to identify Bluetooth keyboards more specifically than the
> >> HID product code which is obviously inaccurate. Users of Omoton
> >> keyboards will just have to set fnmode to 0 manually to get full Fn key
> >> functionality.
> >
> > Regarding the the fnmode=0 thing, could you test this patch:
> >
> > -->8—
> > From e2b2ef3f579800f11ee293fb45838a4004ccaf23 Mon Sep 17 00:00:00 2001
> > From: Aditya Garg <gargaditya08@live.com>
> > Date: Wed, 12 Feb 2025 22:57:58 +0530
> > Subject: [PATCH] HID: apple: Add quirk to disable fn key on some non-apple
> > keyboards
> >
> > ---
> > drivers/hid/hid-apple.c | 54 +++++++++++++++++++++++++++++------------
> > 1 file changed, 39 insertions(+), 15 deletions(-)
> >
> > diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
> > index 49812a76b..9d4cbe636 100644
> > --- a/drivers/hid/hid-apple.c
> > +++ b/drivers/hid/hid-apple.c
> > @@ -42,6 +42,7 @@
> > #define APPLE_BACKLIGHT_CTL BIT(10)
> > #define APPLE_IS_NON_APPLE BIT(11)
> > #define APPLE_MAGIC_BACKLIGHT BIT(12)
> > +#define APPLE_DISABLE_FN BIT(13)
> >
> > #define APPLE_FLAG_FKEY 0x01
> >
> > @@ -89,6 +90,19 @@ struct apple_sc_backlight {
> > struct hid_device *hdev;
> > };
> >
> > +struct apple_backlight_config_report {
> > + u8 report_id;
> > + u8 version;
> > + u16 backlight_off, backlight_on_min, backlight_on_max;
> > +};
> > +
> > +struct apple_backlight_set_report {
> > + u8 report_id;
> > + u8 version;
> > + u16 backlight;
> > + u16 rate;
> > +};
> > +
> > struct apple_magic_backlight {
> > struct led_classdev cdev;
> > struct hid_report *brightness;
> > @@ -152,20 +166,6 @@ static const struct apple_key_translation magic_keyboard_2015_fn_keys[] = {
> > { }
> > };
> >
> > -struct apple_backlight_config_report {
> > - u8 report_id;
> > - u8 version;
> > - u16 backlight_off, backlight_on_min, backlight_on_max;
> > -};
> > -
> > -struct apple_backlight_set_report {
> > - u8 report_id;
> > - u8 version;
> > - u16 backlight;
> > - u16 rate;
> > -};
> > -
> > -
> > static const struct apple_key_translation apple2021_fn_keys[] = {
> > { KEY_BACKSPACE, KEY_DELETE },
> > { KEY_ENTER, KEY_INSERT },
> > @@ -364,6 +364,10 @@ static const struct apple_non_apple_keyboard non_apple_keyboards[] = {
> > { "WKB603" },
> > };
> >
> > +static const struct apple_non_apple_keyboard non_apple_keyboards_disable_fn[] = {
> > + { "Omoton" },
>
> You could try replacing Omoton with OMOTON as well here if it does not work. Alternatively, you could try logging hdev->name for this device and put it in this table to get the correct name.

On the Omoton KB066, hdev->name is "Bluetooth Keyboard". I think I saw
that name in Blueman and assumed that it was just a default for when a
keyboard has no name, but you're right, that string must be coming
from the keyboard itself. After changing "Omoton" to "Bluetooth
Keyboard" in non_apple_keyboards_disable_fn, your patch works!

Unfortunately, this keyboard is even more messed up than I realized.
It is indeed sending different key codes depending on whether or not
the Fn key is held. For example, F11 and F12 are Volume Down and
Volume Up by default, but ordinary F11 and F12 when Fn is held.
However, I was wrong about F1 and F2: With or without Fn, the Omoton
_never_ changes F1 to Brightness Down or F2 to Brightness Up. I
managed to pick the one bad example: All of the other special keys
(Esc, F3 through F12, and Del) are translated internally, but not F1
or F2. That also means that I was wrong about the Fn key not doing
anything in fnmode=2. When Fn is held, all of the special keys do
become ordinary keys in both fnmode=0 and fnmode=2, except for F1 and
F2 which remain ordinary F1 and F2.

When connected to macOS, the results are similar: All of the special
keys are special keys regardless of whether Fn is held, except F1 and
F2, which by default are always translated to Brightness Down and
Brightness Up like in Linux's fnmode=1. If the setting "Use F1, F2,
etc. keys as standard function keys" is enabled in the system keyboard
settings, all of the special keys change to ordinary keys when Fn is
held, except for F1 and F2 which remain F1 and F2, just like in
Linux's fnmode=0 and fnmode=2.

It seems to me that the best way to support the Omoton KB066 would be
to give it its own key translation table that has F1 and F2 and
nothing else. But on the bright side, pun humorously intended, we
wouldn't have to change the default fnmode. Just like on macOS, F1 and
F2 would always be Brightness Down and Brightness Up, unless key
translation is disabled. But unlike macOS (and the current state of
Linux), we wouldn't undo the keyboard's own Fn key handling for the
special keys that it translates internally.

Circling back to the original problem of distinguishing between the
Apple A1255 and the Omoton KB066, changing an Apple keyboard's name in
the macOS keyboard settings also changes the name that it reports to
Linux. Because "Bluetooth Keyboard" is so generic that someone might
actually give their keyboard that name intentionally, if we add
special behavior to look for that name, I think we should restrict it
to PID 022c. For example, we could add the new quirk flag to
USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI in the apple_devices table and
then clear the flag if the keyboard's name is not "Bluetooth
Keyboard".

Thanks for the help!

-Alex

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

* Re: [PATCH resend] HID: apple: fix up the F6 key on the Omoton KB066 keyboard
  2025-02-16  1:08       ` Alex Henrie
@ 2025-02-16  6:06         ` Aditya Garg
  2025-02-16  6:45           ` Aditya Garg
  0 siblings, 1 reply; 24+ messages in thread
From: Aditya Garg @ 2025-02-16  6:06 UTC (permalink / raw)
  To: Alex Henrie
  Cc: linux-input@vger.kernel.org, jkosina@suse.cz,
	benjamin.tissoires@redhat.com

So if I understand correctly

If Fn mode is 0 or 2:

F1 and F2 are brightness keys
Rest are function keys

If Fn mode is 1:

F1 and F2 are function keys
Rest are media keys

Fn key does not work in any mode

In case I am wrong, can you share what exactly happens in each mode with fn on as well as off?


> On 16 Feb 2025, at 6:38 AM, Alex Henrie <alexhenrie24@gmail.com> wrote:
> 
> On Wed, Feb 12, 2025 at 10:44 AM Aditya Garg <gargaditya08@live.com> wrote:
> 
>>> On 12 Feb 2025, at 11:06 PM, Aditya Garg <gargaditya08@live.com> wrote:
> 
>>>> On 17 Jan 2025, at 11:42 AM, Alex Henrie <alexhenrie24@gmail.com> wrote:
>>>> 
>>>> The Omoton KB066 is an Apple A1255 keyboard clone (HID product code
>>>> 05ac:022c). On both keyboards, the F6 key becomes Num Lock when the Fn
>>>> key is held. But unlike its Apple exemplar, when the Omoton's F6 key is
>>>> pressed without Fn, it sends the usage code 0xC0301 from the reserved
>>>> section of the consumer page instead of the standard F6 usage code
>>>> 0x7003F from the keyboard page. The nonstandard code is translated to
>>>> KEY_UNKNOWN and becomes useless on Linux. The Omoton KB066 is a pretty
>>>> popular keyboard, judging from its 29,058 reviews on Amazon at time of
>>>> writing, so let's account for its quirk to make it more usable.
>>>> 
>>>> By the way, it would be nice if we could automatically set fnmode to 0
>>>> for Omoton keyboards because they handle the Fn key internally and the
>>>> kernel's Fn key handling creates undesirable side effects such as making
>>>> F1 and F2 always Brightness Up and Brightness Down in fnmode=1 (the
>>>> default) or always F1 and F2 in fnmode=2. Unfortunately I don't think
>>>> there's a way to identify Bluetooth keyboards more specifically than the
>>>> HID product code which is obviously inaccurate. Users of Omoton
>>>> keyboards will just have to set fnmode to 0 manually to get full Fn key
>>>> functionality.
>>> 
>>> Regarding the the fnmode=0 thing, could you test this patch:
>>> 
>>> -->8—
>>> From e2b2ef3f579800f11ee293fb45838a4004ccaf23 Mon Sep 17 00:00:00 2001
>>> From: Aditya Garg <gargaditya08@live.com>
>>> Date: Wed, 12 Feb 2025 22:57:58 +0530
>>> Subject: [PATCH] HID: apple: Add quirk to disable fn key on some non-apple
>>> keyboards
>>> 
>>> ---
>>> drivers/hid/hid-apple.c | 54 +++++++++++++++++++++++++++++------------
>>> 1 file changed, 39 insertions(+), 15 deletions(-)
>>> 
>>> diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
>>> index 49812a76b..9d4cbe636 100644
>>> --- a/drivers/hid/hid-apple.c
>>> +++ b/drivers/hid/hid-apple.c
>>> @@ -42,6 +42,7 @@
>>> #define APPLE_BACKLIGHT_CTL BIT(10)
>>> #define APPLE_IS_NON_APPLE BIT(11)
>>> #define APPLE_MAGIC_BACKLIGHT BIT(12)
>>> +#define APPLE_DISABLE_FN BIT(13)
>>> 
>>> #define APPLE_FLAG_FKEY 0x01
>>> 
>>> @@ -89,6 +90,19 @@ struct apple_sc_backlight {
>>> struct hid_device *hdev;
>>> };
>>> 
>>> +struct apple_backlight_config_report {
>>> + u8 report_id;
>>> + u8 version;
>>> + u16 backlight_off, backlight_on_min, backlight_on_max;
>>> +};
>>> +
>>> +struct apple_backlight_set_report {
>>> + u8 report_id;
>>> + u8 version;
>>> + u16 backlight;
>>> + u16 rate;
>>> +};
>>> +
>>> struct apple_magic_backlight {
>>> struct led_classdev cdev;
>>> struct hid_report *brightness;
>>> @@ -152,20 +166,6 @@ static const struct apple_key_translation magic_keyboard_2015_fn_keys[] = {
>>> { }
>>> };
>>> 
>>> -struct apple_backlight_config_report {
>>> - u8 report_id;
>>> - u8 version;
>>> - u16 backlight_off, backlight_on_min, backlight_on_max;
>>> -};
>>> -
>>> -struct apple_backlight_set_report {
>>> - u8 report_id;
>>> - u8 version;
>>> - u16 backlight;
>>> - u16 rate;
>>> -};
>>> -
>>> -
>>> static const struct apple_key_translation apple2021_fn_keys[] = {
>>> { KEY_BACKSPACE, KEY_DELETE },
>>> { KEY_ENTER, KEY_INSERT },
>>> @@ -364,6 +364,10 @@ static const struct apple_non_apple_keyboard non_apple_keyboards[] = {
>>> { "WKB603" },
>>> };
>>> 
>>> +static const struct apple_non_apple_keyboard non_apple_keyboards_disable_fn[] = {
>>> + { "Omoton" },
>> 
>> You could try replacing Omoton with OMOTON as well here if it does not work. Alternatively, you could try logging hdev->name for this device and put it in this table to get the correct name.
> 
> On the Omoton KB066, hdev->name is "Bluetooth Keyboard". I think I saw
> that name in Blueman and assumed that it was just a default for when a
> keyboard has no name, but you're right, that string must be coming
> from the keyboard itself. After changing "Omoton" to "Bluetooth
> Keyboard" in non_apple_keyboards_disable_fn, your patch works!
> 
> Unfortunately, this keyboard is even more messed up than I realized.
> It is indeed sending different key codes depending on whether or not
> the Fn key is held. For example, F11 and F12 are Volume Down and
> Volume Up by default, but ordinary F11 and F12 when Fn is held.
> However, I was wrong about F1 and F2: With or without Fn, the Omoton
> _never_ changes F1 to Brightness Down or F2 to Brightness Up. I
> managed to pick the one bad example: All of the other special keys
> (Esc, F3 through F12, and Del) are translated internally, but not F1
> or F2. That also means that I was wrong about the Fn key not doing
> anything in fnmode=2. When Fn is held, all of the special keys do
> become ordinary keys in both fnmode=0 and fnmode=2, except for F1 and
> F2 which remain ordinary F1 and F2.
> 
> When connected to macOS, the results are similar: All of the special
> keys are special keys regardless of whether Fn is held, except F1 and
> F2, which by default are always translated to Brightness Down and
> Brightness Up like in Linux's fnmode=1. If the setting "Use F1, F2,
> etc. keys as standard function keys" is enabled in the system keyboard
> settings, all of the special keys change to ordinary keys when Fn is
> held, except for F1 and F2 which remain F1 and F2, just like in
> Linux's fnmode=0 and fnmode=2.
> 
> It seems to me that the best way to support the Omoton KB066 would be
> to give it its own key translation table that has F1 and F2 and
> nothing else. But on the bright side, pun humorously intended, we
> wouldn't have to change the default fnmode. Just like on macOS, F1 and
> F2 would always be Brightness Down and Brightness Up, unless key
> translation is disabled. But unlike macOS (and the current state of
> Linux), we wouldn't undo the keyboard's own Fn key handling for the
> special keys that it translates internally.
> 
> Circling back to the original problem of distinguishing between the
> Apple A1255 and the Omoton KB066, changing an Apple keyboard's name in
> the macOS keyboard settings also changes the name that it reports to
> Linux. Because "Bluetooth Keyboard" is so generic that someone might
> actually give their keyboard that name intentionally, if we add
> special behavior to look for that name, I think we should restrict it
> to PID 022c. For example, we could add the new quirk flag to
> USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI in the apple_devices table and
> then clear the flag if the keyboard's name is not "Bluetooth
> Keyboard".
> 
> Thanks for the help!
> 
> -Alex



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

* Re: [PATCH resend] HID: apple: fix up the F6 key on the Omoton KB066 keyboard
  2025-02-16  6:06         ` Aditya Garg
@ 2025-02-16  6:45           ` Aditya Garg
  2025-02-17  4:13             ` Alex Henrie
  0 siblings, 1 reply; 24+ messages in thread
From: Aditya Garg @ 2025-02-16  6:45 UTC (permalink / raw)
  To: Alex Henrie
  Cc: linux-input@vger.kernel.org, jkosina@suse.cz,
	benjamin.tissoires@redhat.com

I think its best to disable the internal translation of this keyboard and let the kernel manage it. It can be done by implementing a fixup table that first translates all the media controls to their respective F keys, and other similar internal translations, so that the keyboard can mimic the original Apple version. Like the all the 3 fn modes should also work.

Also looking at the keyboard pic on https://www.amazon.in/OMOTON-Ultra-Slim-Bluetooth-Keyboard-Compatible/dp/B07S7VPQG6?th=1, the translation table for magic keyboard aluminium seems quite different from what this keyboard keys show.

> On 16 Feb 2025, at 11:36 AM, Aditya Garg <gargaditya08@live.com> wrote:
> 
> So if I understand correctly
> 
> If Fn mode is 0 or 2:
> 
> F1 and F2 are brightness keys
> Rest are function keys
> 
> If Fn mode is 1:
> 
> F1 and F2 are function keys
> Rest are media keys
> 
> Fn key does not work in any mode
> 
> In case I am wrong, can you share what exactly happens in each mode with fn on as well as off?
> 
> 
>> On 16 Feb 2025, at 6:38 AM, Alex Henrie <alexhenrie24@gmail.com> wrote:
>> 
>> On Wed, Feb 12, 2025 at 10:44 AM Aditya Garg <gargaditya08@live.com> wrote:
>> 
>>>> On 12 Feb 2025, at 11:06 PM, Aditya Garg <gargaditya08@live.com> wrote:
>> 
>>>>> On 17 Jan 2025, at 11:42 AM, Alex Henrie <alexhenrie24@gmail.com> wrote:
>>>>> 
>>>>> The Omoton KB066 is an Apple A1255 keyboard clone (HID product code
>>>>> 05ac:022c). On both keyboards, the F6 key becomes Num Lock when the Fn
>>>>> key is held. But unlike its Apple exemplar, when the Omoton's F6 key is
>>>>> pressed without Fn, it sends the usage code 0xC0301 from the reserved
>>>>> section of the consumer page instead of the standard F6 usage code
>>>>> 0x7003F from the keyboard page. The nonstandard code is translated to
>>>>> KEY_UNKNOWN and becomes useless on Linux. The Omoton KB066 is a pretty
>>>>> popular keyboard, judging from its 29,058 reviews on Amazon at time of
>>>>> writing, so let's account for its quirk to make it more usable.
>>>>> 
>>>>> By the way, it would be nice if we could automatically set fnmode to 0
>>>>> for Omoton keyboards because they handle the Fn key internally and the
>>>>> kernel's Fn key handling creates undesirable side effects such as making
>>>>> F1 and F2 always Brightness Up and Brightness Down in fnmode=1 (the
>>>>> default) or always F1 and F2 in fnmode=2. Unfortunately I don't think
>>>>> there's a way to identify Bluetooth keyboards more specifically than the
>>>>> HID product code which is obviously inaccurate. Users of Omoton
>>>>> keyboards will just have to set fnmode to 0 manually to get full Fn key
>>>>> functionality.
>>>> 
>>>> Regarding the the fnmode=0 thing, could you test this patch:
>>>> 
>>>> -->8—
>>>> From e2b2ef3f579800f11ee293fb45838a4004ccaf23 Mon Sep 17 00:00:00 2001
>>>> From: Aditya Garg <gargaditya08@live.com>
>>>> Date: Wed, 12 Feb 2025 22:57:58 +0530
>>>> Subject: [PATCH] HID: apple: Add quirk to disable fn key on some non-apple
>>>> keyboards
>>>> 
>>>> ---
>>>> drivers/hid/hid-apple.c | 54 +++++++++++++++++++++++++++++------------
>>>> 1 file changed, 39 insertions(+), 15 deletions(-)
>>>> 
>>>> diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
>>>> index 49812a76b..9d4cbe636 100644
>>>> --- a/drivers/hid/hid-apple.c
>>>> +++ b/drivers/hid/hid-apple.c
>>>> @@ -42,6 +42,7 @@
>>>> #define APPLE_BACKLIGHT_CTL BIT(10)
>>>> #define APPLE_IS_NON_APPLE BIT(11)
>>>> #define APPLE_MAGIC_BACKLIGHT BIT(12)
>>>> +#define APPLE_DISABLE_FN BIT(13)
>>>> 
>>>> #define APPLE_FLAG_FKEY 0x01
>>>> 
>>>> @@ -89,6 +90,19 @@ struct apple_sc_backlight {
>>>> struct hid_device *hdev;
>>>> };
>>>> 
>>>> +struct apple_backlight_config_report {
>>>> + u8 report_id;
>>>> + u8 version;
>>>> + u16 backlight_off, backlight_on_min, backlight_on_max;
>>>> +};
>>>> +
>>>> +struct apple_backlight_set_report {
>>>> + u8 report_id;
>>>> + u8 version;
>>>> + u16 backlight;
>>>> + u16 rate;
>>>> +};
>>>> +
>>>> struct apple_magic_backlight {
>>>> struct led_classdev cdev;
>>>> struct hid_report *brightness;
>>>> @@ -152,20 +166,6 @@ static const struct apple_key_translation magic_keyboard_2015_fn_keys[] = {
>>>> { }
>>>> };
>>>> 
>>>> -struct apple_backlight_config_report {
>>>> - u8 report_id;
>>>> - u8 version;
>>>> - u16 backlight_off, backlight_on_min, backlight_on_max;
>>>> -};
>>>> -
>>>> -struct apple_backlight_set_report {
>>>> - u8 report_id;
>>>> - u8 version;
>>>> - u16 backlight;
>>>> - u16 rate;
>>>> -};
>>>> -
>>>> -
>>>> static const struct apple_key_translation apple2021_fn_keys[] = {
>>>> { KEY_BACKSPACE, KEY_DELETE },
>>>> { KEY_ENTER, KEY_INSERT },
>>>> @@ -364,6 +364,10 @@ static const struct apple_non_apple_keyboard non_apple_keyboards[] = {
>>>> { "WKB603" },
>>>> };
>>>> 
>>>> +static const struct apple_non_apple_keyboard non_apple_keyboards_disable_fn[] = {
>>>> + { "Omoton" },
>>> 
>>> You could try replacing Omoton with OMOTON as well here if it does not work. Alternatively, you could try logging hdev->name for this device and put it in this table to get the correct name.
>> 
>> On the Omoton KB066, hdev->name is "Bluetooth Keyboard". I think I saw
>> that name in Blueman and assumed that it was just a default for when a
>> keyboard has no name, but you're right, that string must be coming
>> from the keyboard itself. After changing "Omoton" to "Bluetooth
>> Keyboard" in non_apple_keyboards_disable_fn, your patch works!
>> 
>> Unfortunately, this keyboard is even more messed up than I realized.
>> It is indeed sending different key codes depending on whether or not
>> the Fn key is held. For example, F11 and F12 are Volume Down and
>> Volume Up by default, but ordinary F11 and F12 when Fn is held.
>> However, I was wrong about F1 and F2: With or without Fn, the Omoton
>> _never_ changes F1 to Brightness Down or F2 to Brightness Up. I
>> managed to pick the one bad example: All of the other special keys
>> (Esc, F3 through F12, and Del) are translated internally, but not F1
>> or F2. That also means that I was wrong about the Fn key not doing
>> anything in fnmode=2. When Fn is held, all of the special keys do
>> become ordinary keys in both fnmode=0 and fnmode=2, except for F1 and
>> F2 which remain ordinary F1 and F2.
>> 
>> When connected to macOS, the results are similar: All of the special
>> keys are special keys regardless of whether Fn is held, except F1 and
>> F2, which by default are always translated to Brightness Down and
>> Brightness Up like in Linux's fnmode=1. If the setting "Use F1, F2,
>> etc. keys as standard function keys" is enabled in the system keyboard
>> settings, all of the special keys change to ordinary keys when Fn is
>> held, except for F1 and F2 which remain F1 and F2, just like in
>> Linux's fnmode=0 and fnmode=2.
>> 
>> It seems to me that the best way to support the Omoton KB066 would be
>> to give it its own key translation table that has F1 and F2 and
>> nothing else. But on the bright side, pun humorously intended, we
>> wouldn't have to change the default fnmode. Just like on macOS, F1 and
>> F2 would always be Brightness Down and Brightness Up, unless key
>> translation is disabled. But unlike macOS (and the current state of
>> Linux), we wouldn't undo the keyboard's own Fn key handling for the
>> special keys that it translates internally.
>> 
>> Circling back to the original problem of distinguishing between the
>> Apple A1255 and the Omoton KB066, changing an Apple keyboard's name in
>> the macOS keyboard settings also changes the name that it reports to
>> Linux. Because "Bluetooth Keyboard" is so generic that someone might
>> actually give their keyboard that name intentionally, if we add
>> special behavior to look for that name, I think we should restrict it
>> to PID 022c. For example, we could add the new quirk flag to
>> USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI in the apple_devices table and
>> then clear the flag if the keyboard's name is not "Bluetooth
>> Keyboard".
>> 
>> Thanks for the help!
>> 
>> -Alex
> 
> 


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

* Re: [PATCH resend] HID: apple: fix up the F6 key on the Omoton KB066 keyboard
  2025-02-16  6:45           ` Aditya Garg
@ 2025-02-17  4:13             ` Alex Henrie
  2025-02-17  5:18               ` Aditya Garg
  0 siblings, 1 reply; 24+ messages in thread
From: Alex Henrie @ 2025-02-17  4:13 UTC (permalink / raw)
  To: Aditya Garg
  Cc: linux-input@vger.kernel.org, jkosina@suse.cz,
	benjamin.tissoires@redhat.com

On Sat, Feb 15, 2025 at 11:06 PM Aditya Garg <gargaditya08@live.com> wrote:

> In case I am wrong, can you share what exactly happens in each mode with fn on as well as off?

In fnmode=0 and fnmode=2, F1 and F2 are F1 and F2, and the rest are
special keys when Fn is not held and ordinary function keys when Fn is
held.

In fnmode=1, F1 and F2 are Brightness Down and Brightness Up, and the
rest are always special keys, although holding Fn changes some of the
special keys to different special keys.

In all modes, Home becomes Escape when Fn is held, Lock (which is
actually Power) becomes Delete when Fn is held, and F6 always sends a
reserved key code.

On Sat, Feb 15, 2025 at 11:45 PM Aditya Garg <gargaditya08@live.com> wrote:
>
> I think its best to disable the internal translation of this keyboard and let the kernel manage it. It can be done by implementing a fixup table that first translates all the media controls to their respective F keys, and other similar internal translations, so that the keyboard can mimic the original Apple version. Like the all the 3 fn modes should also work.

The trouble is, we have no way to read the state of the Omoton's Fn
key in software. The Fn key is entirely internal to the keyboard. I
even looked at the raw HID reports with and without Fn pressed, and
there is nothing. So either we translate F1 and F2 to Brightness Down
and Brightness Up (in fnmode=1) or we don't translate them at all (in
fnmode=0 and fnmode=2); we can't conditionally translate depending on
the Fn key.

But for all the other special keys, what you are saying makes sense
and is a good idea: In fnmode=0, we can translate all of the special
keys to be ordinary keys, and in fnmode=2, we can translate them to
their opposites. For example, if the keyboard sends Volume Down, in
fnmode=0 and fnmode=2 we'd translate it to F11 (because the keyboard
only sends Volume Down when Fn is not held), and if it sends F11, in
fnmode=2 we'd translate it to Volume Down (because the keyboard only
sends F11 when Fn is held).

> Also looking at the keyboard pic on https://www.amazon.in/OMOTON-Ultra-Slim-Bluetooth-Keyboard-Compatible/dp/B07S7VPQG6?th=1, the translation table for magic keyboard aluminium seems quite different from what this keyboard keys show.

Let's please not change the special keys to be different from what
their labels show. For example, F3 is Search on the Omoton KB066 and
Scale on the Apple A1255. Personally I wouldn't even change Power to
Screen Lock to match its icon, although I'm okay with changing it if
others feel strongly.

-Alex

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

* Re: [PATCH resend] HID: apple: fix up the F6 key on the Omoton KB066 keyboard
  2025-02-17  4:13             ` Alex Henrie
@ 2025-02-17  5:18               ` Aditya Garg
  2025-02-17  6:42                 ` Alex Henrie
  0 siblings, 1 reply; 24+ messages in thread
From: Aditya Garg @ 2025-02-17  5:18 UTC (permalink / raw)
  To: Alex Henrie
  Cc: linux-input@vger.kernel.org, jkosina@suse.cz,
	benjamin.tissoires@redhat.com



> On 17 Feb 2025, at 9:43 AM, Alex Henrie <alexhenrie24@gmail.com> wrote:
> 
> On Sat, Feb 15, 2025 at 11:06 PM Aditya Garg <gargaditya08@live.com> wrote:
> 
>> In case I am wrong, can you share what exactly happens in each mode with fn on as well as off?
> 
> In fnmode=0 and fnmode=2, F1 and F2 are F1 and F2, and the rest are
> special keys when Fn is not held and ordinary function keys when Fn is
> held.
> 
> In fnmode=1, F1 and F2 are Brightness Down and Brightness Up, and the
> rest are always special keys, although holding Fn changes some of the
> special keys to different special keys.
> 
> In all modes, Home becomes Escape when Fn is held, Lock (which is
> actually Power) becomes Delete when Fn is held, and F6 always sends a
> reserved key code.
> 

So judging from these observations:

1. Fn key is internal to the keyboard, and does not send KEY_FN like Apple Keyboards
2. F1 and F2 are broken as far as Fn translation is considered.
3. Since fnmode=0 shows the actual state of the keyboard, internal translation of rest keys is just fine.

This makes it impossible to fixup this keyboard since Fn is not there in raw HID reports.

We can then just make fnmode=0 as default for this keyboard, and optionally translate F1 and F2 permanently to media keys.

BTW, are there any differences in HID reports if Fn+F1 and only F1 are pressed?

> On Sat, Feb 15, 2025 at 11:45 PM Aditya Garg <gargaditya08@live.com> wrote:
>> 
>> I think its best to disable the internal translation of this keyboard and let the kernel manage it. It can be done by implementing a fixup table that first translates all the media controls to their respective F keys, and other similar internal translations, so that the keyboard can mimic the original Apple version. Like the all the 3 fn modes should also work.
> 
> The trouble is, we have no way to read the state of the Omoton's Fn
> key in software. The Fn key is entirely internal to the keyboard. I
> even looked at the raw HID reports with and without Fn pressed, and
> there is nothing. So either we translate F1 and F2 to Brightness Down
> and Brightness Up (in fnmode=1) or we don't translate them at all (in
> fnmode=0 and fnmode=2); we can't conditionally translate depending on
> the Fn key.
> 
> But for all the other special keys, what you are saying makes sense
> and is a good idea: In fnmode=0, we can translate all of the special
> keys to be ordinary keys, and in fnmode=2, we can translate them to
> their opposites. For example, if the keyboard sends Volume Down, in
> fnmode=0 and fnmode=2 we'd translate it to F11 (because the keyboard
> only sends Volume Down when Fn is not held), and if it sends F11, in
> fnmode=2 we'd translate it to Volume Down (because the keyboard only
> sends F11 when Fn is held).

My idea was based on the assumption that Fn is sending KEY_FN. Now, if my idea is implemented, the user would have to manually change the fnmod to switch between media and function keys, which is quite inconvenient, just because 2 keys are broken.

I would like to think it as fmode=0 with F1 and F2 broken because of manufacturing defect.

You also said F6 shows a reserved keycode, which IIRC, you sent in a patch to translate to F6. Is the keycode same with and without Fn? I am thinking of using this reserved keycode as a toggle key for the hid-apple driver to switch the modes between media and function keys.
>> Also looking at the keyboard pic on https://www.amazon.in/OMOTON-Ultra-Slim-Bluetooth-Keyboard-Compatible/dp/B07S7VPQG6?th=1, the translation table for magic keyboard aluminium seems quite different from what this keyboard keys show.
> 
> Let's please not change the special keys to be different from what
> their labels show. For example, F3 is Search on the Omoton KB066 and
> Scale on the Apple A1255. Personally I wouldn't even change Power to
> Screen Lock to match its icon, although I'm okay with changing it if
> others feel strongly.

In case you have an Apple A1255, could you check whether hdev->name is different from "Bluetooth Keyboard”. We don’t really want to break the original Apple version just because of this defective clone.


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

* Re: [PATCH resend] HID: apple: fix up the F6 key on the Omoton KB066 keyboard
  2025-02-17  5:18               ` Aditya Garg
@ 2025-02-17  6:42                 ` Alex Henrie
  2025-02-17 10:02                   ` Aditya Garg
  2025-02-24  2:46                   ` Alex Henrie
  0 siblings, 2 replies; 24+ messages in thread
From: Alex Henrie @ 2025-02-17  6:42 UTC (permalink / raw)
  To: Aditya Garg
  Cc: linux-input@vger.kernel.org, jkosina@suse.cz,
	benjamin.tissoires@redhat.com

On Sun, Feb 16, 2025 at 10:18 PM Aditya Garg <gargaditya08@live.com> wrote:

> BTW, are there any differences in HID reports if Fn+F1 and only F1 are pressed?

No.

> You also said F6 shows a reserved keycode, which IIRC, you sent in a patch to translate to F6. Is the keycode same with and without Fn?

When Fn is held, F6 is plain F6 and no translation is required.

> In case you have an Apple A1255, could you check whether hdev->name is different from "Bluetooth Keyboard”. We don’t really want to break the original Apple version just because of this defective clone.

If I understand correctly Mac OS sets each Apple keyboard's internal
name to "<username>'s keyboard" by default, and that's what mine is,
but a user could conceivably override that with "Bluetooth Keyboard".
It's also possible "Bluetooth Keyboard" is the name that all A1255's
had when they walked out of the factory, before they were connected to
an Apple device.

-Alex

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

* Re: [PATCH resend] HID: apple: fix up the F6 key on the Omoton KB066 keyboard
  2025-02-17  6:42                 ` Alex Henrie
@ 2025-02-17 10:02                   ` Aditya Garg
  2025-02-17 10:03                     ` Aditya Garg
  2025-02-24  2:50                     ` Alex Henrie
  2025-02-24  2:46                   ` Alex Henrie
  1 sibling, 2 replies; 24+ messages in thread
From: Aditya Garg @ 2025-02-17 10:02 UTC (permalink / raw)
  To: Alex Henrie
  Cc: linux-input@vger.kernel.org, jkosina@suse.cz,
	benjamin.tissoires@redhat.com

Hi Alex

> If I understand correctly Mac OS sets each Apple keyboard's internal
> name to "<username>'s keyboard" by default, and that's what mine is,
> but a user could conceivably override that with "Bluetooth Keyboard".
> It's also possible "Bluetooth Keyboard" is the name that all A1255's
> had when they walked out of the factory, before they were connected to
> an Apple device.
> 
> -Alex

Can you to test the patch at the bottom of this message?

Before you apply the patch, you first need to apply these 3 patches I have sent upstream:

https://lore.kernel.org/all/FE7D2C98-2BF5-48C2-8183-68EC1085C1EC@live.com/t/#u

Then you have to apply _only_ PATCH 4/4 here:

https://patchwork.kernel.org/project/linux-input/patch/7747D0EE-DA32-4B6A-AB63-DB30C5E856BE@live.com/

Then apply the patch.

Then see if Fn+F6 switches the media to function keys or not, and media keys work by default or not.

—>8—

From 6fd840590b58689b1d99a523156266f790c8e98d Mon Sep 17 00:00:00 2001
From: Aditya Garg <gargaditya08@live.com>
Date: Mon, 17 Feb 2025 15:20:58 +0530
Subject: [PATCH] omoton

---
 drivers/hid/hid-apple.c | 53 ++++++++++++++++++++++++++++++++++++++---
 1 file changed, 50 insertions(+), 3 deletions(-)

diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index 4e8b01793..eaafa285a 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -42,6 +42,7 @@
 #define APPLE_BACKLIGHT_CTL	BIT(10)
 #define APPLE_IS_NON_APPLE	BIT(11)
 #define APPLE_MAGIC_BACKLIGHT	BIT(12)
+#define APPLE_IS_OMOTON		BIT(13)
 
 #define APPLE_FLAG_FKEY			0x01
 #define APPLE_FLAG_DONT_TRANSLATE	0x02
@@ -53,6 +54,8 @@
 #define APPLE_MAGIC_REPORT_ID_POWER		3
 #define APPLE_MAGIC_REPORT_ID_BRIGHTNESS	1
 
+#define KEY_F6_OMOTON	0xc0301
+
 static unsigned int fnmode = 3;
 module_param(fnmode, uint, 0644);
 MODULE_PARM_DESC(fnmode, "Mode of fn key on Apple keyboards (0 = disabled, "
@@ -81,6 +84,8 @@ MODULE_PARM_DESC(swap_fn_leftctrl, "Swap the Fn and left Control keys. "
 		"(For people who want to keep PC keyboard muscle memory. "
 		"[0] = as-is, Mac layout, 1 = swapped, PC layout)");
 
+bool omoton_media_key;
+
 struct apple_non_apple_keyboard {
 	char *name;
 };
@@ -276,6 +281,25 @@ static const struct apple_key_translation powerbook_numlock_keys[] = {
 	{ }
 };
 
+static const struct apple_key_translation omoton_media_keys[] = {
+	{ KEY_F1,	KEY_BRIGHTNESSDOWN },
+	{ KEY_F2,	KEY_BRIGHTNESSUP },
+	{ }
+};
+
+static const struct apple_key_translation omoton_function_keys[] = {
+	{ KEY_SEARCH,		KEY_F3 },
+	{ KEY_EJECTCD,		KEY_F4 },
+	{ KEY_NUMLOCK,		KEY_F5 },
+	{ KEY_PREVIOUSSONG,	KEY_F7 },
+	{ KEY_PLAYPAUSE,	KEY_F8 },
+	{ KEY_NEXTSONG,		KEY_F9 },
+	{ KEY_MUTE,		KEY_F10 },
+	{ KEY_VOLUMEDOWN,	KEY_F11 },
+	{ KEY_VOLUMEUP,		KEY_F12 },
+	{ }
+};
+
 static const struct apple_key_translation apple_iso_keyboard[] = {
 	{ KEY_GRAVE,	KEY_102ND },
 	{ KEY_102ND,	KEY_GRAVE },
@@ -377,6 +401,25 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
 		real_fnmode = fnmode;
 	}
 
+	/* Omoton KB066 quirk */
+	if (asc->quirks & APPLE_IS_OMOTON) {
+		real_fnmode = 0;
+		if (usage->hid == KEY_F6_OMOTON) 
+			code = KEY_F6;
+
+		if (usage->code == KEY_F6) {
+			if (value == 1)
+				omoton_media_key = !omoton_media_key;
+			code = KEY_UNKNOWN;
+		}
+
+		table = omoton_media_key ? omoton_media_keys : omoton_function_keys;
+		trans = apple_find_translation(table, code);
+
+		if (trans)
+			code = trans->to;
+	}
+
 	if (swap_fn_leftctrl) {
 		trans = apple_find_translation(swapped_fn_leftctrl_keys, code);
 
@@ -511,9 +554,6 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
 		}
 	}
 
-	if (usage->hid == 0xc0301) /* Omoton KB066 quirk */
-		code = KEY_F6;
-
 	if (usage->code != code) {
 		input_event_with_scancode(input, usage->type, code, usage->hid, value);
 
@@ -701,6 +741,12 @@ static int apple_input_configured(struct hid_device *hdev,
 		asc->quirks |= APPLE_IS_NON_APPLE;
 	}
 
+	if (strncmp(hdev->name, "Bluetooth Keyboard", 18) == 0 &&
+			hdev->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI) {
+		hid_info(hdev, "Omoton keyboard detected; use Fn+F6 to toggle between media and function keys\n");
+		asc->quirks |= APPLE_IS_OMOTON;
+	}
+
 	return 0;
 }
 
@@ -897,6 +943,7 @@ static int apple_probe(struct hid_device *hdev,
 	mod_timer(&asc->battery_timer,
 		  jiffies + msecs_to_jiffies(APPLE_BATTERY_TIMEOUT_MS));
 	apple_fetch_battery(hdev);
+	omoton_media_key = true;
 
 	if (quirks & APPLE_BACKLIGHT_CTL)
 		apple_backlight_init(hdev);
-- 
2.43.0



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

* Re: [PATCH resend] HID: apple: fix up the F6 key on the Omoton KB066 keyboard
  2025-02-17 10:02                   ` Aditya Garg
@ 2025-02-17 10:03                     ` Aditya Garg
  2025-02-24  2:50                     ` Alex Henrie
  1 sibling, 0 replies; 24+ messages in thread
From: Aditya Garg @ 2025-02-17 10:03 UTC (permalink / raw)
  To: Alex Henrie
  Cc: linux-input@vger.kernel.org, jkosina@suse.cz,
	benjamin.tissoires@redhat.com

[-- Attachment #1: Type: text/plain, Size: 137 bytes --]

To make things easier, I am also sending hid-apple.c as an attachment

> Can you to test the patch at the bottom of this message?
> 

[-- Attachment #2: hid-apple.c --]
[-- Type: application/octet-stream, Size: 42066 bytes --]

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 *  USB HID quirks support for Linux
 *
 *  Copyright (c) 1999 Andreas Gal
 *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
 *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
 *  Copyright (c) 2006-2007 Jiri Kosina
 *  Copyright (c) 2008 Jiri Slaby <jirislaby@gmail.com>
 *  Copyright (c) 2019 Paul Pawlowski <paul@mrarm.io>
 *  Copyright (c) 2023 Orlando Chamberlain <orlandoch.dev@gmail.com>
 *  Copyright (c) 2024 Aditya Garg <gargaditya08@live.com>
 */

/*
 */

#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include <linux/device.h>
#include <linux/hid.h>
#include <linux/jiffies.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/leds.h>
#include <dt-bindings/leds/common.h>

#include "hid-ids.h"

#define APPLE_RDESC_JIS		BIT(0)
/* BIT(1) reserved, was: APPLE_IGNORE_MOUSE */
#define APPLE_HAS_FN		BIT(2)
/* BIT(3) reserved, was: APPLE_HIDDEV */
#define APPLE_ISO_TILDE_QUIRK	BIT(4)
#define APPLE_MIGHTYMOUSE	BIT(5)
#define APPLE_INVERT_HWHEEL	BIT(6)
/* BIT(7) reserved, was: APPLE_IGNORE_HIDINPUT */
#define APPLE_NUMLOCK_EMULATION	BIT(8)
#define APPLE_RDESC_BATTERY	BIT(9)
#define APPLE_BACKLIGHT_CTL	BIT(10)
#define APPLE_IS_NON_APPLE	BIT(11)
#define APPLE_MAGIC_BACKLIGHT	BIT(12)
#define APPLE_IS_OMOTON		BIT(13)

#define APPLE_FLAG_FKEY			0x01
#define APPLE_FLAG_DONT_TRANSLATE	0x02

#define HID_COUNTRY_INTERNATIONAL_ISO	13
#define APPLE_BATTERY_TIMEOUT_MS	60000

#define HID_USAGE_MAGIC_BL			0xff00000f
#define APPLE_MAGIC_REPORT_ID_POWER		3
#define APPLE_MAGIC_REPORT_ID_BRIGHTNESS	1

#define KEY_F6_OMOTON	0xc0301

static unsigned int fnmode = 3;
module_param(fnmode, uint, 0644);
MODULE_PARM_DESC(fnmode, "Mode of fn key on Apple keyboards (0 = disabled, "
		"1 = fkeyslast, 2 = fkeysfirst, [3] = auto)");

static int iso_layout = -1;
module_param(iso_layout, int, 0644);
MODULE_PARM_DESC(iso_layout, "Swap the backtick/tilde and greater-than/less-than keys. "
		"([-1] = auto, 0 = disabled, 1 = enabled)");

static unsigned int swap_opt_cmd;
module_param(swap_opt_cmd, uint, 0644);
MODULE_PARM_DESC(swap_opt_cmd, "Swap the Option (\"Alt\") and Command (\"Flag\") keys. "
		"(For people who want to keep Windows PC keyboard muscle memory. "
		"[0] = as-is, Mac layout. 1 = swapped, Windows layout., 2 = swapped, Swap only left side)");

static unsigned int swap_ctrl_cmd;
module_param(swap_ctrl_cmd, uint, 0644);
MODULE_PARM_DESC(swap_ctrl_cmd, "Swap the Control (\"Ctrl\") and Command (\"Flag\") keys. "
		"(For people who are used to Mac shortcuts involving Command instead of Control. "
		"[0] = No change. 1 = Swapped.)");

static unsigned int swap_fn_leftctrl;
module_param(swap_fn_leftctrl, uint, 0644);
MODULE_PARM_DESC(swap_fn_leftctrl, "Swap the Fn and left Control keys. "
		"(For people who want to keep PC keyboard muscle memory. "
		"[0] = as-is, Mac layout, 1 = swapped, PC layout)");

bool omoton_media_key;

struct apple_non_apple_keyboard {
	char *name;
};

struct apple_sc_backlight {
	struct led_classdev cdev;
	struct hid_device *hdev;
};

struct apple_backlight_config_report {
	u8 report_id;
	u8 version;
	u16 backlight_off, backlight_on_min, backlight_on_max;
};

struct apple_backlight_set_report {
	u8 report_id;
	u8 version;
	u16 backlight;
	u16 rate;
};

struct apple_magic_backlight {
	struct led_classdev cdev;
	struct hid_report *brightness;
	struct hid_report *power;
};

struct apple_sc {
	struct hid_device *hdev;
	unsigned long quirks;
	unsigned int fn_on;
	unsigned int fn_found;
	DECLARE_BITMAP(pressed_numlock, KEY_CNT);
	struct timer_list battery_timer;
	struct apple_sc_backlight *backlight;
};

struct apple_key_translation {
	u16 from;
	u16 to;
	u8 flags;
};

static const struct apple_key_translation magic_keyboard_alu_and_2015_fn_keys[] = {
	{ KEY_BACKSPACE, KEY_DELETE },
	{ KEY_ENTER,	KEY_INSERT },
	{ KEY_F1,	KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY },
	{ KEY_F2,	KEY_BRIGHTNESSUP,   APPLE_FLAG_FKEY },
	{ KEY_F3,	KEY_SCALE,          APPLE_FLAG_FKEY },
	{ KEY_F4,	KEY_DASHBOARD,      APPLE_FLAG_FKEY },
	{ KEY_F6,	KEY_NUMLOCK,        APPLE_FLAG_FKEY | APPLE_FLAG_DONT_TRANSLATE },
	{ KEY_F7,	KEY_PREVIOUSSONG,   APPLE_FLAG_FKEY },
	{ KEY_F8,	KEY_PLAYPAUSE,      APPLE_FLAG_FKEY },
	{ KEY_F9,	KEY_NEXTSONG,       APPLE_FLAG_FKEY },
	{ KEY_F10,	KEY_MUTE,           APPLE_FLAG_FKEY },
	{ KEY_F11,	KEY_VOLUMEDOWN,     APPLE_FLAG_FKEY },
	{ KEY_F12,	KEY_VOLUMEUP,       APPLE_FLAG_FKEY },
	{ KEY_UP,	KEY_PAGEUP },
	{ KEY_DOWN,	KEY_PAGEDOWN },
	{ KEY_LEFT,	KEY_HOME },
	{ KEY_RIGHT,	KEY_END },
	{ }
};

static const struct apple_key_translation magic_keyboard_2021_and_2024_fn_keys[] = {
	{ KEY_BACKSPACE, KEY_DELETE },
	{ KEY_ENTER,	KEY_INSERT },
	{ KEY_F1,	KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY },
	{ KEY_F2,	KEY_BRIGHTNESSUP,   APPLE_FLAG_FKEY },
	{ KEY_F3,	KEY_SCALE,          APPLE_FLAG_FKEY },
	{ KEY_F4,	KEY_SEARCH,         APPLE_FLAG_FKEY },
	{ KEY_F5,	KEY_MICMUTE,        APPLE_FLAG_FKEY },
	{ KEY_F6,	KEY_SLEEP,          APPLE_FLAG_FKEY },
	{ KEY_F7,	KEY_PREVIOUSSONG,   APPLE_FLAG_FKEY },
	{ KEY_F8,	KEY_PLAYPAUSE,      APPLE_FLAG_FKEY },
	{ KEY_F9,	KEY_NEXTSONG,       APPLE_FLAG_FKEY },
	{ KEY_F10,	KEY_MUTE,           APPLE_FLAG_FKEY },
	{ KEY_F11,	KEY_VOLUMEDOWN,     APPLE_FLAG_FKEY },
	{ KEY_F12,	KEY_VOLUMEUP,       APPLE_FLAG_FKEY },
	{ KEY_UP,	KEY_PAGEUP },
	{ KEY_DOWN,	KEY_PAGEDOWN },
	{ KEY_LEFT,	KEY_HOME },
	{ KEY_RIGHT,	KEY_END },
	{ }
};

static const struct apple_key_translation macbookair_fn_keys[] = {
	{ KEY_BACKSPACE, KEY_DELETE },
	{ KEY_ENTER,	KEY_INSERT },
	{ KEY_F1,	KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY },
	{ KEY_F2,	KEY_BRIGHTNESSUP,   APPLE_FLAG_FKEY },
	{ KEY_F3,	KEY_SCALE,          APPLE_FLAG_FKEY },
	{ KEY_F4,	KEY_DASHBOARD,      APPLE_FLAG_FKEY },
	{ KEY_F6,	KEY_PREVIOUSSONG,   APPLE_FLAG_FKEY },
	{ KEY_F7,	KEY_PLAYPAUSE,      APPLE_FLAG_FKEY },
	{ KEY_F8,	KEY_NEXTSONG,       APPLE_FLAG_FKEY },
	{ KEY_F9,	KEY_MUTE,           APPLE_FLAG_FKEY },
	{ KEY_F10,	KEY_VOLUMEDOWN,     APPLE_FLAG_FKEY },
	{ KEY_F11,	KEY_VOLUMEUP,       APPLE_FLAG_FKEY },
	{ KEY_F12,	KEY_EJECTCD,        APPLE_FLAG_FKEY },
	{ KEY_UP,	KEY_PAGEUP },
	{ KEY_DOWN,	KEY_PAGEDOWN },
	{ KEY_LEFT,	KEY_HOME },
	{ KEY_RIGHT,	KEY_END },
	{ }
};

static const struct apple_key_translation macbookpro_fn_keys[] = {
	{ KEY_BACKSPACE, KEY_DELETE },
	{ KEY_ENTER,	KEY_INSERT },
	{ KEY_GRAVE,	KEY_ESC, APPLE_FLAG_DONT_TRANSLATE },
	{ KEY_1,	KEY_F1 },
	{ KEY_2,	KEY_F2 },
	{ KEY_3,	KEY_F3 },
	{ KEY_4,	KEY_F4 },
	{ KEY_5,	KEY_F5 },
	{ KEY_6,	KEY_F6 },
	{ KEY_7,	KEY_F7 },
	{ KEY_8,	KEY_F8 },
	{ KEY_9,	KEY_F9 },
	{ KEY_0,	KEY_F10 },
	{ KEY_MINUS,	KEY_F11 },
	{ KEY_EQUAL,	KEY_F12 },
	{ KEY_UP,	KEY_PAGEUP },
	{ KEY_DOWN,	KEY_PAGEDOWN },
	{ KEY_LEFT,	KEY_HOME },
	{ KEY_RIGHT,	KEY_END },
	{ }
};

static const struct apple_key_translation apple_fn_keys[] = {
	{ KEY_BACKSPACE, KEY_DELETE },
	{ KEY_ENTER,	KEY_INSERT },
	{ KEY_F1,	KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY },
	{ KEY_F2,	KEY_BRIGHTNESSUP,   APPLE_FLAG_FKEY },
	{ KEY_F3,	KEY_SCALE,          APPLE_FLAG_FKEY },
	{ KEY_F4,	KEY_DASHBOARD,      APPLE_FLAG_FKEY },
	{ KEY_F5,	KEY_KBDILLUMDOWN,   APPLE_FLAG_FKEY },
	{ KEY_F6,	KEY_KBDILLUMUP,     APPLE_FLAG_FKEY },
	{ KEY_F7,	KEY_PREVIOUSSONG,   APPLE_FLAG_FKEY },
	{ KEY_F8,	KEY_PLAYPAUSE,      APPLE_FLAG_FKEY },
	{ KEY_F9,	KEY_NEXTSONG,       APPLE_FLAG_FKEY },
	{ KEY_F10,	KEY_MUTE,           APPLE_FLAG_FKEY },
	{ KEY_F11,	KEY_VOLUMEDOWN,     APPLE_FLAG_FKEY },
	{ KEY_F12,	KEY_VOLUMEUP,       APPLE_FLAG_FKEY },
	{ KEY_UP,	KEY_PAGEUP },
	{ KEY_DOWN,	KEY_PAGEDOWN },
	{ KEY_LEFT,	KEY_HOME },
	{ KEY_RIGHT,	KEY_END },
	{ }
};

static const struct apple_key_translation powerbook_fn_keys[] = {
	{ KEY_BACKSPACE, KEY_DELETE },
	{ KEY_F1,	KEY_BRIGHTNESSDOWN,     APPLE_FLAG_FKEY },
	{ KEY_F2,	KEY_BRIGHTNESSUP,       APPLE_FLAG_FKEY },
	{ KEY_F3,	KEY_MUTE,               APPLE_FLAG_FKEY },
	{ KEY_F4,	KEY_VOLUMEDOWN,         APPLE_FLAG_FKEY },
	{ KEY_F5,	KEY_VOLUMEUP,           APPLE_FLAG_FKEY },
	{ KEY_F6,	KEY_NUMLOCK,            APPLE_FLAG_FKEY },
	{ KEY_F7,	KEY_SWITCHVIDEOMODE,    APPLE_FLAG_FKEY },
	{ KEY_F8,	KEY_KBDILLUMTOGGLE,     APPLE_FLAG_FKEY },
	{ KEY_F9,	KEY_KBDILLUMDOWN,       APPLE_FLAG_FKEY },
	{ KEY_F10,	KEY_KBDILLUMUP,         APPLE_FLAG_FKEY },
	{ KEY_UP,	KEY_PAGEUP },
	{ KEY_DOWN,	KEY_PAGEDOWN },
	{ KEY_LEFT,	KEY_HOME },
	{ KEY_RIGHT,	KEY_END },
	{ }
};

static const struct apple_key_translation powerbook_numlock_keys[] = {
	{ KEY_J,	KEY_KP1 },
	{ KEY_K,	KEY_KP2 },
	{ KEY_L,	KEY_KP3 },
	{ KEY_U,	KEY_KP4 },
	{ KEY_I,	KEY_KP5 },
	{ KEY_O,	KEY_KP6 },
	{ KEY_7,	KEY_KP7 },
	{ KEY_8,	KEY_KP8 },
	{ KEY_9,	KEY_KP9 },
	{ KEY_M,	KEY_KP0 },
	{ KEY_DOT,	KEY_KPDOT },
	{ KEY_SLASH,	KEY_KPPLUS },
	{ KEY_SEMICOLON, KEY_KPMINUS },
	{ KEY_P,	KEY_KPASTERISK },
	{ KEY_MINUS,	KEY_KPEQUAL },
	{ KEY_0,	KEY_KPSLASH },
	{ KEY_F6,	KEY_NUMLOCK },
	{ KEY_KPENTER,	KEY_KPENTER },
	{ KEY_BACKSPACE, KEY_BACKSPACE },
	{ }
};

static const struct apple_key_translation omoton_media_keys[] = {
	{ KEY_F1,	KEY_BRIGHTNESSDOWN },
	{ KEY_F2,	KEY_BRIGHTNESSUP },
	{ }
};

static const struct apple_key_translation omoton_function_keys[] = {
	{ KEY_SEARCH,		KEY_F3 },
	{ KEY_EJECTCD,		KEY_F4 },
	{ KEY_NUMLOCK,		KEY_F5 },
	{ KEY_PREVIOUSSONG,	KEY_F7 },
	{ KEY_PLAYPAUSE,	KEY_F8 },
	{ KEY_NEXTSONG,		KEY_F9 },
	{ KEY_MUTE,		KEY_F10 },
	{ KEY_VOLUMEDOWN,	KEY_F11 },
	{ KEY_VOLUMEUP,		KEY_F12 },
	{ }
};

static const struct apple_key_translation apple_iso_keyboard[] = {
	{ KEY_GRAVE,	KEY_102ND },
	{ KEY_102ND,	KEY_GRAVE },
	{ }
};

static const struct apple_key_translation swapped_option_cmd_keys[] = {
	{ KEY_LEFTALT,	KEY_LEFTMETA },
	{ KEY_LEFTMETA,	KEY_LEFTALT },
	{ KEY_RIGHTALT,	KEY_RIGHTMETA, APPLE_FLAG_DONT_TRANSLATE },
	{ KEY_RIGHTMETA, KEY_RIGHTALT, APPLE_FLAG_DONT_TRANSLATE },
	{ }
};

static const struct apple_key_translation swapped_ctrl_cmd_keys[] = {
	{ KEY_LEFTCTRL,	KEY_LEFTMETA },
	{ KEY_LEFTMETA,	KEY_LEFTCTRL },
	{ KEY_RIGHTCTRL, KEY_RIGHTMETA },
	{ KEY_RIGHTMETA, KEY_RIGHTCTRL },
	{ }
};

static const struct apple_key_translation swapped_fn_leftctrl_keys[] = {
	{ KEY_FN, KEY_LEFTCTRL },
	{ KEY_LEFTCTRL, KEY_FN },
	{ }
};

static const struct apple_non_apple_keyboard non_apple_keyboards[] = {
	{ "SONiX USB DEVICE" },
	{ "Keychron" },
	{ "AONE" },
	{ "GANSS" },
	{ "Hailuck" },
	{ "Jamesdonkey" },
	{ "A3R" },
	{ "hfd.cn" },
	{ "WKB603" },
};

static bool apple_is_non_apple_keyboard(struct hid_device *hdev)
{
	int i;

	for (i = 0; i < ARRAY_SIZE(non_apple_keyboards); i++) {
		char *non_apple = non_apple_keyboards[i].name;

		if (strncmp(hdev->name, non_apple, strlen(non_apple)) == 0)
			return true;
	}

	return false;
}

static inline void apple_setup_key_translation(struct input_dev *input,
		const struct apple_key_translation *table)
{
	const struct apple_key_translation *trans;

	for (trans = table; trans->from; trans++)
		set_bit(trans->to, input->keybit);
}

static const struct apple_key_translation *apple_find_translation(
		const struct apple_key_translation *table, u16 from)
{
	const struct apple_key_translation *trans;

	/* Look for the translation */
	for (trans = table; trans->from; trans++)
		if (trans->from == from)
			return trans;

	return NULL;
}

static void input_event_with_scancode(struct input_dev *input,
		__u8 type, __u16 code, unsigned int hid, __s32 value)
{
	if (type == EV_KEY &&
	    (!test_bit(code, input->key)) == value)
		input_event(input, EV_MSC, MSC_SCAN, hid);
	input_event(input, type, code, value);
}

static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
		struct hid_usage *usage, __s32 value)
{
	struct apple_sc *asc = hid_get_drvdata(hid);
	const struct apple_key_translation *trans, *table;
	bool do_translate;
	bool dont_translate_flagged_key = false;
	u16 code = usage->code;
	unsigned int real_fnmode;

	if (fnmode == 3) {
		real_fnmode = (asc->quirks & APPLE_IS_NON_APPLE) ? 2 : 1;
	} else {
		real_fnmode = fnmode;
	}

	/* Omoton KB066 quirk */
	if (asc->quirks & APPLE_IS_OMOTON) {
		real_fnmode = 0;
		if (usage->hid == KEY_F6_OMOTON) 
			code = KEY_F6;

		if (usage->code == KEY_F6) {
			if (value == 1)
				omoton_media_key = !omoton_media_key;
			code = KEY_UNKNOWN;
		}

		table = omoton_media_key ? omoton_media_keys : omoton_function_keys;
		trans = apple_find_translation(table, code);

		if (trans)
			code = trans->to;
	}

	if (swap_fn_leftctrl) {
		trans = apple_find_translation(swapped_fn_leftctrl_keys, code);

		if (trans)
			code = trans->to;
	}

	if (iso_layout > 0 || (iso_layout < 0 && (asc->quirks & APPLE_ISO_TILDE_QUIRK) &&
			hid->country == HID_COUNTRY_INTERNATIONAL_ISO)) {
		trans = apple_find_translation(apple_iso_keyboard, code);

		if (trans)
			code = trans->to;
	}

	if (swap_opt_cmd) {
		trans = apple_find_translation(swapped_option_cmd_keys, code);

		if (trans && !(swap_opt_cmd == 2 && trans->flags & APPLE_FLAG_DONT_TRANSLATE))
			code = trans->to;
	}

	if (swap_ctrl_cmd) {
		trans = apple_find_translation(swapped_ctrl_cmd_keys, code);

		if (trans)
			code = trans->to;
	}

	if (code == KEY_FN)
		asc->fn_on = !!value;

	if (real_fnmode) {
		switch (hid->product) {
		case USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI:
		case USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO:
		case USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS:
		case USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI:
		case USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO:
		case USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS:
		case USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI:
		case USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO:
		case USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_JIS:
			table = magic_keyboard_alu_and_2015_fn_keys;
			break;
		case USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2015:
		case USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2015:
			table = magic_keyboard_alu_and_2015_fn_keys;
			dont_translate_flagged_key = true;
			break;
		case USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021:
		case USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2024:
		case USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2021:
		case USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2021:
			table = magic_keyboard_2021_and_2024_fn_keys;
			break;
		case USB_DEVICE_ID_APPLE_WELLSPRINGT2_J132:
		case USB_DEVICE_ID_APPLE_WELLSPRINGT2_J213:
		case USB_DEVICE_ID_APPLE_WELLSPRINGT2_J680:
			table = macbookpro_fn_keys;
			break;
		case USB_DEVICE_ID_APPLE_WELLSPRINGT2_J152F:
		case USB_DEVICE_ID_APPLE_WELLSPRINGT2_J214K:
		case USB_DEVICE_ID_APPLE_WELLSPRINGT2_J223:
			table = macbookpro_fn_keys;
			dont_translate_flagged_key = true;
			break;
		case USB_DEVICE_ID_APPLE_WELLSPRINGT2_J140K:
		case USB_DEVICE_ID_APPLE_WELLSPRINGT2_J230K:
			table = apple_fn_keys;
			break;
		default:
			if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI &&
			    hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS)
				table = macbookair_fn_keys;
			else if (hid->product < 0x21d || hid->product >= 0x300)
				table = powerbook_fn_keys;
			else
				table = apple_fn_keys;
		}

		trans = apple_find_translation(table, code);

		if (trans) {
			bool from_is_set = test_bit(trans->from, input->key);
			bool to_is_set = test_bit(trans->to, input->key);

			if (from_is_set)
				code = trans->from;
			else if (to_is_set)
				code = trans->to;

			if (!(from_is_set || to_is_set)) {
				if (trans->flags & APPLE_FLAG_FKEY) {
					switch (real_fnmode) {
					case 1:
						do_translate = !asc->fn_on;
						break;
					case 2:
						do_translate = asc->fn_on;
						break;
					default:
						/* should never happen */
						do_translate = false;
					}
				} else {
					do_translate = asc->fn_on;
				}

				if (dont_translate_flagged_key &&
						trans->flags & APPLE_FLAG_DONT_TRANSLATE)
					do_translate = false;

				if (do_translate)
					code = trans->to;
			}
		}

		if (asc->quirks & APPLE_NUMLOCK_EMULATION &&
				(test_bit(code, asc->pressed_numlock) ||
				test_bit(LED_NUML, input->led))) {
			trans = apple_find_translation(powerbook_numlock_keys, code);

			if (trans) {
				if (value)
					set_bit(code, asc->pressed_numlock);
				else
					clear_bit(code, asc->pressed_numlock);

				code = trans->to;
			}
		}
	}

	if (usage->code != code) {
		input_event_with_scancode(input, usage->type, code, usage->hid, value);

		return 1;
	}

	return 0;
}

static int apple_event(struct hid_device *hdev, struct hid_field *field,
		struct hid_usage *usage, __s32 value)
{
	struct apple_sc *asc = hid_get_drvdata(hdev);

	if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput ||
			!usage->type)
		return 0;

	if ((asc->quirks & APPLE_INVERT_HWHEEL) &&
			usage->code == REL_HWHEEL) {
		input_event_with_scancode(field->hidinput->input, usage->type,
				usage->code, usage->hid, -value);
		return 1;
	}

	if ((asc->quirks & APPLE_HAS_FN) &&
			hidinput_apple_event(hdev, field->hidinput->input,
				usage, value))
		return 1;


	return 0;
}

static int apple_fetch_battery(struct hid_device *hdev)
{
#ifdef CONFIG_HID_BATTERY_STRENGTH
	struct apple_sc *asc = hid_get_drvdata(hdev);
	struct hid_report_enum *report_enum;
	struct hid_report *report;

	if (!(asc->quirks & APPLE_RDESC_BATTERY) || !hdev->battery)
		return -1;

	report_enum = &hdev->report_enum[hdev->battery_report_type];
	report = report_enum->report_id_hash[hdev->battery_report_id];

	if (!report || report->maxfield < 1)
		return -1;

	if (hdev->battery_capacity == hdev->battery_max)
		return -1;

	hid_hw_request(hdev, report, HID_REQ_GET_REPORT);
	return 0;
#else
	return -1;
#endif
}

static void apple_battery_timer_tick(struct timer_list *t)
{
	struct apple_sc *asc = from_timer(asc, t, battery_timer);
	struct hid_device *hdev = asc->hdev;

	if (apple_fetch_battery(hdev) == 0) {
		mod_timer(&asc->battery_timer,
			  jiffies + msecs_to_jiffies(APPLE_BATTERY_TIMEOUT_MS));
	}
}

/*
 * MacBook JIS keyboard has wrong logical maximum
 * Magic Keyboard JIS has wrong logical maximum
 */
static const __u8 *apple_report_fixup(struct hid_device *hdev, __u8 *rdesc,
		unsigned int *rsize)
{
	struct apple_sc *asc = hid_get_drvdata(hdev);

	if(*rsize >=71 && rdesc[70] == 0x65 && rdesc[64] == 0x65) {
		hid_info(hdev,
			 "fixing up Magic Keyboard JIS report descriptor\n");
		rdesc[64] = rdesc[70] = 0xe7;
	}

	if ((asc->quirks & APPLE_RDESC_JIS) && *rsize >= 60 &&
			rdesc[53] == 0x65 && rdesc[59] == 0x65) {
		hid_info(hdev,
			 "fixing up MacBook JIS keyboard report descriptor\n");
		rdesc[53] = rdesc[59] = 0xe7;
	}

	/*
	 * Change the usage from:
	 *   0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1)  0
	 *   0x09, 0x0b,       // Usage (Vendor Usage 0x0b)           3
	 * To:
	 *   0x05, 0x01,       // Usage Page (Generic Desktop)        0
	 *   0x09, 0x06,       // Usage (Keyboard)                    2
	 */
	if ((asc->quirks & APPLE_RDESC_BATTERY) && *rsize == 83 &&
	    rdesc[46] == 0x84 && rdesc[58] == 0x85) {
		hid_info(hdev,
			 "fixing up Magic Keyboard battery report descriptor\n");
		*rsize = *rsize - 1;
		rdesc = kmemdup(rdesc + 1, *rsize, GFP_KERNEL);
		if (!rdesc)
			return NULL;

		rdesc[0] = 0x05;
		rdesc[1] = 0x01;
		rdesc[2] = 0x09;
		rdesc[3] = 0x06;
	}

	return rdesc;
}

static void apple_setup_input(struct input_dev *input)
{
	set_bit(KEY_NUMLOCK, input->keybit);

	/* Enable all needed keys */
	apple_setup_key_translation(input, apple_fn_keys);
	apple_setup_key_translation(input, powerbook_fn_keys);
	apple_setup_key_translation(input, powerbook_numlock_keys);
	apple_setup_key_translation(input, apple_iso_keyboard);
	apple_setup_key_translation(input, magic_keyboard_alu_and_2015_fn_keys);
	apple_setup_key_translation(input, magic_keyboard_2021_and_2024_fn_keys);
	apple_setup_key_translation(input, macbookpro_fn_keys);
}

static int apple_input_mapping(struct hid_device *hdev, struct hid_input *hi,
		struct hid_field *field, struct hid_usage *usage,
		unsigned long **bit, int *max)
{
	struct apple_sc *asc = hid_get_drvdata(hdev);

	if (usage->hid == (HID_UP_CUSTOM | 0x0003) ||
			usage->hid == (HID_UP_MSVENDOR | 0x0003) ||
			usage->hid == (HID_UP_HPVENDOR2 | 0x0003)) {
		/* The fn key on Apple USB keyboards */
		set_bit(EV_REP, hi->input->evbit);
		hid_map_usage_clear(hi, usage, bit, max, EV_KEY, KEY_FN);
		asc->fn_found = true;
		apple_setup_input(hi->input);
		return 1;
	}

	/* we want the hid layer to go through standard path (set and ignore) */
	return 0;
}

static int apple_input_mapped(struct hid_device *hdev, struct hid_input *hi,
		struct hid_field *field, struct hid_usage *usage,
		unsigned long **bit, int *max)
{
	struct apple_sc *asc = hid_get_drvdata(hdev);

	if (asc->quirks & APPLE_MIGHTYMOUSE) {
		if (usage->hid == HID_GD_Z)
			hid_map_usage(hi, usage, bit, max, EV_REL, REL_HWHEEL);
		else if (usage->code == BTN_1)
			hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_2);
		else if (usage->code == BTN_2)
			hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_1);
	}

	return 0;
}

static int apple_input_configured(struct hid_device *hdev,
		struct hid_input *hidinput)
{
	struct apple_sc *asc = hid_get_drvdata(hdev);

	if ((asc->quirks & APPLE_HAS_FN) && !asc->fn_found) {
		hid_info(hdev, "Fn key not found (Apple Wireless Keyboard clone?), disabling Fn key handling\n");
		asc->quirks &= ~APPLE_HAS_FN;
	}

	if (apple_is_non_apple_keyboard(hdev)) {
		hid_info(hdev, "Non-apple keyboard detected; function keys will default to fnmode=2 behavior\n");
		asc->quirks |= APPLE_IS_NON_APPLE;
	}

	if (strncmp(hdev->name, "Bluetooth Keyboard", 18) == 0 &&
			hdev->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI) {
		hid_info(hdev, "Omoton keyboard detected; use Fn+F6 to toggle between media and function keys\n");
		asc->quirks |= APPLE_IS_OMOTON;
	}

	return 0;
}

static bool apple_backlight_check_support(struct hid_device *hdev)
{
	int i;
	unsigned int hid;
	struct hid_report *report;

	list_for_each_entry(report, &hdev->report_enum[HID_INPUT_REPORT].report_list, list) {
		for (i = 0; i < report->maxfield; i++) {
			hid = report->field[i]->usage->hid;
			if ((hid & HID_USAGE_PAGE) == HID_UP_MSVENDOR && (hid & HID_USAGE) == 0xf)
				return true;
		}
	}

	return false;
}

static int apple_backlight_set(struct hid_device *hdev, u16 value, u16 rate)
{
	int ret = 0;
	struct apple_backlight_set_report *rep;

	rep = kmalloc(sizeof(*rep), GFP_KERNEL);
	if (rep == NULL)
		return -ENOMEM;

	rep->report_id = 0xB0;
	rep->version = 1;
	rep->backlight = value;
	rep->rate = rate;

	ret = hid_hw_raw_request(hdev, 0xB0u, (u8 *) rep, sizeof(*rep),
				 HID_OUTPUT_REPORT, HID_REQ_SET_REPORT);

	kfree(rep);
	return ret;
}

static int apple_backlight_led_set(struct led_classdev *led_cdev,
	enum led_brightness brightness)
{
	struct apple_sc_backlight *backlight = container_of(led_cdev,
							    struct apple_sc_backlight, cdev);

	return apple_backlight_set(backlight->hdev, brightness, 0);
}

static int apple_backlight_init(struct hid_device *hdev)
{
	int ret;
	struct apple_sc *asc = hid_get_drvdata(hdev);
	struct apple_backlight_config_report *rep;

	if (!apple_backlight_check_support(hdev))
		return -EINVAL;

	rep = kmalloc(0x200, GFP_KERNEL);
	if (rep == NULL)
		return -ENOMEM;

	ret = hid_hw_raw_request(hdev, 0xBFu, (u8 *) rep, sizeof(*rep),
				 HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
	if (ret < 0) {
		hid_err(hdev, "backlight request failed: %d\n", ret);
		goto cleanup_and_exit;
	}
	if (ret < 8 || rep->version != 1) {
		hid_err(hdev, "backlight config struct: bad version %i\n", rep->version);
		ret = -EINVAL;
		goto cleanup_and_exit;
	}

	hid_dbg(hdev, "backlight config: off=%u, on_min=%u, on_max=%u\n",
		rep->backlight_off, rep->backlight_on_min, rep->backlight_on_max);

	asc->backlight = devm_kzalloc(&hdev->dev, sizeof(*asc->backlight), GFP_KERNEL);
	if (!asc->backlight) {
		ret = -ENOMEM;
		goto cleanup_and_exit;
	}

	asc->backlight->hdev = hdev;
	asc->backlight->cdev.name = "apple::kbd_backlight";
	asc->backlight->cdev.max_brightness = rep->backlight_on_max;
	asc->backlight->cdev.brightness_set_blocking = apple_backlight_led_set;

	ret = apple_backlight_set(hdev, 0, 0);
	if (ret < 0) {
		hid_err(hdev, "backlight set request failed: %d\n", ret);
		goto cleanup_and_exit;
	}

	ret = devm_led_classdev_register(&hdev->dev, &asc->backlight->cdev);

cleanup_and_exit:
	kfree(rep);
	return ret;
}

static void apple_magic_backlight_report_set(struct hid_report *rep, s32 value, u8 rate)
{
	rep->field[0]->value[0] = value;
	rep->field[1]->value[0] = 0x5e; /* Mimic Windows */
	rep->field[1]->value[0] |= rate << 8;

	hid_hw_request(rep->device, rep, HID_REQ_SET_REPORT);
}

static void apple_magic_backlight_set(struct apple_magic_backlight *backlight,
				     int brightness, char rate)
{
	apple_magic_backlight_report_set(backlight->power, brightness ? 1 : 0, rate);
	if (brightness)
		apple_magic_backlight_report_set(backlight->brightness, brightness, rate);
}

static int apple_magic_backlight_led_set(struct led_classdev *led_cdev,
					 enum led_brightness brightness)
{
	struct apple_magic_backlight *backlight = container_of(led_cdev,
			struct apple_magic_backlight, cdev);

	apple_magic_backlight_set(backlight, brightness, 1);
	return 0;
}

static int apple_magic_backlight_init(struct hid_device *hdev)
{
	struct apple_magic_backlight *backlight;
	struct hid_report_enum *report_enum;

	/*
	 * Ensure this usb endpoint is for the keyboard backlight, not touchbar
	 * backlight.
	 */
	if (hdev->collection[0].usage != HID_USAGE_MAGIC_BL)
		return -ENODEV;

	backlight = devm_kzalloc(&hdev->dev, sizeof(*backlight), GFP_KERNEL);
	if (!backlight)
		return -ENOMEM;

	report_enum = &hdev->report_enum[HID_FEATURE_REPORT];
	backlight->brightness = report_enum->report_id_hash[APPLE_MAGIC_REPORT_ID_BRIGHTNESS];
	backlight->power = report_enum->report_id_hash[APPLE_MAGIC_REPORT_ID_POWER];

	if (!backlight->brightness || !backlight->power)
		return -ENODEV;

	backlight->cdev.name = ":white:" LED_FUNCTION_KBD_BACKLIGHT;
	backlight->cdev.max_brightness = backlight->brightness->field[0]->logical_maximum;
	backlight->cdev.brightness_set_blocking = apple_magic_backlight_led_set;

	apple_magic_backlight_set(backlight, 0, 0);

	return devm_led_classdev_register(&hdev->dev, &backlight->cdev);

}

static int apple_probe(struct hid_device *hdev,
		const struct hid_device_id *id)
{
	unsigned long quirks = id->driver_data;
	struct apple_sc *asc;
	int ret;

	asc = devm_kzalloc(&hdev->dev, sizeof(*asc), GFP_KERNEL);
	if (asc == NULL) {
		hid_err(hdev, "can't alloc apple descriptor\n");
		return -ENOMEM;
	}

	asc->hdev = hdev;
	asc->quirks = quirks;

	hid_set_drvdata(hdev, asc);

	ret = hid_parse(hdev);
	if (ret) {
		hid_err(hdev, "parse failed\n");
		return ret;
	}

	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
	if (ret) {
		hid_err(hdev, "hw start failed\n");
		return ret;
	}

	timer_setup(&asc->battery_timer, apple_battery_timer_tick, 0);
	mod_timer(&asc->battery_timer,
		  jiffies + msecs_to_jiffies(APPLE_BATTERY_TIMEOUT_MS));
	apple_fetch_battery(hdev);
	omoton_media_key = true;

	if (quirks & APPLE_BACKLIGHT_CTL)
		apple_backlight_init(hdev);

	if (quirks & APPLE_MAGIC_BACKLIGHT) {
		ret = apple_magic_backlight_init(hdev);
		if (ret)
			goto out_err;
	}

	return 0;

out_err:
	del_timer_sync(&asc->battery_timer);
	hid_hw_stop(hdev);
	return ret;
}

static void apple_remove(struct hid_device *hdev)
{
	struct apple_sc *asc = hid_get_drvdata(hdev);

	del_timer_sync(&asc->battery_timer);

	hid_hw_stop(hdev);
}

static const struct hid_device_id apple_devices[] = {
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE),
		.driver_data = APPLE_MIGHTYMOUSE | APPLE_INVERT_HWHEEL },

	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI),
		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO),
		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI),
		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO),
		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS),
		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI),
		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO),
		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
			APPLE_ISO_TILDE_QUIRK },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS),
		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
			APPLE_RDESC_JIS },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI),
		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO),
		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
			APPLE_ISO_TILDE_QUIRK },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS),
		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
			APPLE_RDESC_JIS },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_MINI_ANSI),
		.driver_data = APPLE_HAS_FN },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_MINI_ISO),
		.driver_data = APPLE_HAS_FN },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_MINI_JIS),
		.driver_data = APPLE_HAS_FN },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ANSI),
		.driver_data = APPLE_HAS_FN },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ISO),
		.driver_data = APPLE_HAS_FN },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_JIS),
		.driver_data = APPLE_HAS_FN },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI),
		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO),
		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
			APPLE_ISO_TILDE_QUIRK },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS),
		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
			APPLE_RDESC_JIS },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ANSI),
		.driver_data = APPLE_HAS_FN },
	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ANSI),
		.driver_data = APPLE_HAS_FN },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ISO),
		.driver_data = APPLE_HAS_FN },
	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ISO),
		.driver_data = APPLE_HAS_FN },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_JIS),
		.driver_data = APPLE_HAS_FN },
	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI),
		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO),
		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
			APPLE_ISO_TILDE_QUIRK },
	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO),
		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
			APPLE_ISO_TILDE_QUIRK },
	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
				USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI),
		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
				USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_JIS),
		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS),
		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2015),
		.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK | APPLE_RDESC_BATTERY },
	{ HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2015),
		.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2015),
		.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK | APPLE_RDESC_BATTERY },
	{ HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2015),
		.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI),
		.driver_data = APPLE_HAS_FN },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ISO),
		.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_JIS),
		.driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI),
		.driver_data = APPLE_HAS_FN },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ISO),
		.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_JIS),
		.driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI),
		.driver_data = APPLE_HAS_FN },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ISO),
		.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_JIS),
		.driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI),
		.driver_data = APPLE_HAS_FN },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ISO),
		.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_JIS),
		.driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI),
		.driver_data = APPLE_HAS_FN },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO),
		.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS),
		.driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI),
		.driver_data = APPLE_HAS_FN },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ISO),
		.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_JIS),
		.driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI),
		.driver_data = APPLE_HAS_FN },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ISO),
		.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_JIS),
		.driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI),
		.driver_data = APPLE_HAS_FN },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO),
		.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS),
		.driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI),
		.driver_data = APPLE_HAS_FN },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5A_ISO),
		.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS),
		.driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI),
		.driver_data = APPLE_HAS_FN },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ISO),
		.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_JIS),
		.driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI),
		.driver_data = APPLE_HAS_FN },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO),
		.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS),
		.driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI),
		.driver_data = APPLE_HAS_FN },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ISO),
		.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_JIS),
		.driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI),
		.driver_data = APPLE_HAS_FN },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ISO),
		.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_JIS),
		.driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J140K),
		.driver_data = APPLE_HAS_FN | APPLE_BACKLIGHT_CTL | APPLE_ISO_TILDE_QUIRK },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J132),
		.driver_data = APPLE_HAS_FN | APPLE_BACKLIGHT_CTL | APPLE_ISO_TILDE_QUIRK },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J680),
		.driver_data = APPLE_HAS_FN | APPLE_BACKLIGHT_CTL | APPLE_ISO_TILDE_QUIRK },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J213),
		.driver_data = APPLE_HAS_FN | APPLE_BACKLIGHT_CTL | APPLE_ISO_TILDE_QUIRK },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J214K),
		.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J223),
		.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J230K),
		.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J152F),
		.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI),
		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO),
		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
			APPLE_ISO_TILDE_QUIRK },
	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS),
		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY),
		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY),
		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021),
		.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK | APPLE_RDESC_BATTERY },
	{ HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021),
		.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2024),
		.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK | APPLE_RDESC_BATTERY },
	{ HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2024),
		.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2021),
		.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK | APPLE_RDESC_BATTERY },
	{ HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2021),
		.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2021),
		.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK | APPLE_RDESC_BATTERY },
	{ HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2021),
		.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_TOUCHBAR_BACKLIGHT),
		.driver_data = APPLE_MAGIC_BACKLIGHT },

	{ }
};
MODULE_DEVICE_TABLE(hid, apple_devices);

static struct hid_driver apple_driver = {
	.name = "apple",
	.id_table = apple_devices,
	.report_fixup = apple_report_fixup,
	.probe = apple_probe,
	.remove = apple_remove,
	.event = apple_event,
	.input_mapping = apple_input_mapping,
	.input_mapped = apple_input_mapped,
	.input_configured = apple_input_configured,
};
module_hid_driver(apple_driver);

MODULE_DESCRIPTION("Apple USB HID quirks support for Linux");
MODULE_LICENSE("GPL");

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

* Re: [PATCH resend] HID: apple: fix up the F6 key on the Omoton KB066 keyboard
  2025-02-17  6:42                 ` Alex Henrie
  2025-02-17 10:02                   ` Aditya Garg
@ 2025-02-24  2:46                   ` Alex Henrie
  1 sibling, 0 replies; 24+ messages in thread
From: Alex Henrie @ 2025-02-24  2:46 UTC (permalink / raw)
  To: Aditya Garg
  Cc: linux-input@vger.kernel.org, jkosina@suse.cz,
	benjamin.tissoires@redhat.com

On Sun, Feb 16, 2025 at 11:42 PM Alex Henrie <alexhenrie24@gmail.com> wrote:

> If I understand correctly Mac OS sets each Apple keyboard's internal
> name to "<username>'s keyboard" by default, and that's what mine is,
> but a user could conceivably override that with "Bluetooth Keyboard".
> It's also possible "Bluetooth Keyboard" is the name that all A1255's
> had when they walked out of the factory, before they were connected to
> an Apple device.

Today I successfully used a MacBook5,1 from 2008 to factory-reset my
A1255 keyboard, by holding Shift and Option while clicking the
Bluetooth icon in the menu bar and clicking Debug > Factory reset all
connected Apple devices. After the reset, the keyboard's name reverted
to "Apple Wireless Keyboard". Now that we know that the name
"Bluetooth Keyboard" is not used by default on a real Apple keyboard
and is unlikely to have been set manually, I think it will be fine to
have the hid-apple driver behave differently if the PID is 022c and
the keyboard name is "Bluetooth Keyboard".

-Alex

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

* Re: [PATCH resend] HID: apple: fix up the F6 key on the Omoton KB066 keyboard
  2025-02-17 10:02                   ` Aditya Garg
  2025-02-17 10:03                     ` Aditya Garg
@ 2025-02-24  2:50                     ` Alex Henrie
  2025-02-24  4:44                       ` Alex Henrie
  1 sibling, 1 reply; 24+ messages in thread
From: Alex Henrie @ 2025-02-24  2:50 UTC (permalink / raw)
  To: Aditya Garg; +Cc: open list:HID CORE LAYER, jkosina, Benjamin Tissoires

On Mon, Feb 17, 2025 at 3:02 AM Aditya Garg <gargaditya08@live.com> wrote:

> Can you to test the patch at the bottom of this message?

I tried it and the patch works. However, I don't think it is the right approach.

> Then see if Fn+F6 switches the media to function keys or not, and media keys work by default or not.

The main problem I have with this idea is that there is nothing to
indicate to the user that Fn+F6 switches between Fn modes. If the user
presses Fn+F6 trying to actually type F6, they will be very confused.

What all of this discussion tells me is that it's not possible to make
the Omoton KB066 work perfectly, and it's not worth our time to try.
I'm not even convinced anymore that my original patch was a good idea.
Since we know now that we can detect the Omoton reliably enough based
on its name and its PID, I suggest that we simply add "Bluetooth
Keyboard" to the non_apple_keyboards table, with a new flag to
indicate that the name must match exactly and a new field to indicate
that the PID must be 022c. Being in the table will effectively disable
the counterproductive Fn key handling because fnmode=2 is equivalent
to fnmode=0 on the Omoton.

I will send a new patch.

-Alex

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

* Re: [PATCH resend] HID: apple: fix up the F6 key on the Omoton KB066 keyboard
  2025-02-24  2:50                     ` Alex Henrie
@ 2025-02-24  4:44                       ` Alex Henrie
  2025-02-24  5:05                         ` Aditya Garg
  0 siblings, 1 reply; 24+ messages in thread
From: Alex Henrie @ 2025-02-24  4:44 UTC (permalink / raw)
  To: Aditya Garg; +Cc: open list:HID CORE LAYER, jkosina, Benjamin Tissoires

On Sun, Feb 23, 2025 at 7:50 PM Alex Henrie <alexhenrie24@gmail.com> wrote:

> fnmode=2 is equivalent
> to fnmode=0 on the Omoton.

Ugh, I just discovered that I was wrong about that too: In fnmode=2,
F6 is still converted to Num Lock. fnmode=0 really would be the better
default for the Omoton.

-Alex

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

* Re: [PATCH resend] HID: apple: fix up the F6 key on the Omoton KB066 keyboard
  2025-02-24  4:44                       ` Alex Henrie
@ 2025-02-24  5:05                         ` Aditya Garg
  2025-02-24  5:18                           ` Alex Henrie
  0 siblings, 1 reply; 24+ messages in thread
From: Aditya Garg @ 2025-02-24  5:05 UTC (permalink / raw)
  To: Alex Henrie; +Cc: open list:HID CORE LAYER, jkosina@suse.cz, Benjamin Tissoires



> On 24 Feb 2025, at 10:14 AM, Alex Henrie <alexhenrie24@gmail.com> wrote:
> 
> On Sun, Feb 23, 2025 at 7:50 PM Alex Henrie <alexhenrie24@gmail.com> wrote:
> 
>> fnmode=2 is equivalent
>> to fnmode=0 on the Omoton.
> 
> Ugh, I just discovered that I was wrong about that too: In fnmode=2,
> F6 is still converted to Num Lock. fnmode=0 really would be the better
> default for the Omoton.
> 
Removing APPLE_HAS_FN quirk seems to be a better idea tbh
> -Alex

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

* Re: [PATCH resend] HID: apple: fix up the F6 key on the Omoton KB066 keyboard
  2025-02-24  5:05                         ` Aditya Garg
@ 2025-02-24  5:18                           ` Alex Henrie
  2025-02-24  5:30                             ` Aditya Garg
  0 siblings, 1 reply; 24+ messages in thread
From: Alex Henrie @ 2025-02-24  5:18 UTC (permalink / raw)
  To: Aditya Garg; +Cc: open list:HID CORE LAYER, jkosina@suse.cz, Benjamin Tissoires

On Sun, Feb 23, 2025 at 10:05 PM Aditya Garg <gargaditya08@live.com> wrote:

> > On Sun, Feb 23, 2025 at 7:50 PM Alex Henrie <alexhenrie24@gmail.com> wrote:

> > fnmode=0 really would be the better
> > default for the Omoton.
> >
> Removing APPLE_HAS_FN quirk seems to be a better idea tbh

I agree. I'll send a patch shortly that will do exactly that.

-Alex

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

* Re: [PATCH resend] HID: apple: fix up the F6 key on the Omoton KB066 keyboard
  2025-02-24  5:18                           ` Alex Henrie
@ 2025-02-24  5:30                             ` Aditya Garg
  2025-02-24  5:40                               ` Alex Henrie
  0 siblings, 1 reply; 24+ messages in thread
From: Aditya Garg @ 2025-02-24  5:30 UTC (permalink / raw)
  To: Alex Henrie; +Cc: open list:HID CORE LAYER, jkosina@suse.cz, Benjamin Tissoires



> On 24 Feb 2025, at 10:49 AM, Alex Henrie <alexhenrie24@gmail.com> wrote:
> 
> On Sun, Feb 23, 2025 at 10:05 PM Aditya Garg <gargaditya08@live.com> wrote:
> 
>>> On Sun, Feb 23, 2025 at 7:50 PM Alex Henrie <alexhenrie24@gmail.com> wrote:
> 
>>> fnmode=0 really would be the better
>>> default for the Omoton.
>>> 
>> Removing APPLE_HAS_FN quirk seems to be a better idea tbh
> 
> I agree. I'll send a patch shortly that will do exactly that.

I just made a patch. I'll sent it soon.
> 
> -Alex

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

* Re: [PATCH resend] HID: apple: fix up the F6 key on the Omoton KB066 keyboard
  2025-02-24  5:30                             ` Aditya Garg
@ 2025-02-24  5:40                               ` Alex Henrie
  2025-02-24  5:46                                 ` Aditya Garg
  0 siblings, 1 reply; 24+ messages in thread
From: Alex Henrie @ 2025-02-24  5:40 UTC (permalink / raw)
  To: Aditya Garg; +Cc: open list:HID CORE LAYER, jkosina@suse.cz, Benjamin Tissoires

On Sun, Feb 23, 2025 at 10:30 PM Aditya Garg <gargaditya08@live.com> wrote:

> > On 24 Feb 2025, at 10:49 AM, Alex Henrie <alexhenrie24@gmail.com> wrote:
> >
> > On Sun, Feb 23, 2025 at 10:05 PM Aditya Garg <gargaditya08@live.com> wrote:

> >> Removing APPLE_HAS_FN quirk seems to be a better idea tbh
> >
> > I agree. I'll send a patch shortly that will do exactly that.
>
> I just made a patch. I'll sent it soon.

I was going to spend a little more time looking over the patch I wrote
before I sent it, but I just sent it to avoid wasting your time on
duplicated effort. The most difficult part of the patch was writing a
clear explanation in the commit message.

-Alex

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

* Re: [PATCH resend] HID: apple: fix up the F6 key on the Omoton KB066 keyboard
  2025-02-24  5:40                               ` Alex Henrie
@ 2025-02-24  5:46                                 ` Aditya Garg
  2025-02-24  6:01                                   ` Alex Henrie
  0 siblings, 1 reply; 24+ messages in thread
From: Aditya Garg @ 2025-02-24  5:46 UTC (permalink / raw)
  To: Alex Henrie; +Cc: open list:HID CORE LAYER, jkosina@suse.cz, Benjamin Tissoires



> On 24 Feb 2025, at 11:10 AM, Alex Henrie <alexhenrie24@gmail.com> wrote:
> 
> On Sun, Feb 23, 2025 at 10:30 PM Aditya Garg <gargaditya08@live.com> wrote:
> 
>>> On 24 Feb 2025, at 10:49 AM, Alex Henrie <alexhenrie24@gmail.com> wrote:
>>> 
>>> On Sun, Feb 23, 2025 at 10:05 PM Aditya Garg <gargaditya08@live.com> wrote:
> 
>>>> Removing APPLE_HAS_FN quirk seems to be a better idea tbh
>>> 
>>> I agree. I'll send a patch shortly that will do exactly that.
>> 
>> I just made a patch. I'll sent it soon.
> 
> I was going to spend a little more time looking over the patch I wrote
> before I sent it, but I just sent it to avoid wasting your time on
> duplicated effort. The most difficult part of the patch was writing a
> clear explanation in the commit message.

Commit messages are definitely a PITA LOL

Could you see this patch btw. It also addresses some minor code style issues in the driver.

—>8—

From 09472be6428dd74064b2165a2a78e61e049c2667 Mon Sep 17 00:00:00 2001
From: Aditya Garg <gargaditya08@live.com>
Date: Mon, 24 Feb 2025 11:10:42 +0530
Subject: [PATCH] fix

Signed-off-by: Aditya Garg <gargaditya08@live.com>
---
 drivers/hid/hid-apple.c | 63 ++++++++++++++++++++++++++++-------------
 1 file changed, 43 insertions(+), 20 deletions(-)

diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index 49812a76b..18b779403 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -30,7 +30,7 @@
 #include "hid-ids.h"
 
 #define APPLE_RDESC_JIS		BIT(0)
-#define APPLE_IGNORE_MOUSE	BIT(1)
+/* BIT(1) reserved, was: APPLE_IGNORE_MOUSE */
 #define APPLE_HAS_FN		BIT(2)
 /* BIT(3) reserved, was: APPLE_HIDDEV */
 #define APPLE_ISO_TILDE_QUIRK	BIT(4)
@@ -84,11 +84,29 @@ struct apple_non_apple_keyboard {
 	char *name;
 };
 
+struct apple_non_apple_keyboard_disable_fn {
+	char *name;
+	u32 product_id;
+};
+
 struct apple_sc_backlight {
 	struct led_classdev cdev;
 	struct hid_device *hdev;
 };
 
+struct apple_backlight_config_report {
+	u8 report_id;
+	u8 version;
+	u16 backlight_off, backlight_on_min, backlight_on_max;
+};
+
+struct apple_backlight_set_report {
+	u8 report_id;
+	u8 version;
+	u16 backlight;
+	u16 rate;
+};
+
 struct apple_magic_backlight {
 	struct led_classdev cdev;
 	struct hid_report *brightness;
@@ -152,20 +170,6 @@ static const struct apple_key_translation magic_keyboard_2015_fn_keys[] = {
 	{ }
 };
 
-struct apple_backlight_config_report {
-	u8 report_id;
-	u8 version;
-	u16 backlight_off, backlight_on_min, backlight_on_max;
-};
-
-struct apple_backlight_set_report {
-	u8 report_id;
-	u8 version;
-	u16 backlight;
-	u16 rate;
-};
-
-
 static const struct apple_key_translation apple2021_fn_keys[] = {
 	{ KEY_BACKSPACE, KEY_DELETE },
 	{ KEY_ENTER,	KEY_INSERT },
@@ -352,6 +356,7 @@ static const struct apple_key_translation swapped_fn_leftctrl_keys[] = {
 	{ }
 };
 
+/* We want the default fnmode be 2 in these keyboards */
 static const struct apple_non_apple_keyboard non_apple_keyboards[] = {
 	{ "SONiX USB DEVICE" },
 	{ "Keychron" },
@@ -364,6 +369,11 @@ static const struct apple_non_apple_keyboard non_apple_keyboards[] = {
 	{ "WKB603" },
 };
 
+/* Some non Apple keyboards report they have fn, but do internal translation of their keys */
+static const struct apple_non_apple_keyboard_disable_fn non_apple_keyboards_disable_fn[] = {
+	{ "Bluetooth Keyboard",	USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI},
+};
+
 static bool apple_is_non_apple_keyboard(struct hid_device *hdev)
 {
 	int i;
@@ -378,6 +388,22 @@ static bool apple_is_non_apple_keyboard(struct hid_device *hdev)
 	return false;
 }
 
+static bool apple_disable_fn(struct hid_device *hdev)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(non_apple_keyboards_disable_fn); i++) {
+		char *non_apple = non_apple_keyboards_disable_fn[i].name;
+		u32 pid = non_apple_keyboards_disable_fn[i].product_id;
+
+		if (strncmp(hdev->name, non_apple, strlen(non_apple)) == 0 &&
+			hdev->product == pid)
+			return true;
+	}
+
+	return false;
+}
+
 static inline void apple_setup_key_translation(struct input_dev *input,
 		const struct apple_key_translation *table)
 {
@@ -546,9 +572,6 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
 		}
 	}
 
-	if (usage->hid == 0xc0301) /* Omoton KB066 quirk */
-		code = KEY_F6;
-
 	if (usage->code != code) {
 		input_event_with_scancode(input, usage->type, code, usage->hid, value);
 
@@ -728,8 +751,8 @@ static int apple_input_configured(struct hid_device *hdev,
 {
 	struct apple_sc *asc = hid_get_drvdata(hdev);
 
-	if ((asc->quirks & APPLE_HAS_FN) && !asc->fn_found) {
-		hid_info(hdev, "Fn key not found (Apple Wireless Keyboard clone?), disabling Fn key handling\n");
+	if (((asc->quirks & APPLE_HAS_FN) && !asc->fn_found) || apple_disable_fn(hdev)) {
+		hid_info(hdev, "Fn key not found or has internal handling (Apple Wireless Keyboard clone?), disabling Fn key handling\n");
 		asc->quirks &= ~APPLE_HAS_FN;
 	}
 
-- 
2.43.0


—>8—

Feel free to submit it from my behalf if you want. Ive signed it.


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

* Re: [PATCH resend] HID: apple: fix up the F6 key on the Omoton KB066 keyboard
  2025-02-24  5:46                                 ` Aditya Garg
@ 2025-02-24  6:01                                   ` Alex Henrie
  0 siblings, 0 replies; 24+ messages in thread
From: Alex Henrie @ 2025-02-24  6:01 UTC (permalink / raw)
  To: Aditya Garg; +Cc: open list:HID CORE LAYER, jkosina@suse.cz, Benjamin Tissoires

On Sun, Feb 23, 2025 at 10:47 PM Aditya Garg <gargaditya08@live.com> wrote:

> Could you see this patch btw. It also addresses some minor code style issues in the driver.

Each patch should do one small thing. Style issues in unrelated code
should be addressed in separate patches.

> +               if (strncmp(hdev->name, non_apple, strlen(non_apple)) == 0 &&

This will match any keyboard whose name starts with "Bluetooth
Keyboard", instead of keyboards whose names are exactly "Bluetooth
Keyboard". A name such as "Bluetooth Keyboard 16" is only possible if
the keyboard is a real Apple keyboard that has been renamed in Mac OS,
which means that it is not an Omoton.

All in all, the general idea of having a table like in your patch is
not a bad idea, but like I said in my previous email, it seems
superfluous at this point in time.

-Alex

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

end of thread, other threads:[~2025-02-24  6:01 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-10-01  5:51 [PATCH] HID: apple: fix up the F6 key on the Omoton KB066 keyboard Alex Henrie
2025-01-17  6:12 ` [PATCH resend] " Alex Henrie
2025-02-03 21:57   ` Jiri Kosina
2025-02-05  3:02     ` Alex Henrie
2025-02-07 13:07   ` Jiri Kosina
2025-02-12 17:36   ` Aditya Garg
2025-02-12 17:43     ` Aditya Garg
2025-02-16  1:08       ` Alex Henrie
2025-02-16  6:06         ` Aditya Garg
2025-02-16  6:45           ` Aditya Garg
2025-02-17  4:13             ` Alex Henrie
2025-02-17  5:18               ` Aditya Garg
2025-02-17  6:42                 ` Alex Henrie
2025-02-17 10:02                   ` Aditya Garg
2025-02-17 10:03                     ` Aditya Garg
2025-02-24  2:50                     ` Alex Henrie
2025-02-24  4:44                       ` Alex Henrie
2025-02-24  5:05                         ` Aditya Garg
2025-02-24  5:18                           ` Alex Henrie
2025-02-24  5:30                             ` Aditya Garg
2025-02-24  5:40                               ` Alex Henrie
2025-02-24  5:46                                 ` Aditya Garg
2025-02-24  6:01                                   ` Alex Henrie
2025-02-24  2:46                   ` Alex Henrie

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).