13a3f90c6SAndrew Thompson 23a3f90c6SAndrew Thompson /*- 34d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 4718cf2ccSPedro F. Giffuni * 53a3f90c6SAndrew Thompson * Copyright (c) 2000-2002 Hiroyuki Aizu <aizu@navi.org> 63a3f90c6SAndrew Thompson * Copyright (c) 2006 Hans Petter Selasky 73a3f90c6SAndrew Thompson * 83a3f90c6SAndrew Thompson * Redistribution and use in source and binary forms, with or without 93a3f90c6SAndrew Thompson * modification, are permitted provided that the following conditions 103a3f90c6SAndrew Thompson * are met: 113a3f90c6SAndrew Thompson * 1. Redistributions of source code must retain the above copyright 123a3f90c6SAndrew Thompson * notice, this list of conditions and the following disclaimer. 133a3f90c6SAndrew Thompson * 2. Redistributions in binary form must reproduce the above copyright 143a3f90c6SAndrew Thompson * notice, this list of conditions and the following disclaimer in the 153a3f90c6SAndrew Thompson * documentation and/or other materials provided with the distribution. 163a3f90c6SAndrew Thompson * 173a3f90c6SAndrew Thompson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 183a3f90c6SAndrew Thompson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 193a3f90c6SAndrew Thompson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 203a3f90c6SAndrew Thompson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 213a3f90c6SAndrew Thompson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 223a3f90c6SAndrew Thompson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 233a3f90c6SAndrew Thompson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 243a3f90c6SAndrew Thompson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 253a3f90c6SAndrew Thompson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 263a3f90c6SAndrew Thompson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 273a3f90c6SAndrew Thompson * SUCH DAMAGE. 283a3f90c6SAndrew Thompson */ 293a3f90c6SAndrew Thompson 3090da2b28SAriff Abdullah #ifdef HAVE_KERNEL_OPTION_HEADERS 3190da2b28SAriff Abdullah #include "opt_snd.h" 3290da2b28SAriff Abdullah #endif 3390da2b28SAriff Abdullah 343a3f90c6SAndrew Thompson #include <dev/sound/pcm/sound.h> 353a3f90c6SAndrew Thompson #include <dev/sound/usb/uaudio.h> 363a3f90c6SAndrew Thompson 373a3f90c6SAndrew Thompson #include "mixer_if.h" 383a3f90c6SAndrew Thompson 393a3f90c6SAndrew Thompson /************************************************************/ 403a3f90c6SAndrew Thompson static void * 413a3f90c6SAndrew Thompson ua_chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) 423a3f90c6SAndrew Thompson { 433a3f90c6SAndrew Thompson return (uaudio_chan_init(devinfo, b, c, dir)); 443a3f90c6SAndrew Thompson } 453a3f90c6SAndrew Thompson 463a3f90c6SAndrew Thompson static int 473a3f90c6SAndrew Thompson ua_chan_free(kobj_t obj, void *data) 483a3f90c6SAndrew Thompson { 493a3f90c6SAndrew Thompson return (uaudio_chan_free(data)); 503a3f90c6SAndrew Thompson } 513a3f90c6SAndrew Thompson 523a3f90c6SAndrew Thompson static int 533a3f90c6SAndrew Thompson ua_chan_setformat(kobj_t obj, void *data, uint32_t format) 543a3f90c6SAndrew Thompson { 553a3f90c6SAndrew Thompson /* 563a3f90c6SAndrew Thompson * At this point, no need to query as we 573a3f90c6SAndrew Thompson * shouldn't select an unsorted format 583a3f90c6SAndrew Thompson */ 593a3f90c6SAndrew Thompson return (uaudio_chan_set_param_format(data, format)); 603a3f90c6SAndrew Thompson } 613a3f90c6SAndrew Thompson 6290da2b28SAriff Abdullah static uint32_t 633a3f90c6SAndrew Thompson ua_chan_setspeed(kobj_t obj, void *data, uint32_t speed) 643a3f90c6SAndrew Thompson { 653a3f90c6SAndrew Thompson return (uaudio_chan_set_param_speed(data, speed)); 663a3f90c6SAndrew Thompson } 673a3f90c6SAndrew Thompson 6890da2b28SAriff Abdullah static uint32_t 693a3f90c6SAndrew Thompson ua_chan_setblocksize(kobj_t obj, void *data, uint32_t blocksize) 703a3f90c6SAndrew Thompson { 713a3f90c6SAndrew Thompson return (uaudio_chan_set_param_blocksize(data, blocksize)); 723a3f90c6SAndrew Thompson } 733a3f90c6SAndrew Thompson 743a3f90c6SAndrew Thompson static int 753a3f90c6SAndrew Thompson ua_chan_setfragments(kobj_t obj, void *data, uint32_t blocksize, uint32_t blockcount) 763a3f90c6SAndrew Thompson { 773a3f90c6SAndrew Thompson return (uaudio_chan_set_param_fragments(data, blocksize, blockcount)); 783a3f90c6SAndrew Thompson } 793a3f90c6SAndrew Thompson 803a3f90c6SAndrew Thompson static int 813a3f90c6SAndrew Thompson ua_chan_trigger(kobj_t obj, void *data, int go) 823a3f90c6SAndrew Thompson { 8385bad582SHans Petter Selasky if (PCMTRIG_COMMON(go)) { 843a3f90c6SAndrew Thompson if (go == PCMTRIG_START) { 8585bad582SHans Petter Selasky uaudio_chan_start(data); 863a3f90c6SAndrew Thompson } else { 8785bad582SHans Petter Selasky uaudio_chan_stop(data); 883a3f90c6SAndrew Thompson } 893a3f90c6SAndrew Thompson } 9085bad582SHans Petter Selasky return (0); 9185bad582SHans Petter Selasky } 923a3f90c6SAndrew Thompson 9390da2b28SAriff Abdullah static uint32_t 943a3f90c6SAndrew Thompson ua_chan_getptr(kobj_t obj, void *data) 953a3f90c6SAndrew Thompson { 963a3f90c6SAndrew Thompson return (uaudio_chan_getptr(data)); 973a3f90c6SAndrew Thompson } 983a3f90c6SAndrew Thompson 993a3f90c6SAndrew Thompson static struct pcmchan_caps * 1003a3f90c6SAndrew Thompson ua_chan_getcaps(kobj_t obj, void *data) 1013a3f90c6SAndrew Thompson { 1023a3f90c6SAndrew Thompson return (uaudio_chan_getcaps(data)); 1033a3f90c6SAndrew Thompson } 1043a3f90c6SAndrew Thompson 10590da2b28SAriff Abdullah static struct pcmchan_matrix * 10690da2b28SAriff Abdullah ua_chan_getmatrix(kobj_t obj, void *data, uint32_t format) 10790da2b28SAriff Abdullah { 10890da2b28SAriff Abdullah return (uaudio_chan_getmatrix(data, format)); 10990da2b28SAriff Abdullah } 11090da2b28SAriff Abdullah 1113a3f90c6SAndrew Thompson static kobj_method_t ua_chan_methods[] = { 1123a3f90c6SAndrew Thompson KOBJMETHOD(channel_init, ua_chan_init), 1133a3f90c6SAndrew Thompson KOBJMETHOD(channel_free, ua_chan_free), 1143a3f90c6SAndrew Thompson KOBJMETHOD(channel_setformat, ua_chan_setformat), 1153a3f90c6SAndrew Thompson KOBJMETHOD(channel_setspeed, ua_chan_setspeed), 1163a3f90c6SAndrew Thompson KOBJMETHOD(channel_setblocksize, ua_chan_setblocksize), 1173a3f90c6SAndrew Thompson KOBJMETHOD(channel_setfragments, ua_chan_setfragments), 1183a3f90c6SAndrew Thompson KOBJMETHOD(channel_trigger, ua_chan_trigger), 1193a3f90c6SAndrew Thompson KOBJMETHOD(channel_getptr, ua_chan_getptr), 1203a3f90c6SAndrew Thompson KOBJMETHOD(channel_getcaps, ua_chan_getcaps), 12190da2b28SAriff Abdullah KOBJMETHOD(channel_getmatrix, ua_chan_getmatrix), 12290da2b28SAriff Abdullah KOBJMETHOD_END 1233a3f90c6SAndrew Thompson }; 1243a3f90c6SAndrew Thompson 1253a3f90c6SAndrew Thompson CHANNEL_DECLARE(ua_chan); 1263a3f90c6SAndrew Thompson 1273a3f90c6SAndrew Thompson /************************************************************/ 1283a3f90c6SAndrew Thompson static int 1293a3f90c6SAndrew Thompson ua_mixer_init(struct snd_mixer *m) 1303a3f90c6SAndrew Thompson { 1313a3f90c6SAndrew Thompson return (uaudio_mixer_init_sub(mix_getdevinfo(m), m)); 1323a3f90c6SAndrew Thompson } 1333a3f90c6SAndrew Thompson 1343a3f90c6SAndrew Thompson static int 1353a3f90c6SAndrew Thompson ua_mixer_set(struct snd_mixer *m, unsigned type, unsigned left, unsigned right) 1363a3f90c6SAndrew Thompson { 1373a3f90c6SAndrew Thompson struct mtx *mtx = mixer_get_lock(m); 1383a3f90c6SAndrew Thompson uint8_t do_unlock; 1393a3f90c6SAndrew Thompson 1403a3f90c6SAndrew Thompson if (mtx_owned(mtx)) { 1413a3f90c6SAndrew Thompson do_unlock = 0; 1423a3f90c6SAndrew Thompson } else { 1433a3f90c6SAndrew Thompson do_unlock = 1; 1443a3f90c6SAndrew Thompson mtx_lock(mtx); 1453a3f90c6SAndrew Thompson } 14686c9b3f3SHans Petter Selasky uaudio_mixer_set(mix_getdevinfo(m), m, type, left, right); 1473a3f90c6SAndrew Thompson if (do_unlock) { 1483a3f90c6SAndrew Thompson mtx_unlock(mtx); 1493a3f90c6SAndrew Thompson } 1503a3f90c6SAndrew Thompson return (left | (right << 8)); 1513a3f90c6SAndrew Thompson } 1523a3f90c6SAndrew Thompson 15390da2b28SAriff Abdullah static uint32_t 1543a3f90c6SAndrew Thompson ua_mixer_setrecsrc(struct snd_mixer *m, uint32_t src) 1553a3f90c6SAndrew Thompson { 1563a3f90c6SAndrew Thompson struct mtx *mtx = mixer_get_lock(m); 1573a3f90c6SAndrew Thompson int retval; 1583a3f90c6SAndrew Thompson uint8_t do_unlock; 1593a3f90c6SAndrew Thompson 1603a3f90c6SAndrew Thompson if (mtx_owned(mtx)) { 1613a3f90c6SAndrew Thompson do_unlock = 0; 1623a3f90c6SAndrew Thompson } else { 1633a3f90c6SAndrew Thompson do_unlock = 1; 1643a3f90c6SAndrew Thompson mtx_lock(mtx); 1653a3f90c6SAndrew Thompson } 16686c9b3f3SHans Petter Selasky retval = uaudio_mixer_setrecsrc(mix_getdevinfo(m), m, src); 1673a3f90c6SAndrew Thompson if (do_unlock) { 1683a3f90c6SAndrew Thompson mtx_unlock(mtx); 1693a3f90c6SAndrew Thompson } 1703a3f90c6SAndrew Thompson return (retval); 1713a3f90c6SAndrew Thompson } 1723a3f90c6SAndrew Thompson 1733a3f90c6SAndrew Thompson static int 1743a3f90c6SAndrew Thompson ua_mixer_uninit(struct snd_mixer *m) 1753a3f90c6SAndrew Thompson { 17686c9b3f3SHans Petter Selasky return (uaudio_mixer_uninit_sub(mix_getdevinfo(m), m)); 1773a3f90c6SAndrew Thompson } 1783a3f90c6SAndrew Thompson 1793a3f90c6SAndrew Thompson static kobj_method_t ua_mixer_methods[] = { 1803a3f90c6SAndrew Thompson KOBJMETHOD(mixer_init, ua_mixer_init), 1813a3f90c6SAndrew Thompson KOBJMETHOD(mixer_uninit, ua_mixer_uninit), 1823a3f90c6SAndrew Thompson KOBJMETHOD(mixer_set, ua_mixer_set), 1833a3f90c6SAndrew Thompson KOBJMETHOD(mixer_setrecsrc, ua_mixer_setrecsrc), 18490da2b28SAriff Abdullah KOBJMETHOD_END 1853a3f90c6SAndrew Thompson }; 1863a3f90c6SAndrew Thompson 1873a3f90c6SAndrew Thompson MIXER_DECLARE(ua_mixer); 1883a3f90c6SAndrew Thompson /************************************************************/ 1893a3f90c6SAndrew Thompson 1903a3f90c6SAndrew Thompson static int 1913a3f90c6SAndrew Thompson ua_probe(device_t dev) 1923a3f90c6SAndrew Thompson { 1933a3f90c6SAndrew Thompson struct sndcard_func *func; 1943a3f90c6SAndrew Thompson 1953a3f90c6SAndrew Thompson /* the parent device has already been probed */ 1963a3f90c6SAndrew Thompson 1973a3f90c6SAndrew Thompson func = device_get_ivars(dev); 1983a3f90c6SAndrew Thompson 1993a3f90c6SAndrew Thompson if ((func == NULL) || 2003a3f90c6SAndrew Thompson (func->func != SCF_PCM)) { 2013a3f90c6SAndrew Thompson return (ENXIO); 2023a3f90c6SAndrew Thompson } 2033a3f90c6SAndrew Thompson 2043a3f90c6SAndrew Thompson return (BUS_PROBE_DEFAULT); 2053a3f90c6SAndrew Thompson } 2063a3f90c6SAndrew Thompson 2073a3f90c6SAndrew Thompson static int 2083a3f90c6SAndrew Thompson ua_attach(device_t dev) 2093a3f90c6SAndrew Thompson { 2103a3f90c6SAndrew Thompson return (uaudio_attach_sub(dev, &ua_mixer_class, &ua_chan_class)); 2113a3f90c6SAndrew Thompson } 2123a3f90c6SAndrew Thompson 2133a3f90c6SAndrew Thompson static int 2143a3f90c6SAndrew Thompson ua_detach(device_t dev) 2153a3f90c6SAndrew Thompson { 2163a3f90c6SAndrew Thompson return (uaudio_detach_sub(dev)); 2173a3f90c6SAndrew Thompson } 2183a3f90c6SAndrew Thompson 2193a3f90c6SAndrew Thompson /************************************************************/ 2203a3f90c6SAndrew Thompson 2213a3f90c6SAndrew Thompson static device_method_t ua_pcm_methods[] = { 2223a3f90c6SAndrew Thompson /* Device interface */ 2233a3f90c6SAndrew Thompson DEVMETHOD(device_probe, ua_probe), 2243a3f90c6SAndrew Thompson DEVMETHOD(device_attach, ua_attach), 2253a3f90c6SAndrew Thompson DEVMETHOD(device_detach, ua_detach), 2263a3f90c6SAndrew Thompson 22761bfd867SSofian Brabez DEVMETHOD_END 2283a3f90c6SAndrew Thompson }; 2293a3f90c6SAndrew Thompson 2303a3f90c6SAndrew Thompson static driver_t ua_pcm_driver = { 2313a3f90c6SAndrew Thompson "pcm", 2323a3f90c6SAndrew Thompson ua_pcm_methods, 2333a3f90c6SAndrew Thompson PCM_SOFTC_SIZE, 2343a3f90c6SAndrew Thompson }; 2353a3f90c6SAndrew Thompson 2362287364eSJohn Baldwin DRIVER_MODULE(ua_pcm, uaudio, ua_pcm_driver, 0, 0); 237*06a43763SChristos Margiolis MODULE_DEPEND(ua_pcm, snd_uaudio, 1, 1, 1); 2383a3f90c6SAndrew Thompson MODULE_DEPEND(ua_pcm, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 2393a3f90c6SAndrew Thompson MODULE_VERSION(ua_pcm, 1); 240