+static int snd_pcm_plug_playback_channels_mask(struct snd_pcm_substream *plug,
+ unsigned long *client_vmask)
+{
+ struct snd_pcm_plugin *plugin = snd_pcm_plug_last(plug);
+ if (plugin == NULL) {
+ return 0;
+ } else {
+ int schannels = plugin->dst_format.channels;
+ DECLARE_BITMAP(bs, schannels);
+ unsigned long *srcmask;
+ unsigned long *dstmask = bs;
+ int err;
+ bitmap_fill(dstmask, schannels);
+
+ while (1) {
+ err = plugin->src_channels_mask(plugin, dstmask, &srcmask);
+ if (err < 0)
+ return err;
+ dstmask = srcmask;
+ if (plugin->prev == NULL)
+ break;
+ plugin = plugin->prev;
+ }
+ bitmap_and(client_vmask, client_vmask, dstmask, plugin->src_format.channels);
+ return 0;
+ }
+}
+
+static int snd_pcm_plug_playback_disable_useless_channels(struct snd_pcm_substream *plug,
+ struct snd_pcm_plugin_channel *src_channels)
+{
+ struct snd_pcm_plugin *plugin = snd_pcm_plug_first(plug);
+ unsigned int nchannels = plugin->src_format.channels;
+ DECLARE_BITMAP(bs, nchannels);
+ unsigned long *srcmask = bs;
+ int err;
+ unsigned int channel;
+ for (channel = 0; channel < nchannels; channel++) {
+ if (src_channels[channel].enabled)
+ set_bit(channel, srcmask);
+ else
+ clear_bit(channel, srcmask);
+ }
+ err = snd_pcm_plug_playback_channels_mask(plug, srcmask);
+ if (err < 0)
+ return err;
+ for (channel = 0; channel < nchannels; channel++) {
+ if (!test_bit(channel, srcmask))
+ src_channels[channel].enabled = 0;
+ }
+ return 0;
+}
+
+static int snd_pcm_plug_capture_disable_useless_channels(struct snd_pcm_substream *plug,
+ struct snd_pcm_plugin_channel *src_channels,
+ struct snd_pcm_plugin_channel *client_channels)
+{
+ struct snd_pcm_plugin *plugin = snd_pcm_plug_last(plug);
+ unsigned int nchannels = plugin->dst_format.channels;
+ DECLARE_BITMAP(bs, nchannels);
+ unsigned long *dstmask = bs;
+ unsigned long *srcmask;
+ int err;
+ unsigned int channel;
+ for (channel = 0; channel < nchannels; channel++) {
+ if (client_channels[channel].enabled)
+ set_bit(channel, dstmask);
+ else
+ clear_bit(channel, dstmask);
+ }
+ while (plugin) {
+ err = plugin->src_channels_mask(plugin, dstmask, &srcmask);
+ if (err < 0)
+ return err;
+ dstmask = srcmask;
+ plugin = plugin->prev;
+ }
+ plugin = snd_pcm_plug_first(plug);
+ nchannels = plugin->src_format.channels;
+ for (channel = 0; channel < nchannels; channel++) {
+ if (!test_bit(channel, dstmask))
+ src_channels[channel].enabled = 0;
+ }
+ return 0;
+}
+