From 9a0afdd19a01c6edddb92eb6a464f9e99d946b90 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Thu, 30 Apr 2026 15:33:53 +0100 Subject: [PATCH 01/12] soundwire: stream: sdw_stream_remove_slave(): Check stream is valid In sdw_stream_remove_slave() check that stream is a valid pointer before passing it to functions that dereference it. Return 0 if the pointer is invalid. This is a convenience for callers. They can safely call this function during cleanup code without needing a pointer validity check duplicated at every call point. Signed-off-by: Richard Fitzgerald Reviewed-by: Pierre-Louis Bossart Link: https://patch.msgid.link/20260430143353.2702714-1-rf@opensource.cirrus.com Signed-off-by: Vinod Koul --- drivers/soundwire/stream.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c index 4ed8fb7663ad..c1ef177a0021 100644 --- a/drivers/soundwire/stream.c +++ b/drivers/soundwire/stream.c @@ -2229,11 +2229,15 @@ EXPORT_SYMBOL(sdw_stream_add_slave); * @slave: SDW Slave instance * @stream: SoundWire stream * - * This removes and frees port_rt and slave_rt from a stream + * This removes and frees port_rt and slave_rt from a stream. + * If stream is NULL or an ERR_PTR, do nothing and return 0. */ int sdw_stream_remove_slave(struct sdw_slave *slave, struct sdw_stream_runtime *stream) { + if (IS_ERR_OR_NULL(stream)) + return 0; + mutex_lock(&slave->bus->bus_lock); sdw_slave_port_free(slave, stream); From be6d8daaab654e9b0a8508757534d556d399d0cd Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 29 Apr 2026 16:36:14 +0100 Subject: [PATCH 02/12] soundwire: intel_auxdevice: Add cs42l43b to wake_capable_list Add cs42l43b (both packaging options) to the wake_capable_list because it can generate jack events whilst the bus is stopped. Signed-off-by: Charles Keepax Reviewed-by: Pierre-Louis Bossart Link: https://patch.msgid.link/20260429153614.741899-1-ckeepax@opensource.cirrus.com Signed-off-by: Vinod Koul --- drivers/soundwire/intel_auxdevice.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/soundwire/intel_auxdevice.c b/drivers/soundwire/intel_auxdevice.c index 913e95207ee1..ee951be15465 100644 --- a/drivers/soundwire/intel_auxdevice.c +++ b/drivers/soundwire/intel_auxdevice.c @@ -51,6 +51,8 @@ struct wake_capable_part { }; static struct wake_capable_part wake_capable_list[] = { + {0x01fa, 0x2A30}, + {0x01fa, 0x2A3B}, {0x01fa, 0x4243}, {0x01fa, 0x4245}, {0x01fa, 0x4249}, From 45c7bda7b7440183850012153988e40b300f40d0 Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Fri, 3 Apr 2026 14:55:12 +0800 Subject: [PATCH 03/12] soundwire: validate DT compatible before parsing it `sdw_of_find_slaves()` fetches raw `"compatible"` bytes with `of_get_property()` and then immediately parses them with `sscanf("sdw%01x%04hx%04hx%02hhx", ...)`. Live-tree OF properties are stored as raw bytes plus a separate length; they are not globally guaranteed to be NUL-terminated. Validate the first compatible string before parsing it. Signed-off-by: Pengpeng Hou Link: https://patch.msgid.link/20260403183504.4-soundwire-compatible-pengpeng@iscas.ac.cn Signed-off-by: Vinod Koul --- drivers/soundwire/slave.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/soundwire/slave.c b/drivers/soundwire/slave.c index ff763b692078..e0c49cbcb1ba 100644 --- a/drivers/soundwire/slave.c +++ b/drivers/soundwire/slave.c @@ -244,8 +244,8 @@ int sdw_of_find_slaves(struct sdw_bus *bus) struct sdw_slave_id id; const __be32 *addr; - compat = of_get_property(node, "compatible", NULL); - if (!compat) + ret = of_property_read_string(node, "compatible", &compat); + if (ret) continue; ret = sscanf(compat, "sdw%01x%04hx%04hx%02hhx", &sdw_version, From c368dd5cbd61ffab2b6f8a89b0d5775e2e16cde6 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 28 Apr 2026 16:46:12 +0800 Subject: [PATCH 04/12] soundwire: don't program SDW_SCP_BUSCLOCK_SCALE on a unattached Peripheral MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The SDW_SCP_BUSCLOCK_SCALE register will be programmed when the Peripheral is attached. We can and should skip programming the SDW_SCP_BUSCLOCK_SCALE register when the Peripheral is unattached. Fixes: 645291cfe5e5 ("Soundwire: stream: program BUSCLOCK_SCALE") Signed-off-by: Bard Liao Reviewed-by: Simon Trimmer Reviewed-by: Péter Ujfalusi Reviewed-by: Ranjani Sridharan Link: https://patch.msgid.link/20260428084612.322701-1-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/stream.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c index c1ef177a0021..cdac009b1a75 100644 --- a/drivers/soundwire/stream.c +++ b/drivers/soundwire/stream.c @@ -697,6 +697,13 @@ static int sdw_program_params(struct sdw_bus *bus, bool prepare) if (scale_index < 0) return scale_index; + /* Skip the unattached Peripherals */ + if (!completion_done(&slave->enumeration_complete)) { + dev_warn(&slave->dev, + "Not enumerated, skip programming BUSCLOCK_SCALE\n"); + continue; + } + ret = sdw_write_no_pm(slave, addr1, scale_index); if (ret < 0) { dev_err(&slave->dev, "SDW_SCP_BUSCLOCK_SCALE register write failed\n"); From f772ff5a0e6758fd412803c09e03ba3bca5f5878 Mon Sep 17 00:00:00 2001 From: "Baoli.Zhang" Date: Wed, 6 May 2026 13:50:35 +0800 Subject: [PATCH 05/12] soundwire: fix bug in sdw_add_element_group_count found by syzkaller The original implementation caused an out-of-bounds memory access in the sdw_add_element_group_count for-loop when i == num. for (i = 0; i <= num; i++) { if (rate == group->rates[i] && lane == group->lanes[i]) ... To fix this error, the function now checks for existing rate/lane entries in the group(a function parameter) using a for-loop before adding them. No functional changes apart from this fix. Fixes: 9026118f20e2 ("soundwire: Add generic bandwidth allocation algorithm") Reviewed-by: Bard Liao Reviewed-by: Andy Shevchenko Signed-off-by: Baoli.Zhang Link: https://patch.msgid.link/20260506055039.3751028-2-baoli.zhang@linux.intel.com Signed-off-by: Vinod Koul --- .../soundwire/generic_bandwidth_allocation.c | 57 +++++++++---------- 1 file changed, 27 insertions(+), 30 deletions(-) diff --git a/drivers/soundwire/generic_bandwidth_allocation.c b/drivers/soundwire/generic_bandwidth_allocation.c index fb3970e12dac..f016ad088a1d 100644 --- a/drivers/soundwire/generic_bandwidth_allocation.c +++ b/drivers/soundwire/generic_bandwidth_allocation.c @@ -299,39 +299,36 @@ static int sdw_add_element_group_count(struct sdw_group *group, int num = group->count; int i; - for (i = 0; i <= num; i++) { + for (i = 0; i < num; i++) { if (rate == group->rates[i] && lane == group->lanes[i]) - break; - - if (i != num) - continue; - - if (group->count >= group->max_size) { - unsigned int *rates; - unsigned int *lanes; - - group->max_size += 1; - rates = krealloc(group->rates, - (sizeof(int) * group->max_size), - GFP_KERNEL); - if (!rates) - return -ENOMEM; - - group->rates = rates; - - lanes = krealloc(group->lanes, - (sizeof(int) * group->max_size), - GFP_KERNEL); - if (!lanes) - return -ENOMEM; - - group->lanes = lanes; - } - - group->rates[group->count] = rate; - group->lanes[group->count++] = lane; + return 0; } + if (group->count >= group->max_size) { + unsigned int *rates; + unsigned int *lanes; + + group->max_size += 1; + rates = krealloc(group->rates, + (sizeof(int) * group->max_size), + GFP_KERNEL); + if (!rates) + return -ENOMEM; + + group->rates = rates; + + lanes = krealloc(group->lanes, + (sizeof(int) * group->max_size), + GFP_KERNEL); + if (!lanes) + return -ENOMEM; + + group->lanes = lanes; + } + + group->rates[group->count] = rate; + group->lanes[group->count++] = lane; + return 0; } From 654a7ae10b2ee6b07d5d9193c1c5465410781908 Mon Sep 17 00:00:00 2001 From: "Baoli.Zhang" Date: Wed, 6 May 2026 13:50:36 +0800 Subject: [PATCH 06/12] soundwire: increase group->max_size after allocation Only update `group->max_size` after both allocations succeed to avoid leaving the group's state inconsistent if one allocation fails. Signed-off-by: Baoli.Zhang Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20260506055039.3751028-3-baoli.zhang@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/generic_bandwidth_allocation.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/soundwire/generic_bandwidth_allocation.c b/drivers/soundwire/generic_bandwidth_allocation.c index f016ad088a1d..cd9ccbaf0e46 100644 --- a/drivers/soundwire/generic_bandwidth_allocation.c +++ b/drivers/soundwire/generic_bandwidth_allocation.c @@ -308,9 +308,8 @@ static int sdw_add_element_group_count(struct sdw_group *group, unsigned int *rates; unsigned int *lanes; - group->max_size += 1; rates = krealloc(group->rates, - (sizeof(int) * group->max_size), + sizeof(int) * (group->max_size + 1), GFP_KERNEL); if (!rates) return -ENOMEM; @@ -318,12 +317,14 @@ static int sdw_add_element_group_count(struct sdw_group *group, group->rates = rates; lanes = krealloc(group->lanes, - (sizeof(int) * group->max_size), + sizeof(int) * (group->max_size + 1), GFP_KERNEL); if (!lanes) return -ENOMEM; group->lanes = lanes; + + group->max_size += 1; } group->rates[group->count] = rate; From 35a5ab8ef7f0f00b30eab9d917f3f0f4a2bec5d6 Mon Sep 17 00:00:00 2001 From: "Baoli.Zhang" Date: Wed, 6 May 2026 13:50:37 +0800 Subject: [PATCH 07/12] soundwire: use krealloc_array to prevent integer overflow Replace the use of krealloc() with krealloc_array() in sdw_add_element_group_count to mitigate the risk of integer overflow during memory allocation size calculation. Suggested-by: Andy Shevchenko Signed-off-by: Baoli.Zhang Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20260506055039.3751028-4-baoli.zhang@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/generic_bandwidth_allocation.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/soundwire/generic_bandwidth_allocation.c b/drivers/soundwire/generic_bandwidth_allocation.c index cd9ccbaf0e46..3575d69ce1c5 100644 --- a/drivers/soundwire/generic_bandwidth_allocation.c +++ b/drivers/soundwire/generic_bandwidth_allocation.c @@ -308,17 +308,15 @@ static int sdw_add_element_group_count(struct sdw_group *group, unsigned int *rates; unsigned int *lanes; - rates = krealloc(group->rates, - sizeof(int) * (group->max_size + 1), - GFP_KERNEL); + rates = krealloc_array(group->rates, group->max_size + 1, + sizeof(*group->rates), GFP_KERNEL); if (!rates) return -ENOMEM; group->rates = rates; - lanes = krealloc(group->lanes, - sizeof(int) * (group->max_size + 1), - GFP_KERNEL); + lanes = krealloc_array(group->lanes, group->max_size + 1, + sizeof(*group->lanes), GFP_KERNEL); if (!lanes) return -ENOMEM; From 4e90368e8680d9ddcb06f82f2e63cbbcf21cef2c Mon Sep 17 00:00:00 2001 From: Zhang Yi Date: Thu, 14 May 2026 15:52:06 +0800 Subject: [PATCH 08/12] soundwire: intel_auxdevice: Add es9356 to wake_capable_list Add es9356 to the wake_capable_list because it can generate jack events whilst the bus is stopped Signed-off-by: Zhang Yi Link: https://patch.msgid.link/20260514075206.3483-7-zhangyi@everest-semi.com Signed-off-by: Vinod Koul --- drivers/soundwire/intel_auxdevice.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/soundwire/intel_auxdevice.c b/drivers/soundwire/intel_auxdevice.c index ee951be15465..0b8107bec9ab 100644 --- a/drivers/soundwire/intel_auxdevice.c +++ b/drivers/soundwire/intel_auxdevice.c @@ -72,6 +72,7 @@ static struct wake_capable_part wake_capable_list[] = { {0x025d, 0x717}, {0x025d, 0x721}, {0x025d, 0x722}, + {0x04b3, 0x9356}, }; static bool is_wake_capable(struct sdw_slave *slave) From acf676b9de0c86bc735a7f04962d3d688e156ffc Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 8 May 2026 18:17:55 +0800 Subject: [PATCH 09/12] soundwire: intel: Move suspend tracking from trigger to pm suspend Mark all open DAI runtimes as suspended in the component .suspend callback instead of relying on SNDRV_PCM_TRIGGER_SUSPEND, which is not delivered during PAUSE or xrun states. If during system suspend a dai is open it means that it is in either in SUSPENDED, PAUSED or STOPPED (due to xrun) state and they will need to be re-initialized during resume (which is done in .prepare callback). Signed-off-by: Peter Ujfalusi Signed-off-by: Bard Liao Link: https://patch.msgid.link/20260508101755.1247039-1-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/intel.c | 31 ++++++-------------------- drivers/soundwire/intel_ace2x.c | 39 ++++++++++++++++++++++----------- 2 files changed, 33 insertions(+), 37 deletions(-) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index dcd7440e78fa..af65214836b4 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -906,19 +906,6 @@ static int intel_trigger(struct snd_pcm_substream *substream, int cmd, struct sn } switch (cmd) { - case SNDRV_PCM_TRIGGER_SUSPEND: - - /* - * The .prepare callback is used to deal with xruns and resume operations. - * In the case of xruns, the DMAs and SHIM registers cannot be touched, - * but for resume operations the DMAs and SHIM registers need to be initialized. - * the .trigger callback is used to track the suspend case only. - */ - - dai_runtime->suspended = true; - - break; - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: dai_runtime->paused = true; break; @@ -955,10 +942,12 @@ static int intel_component_dais_suspend(struct snd_soc_component *component) struct snd_soc_dai *dai; /* - * In the corner case where a SUSPEND happens during a PAUSE, the ALSA core - * does not throw the TRIGGER_SUSPEND. This leaves the DAIs in an unbalanced state. - * Since the component suspend is called last, we can trap this corner case - * and force the DAIs to release their resources. + * Mark all open streams as suspended. + * Open streams at this point can be in SUSPENDED, PAUSED or STOPPED + * state and during prepare the DMAs and SHIM registers need to be + * initialized for them. + * The STOPPED state is a special corner case which can happen if audio + * experiences xrun at suspend time. */ for_each_component_dais(component, dai) { struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai); @@ -966,13 +955,7 @@ static int intel_component_dais_suspend(struct snd_soc_component *component) dai_runtime = cdns->dai_runtime_array[dai->id]; - if (!dai_runtime) - continue; - - if (dai_runtime->suspended) - continue; - - if (dai_runtime->paused) + if (dai_runtime) dai_runtime->suspended = true; } diff --git a/drivers/soundwire/intel_ace2x.c b/drivers/soundwire/intel_ace2x.c index 20422534baf1..0a97253fe0c2 100644 --- a/drivers/soundwire/intel_ace2x.c +++ b/drivers/soundwire/intel_ace2x.c @@ -894,19 +894,6 @@ static int intel_trigger(struct snd_pcm_substream *substream, int cmd, struct sn } switch (cmd) { - case SNDRV_PCM_TRIGGER_SUSPEND: - - /* - * The .prepare callback is used to deal with xruns and resume operations. - * In the case of xruns, the DMAs and SHIM registers cannot be touched, - * but for resume operations the DMAs and SHIM registers need to be initialized. - * the .trigger callback is used to track the suspend case only. - */ - - dai_runtime->suspended = true; - - break; - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: dai_runtime->paused = true; break; @@ -930,8 +917,34 @@ static const struct snd_soc_dai_ops intel_pcm_dai_ops = { .get_stream = intel_get_sdw_stream, }; +static int intel_component_dais_suspend(struct snd_soc_component *component) +{ + struct snd_soc_dai *dai; + + /* + * Mark all open streams as suspended. + * Open streams at this point can be in SUSPENDED, PAUSED or STOPPED + * state and during prepare the DMAs and SHIM registers need to be + * initialized for them. + * The STOPPED state is a special corner case which can happen if audio + * experiences xrun at suspend time. + */ + for_each_component_dais(component, dai) { + struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai); + struct sdw_cdns_dai_runtime *dai_runtime; + + dai_runtime = cdns->dai_runtime_array[dai->id]; + + if (dai_runtime) + dai_runtime->suspended = true; + } + + return 0; +} + static const struct snd_soc_component_driver dai_component = { .name = "soundwire", + .suspend = intel_component_dais_suspend, }; /* From 8a7fe10eec64bfb7cf4091bca540de4c55d56bfa Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Thu, 14 May 2026 22:16:25 +0800 Subject: [PATCH 10/12] soundwire: intel_ace2x: release bpt_stream when close it The BPT stream was allocated in intel_ace2x_bpt_open_stream(), we need to free it in intel_ace2x_bpt_close_stream(). Fixes: 4c1ce9f37d8a8 ("soundwire: intel_ace2x: add BPT send_async/wait callbacks") Signed-off-by: Bard Liao Reviewed-by: Simon Trimmer Reviewed-by: Pierre-Louis Bossart Link: https://patch.msgid.link/20260514141625.1834216-1-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/intel_ace2x.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/soundwire/intel_ace2x.c b/drivers/soundwire/intel_ace2x.c index 0a97253fe0c2..b37933efac5d 100644 --- a/drivers/soundwire/intel_ace2x.c +++ b/drivers/soundwire/intel_ace2x.c @@ -317,6 +317,7 @@ static void intel_ace2x_bpt_close_stream(struct sdw_intel *sdw, struct sdw_slave dev_err(cdns->dev, "%s: remove slave failed: %d\n", __func__, ret); + sdw_release_stream(cdns->bus.bpt_stream); cdns->bus.bpt_stream = NULL; } From 38cd651ebce7065a81c7e950d9e2ea1572304605 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 20 May 2026 10:57:20 +0800 Subject: [PATCH 11/12] soundwire: only handle alert events when the peripheral is attached MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It doesn't make sense to handle an alert event when the peripheral is not attached. The slave->status could be SDW_SLAVE_ATTACHED or SDW_SLAVE_ALERT when it is attached on the bus. Signed-off-by: Bard Liao Reviewed-by: Péter Ujfalusi Reviewed-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Link: https://patch.msgid.link/20260520025720.1999367-1-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/bus.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index fe5316d93fef..0490777fa406 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -1958,6 +1958,10 @@ int sdw_handle_slave_status(struct sdw_bus *bus, break; case SDW_SLAVE_ALERT: + if (slave->status != SDW_SLAVE_ATTACHED && + slave->status != SDW_SLAVE_ALERT) + continue; + ret = sdw_handle_slave_alerts(slave); if (ret < 0) dev_err(&slave->dev, From 4dab2b904414fac53535c4e4cdad808132f4cdc2 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 20 May 2026 17:36:31 +0100 Subject: [PATCH 12/12] soundwire: dmi-quirks: Disable ghost Realtek devices Many systems ship with a Realtek audio codec in the ACPI that doesn't physically exist in the system. This confuses the newer function topology system that creates the soundcard, as it builds the card based on the ACPI information. Whilst we are working with the laptop vendors to try and stop this happening there are quite a few systems where this has shipped. Add a quirk to disable this "ghost" device. Currently this patch should cover: - Asus UX5406AA - Lenovo Yoga Pro 9i (83SF) - Lenovo Yoga Slim 7 Ultra (83QK) Signed-off-by: Charles Keepax Reviewed-by: Pierre-Louis Bossart Link: https://patch.msgid.link/20260520163631.3300102-4-ckeepax@opensource.cirrus.com Signed-off-by: Vinod Koul --- drivers/soundwire/dmi-quirks.c | 35 ++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/drivers/soundwire/dmi-quirks.c b/drivers/soundwire/dmi-quirks.c index 5854218e1a27..32a46a2d90f7 100644 --- a/drivers/soundwire/dmi-quirks.c +++ b/drivers/soundwire/dmi-quirks.c @@ -90,6 +90,19 @@ static const struct adr_remap intel_rooks_county[] = { {} }; +/* + * Many platforms have ghost realtek devices in the ACPI that don't physically + * exist, remove those devices. + */ +static const struct adr_remap ghost_realtek[] = { + /* rt722 on link3 */ + { + 0x000330025d072201ull, + 0x0000000000000000ull + }, + {} +}; + static const struct dmi_system_id adr_remap_quirk_table[] = { /* TGL devices */ { @@ -164,6 +177,28 @@ static const struct dmi_system_id adr_remap_quirk_table[] = { }, .driver_data = (void *)hp_omen_16, }, + /* PTL devices */ + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUS"), + DMI_MATCH(DMI_BOARD_NAME, "UX5406AA"), + }, + .driver_data = (void *)ghost_realtek, + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "83QK"), + }, + .driver_data = (void *)ghost_realtek, + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "83SF"), + }, + .driver_data = (void *)ghost_realtek, + }, {} };