1184610Salfred/* $FreeBSD: stable/11/sys/dev/sound/usb/uaudio_pcm.c 359889 2020-04-13 16:33:45Z hselasky $ */
2184610Salfred
3184610Salfred/*-
4184610Salfred * Copyright (c) 2000-2002 Hiroyuki Aizu <aizu@navi.org>
5184610Salfred * Copyright (c) 2006 Hans Petter Selasky
6184610Salfred *
7184610Salfred * Redistribution and use in source and binary forms, with or without
8184610Salfred * modification, are permitted provided that the following conditions
9184610Salfred * are met:
10184610Salfred * 1. Redistributions of source code must retain the above copyright
11184610Salfred *    notice, this list of conditions and the following disclaimer.
12184610Salfred * 2. Redistributions in binary form must reproduce the above copyright
13184610Salfred *    notice, this list of conditions and the following disclaimer in the
14184610Salfred *    documentation and/or other materials provided with the distribution.
15184610Salfred *
16184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19184610Salfred * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26184610Salfred * SUCH DAMAGE.
27184610Salfred */
28184610Salfred
29184610Salfred
30193640Sariff#ifdef HAVE_KERNEL_OPTION_HEADERS
31193640Sariff#include "opt_snd.h"
32193640Sariff#endif
33193640Sariff
34184610Salfred#include <dev/sound/pcm/sound.h>
35184610Salfred#include <dev/sound/chip.h>
36188957Sthompsa#include <dev/sound/usb/uaudio.h>
37184610Salfred
38184610Salfred#include "mixer_if.h"
39184610Salfred
40184610Salfred/************************************************************/
41184610Salfredstatic void *
42184610Salfredua_chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
43184610Salfred{
44184610Salfred	return (uaudio_chan_init(devinfo, b, c, dir));
45184610Salfred}
46184610Salfred
47184610Salfredstatic int
48184610Salfredua_chan_free(kobj_t obj, void *data)
49184610Salfred{
50184610Salfred	return (uaudio_chan_free(data));
51184610Salfred}
52184610Salfred
53184610Salfredstatic int
54184610Salfredua_chan_setformat(kobj_t obj, void *data, uint32_t format)
55184610Salfred{
56184610Salfred	/*
57184610Salfred	 * At this point, no need to query as we
58184610Salfred	 * shouldn't select an unsorted format
59184610Salfred	 */
60184610Salfred	return (uaudio_chan_set_param_format(data, format));
61184610Salfred}
62184610Salfred
63193640Sariffstatic uint32_t
64184610Salfredua_chan_setspeed(kobj_t obj, void *data, uint32_t speed)
65184610Salfred{
66184610Salfred	return (uaudio_chan_set_param_speed(data, speed));
67184610Salfred}
68184610Salfred
69193640Sariffstatic uint32_t
70184610Salfredua_chan_setblocksize(kobj_t obj, void *data, uint32_t blocksize)
71184610Salfred{
72184610Salfred	return (uaudio_chan_set_param_blocksize(data, blocksize));
73184610Salfred}
74184610Salfred
75184610Salfredstatic int
76184610Salfredua_chan_setfragments(kobj_t obj, void *data, uint32_t blocksize, uint32_t blockcount)
77184610Salfred{
78184610Salfred	return (uaudio_chan_set_param_fragments(data, blocksize, blockcount));
79184610Salfred}
80184610Salfred
81184610Salfredstatic int
82184610Salfredua_chan_trigger(kobj_t obj, void *data, int go)
83184610Salfred{
84280322Shselasky	if (PCMTRIG_COMMON(go)) {
85280322Shselasky		if (go == PCMTRIG_START) {
86280322Shselasky			uaudio_chan_start(data);
87280322Shselasky		} else {
88280322Shselasky			uaudio_chan_stop(data);
89280322Shselasky		}
90184610Salfred	}
91280322Shselasky	return (0);
92184610Salfred}
93184610Salfred
94193640Sariffstatic uint32_t
95184610Salfredua_chan_getptr(kobj_t obj, void *data)
96184610Salfred{
97184610Salfred	return (uaudio_chan_getptr(data));
98184610Salfred}
99184610Salfred
100184610Salfredstatic struct pcmchan_caps *
101184610Salfredua_chan_getcaps(kobj_t obj, void *data)
102184610Salfred{
103184610Salfred	return (uaudio_chan_getcaps(data));
104184610Salfred}
105184610Salfred
106193640Sariffstatic struct pcmchan_matrix *
107193640Sariffua_chan_getmatrix(kobj_t obj, void *data, uint32_t format)
108193640Sariff{
109193640Sariff	return (uaudio_chan_getmatrix(data, format));
110193640Sariff}
111193640Sariff
112184610Salfredstatic kobj_method_t ua_chan_methods[] = {
113184610Salfred	KOBJMETHOD(channel_init, ua_chan_init),
114184610Salfred	KOBJMETHOD(channel_free, ua_chan_free),
115184610Salfred	KOBJMETHOD(channel_setformat, ua_chan_setformat),
116184610Salfred	KOBJMETHOD(channel_setspeed, ua_chan_setspeed),
117184610Salfred	KOBJMETHOD(channel_setblocksize, ua_chan_setblocksize),
118184610Salfred	KOBJMETHOD(channel_setfragments, ua_chan_setfragments),
119184610Salfred	KOBJMETHOD(channel_trigger, ua_chan_trigger),
120184610Salfred	KOBJMETHOD(channel_getptr, ua_chan_getptr),
121184610Salfred	KOBJMETHOD(channel_getcaps, ua_chan_getcaps),
122193640Sariff	KOBJMETHOD(channel_getmatrix, ua_chan_getmatrix),
123193640Sariff	KOBJMETHOD_END
124184610Salfred};
125184610Salfred
126184610SalfredCHANNEL_DECLARE(ua_chan);
127184610Salfred
128184610Salfred/************************************************************/
129184610Salfredstatic int
130184610Salfredua_mixer_init(struct snd_mixer *m)
131184610Salfred{
132184610Salfred	return (uaudio_mixer_init_sub(mix_getdevinfo(m), m));
133184610Salfred}
134184610Salfred
135184610Salfredstatic int
136184610Salfredua_mixer_set(struct snd_mixer *m, unsigned type, unsigned left, unsigned right)
137184610Salfred{
138184610Salfred	struct mtx *mtx = mixer_get_lock(m);
139184610Salfred	uint8_t do_unlock;
140184610Salfred
141184610Salfred	if (mtx_owned(mtx)) {
142184610Salfred		do_unlock = 0;
143184610Salfred	} else {
144184610Salfred		do_unlock = 1;
145184610Salfred		mtx_lock(mtx);
146184610Salfred	}
147359889Shselasky	uaudio_mixer_set(mix_getdevinfo(m), m, type, left, right);
148184610Salfred	if (do_unlock) {
149184610Salfred		mtx_unlock(mtx);
150184610Salfred	}
151184610Salfred	return (left | (right << 8));
152184610Salfred}
153184610Salfred
154193640Sariffstatic uint32_t
155184610Salfredua_mixer_setrecsrc(struct snd_mixer *m, uint32_t src)
156184610Salfred{
157184610Salfred	struct mtx *mtx = mixer_get_lock(m);
158184610Salfred	int retval;
159184610Salfred	uint8_t do_unlock;
160184610Salfred
161184610Salfred	if (mtx_owned(mtx)) {
162184610Salfred		do_unlock = 0;
163184610Salfred	} else {
164184610Salfred		do_unlock = 1;
165184610Salfred		mtx_lock(mtx);
166184610Salfred	}
167359889Shselasky	retval = uaudio_mixer_setrecsrc(mix_getdevinfo(m), m, src);
168184610Salfred	if (do_unlock) {
169184610Salfred		mtx_unlock(mtx);
170184610Salfred	}
171184610Salfred	return (retval);
172184610Salfred}
173184610Salfred
174184610Salfredstatic int
175184610Salfredua_mixer_uninit(struct snd_mixer *m)
176184610Salfred{
177359889Shselasky	return (uaudio_mixer_uninit_sub(mix_getdevinfo(m), m));
178184610Salfred}
179184610Salfred
180184610Salfredstatic kobj_method_t ua_mixer_methods[] = {
181184610Salfred	KOBJMETHOD(mixer_init, ua_mixer_init),
182184610Salfred	KOBJMETHOD(mixer_uninit, ua_mixer_uninit),
183184610Salfred	KOBJMETHOD(mixer_set, ua_mixer_set),
184184610Salfred	KOBJMETHOD(mixer_setrecsrc, ua_mixer_setrecsrc),
185193640Sariff	KOBJMETHOD_END
186184610Salfred};
187184610Salfred
188184610SalfredMIXER_DECLARE(ua_mixer);
189184610Salfred/************************************************************/
190184610Salfred
191184610Salfred
192184610Salfredstatic int
193184610Salfredua_probe(device_t dev)
194184610Salfred{
195184610Salfred	struct sndcard_func *func;
196184610Salfred
197184610Salfred	/* the parent device has already been probed */
198184610Salfred
199184610Salfred	func = device_get_ivars(dev);
200184610Salfred
201184610Salfred	if ((func == NULL) ||
202184610Salfred	    (func->func != SCF_PCM)) {
203184610Salfred		return (ENXIO);
204184610Salfred	}
205184610Salfred	device_set_desc(dev, "USB audio");
206184610Salfred
207184610Salfred	return (BUS_PROBE_DEFAULT);
208184610Salfred}
209184610Salfred
210184610Salfredstatic int
211184610Salfredua_attach(device_t dev)
212184610Salfred{
213184610Salfred	return (uaudio_attach_sub(dev, &ua_mixer_class, &ua_chan_class));
214184610Salfred}
215184610Salfred
216184610Salfredstatic int
217184610Salfredua_detach(device_t dev)
218184610Salfred{
219184610Salfred	return (uaudio_detach_sub(dev));
220184610Salfred}
221184610Salfred
222184610Salfred/************************************************************/
223184610Salfred
224184610Salfredstatic device_method_t ua_pcm_methods[] = {
225184610Salfred	/* Device interface */
226184610Salfred	DEVMETHOD(device_probe, ua_probe),
227184610Salfred	DEVMETHOD(device_attach, ua_attach),
228184610Salfred	DEVMETHOD(device_detach, ua_detach),
229184610Salfred
230246128Ssbz	DEVMETHOD_END
231184610Salfred};
232184610Salfred
233184610Salfredstatic driver_t ua_pcm_driver = {
234184610Salfred	"pcm",
235184610Salfred	ua_pcm_methods,
236184610Salfred	PCM_SOFTC_SIZE,
237184610Salfred};
238184610Salfred
239184610SalfredDRIVER_MODULE(ua_pcm, uaudio, ua_pcm_driver, pcm_devclass, 0, 0);
240184610SalfredMODULE_DEPEND(ua_pcm, uaudio, 1, 1, 1);
241184610SalfredMODULE_DEPEND(ua_pcm, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
242184610SalfredMODULE_VERSION(ua_pcm, 1);
243