Files
linux/drivers/platform/x86/serdev_helpers.h
Hans de Goede 1c1c91bf05 platform/x86: serdev_helpers: Check for serial_ctrl_uid == NULL
commit 478b00a623 upstream.

dell_uart_bl_pdev_probe() calls get_serdev_controller() with the
serial_ctrl_uid parameter set to NULL.

In case of errors this NULL parameter then gets passed to pr_err()
as argument matching a "%s" conversion specification. This leads to
compiler warnings when building with "make W=1".

Check serial_ctrl_uid before passing it to pr_err() to avoid these.

Fixes: dc5afd720f ("platform/x86: Add new get_serdev_controller() helper")
Cc: stable@vger.kernel.org
Suggested-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Reviewed-by: Andy Shevchenko <andy@kernel.org>
Link: https://lore.kernel.org/r/20241204204227.95757-4-hdegoede@redhat.com
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2025-02-17 10:04:57 +01:00

81 lines
2.3 KiB
C

/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* In some cases UART attached devices which require an in kernel driver,
* e.g. UART attached Bluetooth HCIs are described in the ACPI tables
* by an ACPI device with a broken or missing UartSerialBusV2() resource.
*
* This causes the kernel to create a /dev/ttyS# char-device for the UART
* instead of creating an in kernel serdev-controller + serdev-device pair
* for the in kernel driver.
*
* The quirk handling in acpi_quirk_skip_serdev_enumeration() makes the kernel
* create a serdev-controller device for these UARTs instead of a /dev/ttyS#.
*
* Instantiating the actual serdev-device to bind to is up to pdx86 code,
* this header provides a helper for getting the serdev-controller device.
*/
#include <linux/acpi.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/printk.h>
#include <linux/sprintf.h>
#include <linux/string.h>
static inline struct device *
get_serdev_controller(const char *serial_ctrl_hid,
const char *serial_ctrl_uid,
int serial_ctrl_port,
const char *serdev_ctrl_name)
{
struct device *ctrl_dev, *child;
struct acpi_device *ctrl_adev;
char name[32];
int i;
ctrl_adev = acpi_dev_get_first_match_dev(serial_ctrl_hid, serial_ctrl_uid, -1);
if (!ctrl_adev) {
pr_err("error could not get %s/%s serial-ctrl adev\n",
serial_ctrl_hid, serial_ctrl_uid ?: "*");
return ERR_PTR(-ENODEV);
}
/* get_first_physical_node() returns a weak ref */
ctrl_dev = get_device(acpi_get_first_physical_node(ctrl_adev));
if (!ctrl_dev) {
pr_err("error could not get %s/%s serial-ctrl physical node\n",
serial_ctrl_hid, serial_ctrl_uid ?: "*");
ctrl_dev = ERR_PTR(-ENODEV);
goto put_ctrl_adev;
}
/* Walk host -> uart-ctrl -> port -> serdev-ctrl */
for (i = 0; i < 3; i++) {
switch (i) {
case 0:
snprintf(name, sizeof(name), "%s:0", dev_name(ctrl_dev));
break;
case 1:
snprintf(name, sizeof(name), "%s.%d",
dev_name(ctrl_dev), serial_ctrl_port);
break;
case 2:
strscpy(name, serdev_ctrl_name, sizeof(name));
break;
}
child = device_find_child_by_name(ctrl_dev, name);
put_device(ctrl_dev);
if (!child) {
pr_err("error could not find '%s' device\n", name);
ctrl_dev = ERR_PTR(-ENODEV);
goto put_ctrl_adev;
}
ctrl_dev = child;
}
put_ctrl_adev:
acpi_dev_put(ctrl_adev);
return ctrl_dev;
}