From f61a5cfad842b8cbb05ffe9b83e7bac14d3bb4ba Mon Sep 17 00:00:00 2001 From: Seungbae Shin Date: Thu, 29 Dec 2022 20:41:12 +0900 Subject: [PATCH] module-udev-detect: support hdmi hotplug using extcon + check DEVPATH instead of DRIVERS for HDMI detection on udev rules [Version] 15.0-13 [Issue Type] Update Change-Id: I131adee21e5dbc1add8ca6d046d74d3d60e475a1 --- packaging/pulseaudio.spec | 2 +- src/modules/alsa/90-pulseaudio.rules | 2 +- src/modules/module-udev-detect.c | 156 +++++++++++++++++++++++++++++++++-- 3 files changed, 150 insertions(+), 10 deletions(-) diff --git a/packaging/pulseaudio.spec b/packaging/pulseaudio.spec index dc88318..07dc916 100644 --- a/packaging/pulseaudio.spec +++ b/packaging/pulseaudio.spec @@ -4,7 +4,7 @@ Name: pulseaudio Summary: Improved Linux sound server Version: 15.0 -Release: 12 +Release: 13 Group: Multimedia/Audio License: LGPL-2.1 URL: http://pulseaudio.org diff --git a/src/modules/alsa/90-pulseaudio.rules b/src/modules/alsa/90-pulseaudio.rules index 4811ba9..73b6746 100644 --- a/src/modules/alsa/90-pulseaudio.rules +++ b/src/modules/alsa/90-pulseaudio.rules @@ -18,7 +18,7 @@ SUBSYSTEM!="sound", GOTO="pulseaudio_end" ACTION!="change", GOTO="pulseaudio_end" KERNEL!="card*", GOTO="pulseaudio_end" -DRIVERS=="*hdmi*", ENV{PULSE_PROFILE_SET}="default.conf" GOTO="pulseaudio_end" +DEVPATH=="*hdmi*", ENV{PULSE_PROFILE_SET}="default.conf" GOTO="pulseaudio_end" SUBSYSTEMS=="usb", GOTO="pulseaudio_check_usb" # For tizen platform, we only allow usb devices from udev SUBSYSTEMS!="usb", ENV{PULSE_IGNORE}="1", GOTO="pulseaudio_end" diff --git a/src/modules/module-udev-detect.c b/src/modules/module-udev-detect.c index a2885ce..f91ab5b 100644 --- a/src/modules/module-udev-detect.c +++ b/src/modules/module-udev-detect.c @@ -470,6 +470,139 @@ static void remove_card(struct userdata *u, struct udev_device *dev) { device_free(d); } +#ifdef __TIZEN__ +static void dump_device(struct udev_device *dev) { + pa_log_debug("[ devpath = %s", udev_device_get_devpath(dev)); + pa_log_debug(" subsystem = %s", udev_device_get_subsystem(dev)); + pa_log_debug(" devtype = %s", udev_device_get_devtype(dev)); + pa_log_debug(" syspath = %s", udev_device_get_syspath(dev)); + pa_log_debug(" sysname = %s", udev_device_get_sysname(dev)); + pa_log_debug(" sysnum = %s", udev_device_get_sysnum(dev)); + pa_log_debug(" devnode = %s", udev_device_get_devnode(dev)); + pa_log_debug(" parent subsystem = %s ]", udev_device_get_subsystem(udev_device_get_parent(dev))); +} + +static bool is_devpath_hdmi_extcon(struct udev_device *dev) { + return (bool)strstr(udev_device_get_devpath(dev), "hdmi"); +} + +static void add_hdmi_card(struct userdata *u, const char *card) { + struct udev *udev; + struct udev_device *card_dev; + char *syspath; + + if (!(udev = udev_new())) { + pa_log_error("Failed to allocate udev context."); + return; + } + + syspath = pa_sprintf_malloc("/sys/class/sound/%s", card); + + if ((card_dev = udev_device_new_from_syspath(udev, syspath))) { + card_changed(u, card_dev); + udev_device_unref(card_dev); + } else { + pa_log_error("Failed to get card object."); + } + + pa_xfree(syspath); + udev_unref(udev); +} + +/* NOTE : based from pa_card_choose_initial_profile() */ +pa_card_profile *find_best_card_profile(pa_card *card) { + pa_card_profile *profile; + void *state; + pa_card_profile *best = NULL; + + pa_assert(card); + + pa_log_info("Looking for best profile for card %s", card->name); + PA_HASHMAP_FOREACH(profile, card->profiles, state) { + pa_log_debug(" name(%s), avail(%s)", profile->name, pa_available_to_string(profile->available)); + if (profile->available == PA_AVAILABLE_NO) + continue; + + if (!best || profile->priority > best->priority) + best = profile; + } + + if (!best) { + PA_HASHMAP_FOREACH(profile, card->profiles, state) { + if (!best || profile->priority > best->priority) + best = profile; + } + } + + if (best) + pa_log_info("Found best profile %s", best->name); + else + pa_log_error("No best profile!"); + + return best; +} + +static void process_hdmi_device(struct userdata *u, struct udev_device *dev) { + pa_card *card; + uint32_t idx; + bool is_removed; + const char *devtype; + const char *event_str[] = { "Added", "Removed" }; + const char *sysfs_path; + char *card_to_find; + pa_card_profile *profile_to_set; + + pa_assert(u); + pa_assert(dev); + + devtype = udev_device_get_devtype(dev); + if (!devtype) { + pa_log_error("no parent devtype exist!"); + return; + } + + dump_device(dev); + is_removed = pa_safe_streq(udev_device_get_property_value(dev, "STATE"), "HDMI=0"); + + if (!pa_startswith(devtype, "extcon")) { + pa_log_error("invalid devtype %s", devtype); + return; + } + + card_to_find = pa_replace(devtype, "extcon", "card"); + + pa_log_info("%s %s, devtype : %s", card_to_find, event_str[is_removed], devtype); + + PA_IDXSET_FOREACH(card, u->core->cards, idx) { + sysfs_path = pa_proplist_gets(card->proplist, "sysfs.path"); + if (!sysfs_path) { + pa_log_warn("no sysfs.path property..."); + continue; + } + pa_log_info("sysfs.path : %s, finding : %s", sysfs_path, card_to_find); + + if (pa_endswith(sysfs_path, card_to_find)) { + pa_log_info(" card exists, update proper profile for event (%s)", event_str[is_removed]); + + profile_to_set = is_removed ? pa_hashmap_get(card->profiles, "off") : find_best_card_profile(card); + + if (profile_to_set) + pa_card_set_profile(card, profile_to_set, false); + else + pa_log_error("no profile to set!"); + + goto profile_done; + } + } + + pa_log_info("No card found, add new card (%s)", card_to_find); + add_hdmi_card(u, card_to_find); + +profile_done: + pa_xfree(card_to_find); +} +#endif /* __TIZEN__ */ + static void process_device(struct userdata *u, struct udev_device *dev) { const char *action, *ff; @@ -488,14 +621,7 @@ static void process_device(struct userdata *u, struct udev_device *dev) { } #ifdef __TIZEN__ - pa_log_debug ("devpath = %s", udev_device_get_devpath(dev)); - pa_log_debug ("subsystem = %s", udev_device_get_subsystem(dev)); - pa_log_debug ("devtype = %s", udev_device_get_devtype(dev)); - pa_log_debug ("syspath = %s", udev_device_get_syspath(dev)); - pa_log_debug ("sysname = %s", udev_device_get_sysname(dev)); - pa_log_debug ("sysnum = %s", udev_device_get_sysnum(dev)); - pa_log_debug ("devnode = %s", udev_device_get_devnode(dev)); - pa_log_debug ("parent subsystem = %s", udev_device_get_subsystem(udev_device_get_parent(dev))); + dump_device(dev); #endif action = udev_device_get_action(dev); @@ -540,6 +666,14 @@ static void monitor_cb( goto fail; } +#ifdef __TIZEN__ + if (is_devpath_hdmi_extcon(dev)) { + pa_log_info("HDMI, devpath : %s", udev_device_get_devpath(dev)); + process_hdmi_device(u, dev); + udev_device_unref(dev); + return; + } +#endif if (!path_get_card_id(udev_device_get_devpath(dev))) { udev_device_unref(dev); return; @@ -807,6 +941,12 @@ int pa__init(pa_module *m) { pa_log("Failed to subscribe to sound devices."); goto fail; } +#ifdef __TIZEN__ + if (udev_monitor_filter_add_match_subsystem_devtype(u->monitor, "extcon", NULL) < 0) { + pa_log("Failed to subscribe to extcon devices."); + goto fail; + } +#endif errno = 0; if (udev_monitor_enable_receiving(u->monitor) < 0) { -- 2.7.4