xref: /freebsd/sys/dev/sound/usb/uaudio_pcm.c (revision 923e0040a59af8ac2271d3e673fef1c641d0cce7)
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