uaudio_pcm.c revision 280322
1/* $FreeBSD: head/sys/dev/sound/usb/uaudio_pcm.c 280322 2015-03-21 09:45:45Z hselasky $ */
2
3/*-
4 * Copyright (c) 2000-2002 Hiroyuki Aizu <aizu@navi.org>
5 * Copyright (c) 2006 Hans Petter Selasky
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29
30#ifdef HAVE_KERNEL_OPTION_HEADERS
31#include "opt_snd.h"
32#endif
33
34#include <dev/sound/pcm/sound.h>
35#include <dev/sound/chip.h>
36#include <dev/sound/usb/uaudio.h>
37
38#include "mixer_if.h"
39
40/************************************************************/
41static void *
42ua_chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
43{
44	return (uaudio_chan_init(devinfo, b, c, dir));
45}
46
47static int
48ua_chan_free(kobj_t obj, void *data)
49{
50	return (uaudio_chan_free(data));
51}
52
53static int
54ua_chan_setformat(kobj_t obj, void *data, uint32_t format)
55{
56	/*
57	 * At this point, no need to query as we
58	 * shouldn't select an unsorted format
59	 */
60	return (uaudio_chan_set_param_format(data, format));
61}
62
63static uint32_t
64ua_chan_setspeed(kobj_t obj, void *data, uint32_t speed)
65{
66	return (uaudio_chan_set_param_speed(data, speed));
67}
68
69static uint32_t
70ua_chan_setblocksize(kobj_t obj, void *data, uint32_t blocksize)
71{
72	return (uaudio_chan_set_param_blocksize(data, blocksize));
73}
74
75static int
76ua_chan_setfragments(kobj_t obj, void *data, uint32_t blocksize, uint32_t blockcount)
77{
78	return (uaudio_chan_set_param_fragments(data, blocksize, blockcount));
79}
80
81static int
82ua_chan_trigger(kobj_t obj, void *data, int go)
83{
84	if (PCMTRIG_COMMON(go)) {
85		if (go == PCMTRIG_START) {
86			uaudio_chan_start(data);
87		} else {
88			uaudio_chan_stop(data);
89		}
90	}
91	return (0);
92}
93
94static uint32_t
95ua_chan_getptr(kobj_t obj, void *data)
96{
97	return (uaudio_chan_getptr(data));
98}
99
100static struct pcmchan_caps *
101ua_chan_getcaps(kobj_t obj, void *data)
102{
103	return (uaudio_chan_getcaps(data));
104}
105
106static struct pcmchan_matrix *
107ua_chan_getmatrix(kobj_t obj, void *data, uint32_t format)
108{
109	return (uaudio_chan_getmatrix(data, format));
110}
111
112static kobj_method_t ua_chan_methods[] = {
113	KOBJMETHOD(channel_init, ua_chan_init),
114	KOBJMETHOD(channel_free, ua_chan_free),
115	KOBJMETHOD(channel_setformat, ua_chan_setformat),
116	KOBJMETHOD(channel_setspeed, ua_chan_setspeed),
117	KOBJMETHOD(channel_setblocksize, ua_chan_setblocksize),
118	KOBJMETHOD(channel_setfragments, ua_chan_setfragments),
119	KOBJMETHOD(channel_trigger, ua_chan_trigger),
120	KOBJMETHOD(channel_getptr, ua_chan_getptr),
121	KOBJMETHOD(channel_getcaps, ua_chan_getcaps),
122	KOBJMETHOD(channel_getmatrix, ua_chan_getmatrix),
123	KOBJMETHOD_END
124};
125
126CHANNEL_DECLARE(ua_chan);
127
128/************************************************************/
129static int
130ua_mixer_init(struct snd_mixer *m)
131{
132	return (uaudio_mixer_init_sub(mix_getdevinfo(m), m));
133}
134
135static int
136ua_mixer_set(struct snd_mixer *m, unsigned type, unsigned left, unsigned right)
137{
138	struct mtx *mtx = mixer_get_lock(m);
139	uint8_t do_unlock;
140
141	if (mtx_owned(mtx)) {
142		do_unlock = 0;
143	} else {
144		do_unlock = 1;
145		mtx_lock(mtx);
146	}
147	uaudio_mixer_set(mix_getdevinfo(m), type, left, right);
148	if (do_unlock) {
149		mtx_unlock(mtx);
150	}
151	return (left | (right << 8));
152}
153
154static uint32_t
155ua_mixer_setrecsrc(struct snd_mixer *m, uint32_t src)
156{
157	struct mtx *mtx = mixer_get_lock(m);
158	int retval;
159	uint8_t do_unlock;
160
161	if (mtx_owned(mtx)) {
162		do_unlock = 0;
163	} else {
164		do_unlock = 1;
165		mtx_lock(mtx);
166	}
167	retval = uaudio_mixer_setrecsrc(mix_getdevinfo(m), src);
168	if (do_unlock) {
169		mtx_unlock(mtx);
170	}
171	return (retval);
172}
173
174static int
175ua_mixer_uninit(struct snd_mixer *m)
176{
177	return (uaudio_mixer_uninit_sub(mix_getdevinfo(m)));
178}
179
180static kobj_method_t ua_mixer_methods[] = {
181	KOBJMETHOD(mixer_init, ua_mixer_init),
182	KOBJMETHOD(mixer_uninit, ua_mixer_uninit),
183	KOBJMETHOD(mixer_set, ua_mixer_set),
184	KOBJMETHOD(mixer_setrecsrc, ua_mixer_setrecsrc),
185	KOBJMETHOD_END
186};
187
188MIXER_DECLARE(ua_mixer);
189/************************************************************/
190
191
192static int
193ua_probe(device_t dev)
194{
195	struct sndcard_func *func;
196
197	/* the parent device has already been probed */
198
199	func = device_get_ivars(dev);
200
201	if ((func == NULL) ||
202	    (func->func != SCF_PCM)) {
203		return (ENXIO);
204	}
205	device_set_desc(dev, "USB audio");
206
207	return (BUS_PROBE_DEFAULT);
208}
209
210static int
211ua_attach(device_t dev)
212{
213	return (uaudio_attach_sub(dev, &ua_mixer_class, &ua_chan_class));
214}
215
216static int
217ua_detach(device_t dev)
218{
219	return (uaudio_detach_sub(dev));
220}
221
222/************************************************************/
223
224static device_method_t ua_pcm_methods[] = {
225	/* Device interface */
226	DEVMETHOD(device_probe, ua_probe),
227	DEVMETHOD(device_attach, ua_attach),
228	DEVMETHOD(device_detach, ua_detach),
229
230	DEVMETHOD_END
231};
232
233static driver_t ua_pcm_driver = {
234	"pcm",
235	ua_pcm_methods,
236	PCM_SOFTC_SIZE,
237};
238
239DRIVER_MODULE(ua_pcm, uaudio, ua_pcm_driver, pcm_devclass, 0, 0);
240MODULE_DEPEND(ua_pcm, uaudio, 1, 1, 1);
241MODULE_DEPEND(ua_pcm, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
242MODULE_VERSION(ua_pcm, 1);
243