From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from fhigh-b7-smtp.messagingengine.com (fhigh-b7-smtp.messagingengine.com [202.12.124.158]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8D4C8433A8; Sun, 23 Mar 2025 20:13:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=202.12.124.158 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1742760834; cv=none; b=MyXjmakShSyzq4Gtr35AzTcK0Y6RWJhlwXgIg0tzVeNBC+CALuHvZAB/FRREeiTYMFLD9n0meomipH0aibQnDHMyl+E9zsLDe4fj8+AW5wY8XZeEvkQTnL4uiGF93T7n0rJaukT2AynJkwmcT1GhLQjQKxhTZF5bwYK1UtzUN1s= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1742760834; c=relaxed/simple; bh=xUiGl3i1+1PW4Duj9gQG9TndBZJkryrTmxEu4B826Us=; h=Message-ID:Date:MIME-Version:Subject:To:Cc:References:From: In-Reply-To:Content-Type; b=p0iO5GCEbBeMDVt/T/FkQcugx2Y9HMeF9jGK1p0US4lklbAw4GhMNLAfkpSh2fqXs3amvt1g0E8XO2npw1suBU4GNDCXSo3IBYq4viCd3PfcF6mBJYDW/yxGqbgYqLdRRe79n7D6WTOlWP9v2SOr+pYS/bNesacgZBzbJov0y78= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=ljones.dev; spf=none smtp.mailfrom=ljones.dev; dkim=pass (2048-bit key) header.d=ljones.dev header.i=@ljones.dev header.b=KxXodlBM; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=i6SVb3cb; arc=none smtp.client-ip=202.12.124.158 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=ljones.dev Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=ljones.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=ljones.dev header.i=@ljones.dev header.b="KxXodlBM"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="i6SVb3cb" Received: from phl-compute-07.internal (phl-compute-07.phl.internal [10.202.2.47]) by mailfhigh.stl.internal (Postfix) with ESMTP id 36FDF2540111; Sun, 23 Mar 2025 16:13:50 -0400 (EDT) Received: from phl-mailfrontend-01 ([10.202.2.162]) by phl-compute-07.internal (MEProxy); Sun, 23 Mar 2025 16:13:50 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ljones.dev; h=cc :cc:content-transfer-encoding:content-type:content-type:date :date:from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to; s=fm3; t=1742760830; x=1742847230; bh=wtATCcX+e4qugvlmg37n+HQi9IzQPREWk3KKDO84RsA=; b= KxXodlBMTHz6dGc8WKcb2bDVNEY4BNnWjmpCsrysJLhkgUD/Qb1N5p/d5nnoeUuZ NRt64USfEpnUHjQYuf+hWVIM8H3ygmQooDNQLs0CAMIsh7HmKOhdrqvFWJCL0oNw SgbB34zlW+YKK8C7pzAlgDlT8Soi9jjySdtnw/LQGVq+aLBDimnzcinNdAhEGBQu skGpz8TYxE62Q/guTR4jPbfT+Ekq86Kq003WiDIHG3htNJ15Dtcr0IiE+uIz4l2H AtvHc6FsmjgjcGEFn131ra5EyRrXfHVPFCpgaZmMBwo39xD/GzM0g9t3OTHD/N/m SP3FzTGLtyUYk3jhriWfOg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:content-type:date:date:feedback-id:feedback-id :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t=1742760830; x= 1742847230; bh=wtATCcX+e4qugvlmg37n+HQi9IzQPREWk3KKDO84RsA=; b=i 6SVb3cbxsSJ/vUgKAZm+pSEhEeEfieue9mN96zwX8FVsmMZX7G55t/kCFh2mWZvJ fEmoycu13FvuZKVxM04cnubfl+CqINhZgyKOHv2LCCp2ad4ttVrZwQ9Mst76JxOW KneABZR8gaHR8iJTQTHtxx5O9lq7qOoAD5pQCoHeyxDZU6UdBQSzlon5Sq0nk7GB 98MEG5OXJ7O4eAaXNHjq9HuEcDm5OPOwZzGgOVhseDD5CurrPx0Q3ThT5f8p/46n TpDixUcWaQkmi4v6OXJ3mAh6zlgX6GJv+KkrbU9qD62brKmQbc/JdH/rbq7BLANL KWZj8HVxwgUVUASiwHEYg== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefvddrtddtgdduheejkeduucetufdoteggodetrf dotffvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdggtfgfnhhsuhgsshgtrhhisggv pdfurfetoffkrfgpnffqhgenuceurghilhhouhhtmecufedttdenucesvcftvggtihhpih gvnhhtshculddquddttddmnecujfgurhepkfffgggfuffvvehfhfgjtgfgsehtjeertddt vdejnecuhfhrohhmpedfnfhukhgvucffrdculfhonhgvshdfuceolhhukhgvsehljhhonh gvshdruggvvheqnecuggftrfgrthhtvghrnhepjeelteffieehueduvddvjeejgfekjeeh heevkeeiieejvdfhfeeluefggedvfeefnecuffhomhgrihhnpehlvggupggtuggvvhdrnh grmhgvnecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhep lhhukhgvsehljhhonhgvshdruggvvhdpnhgspghrtghpthhtohepledpmhhouggvpehsmh htphhouhhtpdhrtghpthhtoheplhhkmhhlsegrnhhthhgvrghsrdguvghvpdhrtghpthht ohepphhlrghtfhhorhhmqdgurhhivhgvrhdqgiekieesvhhgvghrrdhkvghrnhgvlhdroh hrghdprhgtphhtthhopehlihhnuhigqdhinhhpuhhtsehvghgvrhdrkhgvrhhnvghlrdho rhhgpdhrtghpthhtoheplhhinhhugidqkhgvrhhnvghlsehvghgvrhdrkhgvrhhnvghlrd horhhgpdhrtghpthhtohepjhhikhhosheskhgvrhhnvghlrdhorhhgpdhrtghpthhtohep sggvnhhtihhssheskhgvrhhnvghlrdhorhhgpdhrtghpthhtoheptghorhgvnhhtihhnrd gthhgrrhihsehgmhgrihhlrdgtohhmpdhrtghpthhtohephhguvghgohgvuggvsehrvggu hhgrthdrtghomhdprhgtphhtthhopehilhhpohdrjhgrrhhvihhnvghnsehlihhnuhigrd hinhhtvghlrdgtohhm X-ME-Proxy: Feedback-ID: i5ec1447f:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Sun, 23 Mar 2025 16:13:45 -0400 (EDT) Message-ID: <73987b72-e3ab-4e98-9c03-318b4a97f7b0@ljones.dev> Date: Mon, 24 Mar 2025 09:13:43 +1300 Precedence: bulk X-Mailing-List: linux-input@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: [PATCH v3 09/10] HID: asus: add basic RGB support To: Antheas Kapenekakis Cc: platform-driver-x86@vger.kernel.org, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, Jiri Kosina , Benjamin Tissoires , Corentin Chary , Hans de Goede , =?UTF-8?Q?Ilpo_J=C3=A4rvinen?= References: <20250322102804.418000-1-lkml@antheas.dev> <20250322102804.418000-10-lkml@antheas.dev> Content-Language: en-US From: "Luke D. Jones" In-Reply-To: Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit On 24/03/25 03:45, Antheas Kapenekakis wrote: > On Sun, 23 Mar 2025 at 12:37, Antheas Kapenekakis wrote: >> >> On Sun, 23 Mar 2025 at 07:40, Luke D. Jones wrote: >>> >>> On 22/03/25 23:28, Antheas Kapenekakis wrote: >>>> Adds basic RGB support to hid-asus through multi-index. The interface >>>> works quite well, but has not gone through much stability testing. >>>> Applied on demand, if userspace does not touch the RGB sysfs, not >>>> even initialization is done. Ensuring compatibility with existing >>>> userspace programs. >>>> >>>> Signed-off-by: Antheas Kapenekakis >>>> --- >>>> drivers/hid/hid-asus.c | 169 +++++++++++++++++++++++++++++++++++++---- >>>> 1 file changed, 155 insertions(+), 14 deletions(-) >>>> >>>> diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c >>>> index 905453a4eb5b7..9d8ccfde5912e 100644 >>>> --- a/drivers/hid/hid-asus.c >>>> +++ b/drivers/hid/hid-asus.c >>>> @@ -30,6 +30,7 @@ >>>> #include >>>> #include /* For to_usb_interface for T100 touchpad intf check */ >>>> #include >>>> +#include >>>> #include >>>> >>>> #include "hid-ids.h" >>>> @@ -85,6 +86,7 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad"); >>>> #define QUIRK_ROG_NKEY_KEYBOARD BIT(11) >>>> #define QUIRK_ROG_CLAYMORE_II_KEYBOARD BIT(12) >>>> #define QUIRK_HANDLE_GENERIC BIT(13) >>>> +#define QUIRK_ROG_NKEY_RGB BIT(14) >>>> >>>> #define I2C_KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \ >>>> QUIRK_NO_INIT_REPORTS | \ >>>> @@ -97,9 +99,15 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad"); >>>> >>>> struct asus_kbd_leds { >>>> struct asus_hid_listener listener; >>>> + struct led_classdev_mc mc_led; >>>> + struct mc_subled subled_info[3]; >>>> struct hid_device *hdev; >>>> struct work_struct work; >>>> unsigned int brightness; >>>> + uint8_t rgb_colors[3]; >>>> + bool rgb_init; >>>> + bool rgb_set; >>>> + bool rgb_registered; >>>> spinlock_t lock; >>>> bool removed; >>>> }; >>>> @@ -504,23 +512,67 @@ static void asus_schedule_work(struct asus_kbd_leds *led) >>>> spin_unlock_irqrestore(&led->lock, flags); >>>> } >>>> >>>> -static void asus_kbd_backlight_set(struct asus_hid_listener *listener, >>>> +static void do_asus_kbd_backlight_set(struct asus_kbd_leds *led, int brightness) >>>> +{ >>>> + unsigned long flags; >>>> + >>>> + spin_lock_irqsave(&led->lock, flags); >>>> + led->brightness = brightness; >>>> + spin_unlock_irqrestore(&led->lock, flags); >>>> + >>>> + asus_schedule_work(led); >>>> +} >>>> + >>>> +static void asus_kbd_listener_set(struct asus_hid_listener *listener, >>>> int brightness) >>>> { >>>> struct asus_kbd_leds *led = container_of(listener, struct asus_kbd_leds, >>>> listener); >>>> + do_asus_kbd_backlight_set(led, brightness); >>>> + if (led->rgb_registered) { >>>> + led->mc_led.led_cdev.brightness = brightness; >>>> + led_classdev_notify_brightness_hw_changed(&led->mc_led.led_cdev, >>>> + brightness); >>>> + } >>>> +} >>>> + >>>> +static void asus_kbd_brightness_set(struct led_classdev *led_cdev, >>>> + enum led_brightness brightness) >>>> +{ >>>> + struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(led_cdev); >>>> + struct asus_kbd_leds *led = container_of(mc_cdev, struct asus_kbd_leds, >>>> + mc_led); >>>> unsigned long flags; >>>> >>>> spin_lock_irqsave(&led->lock, flags); >>>> - led->brightness = brightness; >>>> + led->rgb_colors[0] = mc_cdev->subled_info[0].intensity; >>>> + led->rgb_colors[1] = mc_cdev->subled_info[1].intensity; >>>> + led->rgb_colors[2] = mc_cdev->subled_info[2].intensity; >>>> + led->rgb_set = true; >>>> spin_unlock_irqrestore(&led->lock, flags); >>>> >>>> - asus_schedule_work(led); >>>> + do_asus_kbd_backlight_set(led, brightness); >>>> +} >>>> + >>>> +static enum led_brightness asus_kbd_brightness_get(struct led_classdev *led_cdev) >>>> +{ >>>> + struct led_classdev_mc *mc_led; >>>> + struct asus_kbd_leds *led; >>>> + enum led_brightness brightness; >>>> + unsigned long flags; >>>> + >>>> + mc_led = lcdev_to_mccdev(led_cdev); >>>> + led = container_of(mc_led, struct asus_kbd_leds, mc_led); >>>> + >>>> + spin_lock_irqsave(&led->lock, flags); >>>> + brightness = led->brightness; >>>> + spin_unlock_irqrestore(&led->lock, flags); >>>> + >>>> + return brightness; >>>> } >>>> >>>> -static void asus_kbd_backlight_work(struct work_struct *work) >>>> +static void asus_kbd_backlight_work(struct asus_kbd_leds *led) >>>> { >>>> - struct asus_kbd_leds *led = container_of(work, struct asus_kbd_leds, work); >>>> u8 buf[] = { FEATURE_KBD_REPORT_ID, 0xba, 0xc5, 0xc4, 0x00 }; >>>> int ret; >>>> unsigned long flags; >>>> @@ -534,10 +586,69 @@ static void asus_kbd_backlight_work(struct work_struct *work) >>>> hid_err(led->hdev, "Asus failed to set keyboard backlight: %d\n", ret); >>>> } >>>> >>>> +static void asus_kbd_rgb_work(struct asus_kbd_leds *led) >>>> +{ >>>> + u8 rgb_buf[][7] = { >>>> + { FEATURE_KBD_LED_REPORT_ID1, 0xB3 }, /* set mode */ >>>> + { FEATURE_KBD_LED_REPORT_ID1, 0xB5 }, /* apply mode */ >>>> + { FEATURE_KBD_LED_REPORT_ID1, 0xB4 }, /* save to mem */ >>>> + }; >>>> + unsigned long flags; >>>> + uint8_t colors[3]; >>>> + bool rgb_init, rgb_set; >>>> + int ret; >>>> + >>>> + spin_lock_irqsave(&led->lock, flags); >>>> + rgb_init = led->rgb_init; >>>> + rgb_set = led->rgb_set; >>>> + led->rgb_set = false; >>>> + colors[0] = led->rgb_colors[0]; >>>> + colors[1] = led->rgb_colors[1]; >>>> + colors[2] = led->rgb_colors[2]; >>>> + spin_unlock_irqrestore(&led->lock, flags); >>>> + >>>> + if (!rgb_set) >>>> + return; >>>> + >>>> + if (rgb_init) { >>>> + ret = asus_kbd_init(led->hdev, FEATURE_KBD_LED_REPORT_ID1); >>>> + if (ret < 0) { >>>> + hid_err(led->hdev, "Asus failed to init RGB: %d\n", ret); >>>> + return; >>>> + } >>>> + spin_lock_irqsave(&led->lock, flags); >>>> + led->rgb_init = false; >>>> + spin_unlock_irqrestore(&led->lock, flags); >>>> + } >>>> + >>>> + /* Protocol is: 54b3 zone (0=all) mode (0=solid) RGB */ >>>> + rgb_buf[0][4] = colors[0]; >>>> + rgb_buf[0][5] = colors[1]; >>>> + rgb_buf[0][6] = colors[2]; >>>> + >>>> + for (size_t i = 0; i < ARRAY_SIZE(rgb_buf); i++) { >>>> + ret = asus_kbd_set_report(led->hdev, rgb_buf[i], sizeof(rgb_buf[i])); >>>> + if (ret < 0) { >>>> + hid_err(led->hdev, "Asus failed to set RGB: %d\n", ret); >>>> + return; >>>> + } >>>> + } >>>> +} >>>> + >>>> +static void asus_kbd_work(struct work_struct *work) >>>> +{ >>>> + struct asus_kbd_leds *led = container_of(work, struct asus_kbd_leds, >>>> + work); >>>> + asus_kbd_backlight_work(led); >>>> + asus_kbd_rgb_work(led); >>>> +} >>>> + >>>> static int asus_kbd_register_leds(struct hid_device *hdev) >>>> { >>>> struct asus_drvdata *drvdata = hid_get_drvdata(hdev); >>>> unsigned char kbd_func; >>>> + struct asus_kbd_leds *leds; >>>> + bool no_led; >>>> int ret; >>>> >>>> ret = asus_kbd_init(hdev, FEATURE_KBD_REPORT_ID); >>>> @@ -565,21 +676,51 @@ static int asus_kbd_register_leds(struct hid_device *hdev) >>>> if (!drvdata->kbd_backlight) >>>> return -ENOMEM; >>>> >>>> - drvdata->kbd_backlight->removed = false; >>>> - drvdata->kbd_backlight->brightness = 0; >>>> - drvdata->kbd_backlight->hdev = hdev; >>>> - drvdata->kbd_backlight->listener.brightness_set = asus_kbd_backlight_set; >>>> - INIT_WORK(&drvdata->kbd_backlight->work, asus_kbd_backlight_work); >>>> + leds = drvdata->kbd_backlight; >>>> + leds->removed = false; >>>> + leds->brightness = 3; >>>> + leds->hdev = hdev; >>>> + leds->listener.brightness_set = asus_kbd_listener_set; >>>> + >>>> + leds->rgb_colors[0] = 0; >>>> + leds->rgb_colors[1] = 0; >>>> + leds->rgb_colors[2] = 0; >>>> + leds->rgb_init = true; >>>> + leds->rgb_set = false; >>>> + leds->mc_led.led_cdev.name = devm_kasprintf(&hdev->dev, GFP_KERNEL, >>>> + "asus-%s-led", >>>> + strlen(hdev->uniq) ? >>>> + hdev->uniq : dev_name(&hdev->dev)); >>> >>> A quick note. This breaks convention for LED names. The style guide is >>> at Documentation/leds/leds-class.rst. Per my parallel email to this one >>> I would like to see the mentioned naming scheme `asus:rgb:kbd_backlight` >>> adopted. >> >> Perhaps. It would be the first kbd_backlight driver to have "rgb" in >> it. It is a bit out of scope for this series as I do not touch the >> functionality of it but I can add a patch for it and a fixes >> e305a71cea37a64c75 tag. >> >>> Expanding further on one of the points there you might need to >>> move the led_classdev_mc in to asus-wmi to fulfil having the single >>> sysfs endpoint. Since you're using the listner pattern it shouldn't be >>> much work. >> >> I only want the brightness to sync, not the color. Only the brightness >> between Aura devices needs to be the same. In this case >> asus::kbd_backlight if it has a color controls the wmi color, and the >> asus- devices control the usb. >> >> Also, groups are not dynamic so this is not possible. E.g., if you >> setup a WMI listener that does not have RGB, and then the USB keyboard >> connects you can no longer change the groups unless you reconnect the >> device. > > Sorry, I confused the patches. Yes you are right. I cannot do > kbd_backlight because userspace might pick the wrong handler. And with > this patch series on the Z13 there are 3, one for the common > backlight, one for the keyboard, and one for the lightbar. > > I can do asus-UNIQ:rgb:peripheral though. There is no appropriate > function that is close enough currently. Also, since there can be > multiple devices, UNIQ or something similar needs to be added, > otherwise the led handler will suffix _X. > That sounds appropriate yeah. Is there an issue with the suffix number being added? I've not encountered any myself. Cheers. Luke. > Antheas > >>>> + leds->mc_led.led_cdev.flags = LED_BRIGHT_HW_CHANGED; >>>> + leds->mc_led.led_cdev.max_brightness = 3, >>>> + leds->mc_led.led_cdev.brightness_set = asus_kbd_brightness_set, >>>> + leds->mc_led.led_cdev.brightness_get = asus_kbd_brightness_get, >>>> + leds->mc_led.subled_info = leds->subled_info, >>>> + leds->mc_led.num_colors = ARRAY_SIZE(leds->subled_info), >>>> + leds->subled_info[0].color_index = LED_COLOR_ID_RED; >>>> + leds->subled_info[1].color_index = LED_COLOR_ID_GREEN; >>>> + leds->subled_info[2].color_index = LED_COLOR_ID_BLUE; >>>> + >>>> + INIT_WORK(&drvdata->kbd_backlight->work, asus_kbd_work); >>>> spin_lock_init(&drvdata->kbd_backlight->lock); >>>> >>>> ret = asus_hid_register_listener(&drvdata->kbd_backlight->listener); >>>> + no_led = !!ret; >>>> + >>>> + if (drvdata->quirks & QUIRK_ROG_NKEY_RGB) { >>>> + ret = devm_led_classdev_multicolor_register( >>>> + &hdev->dev, &leds->mc_led); >>>> + if (!ret) >>>> + leds->rgb_registered = true; >>>> + no_led &= !!ret; >>>> + } >>>> >>>> - if (ret < 0) { >>>> + if (no_led) { >>>> /* No need to have this still around */ >>>> devm_kfree(&hdev->dev, drvdata->kbd_backlight); >>>> } >>>> >>>> - return ret; >>>> + return no_led ? -ENODEV : 0; >>>> } >>>> >>>> /* >>>> @@ -1289,7 +1430,7 @@ static const struct hid_device_id asus_devices[] = { >>>> QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD }, >>>> { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, >>>> USB_DEVICE_ID_ASUSTEK_ROG_Z13_LIGHTBAR), >>>> - QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD }, >>>> + QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD | QUIRK_ROG_NKEY_RGB }, >>>> { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, >>>> USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY), >>>> QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD }, >>>> @@ -1318,7 +1459,7 @@ static const struct hid_device_id asus_devices[] = { >>>> */ >>>> { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, >>>> USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_ROG_Z13_FOLIO), >>>> - QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD }, >>>> + QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD | QUIRK_ROG_NKEY_RGB }, >>>> { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, >>>> USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_T101HA_KEYBOARD) }, >>>> { } >>>