Commit | Line | Data |
---|---|---|
a963377a | 1 | /* $FreeBSD: head/sys/dev/sound/usb/uaudio_pcm.c 246128 2013-01-30 18:01:20Z sbz $ */ |
09b9c6f2 SW |
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 | ||
09b9c6f2 | 30 | #include "opt_snd.h" |
09b9c6f2 SW |
31 | |
32 | #include <dev/sound/pcm/sound.h> | |
33 | #include <dev/sound/chip.h> | |
5a82fc1a | 34 | #include <bus/u4b/audio/uaudio.h> |
09b9c6f2 SW |
35 | |
36 | #include "mixer_if.h" | |
37 | ||
38 | /************************************************************/ | |
39 | static void * | |
40 | ua_chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) | |
41 | { | |
42 | return (uaudio_chan_init(devinfo, b, c, dir)); | |
43 | } | |
44 | ||
45 | static int | |
46 | ua_chan_free(kobj_t obj, void *data) | |
47 | { | |
48 | return (uaudio_chan_free(data)); | |
49 | } | |
50 | ||
51 | static int | |
52 | ua_chan_setformat(kobj_t obj, void *data, uint32_t format) | |
53 | { | |
54 | /* | |
55 | * At this point, no need to query as we | |
56 | * shouldn't select an unsorted format | |
57 | */ | |
58 | return (uaudio_chan_set_param_format(data, format)); | |
59 | } | |
60 | ||
61 | static uint32_t | |
62 | ua_chan_setspeed(kobj_t obj, void *data, uint32_t speed) | |
63 | { | |
64 | return (uaudio_chan_set_param_speed(data, speed)); | |
65 | } | |
66 | ||
67 | static uint32_t | |
68 | ua_chan_setblocksize(kobj_t obj, void *data, uint32_t blocksize) | |
69 | { | |
70 | return (uaudio_chan_set_param_blocksize(data, blocksize)); | |
71 | } | |
72 | ||
73 | static int | |
74 | ua_chan_setfragments(kobj_t obj, void *data, uint32_t blocksize, uint32_t blockcount) | |
75 | { | |
76 | return (uaudio_chan_set_param_fragments(data, blocksize, blockcount)); | |
77 | } | |
78 | ||
79 | static int | |
80 | ua_chan_trigger(kobj_t obj, void *data, int go) | |
81 | { | |
5e4edd23 | 82 | if (PCMTRIG_COMMON(go)) { |
3b964699 | 83 | if (go == PCMTRIG_START) { |
5e4edd23 | 84 | uaudio_chan_start(data); |
3b964699 | 85 | } else { |
5e4edd23 | 86 | uaudio_chan_stop(data); |
3b964699 | 87 | } |
09b9c6f2 | 88 | } |
5e4edd23 MD |
89 | return (0); |
90 | } | |
09b9c6f2 SW |
91 | |
92 | static uint32_t | |
93 | ua_chan_getptr(kobj_t obj, void *data) | |
94 | { | |
95 | return (uaudio_chan_getptr(data)); | |
96 | } | |
97 | ||
98 | static struct pcmchan_caps * | |
99 | ua_chan_getcaps(kobj_t obj, void *data) | |
100 | { | |
101 | return (uaudio_chan_getcaps(data)); | |
102 | } | |
103 | ||
104 | static struct pcmchan_matrix * | |
105 | ua_chan_getmatrix(kobj_t obj, void *data, uint32_t format) | |
106 | { | |
107 | return (uaudio_chan_getmatrix(data, format)); | |
108 | } | |
109 | ||
110 | static kobj_method_t ua_chan_methods[] = { | |
111 | KOBJMETHOD(channel_init, ua_chan_init), | |
112 | KOBJMETHOD(channel_free, ua_chan_free), | |
113 | KOBJMETHOD(channel_setformat, ua_chan_setformat), | |
114 | KOBJMETHOD(channel_setspeed, ua_chan_setspeed), | |
115 | KOBJMETHOD(channel_setblocksize, ua_chan_setblocksize), | |
116 | KOBJMETHOD(channel_setfragments, ua_chan_setfragments), | |
117 | KOBJMETHOD(channel_trigger, ua_chan_trigger), | |
118 | KOBJMETHOD(channel_getptr, ua_chan_getptr), | |
119 | KOBJMETHOD(channel_getcaps, ua_chan_getcaps), | |
120 | KOBJMETHOD(channel_getmatrix, ua_chan_getmatrix), | |
121 | KOBJMETHOD_END | |
122 | }; | |
123 | ||
124 | CHANNEL_DECLARE(ua_chan); | |
125 | ||
126 | /************************************************************/ | |
127 | static int | |
128 | ua_mixer_init(struct snd_mixer *m) | |
129 | { | |
130 | return (uaudio_mixer_init_sub(mix_getdevinfo(m), m)); | |
131 | } | |
132 | ||
133 | static int | |
134 | ua_mixer_set(struct snd_mixer *m, unsigned type, unsigned left, unsigned right) | |
135 | { | |
47b126bb FT |
136 | struct lock *lock = mixer_get_lock(m); |
137 | uint8_t do_unlock; | |
138 | ||
a963377a | 139 | if (lockowned(lock)) { |
47b126bb FT |
140 | do_unlock = 0; |
141 | } else { | |
142 | do_unlock = 1; | |
143 | lockmgr(lock, LK_EXCLUSIVE); | |
144 | } | |
09b9c6f2 | 145 | uaudio_mixer_set(mix_getdevinfo(m), type, left, right); |
47b126bb FT |
146 | if (do_unlock) { |
147 | lockmgr(lock, LK_RELEASE); | |
148 | } | |
09b9c6f2 SW |
149 | return (left | (right << 8)); |
150 | } | |
151 | ||
152 | static uint32_t | |
153 | ua_mixer_setrecsrc(struct snd_mixer *m, uint32_t src) | |
154 | { | |
47b126bb | 155 | struct lock *lock = mixer_get_lock(m); |
09b9c6f2 | 156 | int retval; |
47b126bb FT |
157 | uint8_t do_unlock; |
158 | ||
a963377a | 159 | if (lockowned(lock)) { |
47b126bb FT |
160 | do_unlock = 0; |
161 | } else { | |
162 | do_unlock = 1; | |
163 | lockmgr(lock, LK_EXCLUSIVE); | |
164 | } | |
09b9c6f2 | 165 | retval = uaudio_mixer_setrecsrc(mix_getdevinfo(m), src); |
47b126bb FT |
166 | if (do_unlock) { |
167 | lockmgr(lock, LK_RELEASE); | |
168 | } | |
09b9c6f2 SW |
169 | return (retval); |
170 | } | |
171 | ||
172 | static int | |
173 | ua_mixer_uninit(struct snd_mixer *m) | |
174 | { | |
175 | return (uaudio_mixer_uninit_sub(mix_getdevinfo(m))); | |
176 | } | |
177 | ||
178 | static kobj_method_t ua_mixer_methods[] = { | |
179 | KOBJMETHOD(mixer_init, ua_mixer_init), | |
180 | KOBJMETHOD(mixer_uninit, ua_mixer_uninit), | |
181 | KOBJMETHOD(mixer_set, ua_mixer_set), | |
182 | KOBJMETHOD(mixer_setrecsrc, ua_mixer_setrecsrc), | |
183 | KOBJMETHOD_END | |
184 | }; | |
185 | ||
186 | MIXER_DECLARE(ua_mixer); | |
187 | /************************************************************/ | |
188 | ||
189 | ||
190 | static int | |
191 | ua_probe(device_t dev) | |
192 | { | |
193 | struct sndcard_func *func; | |
194 | ||
195 | /* the parent device has already been probed */ | |
196 | ||
197 | func = device_get_ivars(dev); | |
198 | ||
199 | if ((func == NULL) || | |
200 | (func->func != SCF_PCM)) { | |
201 | return (ENXIO); | |
202 | } | |
203 | device_set_desc(dev, "USB audio"); | |
204 | ||
205 | return (BUS_PROBE_DEFAULT); | |
206 | } | |
207 | ||
208 | static int | |
209 | ua_attach(device_t dev) | |
210 | { | |
211 | return (uaudio_attach_sub(dev, &ua_mixer_class, &ua_chan_class)); | |
212 | } | |
213 | ||
214 | static int | |
215 | ua_detach(device_t dev) | |
216 | { | |
217 | return (uaudio_detach_sub(dev)); | |
218 | } | |
219 | ||
220 | /************************************************************/ | |
221 | ||
222 | static device_method_t ua_pcm_methods[] = { | |
223 | /* Device interface */ | |
224 | DEVMETHOD(device_probe, ua_probe), | |
225 | DEVMETHOD(device_attach, ua_attach), | |
226 | DEVMETHOD(device_detach, ua_detach), | |
227 | ||
d3c9c58e | 228 | DEVMETHOD_END |
09b9c6f2 SW |
229 | }; |
230 | ||
231 | static driver_t ua_pcm_driver = { | |
232 | "pcm", | |
233 | ua_pcm_methods, | |
234 | PCM_SOFTC_SIZE, | |
235 | }; | |
236 | ||
aa6ac96e | 237 | DRIVER_MODULE(ua_pcm, uaudio, ua_pcm_driver, pcm_devclass, NULL, NULL); |
09b9c6f2 SW |
238 | MODULE_DEPEND(ua_pcm, uaudio, 1, 1, 1); |
239 | MODULE_DEPEND(ua_pcm, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); | |
240 | MODULE_VERSION(ua_pcm, 1); |