diff options
Diffstat (limited to 'configfs.c')
-rw-r--r-- | configfs.c | 153 |
1 files changed, 113 insertions, 40 deletions
@@ -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; } |