aboutsummaryrefslogtreecommitdiffstats
path: root/configfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'configfs.c')
-rw-r--r--configfs.c153
1 files changed, 113 insertions, 40 deletions
diff --git a/configfs.c b/configfs.c
index 5668cb3..bc10efb 100644
--- a/configfs.c
+++ b/configfs.c
@@ -68,6 +68,66 @@ CFG_SND_AVIRT_CHANNELS(stream);
CFG_SND_AVIRT_DIRECTION_RO(route);
CFG_SND_AVIRT_CHANNELS(route);
+/*
+ * Check PCM hw params between a source and a sink
+ */
+#define CHK_ROUTE_ERR(source_hw, sink_hw, field) \
+ do { \
+ if (source_hw->field != sink_hw->field) { \
+ D_ERRORK( \
+ "Route HW mismatch: ##field (src:%d, sink:%d)", \
+ source_hw->field, sink_hw->field); \
+ return -1; \
+ } \
+ } while (0)
+
+/*
+ * Check the a route's source and sink Audio Path's hardware params, to ensure
+ * compatibility
+ */
+static int cfg_snd_avirt_route_verify_hw(struct snd_avirt_audiopath *source_ap,
+ struct snd_avirt_audiopath *sink_ap)
+{
+ const struct snd_pcm_hardware *source_hw = source_ap->hw;
+ const struct snd_pcm_hardware *sink_hw = sink_ap->hw;
+
+ CHK_ROUTE_ERR(source_hw, sink_hw, channels_max);
+ CHK_ROUTE_ERR(source_hw, sink_hw, channels_min);
+ CHK_ROUTE_ERR(source_hw, sink_hw, rate_max);
+ CHK_ROUTE_ERR(source_hw, sink_hw, rate_min);
+ CHK_ROUTE_ERR(source_hw, sink_hw, rates);
+
+ return 0;
+}
+
+/*
+ * Store the Audio Path endpoint (source or sink), and check compatiblity
+ */
+static int cfg_snd_avirt_route_ap_store(struct snd_avirt_route *route,
+ struct snd_avirt_audiopath *ap,
+ snd_avirt_route_endpoint endpoint)
+{
+ /* If other endpoint is set, we want to check that the two Audio Path
+ * endpoints are compatible before we set this endpoint */
+ if (route->endpoint_ap[!endpoint]) {
+ if (!cfg_snd_avirt_route_verify_hw(
+ route->endpoint_ap[!endpoint], ap)) {
+ route->endpoint_ap[endpoint] = ap;
+ D_INFOK("Route successfully created: '%s' [%s -> %s]",
+ route->uid, ap->uid,
+ route->endpoint_ap[!endpoint]->uid);
+ return 0;
+ } else {
+ D_ERRORK("Route could not be created: %s", route->uid);
+ return -1;
+ }
+ } else {
+ route->endpoint_ap[endpoint] = ap;
+ }
+
+ return 0;
+}
+
static ssize_t cfg_snd_avirt_stream_map_show(struct config_item *item,
char *page)
{
@@ -98,85 +158,100 @@ static struct configfs_attribute *cfg_snd_avirt_stream_attrs[] = {
NULL,
};
-static ssize_t cfg_snd_avirt_route_to_ap_show(struct config_item *item,
- char *page)
+static ssize_t cfg_snd_avirt_route_sink_ap_show(struct config_item *item,
+ char *page)
{
struct snd_avirt_route *route = snd_avirt_route_from_config_item(item);
+ if (!route) {
+ D_ERRORK("Cannot get route!");
+ goto exit_err;
+ }
- if (route)
- if (route->to_ap)
- return sprintf(page, "%s\n", route->to_ap->uid);
+ if (route->endpoint_ap[SND_AVIRT_ROUTE_SINK])
+ return sprintf(page, "%s\n",
+ route->endpoint_ap[SND_AVIRT_ROUTE_SINK]->uid);
+exit_err:
return sprintf(page, "\n");
}
-static ssize_t cfg_snd_avirt_route_to_ap_store(struct config_item *item,
- const char *page, size_t count)
+static ssize_t cfg_snd_avirt_route_sink_ap_store(struct config_item *item,
+ const char *page, size_t count)
{
char *uid_ap;
struct snd_avirt_route *route = snd_avirt_route_from_config_item(item);
- struct snd_avirt_audiopath *to_ap;
+ struct snd_avirt_audiopath *sink_ap;
+
+ if (!route) {
+ D_ERRORK("Cannot get route!");
+ goto exit;
+ }
uid_ap = strsep((char **)&page, "\n");
- to_ap = snd_avirt_audiopath_get(uid_ap);
- if (!to_ap) {
+ sink_ap = snd_avirt_audiopath_get(uid_ap);
+ if (!sink_ap) {
D_ERRORK("Audio Path '%s' does not exist!", uid_ap);
- D_ERRORK("Cannot set 'route'->'to_ap'");
- return count;
+ D_ERRORK("Cannot set 'route'->'sink_ap'");
+ goto exit;
}
- route->to_ap = to_ap;
- if (route->from_ap) {
- route->from_ap->route_to_ap = to_ap;
- route->to_ap->route_from_ap = route->from_ap;
- }
+ cfg_snd_avirt_route_ap_store(route, sink_ap, SND_AVIRT_ROUTE_SINK);
+exit:
return count;
}
-CONFIGFS_ATTR(cfg_snd_avirt_route_, to_ap);
+CONFIGFS_ATTR(cfg_snd_avirt_route_, sink_ap);
-static ssize_t cfg_snd_avirt_route_from_ap_show(struct config_item *item,
- char *page)
+static ssize_t cfg_snd_avirt_route_source_ap_show(struct config_item *item,
+ char *page)
{
struct snd_avirt_route *route = snd_avirt_route_from_config_item(item);
+ if (!route) {
+ D_ERRORK("Cannot get route!");
+ goto exit_err;
+ }
- if (route)
- if (route->from_ap)
- return sprintf(page, "%s\n", route->from_ap->uid);
+ if (route->endpoint_ap[SND_AVIRT_ROUTE_SOURCE])
+ return sprintf(page, "%s\n",
+ route->endpoint_ap[SND_AVIRT_ROUTE_SOURCE]->uid);
+exit_err:
return sprintf(page, "\n");
}
-static ssize_t cfg_snd_avirt_route_from_ap_store(struct config_item *item,
- const char *page, size_t count)
+static ssize_t cfg_snd_avirt_route_source_ap_store(struct config_item *item,
+ const char *page,
+ size_t count)
{
char *uid_ap;
struct snd_avirt_route *route = snd_avirt_route_from_config_item(item);
- struct snd_avirt_audiopath *from_ap;
+ struct snd_avirt_audiopath *source_ap;
+
+ if (!route) {
+ D_ERRORK("Cannot get route!");
+ goto exit;
+ }
uid_ap = strsep((char **)&page, "\n");
- from_ap = snd_avirt_audiopath_get(uid_ap);
- if (!from_ap) {
+ source_ap = snd_avirt_audiopath_get(uid_ap);
+ if (!source_ap) {
D_ERRORK("Audio Path '%s' does not exist!", uid_ap);
- D_ERRORK("Cannot set 'route'->'from_ap'");
+ D_ERRORK("Cannot set 'route'->'source_ap'");
return count;
}
- route->from_ap = from_ap;
- if (route->to_ap) {
- route->to_ap->route_from_ap = from_ap;
- route->from_ap->route_to_ap = route->to_ap;
- }
+ cfg_snd_avirt_route_ap_store(route, source_ap, SND_AVIRT_ROUTE_SOURCE);
+exit:
return count;
}
-CONFIGFS_ATTR(cfg_snd_avirt_route_, from_ap);
+CONFIGFS_ATTR(cfg_snd_avirt_route_, source_ap);
static struct configfs_attribute *cfg_snd_avirt_route_attrs[] = {
&cfg_snd_avirt_route_attr_channels,
&cfg_snd_avirt_route_attr_direction,
- &cfg_snd_avirt_route_attr_from_ap,
- &cfg_snd_avirt_route_attr_to_ap,
+ &cfg_snd_avirt_route_attr_source_ap,
+ &cfg_snd_avirt_route_attr_sink_ap,
NULL,
};
@@ -202,7 +277,7 @@ static void cfg_snd_avirt_route_release(struct config_item *item)
return;
}
- D_INFOK("Release route: %s", route->name);
+ D_INFOK("Release route: %s", route->uid);
kfree(route);
}
@@ -297,8 +372,6 @@ cfg_snd_avirt_route_make_item(struct config_group *group, const char *name)
config_item_init_type_name(&route->item, name,
&cfg_snd_avirt_route_type);
- D_INFOK("Make route: %s", route->name);
-
return &route->item;
}