139230Sgibbs/* $FreeBSD: stable/10/sys/dev/sound/usb/uaudio_pcm.c 359890 2020-04-13 16:34:21Z hselasky $ */
282168Sken
339230Sgibbs/*-
439230Sgibbs * Copyright (c) 2000-2002 Hiroyuki Aizu <aizu@navi.org>
539230Sgibbs * Copyright (c) 2006 Hans Petter Selasky
639230Sgibbs *
739230Sgibbs * Redistribution and use in source and binary forms, with or without
839230Sgibbs * modification, are permitted provided that the following conditions
939230Sgibbs * are met:
1039230Sgibbs * 1. Redistributions of source code must retain the above copyright
1139230Sgibbs *    notice, this list of conditions and the following disclaimer.
1239230Sgibbs * 2. Redistributions in binary form must reproduce the above copyright
1339230Sgibbs *    notice, this list of conditions and the following disclaimer in the
1439230Sgibbs *    documentation and/or other materials provided with the distribution.
1539230Sgibbs *
1639230Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1739230Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1839230Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1939230Sgibbs * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2039230Sgibbs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2139230Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2239230Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2339230Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2439230Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2539230Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2639230Sgibbs * SUCH DAMAGE.
2756561Scharnier */
2856561Scharnier
2939230Sgibbs
3039230Sgibbs#ifdef HAVE_KERNEL_OPTION_HEADERS
3139230Sgibbs#include "opt_snd.h"
3239230Sgibbs#endif
3339230Sgibbs
341553Srgrimes#include <dev/sound/pcm/sound.h>
351553Srgrimes#include <dev/sound/chip.h>
361553Srgrimes#include <dev/sound/usb/uaudio.h>
371553Srgrimes
381553Srgrimes#include "mixer_if.h"
391553Srgrimes
401553Srgrimes/************************************************************/
411553Srgrimesstatic void *
421553Srgrimesua_chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
431553Srgrimes{
441553Srgrimes	return (uaudio_chan_init(devinfo, b, c, dir));
451553Srgrimes}
461553Srgrimes
471553Srgrimesstatic int
481553Srgrimesua_chan_free(kobj_t obj, void *data)
491553Srgrimes{
501553Srgrimes	return (uaudio_chan_free(data));
511553Srgrimes}
521553Srgrimes
531553Srgrimesstatic int
541553Srgrimesua_chan_setformat(kobj_t obj, void *data, uint32_t format)
551553Srgrimes{
561553Srgrimes	/*
571553Srgrimes	 * At this point, no need to query as we
581553Srgrimes	 * shouldn't select an unsorted format
591553Srgrimes	 */
601553Srgrimes	return (uaudio_chan_set_param_format(data, format));
611553Srgrimes}
6239230Sgibbs
6339230Sgibbsstatic uint32_t
6439230Sgibbsua_chan_setspeed(kobj_t obj, void *data, uint32_t speed)
6539230Sgibbs{
6639230Sgibbs	return (uaudio_chan_set_param_speed(data, speed));
6739230Sgibbs}
6839230Sgibbs
6939230Sgibbsstatic uint32_t
7039230Sgibbsua_chan_setblocksize(kobj_t obj, void *data, uint32_t blocksize)
7139230Sgibbs{
7239230Sgibbs	return (uaudio_chan_set_param_blocksize(data, blocksize));
7339230Sgibbs}
7439230Sgibbs
7539230Sgibbsstatic int
7639230Sgibbsua_chan_setfragments(kobj_t obj, void *data, uint32_t blocksize, uint32_t blockcount)
7739230Sgibbs{
7839230Sgibbs	return (uaudio_chan_set_param_fragments(data, blocksize, blockcount));
7939230Sgibbs}
8039230Sgibbs
8139230Sgibbsstatic int
8239230Sgibbsua_chan_trigger(kobj_t obj, void *data, int go)
8339230Sgibbs{
8439230Sgibbs	if (PCMTRIG_COMMON(go)) {
8539230Sgibbs		if (go == PCMTRIG_START) {
8639230Sgibbs			uaudio_chan_start(data);
8739230Sgibbs		} else {
8839230Sgibbs			uaudio_chan_stop(data);
8939230Sgibbs		}
9039230Sgibbs	}
9139230Sgibbs	return (0);
9239230Sgibbs}
9339230Sgibbs
9439230Sgibbsstatic uint32_t
9539230Sgibbsua_chan_getptr(kobj_t obj, void *data)
9639230Sgibbs{
971553Srgrimes	return (uaudio_chan_getptr(data));
981553Srgrimes}
991553Srgrimes
10039230Sgibbsstatic struct pcmchan_caps *
101111008Sphkua_chan_getcaps(kobj_t obj, void *data)
10281134Stmm{
1031553Srgrimes	return (uaudio_chan_getcaps(data));
104228661Sdim}
105228661Sdim
1061553Srgrimesstatic struct pcmchan_matrix *
1071553Srgrimesua_chan_getmatrix(kobj_t obj, void *data, uint32_t format)
108228661Sdim{
1091553Srgrimes	return (uaudio_chan_getmatrix(data, format));
110228661Sdim}
111228661Sdim
112102067Sbdestatic kobj_method_t ua_chan_methods[] = {
113293696Sasomers	KOBJMETHOD(channel_init, ua_chan_init),
1141553Srgrimes	KOBJMETHOD(channel_free, ua_chan_free),
1151553Srgrimes	KOBJMETHOD(channel_setformat, ua_chan_setformat),
1161553Srgrimes	KOBJMETHOD(channel_setspeed, ua_chan_setspeed),
117175562Skeramida	KOBJMETHOD(channel_setblocksize, ua_chan_setblocksize),
1181553Srgrimes	KOBJMETHOD(channel_setfragments, ua_chan_setfragments),
1191553Srgrimes	KOBJMETHOD(channel_trigger, ua_chan_trigger),
120296995Sasomers	KOBJMETHOD(channel_getptr, ua_chan_getptr),
12139230Sgibbs	KOBJMETHOD(channel_getcaps, ua_chan_getcaps),
122296995Sasomers	KOBJMETHOD(channel_getmatrix, ua_chan_getmatrix),
123296995Sasomers	KOBJMETHOD_END
12439230Sgibbs};
125296995Sasomers
126296995SasomersCHANNEL_DECLARE(ua_chan);
127181881Sjhb
128296995Sasomers/************************************************************/
129296995Sasomersstatic int
130181881Sjhbua_mixer_init(struct snd_mixer *m)
131296995Sasomers{
132296995Sasomers	return (uaudio_mixer_init_sub(mix_getdevinfo(m), m));
1331553Srgrimes}
1341553Srgrimes
135175562Skeramidastatic int
136175562Skeramidaua_mixer_set(struct snd_mixer *m, unsigned type, unsigned left, unsigned right)
137296995Sasomers{
138296995Sasomers	struct mtx *mtx = mixer_get_lock(m);
139296995Sasomers	uint8_t do_unlock;
140296995Sasomers
141296995Sasomers	if (mtx_owned(mtx)) {
142296995Sasomers		do_unlock = 0;
143296995Sasomers	} else {
144296995Sasomers		do_unlock = 1;
145296995Sasomers		mtx_lock(mtx);
146296995Sasomers	}
147296995Sasomers	uaudio_mixer_set(mix_getdevinfo(m), m, type, left, right);
1481553Srgrimes	if (do_unlock) {
14939230Sgibbs		mtx_unlock(mtx);
15039230Sgibbs	}
15183965Sguido	return (left | (right << 8));
152175562Skeramida}
153293696Sasomers
154293696Sasomersstatic uint32_t
155175562Skeramidaua_mixer_setrecsrc(struct snd_mixer *m, uint32_t src)
15683965Sguido{
15782168Sken	struct mtx *mtx = mixer_get_lock(m);
15839230Sgibbs	int retval;
15982168Sken	uint8_t do_unlock;
16082168Sken
1611553Srgrimes	if (mtx_owned(mtx)) {
16239230Sgibbs		do_unlock = 0;
16339230Sgibbs	} else {
16439230Sgibbs		do_unlock = 1;
16539230Sgibbs		mtx_lock(mtx);
16639230Sgibbs	}
16739230Sgibbs	retval = uaudio_mixer_setrecsrc(mix_getdevinfo(m), m, src);
16839230Sgibbs	if (do_unlock) {
16939230Sgibbs		mtx_unlock(mtx);
17039230Sgibbs	}
171157800Smaxim	return (retval);
17256561Scharnier}
17356561Scharnier
17439230Sgibbsstatic int
1751553Srgrimesua_mixer_uninit(struct snd_mixer *m)
1761553Srgrimes{
17739230Sgibbs	return (uaudio_mixer_uninit_sub(mix_getdevinfo(m), m));
1781553Srgrimes}
179157802Smaxim
18039230Sgibbsstatic kobj_method_t ua_mixer_methods[] = {
18139230Sgibbs	KOBJMETHOD(mixer_init, ua_mixer_init),
18239230Sgibbs	KOBJMETHOD(mixer_uninit, ua_mixer_uninit),
18339230Sgibbs	KOBJMETHOD(mixer_set, ua_mixer_set),
184293696Sasomers	KOBJMETHOD(mixer_setrecsrc, ua_mixer_setrecsrc),
18539230Sgibbs	KOBJMETHOD_END
186157801Smaxim};
18781134Stmm
18839498SkenMIXER_DECLARE(ua_mixer);
18939230Sgibbs/************************************************************/
19039498Sken
19139498Sken
19239230Sgibbsstatic int
19339230Sgibbsua_probe(device_t dev)
194208389Ssbruno{
19582168Sken	struct sndcard_func *func;
1961553Srgrimes
19739230Sgibbs	/* the parent device has already been probed */
19839230Sgibbs
19939230Sgibbs	func = device_get_ivars(dev);
200157800Smaxim
20139230Sgibbs	if ((func == NULL) ||
20239230Sgibbs	    (func->func != SCF_PCM)) {
20339230Sgibbs		return (ENXIO);
20439230Sgibbs	}
20539230Sgibbs	device_set_desc(dev, "USB audio");
20639230Sgibbs
20739230Sgibbs	return (BUS_PROBE_DEFAULT);
20839230Sgibbs}
20939230Sgibbs
21039230Sgibbsstatic int
21139230Sgibbsua_attach(device_t dev)
21239230Sgibbs{
21339230Sgibbs	return (uaudio_attach_sub(dev, &ua_mixer_class, &ua_chan_class));
21439230Sgibbs}
21539230Sgibbs
21639230Sgibbsstatic int
21739387Skenua_detach(device_t dev)
21839387Sken{
21939387Sken	return (uaudio_detach_sub(dev));
22039371Sdillon}
22139371Sdillon
22239371Sdillon/************************************************************/
22339230Sgibbs
22439230Sgibbsstatic device_method_t ua_pcm_methods[] = {
22539230Sgibbs	/* Device interface */
22639230Sgibbs	DEVMETHOD(device_probe, ua_probe),
22739230Sgibbs	DEVMETHOD(device_attach, ua_attach),
22839230Sgibbs	DEVMETHOD(device_detach, ua_detach),
22939230Sgibbs
23056483Scharnier	DEVMETHOD_END
23139230Sgibbs};
23239230Sgibbs
23339230Sgibbsstatic driver_t ua_pcm_driver = {
23439230Sgibbs	"pcm",
23539230Sgibbs	ua_pcm_methods,
23639230Sgibbs	PCM_SOFTC_SIZE,
23739230Sgibbs};
23839230Sgibbs
23939230SgibbsDRIVER_MODULE(ua_pcm, uaudio, ua_pcm_driver, pcm_devclass, 0, 0);
24039230SgibbsMODULE_DEPEND(ua_pcm, uaudio, 1, 1, 1);
241157801SmaximMODULE_DEPEND(ua_pcm, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
24281134StmmMODULE_VERSION(ua_pcm, 1);
24339230Sgibbs