1558a398bSSimon Schubert /*- 22a1ad637SFrançois Tigeot * Copyright (c) 2005-2009 Ariff Abdullah <ariff@FreeBSD.org> 3558a398bSSimon Schubert * All rights reserved. 4558a398bSSimon Schubert * 5558a398bSSimon Schubert * Redistribution and use in source and binary forms, with or without 6558a398bSSimon Schubert * modification, are permitted provided that the following conditions 7558a398bSSimon Schubert * are met: 8558a398bSSimon Schubert * 1. Redistributions of source code must retain the above copyright 9558a398bSSimon Schubert * notice, this list of conditions and the following disclaimer. 10558a398bSSimon Schubert * 2. Redistributions in binary form must reproduce the above copyright 11558a398bSSimon Schubert * notice, this list of conditions and the following disclaimer in the 12558a398bSSimon Schubert * documentation and/or other materials provided with the distribution. 13558a398bSSimon Schubert * 14558a398bSSimon Schubert * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15558a398bSSimon Schubert * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16558a398bSSimon Schubert * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17558a398bSSimon Schubert * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18558a398bSSimon Schubert * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19558a398bSSimon Schubert * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20558a398bSSimon Schubert * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21558a398bSSimon Schubert * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22558a398bSSimon Schubert * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23558a398bSSimon Schubert * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24558a398bSSimon Schubert * SUCH DAMAGE. 25558a398bSSimon Schubert */ 26558a398bSSimon Schubert 272a1ad637SFrançois Tigeot /* feeder_volume, a long 'Lost Technology' rather than a new feature. */ 282a1ad637SFrançois Tigeot 292a1ad637SFrançois Tigeot #ifdef _KERNEL 302a1ad637SFrançois Tigeot #ifdef HAVE_KERNEL_OPTION_HEADERS 312a1ad637SFrançois Tigeot #include "opt_snd.h" 322a1ad637SFrançois Tigeot #endif 33558a398bSSimon Schubert #include <dev/sound/pcm/sound.h> 342a1ad637SFrançois Tigeot #include <dev/sound/pcm/pcm.h> 35558a398bSSimon Schubert #include "feeder_if.h" 36558a398bSSimon Schubert 372a1ad637SFrançois Tigeot #define SND_USE_FXDIV 382a1ad637SFrançois Tigeot #include "snd_fxdiv_gen.h" 392a1ad637SFrançois Tigeot 402a1ad637SFrançois Tigeot SND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pcm/feeder_volume.c 193640 2009-06-07 19:12:08Z ariff $"); 412a1ad637SFrançois Tigeot #endif 422a1ad637SFrançois Tigeot 432a1ad637SFrançois Tigeot typedef void (*feed_volume_t)(int *, int *, uint32_t, uint8_t *, uint32_t); 442a1ad637SFrançois Tigeot 452a1ad637SFrançois Tigeot #define FEEDVOLUME_CALC8(s, v) (SND_VOL_CALC_SAMPLE((intpcm_t) \ 462a1ad637SFrançois Tigeot (s) << 8, v) >> 8) 472a1ad637SFrançois Tigeot #define FEEDVOLUME_CALC16(s, v) SND_VOL_CALC_SAMPLE((intpcm_t)(s), v) 482a1ad637SFrançois Tigeot #define FEEDVOLUME_CALC24(s, v) SND_VOL_CALC_SAMPLE((intpcm64_t)(s), v) 492a1ad637SFrançois Tigeot #define FEEDVOLUME_CALC32(s, v) SND_VOL_CALC_SAMPLE((intpcm64_t)(s), v) 502a1ad637SFrançois Tigeot 512a1ad637SFrançois Tigeot #define FEEDVOLUME_DECLARE(SIGN, BIT, ENDIAN) \ 522a1ad637SFrançois Tigeot static void \ 532a1ad637SFrançois Tigeot feed_volume_##SIGN##BIT##ENDIAN(int *vol, int *matrix, \ 542a1ad637SFrançois Tigeot uint32_t channels, uint8_t *dst, uint32_t count) \ 552a1ad637SFrançois Tigeot { \ 562a1ad637SFrançois Tigeot intpcm##BIT##_t v; \ 572a1ad637SFrançois Tigeot intpcm_t x; \ 582a1ad637SFrançois Tigeot uint32_t i; \ 592a1ad637SFrançois Tigeot \ 602a1ad637SFrançois Tigeot dst += count * PCM_##BIT##_BPS * channels; \ 612a1ad637SFrançois Tigeot do { \ 622a1ad637SFrançois Tigeot i = channels; \ 632a1ad637SFrançois Tigeot do { \ 642a1ad637SFrançois Tigeot dst -= PCM_##BIT##_BPS; \ 652a1ad637SFrançois Tigeot i--; \ 662a1ad637SFrançois Tigeot x = PCM_READ_##SIGN##BIT##_##ENDIAN(dst); \ 672a1ad637SFrançois Tigeot v = FEEDVOLUME_CALC##BIT(x, vol[matrix[i]]); \ 682a1ad637SFrançois Tigeot x = PCM_CLAMP_##SIGN##BIT(v); \ 692a1ad637SFrançois Tigeot _PCM_WRITE_##SIGN##BIT##_##ENDIAN(dst, x); \ 702a1ad637SFrançois Tigeot } while (i != 0); \ 712a1ad637SFrançois Tigeot } while (--count != 0); \ 722a1ad637SFrançois Tigeot } 732a1ad637SFrançois Tigeot 742a1ad637SFrançois Tigeot #if BYTE_ORDER == LITTLE_ENDIAN || defined(SND_FEEDER_MULTIFORMAT) 752a1ad637SFrançois Tigeot FEEDVOLUME_DECLARE(S, 16, LE) 762a1ad637SFrançois Tigeot FEEDVOLUME_DECLARE(S, 32, LE) 772a1ad637SFrançois Tigeot #endif 782a1ad637SFrançois Tigeot #if BYTE_ORDER == BIG_ENDIAN || defined(SND_FEEDER_MULTIFORMAT) 792a1ad637SFrançois Tigeot FEEDVOLUME_DECLARE(S, 16, BE) 802a1ad637SFrançois Tigeot FEEDVOLUME_DECLARE(S, 32, BE) 812a1ad637SFrançois Tigeot #endif 822a1ad637SFrançois Tigeot #ifdef SND_FEEDER_MULTIFORMAT 832a1ad637SFrançois Tigeot FEEDVOLUME_DECLARE(S, 8, NE) 842a1ad637SFrançois Tigeot FEEDVOLUME_DECLARE(S, 24, LE) 852a1ad637SFrançois Tigeot FEEDVOLUME_DECLARE(S, 24, BE) 862a1ad637SFrançois Tigeot FEEDVOLUME_DECLARE(U, 8, NE) 872a1ad637SFrançois Tigeot FEEDVOLUME_DECLARE(U, 16, LE) 882a1ad637SFrançois Tigeot FEEDVOLUME_DECLARE(U, 24, LE) 892a1ad637SFrançois Tigeot FEEDVOLUME_DECLARE(U, 32, LE) 902a1ad637SFrançois Tigeot FEEDVOLUME_DECLARE(U, 16, BE) 912a1ad637SFrançois Tigeot FEEDVOLUME_DECLARE(U, 24, BE) 922a1ad637SFrançois Tigeot FEEDVOLUME_DECLARE(U, 32, BE) 932a1ad637SFrançois Tigeot #endif 942a1ad637SFrançois Tigeot 952a1ad637SFrançois Tigeot struct feed_volume_info { 962a1ad637SFrançois Tigeot uint32_t bps, channels; 972a1ad637SFrançois Tigeot feed_volume_t apply; 982a1ad637SFrançois Tigeot int volume_class; 992a1ad637SFrançois Tigeot int state; 1002a1ad637SFrançois Tigeot int matrix[SND_CHN_MAX]; 1012a1ad637SFrançois Tigeot }; 1022a1ad637SFrançois Tigeot 1032a1ad637SFrançois Tigeot #define FEEDVOLUME_ENTRY(SIGN, BIT, ENDIAN) \ 1042a1ad637SFrançois Tigeot { \ 1052a1ad637SFrançois Tigeot AFMT_##SIGN##BIT##_##ENDIAN, \ 1062a1ad637SFrançois Tigeot feed_volume_##SIGN##BIT##ENDIAN \ 1072a1ad637SFrançois Tigeot } 1082a1ad637SFrançois Tigeot 1092a1ad637SFrançois Tigeot static const struct { 1102a1ad637SFrançois Tigeot uint32_t format; 1112a1ad637SFrançois Tigeot feed_volume_t apply; 1122a1ad637SFrançois Tigeot } feed_volume_info_tab[] = { 1132a1ad637SFrançois Tigeot #if BYTE_ORDER == LITTLE_ENDIAN || defined(SND_FEEDER_MULTIFORMAT) 1142a1ad637SFrançois Tigeot FEEDVOLUME_ENTRY(S, 16, LE), 1152a1ad637SFrançois Tigeot FEEDVOLUME_ENTRY(S, 32, LE), 1162a1ad637SFrançois Tigeot #endif 1172a1ad637SFrançois Tigeot #if BYTE_ORDER == BIG_ENDIAN || defined(SND_FEEDER_MULTIFORMAT) 1182a1ad637SFrançois Tigeot FEEDVOLUME_ENTRY(S, 16, BE), 1192a1ad637SFrançois Tigeot FEEDVOLUME_ENTRY(S, 32, BE), 1202a1ad637SFrançois Tigeot #endif 1212a1ad637SFrançois Tigeot #ifdef SND_FEEDER_MULTIFORMAT 1222a1ad637SFrançois Tigeot FEEDVOLUME_ENTRY(S, 8, NE), 1232a1ad637SFrançois Tigeot FEEDVOLUME_ENTRY(S, 24, LE), 1242a1ad637SFrançois Tigeot FEEDVOLUME_ENTRY(S, 24, BE), 1252a1ad637SFrançois Tigeot FEEDVOLUME_ENTRY(U, 8, NE), 1262a1ad637SFrançois Tigeot FEEDVOLUME_ENTRY(U, 16, LE), 1272a1ad637SFrançois Tigeot FEEDVOLUME_ENTRY(U, 24, LE), 1282a1ad637SFrançois Tigeot FEEDVOLUME_ENTRY(U, 32, LE), 1292a1ad637SFrançois Tigeot FEEDVOLUME_ENTRY(U, 16, BE), 1302a1ad637SFrançois Tigeot FEEDVOLUME_ENTRY(U, 24, BE), 1312a1ad637SFrançois Tigeot FEEDVOLUME_ENTRY(U, 32, BE) 1322a1ad637SFrançois Tigeot #endif 1332a1ad637SFrançois Tigeot }; 1342a1ad637SFrançois Tigeot 1352a1ad637SFrançois Tigeot #define FEEDVOLUME_TAB_SIZE ((int32_t) \ 1362a1ad637SFrançois Tigeot (sizeof(feed_volume_info_tab) / \ 1372a1ad637SFrançois Tigeot sizeof(feed_volume_info_tab[0]))) 138558a398bSSimon Schubert 139558a398bSSimon Schubert static int 1402a1ad637SFrançois Tigeot feed_volume_init(struct pcm_feeder *f) 1412a1ad637SFrançois Tigeot { 1422a1ad637SFrançois Tigeot struct feed_volume_info *info; 1432a1ad637SFrançois Tigeot struct pcmchan_matrix *m; 1442a1ad637SFrançois Tigeot uint32_t i; 1452a1ad637SFrançois Tigeot int ret; 1462a1ad637SFrançois Tigeot 1472a1ad637SFrançois Tigeot if (f->desc->in != f->desc->out || 1482a1ad637SFrançois Tigeot AFMT_CHANNEL(f->desc->in) > SND_CHN_MAX) 1492a1ad637SFrançois Tigeot return (EINVAL); 1502a1ad637SFrançois Tigeot 1512a1ad637SFrançois Tigeot for (i = 0; i < FEEDVOLUME_TAB_SIZE; i++) { 1522a1ad637SFrançois Tigeot if (AFMT_ENCODING(f->desc->in) == 1532a1ad637SFrançois Tigeot feed_volume_info_tab[i].format) { 154*67931cc4SFrançois Tigeot info = kmalloc(sizeof(*info), M_DEVBUF, 1552a1ad637SFrançois Tigeot M_NOWAIT | M_ZERO); 1562a1ad637SFrançois Tigeot if (info == NULL) 1572a1ad637SFrançois Tigeot return (ENOMEM); 1582a1ad637SFrançois Tigeot 1592a1ad637SFrançois Tigeot info->bps = AFMT_BPS(f->desc->in); 1602a1ad637SFrançois Tigeot info->channels = AFMT_CHANNEL(f->desc->in); 1612a1ad637SFrançois Tigeot info->apply = feed_volume_info_tab[i].apply; 1622a1ad637SFrançois Tigeot info->volume_class = SND_VOL_C_PCM; 1632a1ad637SFrançois Tigeot info->state = FEEDVOLUME_ENABLE; 1642a1ad637SFrançois Tigeot 1652a1ad637SFrançois Tigeot f->data = info; 1662a1ad637SFrançois Tigeot m = feeder_matrix_default_channel_map(info->channels); 1672a1ad637SFrançois Tigeot if (m == NULL) { 168*67931cc4SFrançois Tigeot kfree(info, M_DEVBUF); 1692a1ad637SFrançois Tigeot return (EINVAL); 1702a1ad637SFrançois Tigeot } 1712a1ad637SFrançois Tigeot 1722a1ad637SFrançois Tigeot ret = feeder_volume_apply_matrix(f, m); 1732a1ad637SFrançois Tigeot if (ret != 0) 174*67931cc4SFrançois Tigeot kfree(info, M_DEVBUF); 1752a1ad637SFrançois Tigeot 1762a1ad637SFrançois Tigeot return (ret); 1772a1ad637SFrançois Tigeot } 1782a1ad637SFrançois Tigeot } 1792a1ad637SFrançois Tigeot 1802a1ad637SFrançois Tigeot return (EINVAL); 1812a1ad637SFrançois Tigeot } 1822a1ad637SFrançois Tigeot 1832a1ad637SFrançois Tigeot static int 1842a1ad637SFrançois Tigeot feed_volume_free(struct pcm_feeder *f) 1852a1ad637SFrançois Tigeot { 1862a1ad637SFrançois Tigeot struct feed_volume_info *info; 1872a1ad637SFrançois Tigeot 1882a1ad637SFrançois Tigeot info = f->data; 1892a1ad637SFrançois Tigeot if (info != NULL) 190*67931cc4SFrançois Tigeot kfree(info, M_DEVBUF); 1912a1ad637SFrançois Tigeot 1922a1ad637SFrançois Tigeot f->data = NULL; 1932a1ad637SFrançois Tigeot 1942a1ad637SFrançois Tigeot return (0); 1952a1ad637SFrançois Tigeot } 1962a1ad637SFrançois Tigeot 1972a1ad637SFrançois Tigeot static int 1982a1ad637SFrançois Tigeot feed_volume_set(struct pcm_feeder *f, int what, int value) 1992a1ad637SFrançois Tigeot { 2002a1ad637SFrançois Tigeot struct feed_volume_info *info; 2012a1ad637SFrançois Tigeot struct pcmchan_matrix *m; 2022a1ad637SFrançois Tigeot int ret; 2032a1ad637SFrançois Tigeot 2042a1ad637SFrançois Tigeot info = f->data; 2052a1ad637SFrançois Tigeot ret = 0; 2062a1ad637SFrançois Tigeot 2072a1ad637SFrançois Tigeot switch (what) { 2082a1ad637SFrançois Tigeot case FEEDVOLUME_CLASS: 2092a1ad637SFrançois Tigeot if (value < SND_VOL_C_BEGIN || value > SND_VOL_C_END) 2102a1ad637SFrançois Tigeot return (EINVAL); 2112a1ad637SFrançois Tigeot info->volume_class = value; 2122a1ad637SFrançois Tigeot break; 2132a1ad637SFrançois Tigeot case FEEDVOLUME_CHANNELS: 2142a1ad637SFrançois Tigeot if (value < SND_CHN_MIN || value > SND_CHN_MAX) 2152a1ad637SFrançois Tigeot return (EINVAL); 2162a1ad637SFrançois Tigeot m = feeder_matrix_default_channel_map(value); 2172a1ad637SFrançois Tigeot if (m == NULL) 2182a1ad637SFrançois Tigeot return (EINVAL); 2192a1ad637SFrançois Tigeot ret = feeder_volume_apply_matrix(f, m); 2202a1ad637SFrançois Tigeot break; 2212a1ad637SFrançois Tigeot case FEEDVOLUME_STATE: 2222a1ad637SFrançois Tigeot if (!(value == FEEDVOLUME_ENABLE || value == FEEDVOLUME_BYPASS)) 2232a1ad637SFrançois Tigeot return (EINVAL); 2242a1ad637SFrançois Tigeot info->state = value; 2252a1ad637SFrançois Tigeot break; 2262a1ad637SFrançois Tigeot default: 2272a1ad637SFrançois Tigeot return (EINVAL); 2282a1ad637SFrançois Tigeot break; 2292a1ad637SFrançois Tigeot } 2302a1ad637SFrançois Tigeot 2312a1ad637SFrançois Tigeot return (ret); 2322a1ad637SFrançois Tigeot } 2332a1ad637SFrançois Tigeot 2342a1ad637SFrançois Tigeot static int 2352a1ad637SFrançois Tigeot feed_volume_feed(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, 236558a398bSSimon Schubert uint32_t count, void *source) 237558a398bSSimon Schubert { 2382a1ad637SFrançois Tigeot struct feed_volume_info *info; 2392a1ad637SFrançois Tigeot uint32_t j, align; 2402a1ad637SFrançois Tigeot int i, *vol, *matrix; 2412a1ad637SFrançois Tigeot uint8_t *dst; 242558a398bSSimon Schubert 2432a1ad637SFrançois Tigeot /* 2442a1ad637SFrançois Tigeot * Fetch filter data operation. 2452a1ad637SFrançois Tigeot */ 2462a1ad637SFrançois Tigeot info = f->data; 2472a1ad637SFrançois Tigeot 2482a1ad637SFrançois Tigeot if (info->state == FEEDVOLUME_BYPASS) 2492a1ad637SFrançois Tigeot return (FEEDER_FEED(f->source, c, b, count, source)); 2502a1ad637SFrançois Tigeot 2512a1ad637SFrançois Tigeot vol = c->volume[SND_VOL_C_VAL(info->volume_class)]; 2522a1ad637SFrançois Tigeot matrix = info->matrix; 2532a1ad637SFrançois Tigeot 2542a1ad637SFrançois Tigeot /* 2552a1ad637SFrançois Tigeot * First, let see if we really need to apply gain at all. 2562a1ad637SFrançois Tigeot */ 2572a1ad637SFrançois Tigeot j = 0; 2582a1ad637SFrançois Tigeot i = info->channels; 2592a1ad637SFrançois Tigeot do { 2602a1ad637SFrançois Tigeot if (vol[matrix[--i]] != SND_VOL_FLAT) { 2612a1ad637SFrançois Tigeot j = 1; 2622a1ad637SFrançois Tigeot break; 263558a398bSSimon Schubert } 2642a1ad637SFrançois Tigeot } while (i != 0); 2652a1ad637SFrançois Tigeot 2662a1ad637SFrançois Tigeot /* Nope, just bypass entirely. */ 2672a1ad637SFrançois Tigeot if (j == 0) 2682a1ad637SFrançois Tigeot return (FEEDER_FEED(f->source, c, b, count, source)); 2692a1ad637SFrançois Tigeot 2702a1ad637SFrançois Tigeot dst = b; 2712a1ad637SFrançois Tigeot align = info->bps * info->channels; 2722a1ad637SFrançois Tigeot 2732a1ad637SFrançois Tigeot do { 2742a1ad637SFrançois Tigeot if (count < align) 2752a1ad637SFrançois Tigeot break; 2762a1ad637SFrançois Tigeot 2772a1ad637SFrançois Tigeot j = SND_FXDIV(FEEDER_FEED(f->source, c, dst, count, source), 2782a1ad637SFrançois Tigeot align); 2792a1ad637SFrançois Tigeot if (j == 0) 2802a1ad637SFrançois Tigeot break; 2812a1ad637SFrançois Tigeot 2822a1ad637SFrançois Tigeot info->apply(vol, matrix, info->channels, dst, j); 2832a1ad637SFrançois Tigeot 2842a1ad637SFrançois Tigeot j *= align; 2852a1ad637SFrançois Tigeot dst += j; 2862a1ad637SFrançois Tigeot count -= j; 2872a1ad637SFrançois Tigeot 2882a1ad637SFrançois Tigeot } while (count != 0); 2892a1ad637SFrançois Tigeot 2902a1ad637SFrançois Tigeot return (dst - b); 291558a398bSSimon Schubert } 292558a398bSSimon Schubert 2932a1ad637SFrançois Tigeot static struct pcm_feederdesc feeder_volume_desc[] = { 2942a1ad637SFrançois Tigeot { FEEDER_VOLUME, 0, 0, 0, 0 }, 2952a1ad637SFrançois Tigeot { 0, 0, 0, 0, 0 } 296558a398bSSimon Schubert }; 2972a1ad637SFrançois Tigeot 2982a1ad637SFrançois Tigeot static kobj_method_t feeder_volume_methods[] = { 2992a1ad637SFrançois Tigeot KOBJMETHOD(feeder_init, feed_volume_init), 3002a1ad637SFrançois Tigeot KOBJMETHOD(feeder_free, feed_volume_free), 3012a1ad637SFrançois Tigeot KOBJMETHOD(feeder_set, feed_volume_set), 3022a1ad637SFrançois Tigeot KOBJMETHOD(feeder_feed, feed_volume_feed), 3037774cda2SSascha Wildner KOBJMETHOD_END 304558a398bSSimon Schubert }; 3052a1ad637SFrançois Tigeot 3062a1ad637SFrançois Tigeot FEEDER_DECLARE(feeder_volume, NULL); 3072a1ad637SFrançois Tigeot 3082a1ad637SFrançois Tigeot /* Extern */ 3092a1ad637SFrançois Tigeot 3102a1ad637SFrançois Tigeot /* 3112a1ad637SFrançois Tigeot * feeder_volume_apply_matrix(): For given matrix map, apply its configuration 3122a1ad637SFrançois Tigeot * to feeder_volume matrix structure. There are 3132a1ad637SFrançois Tigeot * possibilites that feeder_volume be inserted 3142a1ad637SFrançois Tigeot * before or after feeder_matrix, which in this 3152a1ad637SFrançois Tigeot * case feeder_volume must be in a good terms 3162a1ad637SFrançois Tigeot * with _current_ matrix. 3172a1ad637SFrançois Tigeot */ 3182a1ad637SFrançois Tigeot int 3192a1ad637SFrançois Tigeot feeder_volume_apply_matrix(struct pcm_feeder *f, struct pcmchan_matrix *m) 3202a1ad637SFrançois Tigeot { 3212a1ad637SFrançois Tigeot struct feed_volume_info *info; 3222a1ad637SFrançois Tigeot uint32_t i; 3232a1ad637SFrançois Tigeot 3242a1ad637SFrançois Tigeot if (f == NULL || f->desc == NULL || f->desc->type != FEEDER_VOLUME || 3252a1ad637SFrançois Tigeot f->data == NULL || m == NULL || m->channels < SND_CHN_MIN || 3262a1ad637SFrançois Tigeot m->channels > SND_CHN_MAX) 3272a1ad637SFrançois Tigeot return (EINVAL); 3282a1ad637SFrançois Tigeot 3292a1ad637SFrançois Tigeot info = f->data; 3302a1ad637SFrançois Tigeot 3312a1ad637SFrançois Tigeot for (i = 0; i < (sizeof(info->matrix) / sizeof(info->matrix[0])); i++) { 3322a1ad637SFrançois Tigeot if (i < m->channels) 3332a1ad637SFrançois Tigeot info->matrix[i] = m->map[i].type; 3342a1ad637SFrançois Tigeot else 3352a1ad637SFrançois Tigeot info->matrix[i] = SND_CHN_T_FL; 3362a1ad637SFrançois Tigeot } 3372a1ad637SFrançois Tigeot 3382a1ad637SFrançois Tigeot info->channels = m->channels; 3392a1ad637SFrançois Tigeot 3402a1ad637SFrançois Tigeot return (0); 3412a1ad637SFrançois Tigeot } 342