Skip to content

Commit dc5afd7

Browse files
committed
platform/x86: Add new get_serdev_controller() helper
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, so far this was handled by the x86-android-tablets code. But since commit b286f4e ("serial: core: Move tty and serdev to be children of serial core port device") the serdev-controller device has moved in the device hierarchy from (e.g.) /sys/devices/pci0000:00/8086228A:00/serial0 to /sys/devices/pci0000:00/8086228A:00/8086228A:00:0/8086228A:00:0.0/serial0 . This makes this a bit trickier to do and another driver is in the works which will also need this functionality. Add a new helper to get the serdev-controller device, so that the new code for this can be shared. Fixes: b286f4e ("serial: core: Move tty and serdev to be children of serial core port device") Cc: Tony Lindgren <[email protected]> Signed-off-by: Hans de Goede <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent bd8905d commit dc5afd7

File tree

1 file changed

+80
-0
lines changed

1 file changed

+80
-0
lines changed

drivers/platform/x86/serdev_helpers.h

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/* SPDX-License-Identifier: GPL-2.0-or-later */
2+
/*
3+
* In some cases UART attached devices which require an in kernel driver,
4+
* e.g. UART attached Bluetooth HCIs are described in the ACPI tables
5+
* by an ACPI device with a broken or missing UartSerialBusV2() resource.
6+
*
7+
* This causes the kernel to create a /dev/ttyS# char-device for the UART
8+
* instead of creating an in kernel serdev-controller + serdev-device pair
9+
* for the in kernel driver.
10+
*
11+
* The quirk handling in acpi_quirk_skip_serdev_enumeration() makes the kernel
12+
* create a serdev-controller device for these UARTs instead of a /dev/ttyS#.
13+
*
14+
* Instantiating the actual serdev-device to bind to is up to pdx86 code,
15+
* this header provides a helper for getting the serdev-controller device.
16+
*/
17+
#include <linux/acpi.h>
18+
#include <linux/device.h>
19+
#include <linux/err.h>
20+
#include <linux/printk.h>
21+
#include <linux/sprintf.h>
22+
#include <linux/string.h>
23+
24+
static inline struct device *
25+
get_serdev_controller(const char *serial_ctrl_hid,
26+
const char *serial_ctrl_uid,
27+
int serial_ctrl_port,
28+
const char *serdev_ctrl_name)
29+
{
30+
struct device *ctrl_dev, *child;
31+
struct acpi_device *ctrl_adev;
32+
char name[32];
33+
int i;
34+
35+
ctrl_adev = acpi_dev_get_first_match_dev(serial_ctrl_hid, serial_ctrl_uid, -1);
36+
if (!ctrl_adev) {
37+
pr_err("error could not get %s/%s serial-ctrl adev\n",
38+
serial_ctrl_hid, serial_ctrl_uid);
39+
return ERR_PTR(-ENODEV);
40+
}
41+
42+
/* get_first_physical_node() returns a weak ref */
43+
ctrl_dev = get_device(acpi_get_first_physical_node(ctrl_adev));
44+
if (!ctrl_dev) {
45+
pr_err("error could not get %s/%s serial-ctrl physical node\n",
46+
serial_ctrl_hid, serial_ctrl_uid);
47+
ctrl_dev = ERR_PTR(-ENODEV);
48+
goto put_ctrl_adev;
49+
}
50+
51+
/* Walk host -> uart-ctrl -> port -> serdev-ctrl */
52+
for (i = 0; i < 3; i++) {
53+
switch (i) {
54+
case 0:
55+
snprintf(name, sizeof(name), "%s:0", dev_name(ctrl_dev));
56+
break;
57+
case 1:
58+
snprintf(name, sizeof(name), "%s.%d",
59+
dev_name(ctrl_dev), serial_ctrl_port);
60+
break;
61+
case 2:
62+
strscpy(name, serdev_ctrl_name, sizeof(name));
63+
break;
64+
}
65+
66+
child = device_find_child_by_name(ctrl_dev, name);
67+
put_device(ctrl_dev);
68+
if (!child) {
69+
pr_err("error could not find '%s' device\n", name);
70+
ctrl_dev = ERR_PTR(-ENODEV);
71+
goto put_ctrl_adev;
72+
}
73+
74+
ctrl_dev = child;
75+
}
76+
77+
put_ctrl_adev:
78+
acpi_dev_put(ctrl_adev);
79+
return ctrl_dev;
80+
}

0 commit comments

Comments
 (0)