Deleted Added
full compact
channel.c (168243) channel.c (170161)
1/*-
2 * Copyright (c) 1999 Cameron Grant <cg@freebsd.org>
3 * Portions Copyright by Luigi Rizzo - 1997-99
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include "opt_isa.h"
29
30#include <dev/sound/pcm/sound.h>
31
32#include "feeder_if.h"
33
1/*-
2 * Copyright (c) 1999 Cameron Grant <cg@freebsd.org>
3 * Portions Copyright by Luigi Rizzo - 1997-99
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include "opt_isa.h"
29
30#include <dev/sound/pcm/sound.h>
31
32#include "feeder_if.h"
33
34SND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pcm/channel.c 168243 2007-04-02 03:03:06Z ariff $");
34SND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pcm/channel.c 170161 2007-05-31 18:43:33Z ariff $");
35
36#define MIN_CHUNK_SIZE 256 /* for uiomove etc. */
37#if 0
38#define DMA_ALIGN_THRESHOLD 4
39#define DMA_ALIGN_MASK (~(DMA_ALIGN_THRESHOLD - 1))
40#endif
41
42#define CHN_STARTED(c) ((c)->flags & CHN_F_TRIGGERED)
43#define CHN_STOPPED(c) (!CHN_STARTED(c))
44#define CHN_DIRSTR(c) (((c)->direction == PCMDIR_PLAY) ? \
45 "PCMDIR_PLAY" : "PCMDIR_REC")
46
47#define BUF_PARENT(c, b) \
48 (((c) != NULL && (c)->parentchannel != NULL && \
49 (c)->parentchannel->bufhard != NULL) ? \
50 (c)->parentchannel->bufhard : (b))
51
52#define CHN_TIMEOUT 5
53#define CHN_TIMEOUT_MIN 1
54#define CHN_TIMEOUT_MAX 10
55
56/*
57#define DEB(x) x
58*/
59
60int report_soft_formats = 1;
61SYSCTL_INT(_hw_snd, OID_AUTO, report_soft_formats, CTLFLAG_RW,
62 &report_soft_formats, 1, "report software-emulated formats");
63
64int chn_latency = CHN_LATENCY_DEFAULT;
65TUNABLE_INT("hw.snd.latency", &chn_latency);
66
67static int
68sysctl_hw_snd_latency(SYSCTL_HANDLER_ARGS)
69{
70 int err, val;
71
72 val = chn_latency;
73 err = sysctl_handle_int(oidp, &val, sizeof(val), req);
74 if (err != 0 || req->newptr == NULL)
75 return err;
76 if (val < CHN_LATENCY_MIN || val > CHN_LATENCY_MAX)
77 err = EINVAL;
78 else
79 chn_latency = val;
80
81 return err;
82}
83SYSCTL_PROC(_hw_snd, OID_AUTO, latency, CTLTYPE_INT | CTLFLAG_RW,
84 0, sizeof(int), sysctl_hw_snd_latency, "I",
85 "buffering latency (0=low ... 10=high)");
86
87int chn_latency_profile = CHN_LATENCY_PROFILE_DEFAULT;
88TUNABLE_INT("hw.snd.latency_profile", &chn_latency_profile);
89
90static int
91sysctl_hw_snd_latency_profile(SYSCTL_HANDLER_ARGS)
92{
93 int err, val;
94
95 val = chn_latency_profile;
96 err = sysctl_handle_int(oidp, &val, sizeof(val), req);
97 if (err != 0 || req->newptr == NULL)
98 return err;
99 if (val < CHN_LATENCY_PROFILE_MIN || val > CHN_LATENCY_PROFILE_MAX)
100 err = EINVAL;
101 else
102 chn_latency_profile = val;
103
104 return err;
105}
106SYSCTL_PROC(_hw_snd, OID_AUTO, latency_profile, CTLTYPE_INT | CTLFLAG_RW,
107 0, sizeof(int), sysctl_hw_snd_latency_profile, "I",
108 "buffering latency profile (0=aggresive 1=safe)");
109
110static int chn_timeout = CHN_TIMEOUT;
111TUNABLE_INT("hw.snd.timeout", &chn_timeout);
112#ifdef SND_DEBUG
113static int
114sysctl_hw_snd_timeout(SYSCTL_HANDLER_ARGS)
115{
116 int err, val;
117
118 val = chn_timeout;
119 err = sysctl_handle_int(oidp, &val, sizeof(val), req);
120 if (err != 0 || req->newptr == NULL)
121 return err;
122 if (val < CHN_TIMEOUT_MIN || val > CHN_TIMEOUT_MAX)
123 err = EINVAL;
124 else
125 chn_timeout = val;
126
127 return err;
128}
129SYSCTL_PROC(_hw_snd, OID_AUTO, timeout, CTLTYPE_INT | CTLFLAG_RW,
130 0, sizeof(int), sysctl_hw_snd_timeout, "I",
131 "interrupt timeout (1 - 10) seconds");
132#endif
133
134static int chn_usefrags = 0;
135TUNABLE_INT("hw.snd.usefrags", &chn_usefrags);
136static int chn_syncdelay = -1;
137TUNABLE_INT("hw.snd.syncdelay", &chn_syncdelay);
138#ifdef SND_DEBUG
139SYSCTL_INT(_hw_snd, OID_AUTO, usefrags, CTLFLAG_RW,
140 &chn_usefrags, 1, "prefer setfragments() over setblocksize()");
141SYSCTL_INT(_hw_snd, OID_AUTO, syncdelay, CTLFLAG_RW,
142 &chn_syncdelay, 1,
143 "append (0-1000) millisecond trailing buffer delay on each sync");
144#endif
145
146/**
147 * @brief Channel sync group lock
148 *
149 * Clients should acquire this lock @b without holding any channel locks
150 * before touching syncgroups or the main syncgroup list.
151 */
152struct mtx snd_pcm_syncgroups_mtx;
153MTX_SYSINIT(pcm_syncgroup, &snd_pcm_syncgroups_mtx, "PCM channel sync group lock", MTX_DEF);
154/**
155 * @brief syncgroups' master list
156 *
157 * Each time a channel syncgroup is created, it's added to this list. This
158 * list should only be accessed with @sa snd_pcm_syncgroups_mtx held.
159 *
160 * See SNDCTL_DSP_SYNCGROUP for more information.
161 */
162struct pcm_synclist snd_pcm_syncgroups = SLIST_HEAD_INITIALIZER(head);
163
164static int chn_buildfeeder(struct pcm_channel *c);
165
166static void
167chn_lockinit(struct pcm_channel *c, int dir)
168{
169 switch(dir) {
170 case PCMDIR_PLAY:
171 c->lock = snd_mtxcreate(c->name, "pcm play channel");
172 break;
35
36#define MIN_CHUNK_SIZE 256 /* for uiomove etc. */
37#if 0
38#define DMA_ALIGN_THRESHOLD 4
39#define DMA_ALIGN_MASK (~(DMA_ALIGN_THRESHOLD - 1))
40#endif
41
42#define CHN_STARTED(c) ((c)->flags & CHN_F_TRIGGERED)
43#define CHN_STOPPED(c) (!CHN_STARTED(c))
44#define CHN_DIRSTR(c) (((c)->direction == PCMDIR_PLAY) ? \
45 "PCMDIR_PLAY" : "PCMDIR_REC")
46
47#define BUF_PARENT(c, b) \
48 (((c) != NULL && (c)->parentchannel != NULL && \
49 (c)->parentchannel->bufhard != NULL) ? \
50 (c)->parentchannel->bufhard : (b))
51
52#define CHN_TIMEOUT 5
53#define CHN_TIMEOUT_MIN 1
54#define CHN_TIMEOUT_MAX 10
55
56/*
57#define DEB(x) x
58*/
59
60int report_soft_formats = 1;
61SYSCTL_INT(_hw_snd, OID_AUTO, report_soft_formats, CTLFLAG_RW,
62 &report_soft_formats, 1, "report software-emulated formats");
63
64int chn_latency = CHN_LATENCY_DEFAULT;
65TUNABLE_INT("hw.snd.latency", &chn_latency);
66
67static int
68sysctl_hw_snd_latency(SYSCTL_HANDLER_ARGS)
69{
70 int err, val;
71
72 val = chn_latency;
73 err = sysctl_handle_int(oidp, &val, sizeof(val), req);
74 if (err != 0 || req->newptr == NULL)
75 return err;
76 if (val < CHN_LATENCY_MIN || val > CHN_LATENCY_MAX)
77 err = EINVAL;
78 else
79 chn_latency = val;
80
81 return err;
82}
83SYSCTL_PROC(_hw_snd, OID_AUTO, latency, CTLTYPE_INT | CTLFLAG_RW,
84 0, sizeof(int), sysctl_hw_snd_latency, "I",
85 "buffering latency (0=low ... 10=high)");
86
87int chn_latency_profile = CHN_LATENCY_PROFILE_DEFAULT;
88TUNABLE_INT("hw.snd.latency_profile", &chn_latency_profile);
89
90static int
91sysctl_hw_snd_latency_profile(SYSCTL_HANDLER_ARGS)
92{
93 int err, val;
94
95 val = chn_latency_profile;
96 err = sysctl_handle_int(oidp, &val, sizeof(val), req);
97 if (err != 0 || req->newptr == NULL)
98 return err;
99 if (val < CHN_LATENCY_PROFILE_MIN || val > CHN_LATENCY_PROFILE_MAX)
100 err = EINVAL;
101 else
102 chn_latency_profile = val;
103
104 return err;
105}
106SYSCTL_PROC(_hw_snd, OID_AUTO, latency_profile, CTLTYPE_INT | CTLFLAG_RW,
107 0, sizeof(int), sysctl_hw_snd_latency_profile, "I",
108 "buffering latency profile (0=aggresive 1=safe)");
109
110static int chn_timeout = CHN_TIMEOUT;
111TUNABLE_INT("hw.snd.timeout", &chn_timeout);
112#ifdef SND_DEBUG
113static int
114sysctl_hw_snd_timeout(SYSCTL_HANDLER_ARGS)
115{
116 int err, val;
117
118 val = chn_timeout;
119 err = sysctl_handle_int(oidp, &val, sizeof(val), req);
120 if (err != 0 || req->newptr == NULL)
121 return err;
122 if (val < CHN_TIMEOUT_MIN || val > CHN_TIMEOUT_MAX)
123 err = EINVAL;
124 else
125 chn_timeout = val;
126
127 return err;
128}
129SYSCTL_PROC(_hw_snd, OID_AUTO, timeout, CTLTYPE_INT | CTLFLAG_RW,
130 0, sizeof(int), sysctl_hw_snd_timeout, "I",
131 "interrupt timeout (1 - 10) seconds");
132#endif
133
134static int chn_usefrags = 0;
135TUNABLE_INT("hw.snd.usefrags", &chn_usefrags);
136static int chn_syncdelay = -1;
137TUNABLE_INT("hw.snd.syncdelay", &chn_syncdelay);
138#ifdef SND_DEBUG
139SYSCTL_INT(_hw_snd, OID_AUTO, usefrags, CTLFLAG_RW,
140 &chn_usefrags, 1, "prefer setfragments() over setblocksize()");
141SYSCTL_INT(_hw_snd, OID_AUTO, syncdelay, CTLFLAG_RW,
142 &chn_syncdelay, 1,
143 "append (0-1000) millisecond trailing buffer delay on each sync");
144#endif
145
146/**
147 * @brief Channel sync group lock
148 *
149 * Clients should acquire this lock @b without holding any channel locks
150 * before touching syncgroups or the main syncgroup list.
151 */
152struct mtx snd_pcm_syncgroups_mtx;
153MTX_SYSINIT(pcm_syncgroup, &snd_pcm_syncgroups_mtx, "PCM channel sync group lock", MTX_DEF);
154/**
155 * @brief syncgroups' master list
156 *
157 * Each time a channel syncgroup is created, it's added to this list. This
158 * list should only be accessed with @sa snd_pcm_syncgroups_mtx held.
159 *
160 * See SNDCTL_DSP_SYNCGROUP for more information.
161 */
162struct pcm_synclist snd_pcm_syncgroups = SLIST_HEAD_INITIALIZER(head);
163
164static int chn_buildfeeder(struct pcm_channel *c);
165
166static void
167chn_lockinit(struct pcm_channel *c, int dir)
168{
169 switch(dir) {
170 case PCMDIR_PLAY:
171 c->lock = snd_mtxcreate(c->name, "pcm play channel");
172 break;
173 case PCMDIR_PLAY_VIRTUAL:
174 c->lock = snd_mtxcreate(c->name, "pcm virtual play channel");
175 break;
173 case PCMDIR_REC:
174 c->lock = snd_mtxcreate(c->name, "pcm record channel");
175 break;
176 case PCMDIR_REC:
177 c->lock = snd_mtxcreate(c->name, "pcm record channel");
178 break;
176 case PCMDIR_VIRTUAL:
177 c->lock = snd_mtxcreate(c->name, "pcm virtual play channel");
179 case PCMDIR_REC_VIRTUAL:
180 c->lock = snd_mtxcreate(c->name, "pcm virtual record channel");
178 break;
179 case 0:
180 c->lock = snd_mtxcreate(c->name, "pcm fake channel");
181 break;
182 }
183
184 cv_init(&c->cv, c->name);
185}
186
187static void
188chn_lockdestroy(struct pcm_channel *c)
189{
190 snd_mtxfree(c->lock);
191 cv_destroy(&c->cv);
192}
193
194/**
195 * @brief Determine channel is ready for I/O
196 *
197 * @retval 1 = ready for I/O
198 * @retval 0 = not ready for I/O
199 */
200static int
201chn_polltrigger(struct pcm_channel *c)
202{
203 struct snd_dbuf *bs = c->bufsoft;
204 unsigned amt, lim;
205
206 CHN_LOCKASSERT(c);
207 if (c->flags & CHN_F_MAPPED) {
208 if (sndbuf_getprevblocks(bs) == 0)
209 return 1;
210 else
211 return (sndbuf_getblocks(bs) > sndbuf_getprevblocks(bs))? 1 : 0;
212 } else {
213 amt = (c->direction == PCMDIR_PLAY)? sndbuf_getfree(bs) : sndbuf_getready(bs);
214#if 0
215 lim = (c->flags & CHN_F_HAS_SIZE)? sndbuf_getblksz(bs) : 1;
216#endif
217 lim = c->lw;
218 return (amt >= lim) ? 1 : 0;
219 }
220 return 0;
221}
222
223static int
224chn_pollreset(struct pcm_channel *c)
225{
226 struct snd_dbuf *bs = c->bufsoft;
227
228 CHN_LOCKASSERT(c);
229 sndbuf_updateprevtotal(bs);
230 return 1;
231}
232
233static void
234chn_wakeup(struct pcm_channel *c)
235{
236 struct snd_dbuf *bs = c->bufsoft;
181 break;
182 case 0:
183 c->lock = snd_mtxcreate(c->name, "pcm fake channel");
184 break;
185 }
186
187 cv_init(&c->cv, c->name);
188}
189
190static void
191chn_lockdestroy(struct pcm_channel *c)
192{
193 snd_mtxfree(c->lock);
194 cv_destroy(&c->cv);
195}
196
197/**
198 * @brief Determine channel is ready for I/O
199 *
200 * @retval 1 = ready for I/O
201 * @retval 0 = not ready for I/O
202 */
203static int
204chn_polltrigger(struct pcm_channel *c)
205{
206 struct snd_dbuf *bs = c->bufsoft;
207 unsigned amt, lim;
208
209 CHN_LOCKASSERT(c);
210 if (c->flags & CHN_F_MAPPED) {
211 if (sndbuf_getprevblocks(bs) == 0)
212 return 1;
213 else
214 return (sndbuf_getblocks(bs) > sndbuf_getprevblocks(bs))? 1 : 0;
215 } else {
216 amt = (c->direction == PCMDIR_PLAY)? sndbuf_getfree(bs) : sndbuf_getready(bs);
217#if 0
218 lim = (c->flags & CHN_F_HAS_SIZE)? sndbuf_getblksz(bs) : 1;
219#endif
220 lim = c->lw;
221 return (amt >= lim) ? 1 : 0;
222 }
223 return 0;
224}
225
226static int
227chn_pollreset(struct pcm_channel *c)
228{
229 struct snd_dbuf *bs = c->bufsoft;
230
231 CHN_LOCKASSERT(c);
232 sndbuf_updateprevtotal(bs);
233 return 1;
234}
235
236static void
237chn_wakeup(struct pcm_channel *c)
238{
239 struct snd_dbuf *bs = c->bufsoft;
237 struct pcmchan_children *pce;
240 struct pcm_channel *ch;
238
239 CHN_LOCKASSERT(c);
241
242 CHN_LOCKASSERT(c);
240 if (SLIST_EMPTY(&c->children)) {
243 if (CHN_EMPTY(c, children)) {
241 if (SEL_WAITING(sndbuf_getsel(bs)) && chn_polltrigger(c))
242 selwakeuppri(sndbuf_getsel(bs), PRIBIO);
244 if (SEL_WAITING(sndbuf_getsel(bs)) && chn_polltrigger(c))
245 selwakeuppri(sndbuf_getsel(bs), PRIBIO);
243 wakeup_one(bs);
246 } else if (CHN_EMPTY(c, children.busy)) {
247 CHN_FOREACH(ch, c, children) {
248 CHN_LOCK(ch);
249 chn_wakeup(ch);
250 CHN_UNLOCK(ch);
251 }
244 } else {
252 } else {
245 SLIST_FOREACH(pce, &c->children, link) {
246 CHN_LOCK(pce->channel);
247 chn_wakeup(pce->channel);
248 CHN_UNLOCK(pce->channel);
253 CHN_FOREACH(ch, c, children.busy) {
254 CHN_LOCK(ch);
255 chn_wakeup(ch);
256 CHN_UNLOCK(ch);
249 }
250 }
257 }
258 }
259 if (c->flags & CHN_F_SLEEPING)
260 wakeup_one(bs);
251}
252
253static int
254chn_sleep(struct pcm_channel *c, char *str, int timeout)
255{
256 struct snd_dbuf *bs = c->bufsoft;
257 int ret;
258
259 CHN_LOCKASSERT(c);
261}
262
263static int
264chn_sleep(struct pcm_channel *c, char *str, int timeout)
265{
266 struct snd_dbuf *bs = c->bufsoft;
267 int ret;
268
269 CHN_LOCKASSERT(c);
270
271 c->flags |= CHN_F_SLEEPING;
260#ifdef USING_MUTEX
261 ret = msleep(bs, c->lock, PRIBIO | PCATCH, str, timeout);
262#else
263 ret = tsleep(bs, PRIBIO | PCATCH, str, timeout);
264#endif
272#ifdef USING_MUTEX
273 ret = msleep(bs, c->lock, PRIBIO | PCATCH, str, timeout);
274#else
275 ret = tsleep(bs, PRIBIO | PCATCH, str, timeout);
276#endif
277 c->flags &= ~CHN_F_SLEEPING;
265
266 return ret;
267}
268
269/*
270 * chn_dmaupdate() tracks the status of a dma transfer,
271 * updating pointers.
272 */
273
274static unsigned int
275chn_dmaupdate(struct pcm_channel *c)
276{
277 struct snd_dbuf *b = c->bufhard;
278 unsigned int delta, old, hwptr, amt;
279
280 KASSERT(sndbuf_getsize(b) > 0, ("bufsize == 0"));
281 CHN_LOCKASSERT(c);
282
283 old = sndbuf_gethwptr(b);
284 hwptr = chn_getptr(c);
285 delta = (sndbuf_getsize(b) + hwptr - old) % sndbuf_getsize(b);
286 sndbuf_sethwptr(b, hwptr);
287
288 DEB(
289 if (delta >= ((sndbuf_getsize(b) * 15) / 16)) {
290 if (!(c->flags & (CHN_F_CLOSING | CHN_F_ABORTING)))
291 device_printf(c->dev, "hwptr went backwards %d -> %d\n", old, hwptr);
292 }
293 );
294
295 if (c->direction == PCMDIR_PLAY) {
296 amt = min(delta, sndbuf_getready(b));
297 amt -= amt % sndbuf_getbps(b);
298 if (amt > 0)
299 sndbuf_dispose(b, NULL, amt);
300 } else {
301 amt = min(delta, sndbuf_getfree(b));
302 amt -= amt % sndbuf_getbps(b);
303 if (amt > 0)
304 sndbuf_acquire(b, NULL, amt);
305 }
306 if (snd_verbose > 3 && CHN_STARTED(c) && delta == 0) {
307 device_printf(c->dev, "WARNING: %s DMA completion "
308 "too fast/slow ! hwptr=%u, old=%u "
309 "delta=%u amt=%u ready=%u free=%u\n",
310 CHN_DIRSTR(c), hwptr, old, delta, amt,
311 sndbuf_getready(b), sndbuf_getfree(b));
312 }
313
314 return delta;
315}
316
317void
318chn_wrupdate(struct pcm_channel *c)
319{
320 int ret;
321
322 CHN_LOCKASSERT(c);
323 KASSERT(c->direction == PCMDIR_PLAY, ("chn_wrupdate on bad channel"));
324
325 if ((c->flags & (CHN_F_MAPPED | CHN_F_VIRTUAL)) || CHN_STOPPED(c))
326 return;
327 chn_dmaupdate(c);
328 ret = chn_wrfeed(c);
329 /* tell the driver we've updated the primary buffer */
330 chn_trigger(c, PCMTRIG_EMLDMAWR);
331 DEB(if (ret)
332 printf("chn_wrupdate: chn_wrfeed returned %d\n", ret);)
333
334}
335
336int
337chn_wrfeed(struct pcm_channel *c)
338{
339 struct snd_dbuf *b = c->bufhard;
340 struct snd_dbuf *bs = c->bufsoft;
341 unsigned int ret, amt;
342
343 CHN_LOCKASSERT(c);
344#if 0
345 DEB(
346 if (c->flags & CHN_F_CLOSING) {
347 sndbuf_dump(b, "b", 0x02);
348 sndbuf_dump(bs, "bs", 0x02);
349 })
350#endif
351
352 if ((c->flags & CHN_F_MAPPED) && !(c->flags & CHN_F_CLOSING))
353 sndbuf_acquire(bs, NULL, sndbuf_getfree(bs));
354
355 amt = sndbuf_getfree(b);
356 DEB(if (amt > sndbuf_getsize(bs) &&
357 sndbuf_getbps(bs) >= sndbuf_getbps(b)) {
358 printf("%s(%s): amt %d > source size %d, flags 0x%x", __func__, c->name,
359 amt, sndbuf_getsize(bs), c->flags);
360 });
361
362 ret = (amt > 0) ? sndbuf_feed(bs, b, c, c->feeder, amt) : ENOSPC;
363 /*
364 * Possible xruns. There should be no empty space left in buffer.
365 */
366 if (sndbuf_getfree(b) > 0)
367 c->xruns++;
368
369 if (sndbuf_getfree(b) < amt)
370 chn_wakeup(c);
371
372 return ret;
373}
374
375static void
376chn_wrintr(struct pcm_channel *c)
377{
378 int ret;
379
380 CHN_LOCKASSERT(c);
381 /* update pointers in primary buffer */
382 chn_dmaupdate(c);
383 /* ...and feed from secondary to primary */
384 ret = chn_wrfeed(c);
385 /* tell the driver we've updated the primary buffer */
386 chn_trigger(c, PCMTRIG_EMLDMAWR);
387 DEB(if (ret)
388 printf("chn_wrintr: chn_wrfeed returned %d\n", ret);)
389}
390
391/*
392 * user write routine - uiomove data into secondary buffer, trigger if necessary
393 * if blocking, sleep, rinse and repeat.
394 *
395 * called externally, so must handle locking
396 */
397
398int
399chn_write(struct pcm_channel *c, struct uio *buf)
400{
401 struct snd_dbuf *bs = c->bufsoft;
402 void *off;
403 int ret, timeout, sz, t, p;
404
405 CHN_LOCKASSERT(c);
406
407 ret = 0;
408 timeout = chn_timeout * hz;
409
410 while (ret == 0 && buf->uio_resid > 0) {
411 sz = min(buf->uio_resid, sndbuf_getfree(bs));
412 if (sz > 0) {
413 /*
414 * The following assumes that the free space in
415 * the buffer can never be less around the
416 * unlock-uiomove-lock sequence.
417 */
418 while (ret == 0 && sz > 0) {
419 p = sndbuf_getfreeptr(bs);
420 t = min(sz, sndbuf_getsize(bs) - p);
421 off = sndbuf_getbufofs(bs, p);
422 CHN_UNLOCK(c);
423 ret = uiomove(off, t, buf);
424 CHN_LOCK(c);
425 sz -= t;
426 sndbuf_acquire(bs, NULL, t);
427 }
428 ret = 0;
429 if (CHN_STOPPED(c))
430 chn_start(c, 0);
431 } else if (c->flags & (CHN_F_NBIO | CHN_F_NOTRIGGER)) {
432 /**
433 * @todo Evaluate whether EAGAIN is truly desirable.
434 * 4Front drivers behave like this, but I'm
435 * not sure if it at all violates the "write
436 * should be allowed to block" model.
437 *
438 * The idea is that, while set with CHN_F_NOTRIGGER,
439 * a channel isn't playing, *but* without this we
440 * end up with "interrupt timeout / channel dead".
441 */
442 ret = EAGAIN;
443 } else {
444 ret = chn_sleep(c, "pcmwr", timeout);
445 if (ret == EAGAIN) {
446 ret = EINVAL;
447 c->flags |= CHN_F_DEAD;
448 printf("%s: play interrupt timeout, "
449 "channel dead\n", c->name);
450 } else if (ret == ERESTART || ret == EINTR)
451 c->flags |= CHN_F_ABORTING;
452 }
453 }
454
455 return ret;
456}
457
458#if 0
459static int
460chn_rddump(struct pcm_channel *c, unsigned int cnt)
461{
462 struct snd_dbuf *b = c->bufhard;
463
464 CHN_LOCKASSERT(c);
465#if 0
466 static u_int32_t kk = 0;
467 printf("%u: dumping %d bytes\n", ++kk, cnt);
468#endif
469 c->xruns++;
470 sndbuf_setxrun(b, sndbuf_getxrun(b) + cnt);
471 return sndbuf_dispose(b, NULL, cnt);
472}
473#endif
474
475/*
476 * Feed new data from the read buffer. Can be called in the bottom half.
477 */
478int
479chn_rdfeed(struct pcm_channel *c)
480{
481 struct snd_dbuf *b = c->bufhard;
482 struct snd_dbuf *bs = c->bufsoft;
483 unsigned int ret, amt;
484
485 CHN_LOCKASSERT(c);
486 DEB(
487 if (c->flags & CHN_F_CLOSING) {
488 sndbuf_dump(b, "b", 0x02);
489 sndbuf_dump(bs, "bs", 0x02);
490 })
491
492#if 0
493 amt = sndbuf_getready(b);
494 if (sndbuf_getfree(bs) < amt) {
495 c->xruns++;
496 amt = sndbuf_getfree(bs);
497 }
498#endif
499 amt = sndbuf_getfree(bs);
278
279 return ret;
280}
281
282/*
283 * chn_dmaupdate() tracks the status of a dma transfer,
284 * updating pointers.
285 */
286
287static unsigned int
288chn_dmaupdate(struct pcm_channel *c)
289{
290 struct snd_dbuf *b = c->bufhard;
291 unsigned int delta, old, hwptr, amt;
292
293 KASSERT(sndbuf_getsize(b) > 0, ("bufsize == 0"));
294 CHN_LOCKASSERT(c);
295
296 old = sndbuf_gethwptr(b);
297 hwptr = chn_getptr(c);
298 delta = (sndbuf_getsize(b) + hwptr - old) % sndbuf_getsize(b);
299 sndbuf_sethwptr(b, hwptr);
300
301 DEB(
302 if (delta >= ((sndbuf_getsize(b) * 15) / 16)) {
303 if (!(c->flags & (CHN_F_CLOSING | CHN_F_ABORTING)))
304 device_printf(c->dev, "hwptr went backwards %d -> %d\n", old, hwptr);
305 }
306 );
307
308 if (c->direction == PCMDIR_PLAY) {
309 amt = min(delta, sndbuf_getready(b));
310 amt -= amt % sndbuf_getbps(b);
311 if (amt > 0)
312 sndbuf_dispose(b, NULL, amt);
313 } else {
314 amt = min(delta, sndbuf_getfree(b));
315 amt -= amt % sndbuf_getbps(b);
316 if (amt > 0)
317 sndbuf_acquire(b, NULL, amt);
318 }
319 if (snd_verbose > 3 && CHN_STARTED(c) && delta == 0) {
320 device_printf(c->dev, "WARNING: %s DMA completion "
321 "too fast/slow ! hwptr=%u, old=%u "
322 "delta=%u amt=%u ready=%u free=%u\n",
323 CHN_DIRSTR(c), hwptr, old, delta, amt,
324 sndbuf_getready(b), sndbuf_getfree(b));
325 }
326
327 return delta;
328}
329
330void
331chn_wrupdate(struct pcm_channel *c)
332{
333 int ret;
334
335 CHN_LOCKASSERT(c);
336 KASSERT(c->direction == PCMDIR_PLAY, ("chn_wrupdate on bad channel"));
337
338 if ((c->flags & (CHN_F_MAPPED | CHN_F_VIRTUAL)) || CHN_STOPPED(c))
339 return;
340 chn_dmaupdate(c);
341 ret = chn_wrfeed(c);
342 /* tell the driver we've updated the primary buffer */
343 chn_trigger(c, PCMTRIG_EMLDMAWR);
344 DEB(if (ret)
345 printf("chn_wrupdate: chn_wrfeed returned %d\n", ret);)
346
347}
348
349int
350chn_wrfeed(struct pcm_channel *c)
351{
352 struct snd_dbuf *b = c->bufhard;
353 struct snd_dbuf *bs = c->bufsoft;
354 unsigned int ret, amt;
355
356 CHN_LOCKASSERT(c);
357#if 0
358 DEB(
359 if (c->flags & CHN_F_CLOSING) {
360 sndbuf_dump(b, "b", 0x02);
361 sndbuf_dump(bs, "bs", 0x02);
362 })
363#endif
364
365 if ((c->flags & CHN_F_MAPPED) && !(c->flags & CHN_F_CLOSING))
366 sndbuf_acquire(bs, NULL, sndbuf_getfree(bs));
367
368 amt = sndbuf_getfree(b);
369 DEB(if (amt > sndbuf_getsize(bs) &&
370 sndbuf_getbps(bs) >= sndbuf_getbps(b)) {
371 printf("%s(%s): amt %d > source size %d, flags 0x%x", __func__, c->name,
372 amt, sndbuf_getsize(bs), c->flags);
373 });
374
375 ret = (amt > 0) ? sndbuf_feed(bs, b, c, c->feeder, amt) : ENOSPC;
376 /*
377 * Possible xruns. There should be no empty space left in buffer.
378 */
379 if (sndbuf_getfree(b) > 0)
380 c->xruns++;
381
382 if (sndbuf_getfree(b) < amt)
383 chn_wakeup(c);
384
385 return ret;
386}
387
388static void
389chn_wrintr(struct pcm_channel *c)
390{
391 int ret;
392
393 CHN_LOCKASSERT(c);
394 /* update pointers in primary buffer */
395 chn_dmaupdate(c);
396 /* ...and feed from secondary to primary */
397 ret = chn_wrfeed(c);
398 /* tell the driver we've updated the primary buffer */
399 chn_trigger(c, PCMTRIG_EMLDMAWR);
400 DEB(if (ret)
401 printf("chn_wrintr: chn_wrfeed returned %d\n", ret);)
402}
403
404/*
405 * user write routine - uiomove data into secondary buffer, trigger if necessary
406 * if blocking, sleep, rinse and repeat.
407 *
408 * called externally, so must handle locking
409 */
410
411int
412chn_write(struct pcm_channel *c, struct uio *buf)
413{
414 struct snd_dbuf *bs = c->bufsoft;
415 void *off;
416 int ret, timeout, sz, t, p;
417
418 CHN_LOCKASSERT(c);
419
420 ret = 0;
421 timeout = chn_timeout * hz;
422
423 while (ret == 0 && buf->uio_resid > 0) {
424 sz = min(buf->uio_resid, sndbuf_getfree(bs));
425 if (sz > 0) {
426 /*
427 * The following assumes that the free space in
428 * the buffer can never be less around the
429 * unlock-uiomove-lock sequence.
430 */
431 while (ret == 0 && sz > 0) {
432 p = sndbuf_getfreeptr(bs);
433 t = min(sz, sndbuf_getsize(bs) - p);
434 off = sndbuf_getbufofs(bs, p);
435 CHN_UNLOCK(c);
436 ret = uiomove(off, t, buf);
437 CHN_LOCK(c);
438 sz -= t;
439 sndbuf_acquire(bs, NULL, t);
440 }
441 ret = 0;
442 if (CHN_STOPPED(c))
443 chn_start(c, 0);
444 } else if (c->flags & (CHN_F_NBIO | CHN_F_NOTRIGGER)) {
445 /**
446 * @todo Evaluate whether EAGAIN is truly desirable.
447 * 4Front drivers behave like this, but I'm
448 * not sure if it at all violates the "write
449 * should be allowed to block" model.
450 *
451 * The idea is that, while set with CHN_F_NOTRIGGER,
452 * a channel isn't playing, *but* without this we
453 * end up with "interrupt timeout / channel dead".
454 */
455 ret = EAGAIN;
456 } else {
457 ret = chn_sleep(c, "pcmwr", timeout);
458 if (ret == EAGAIN) {
459 ret = EINVAL;
460 c->flags |= CHN_F_DEAD;
461 printf("%s: play interrupt timeout, "
462 "channel dead\n", c->name);
463 } else if (ret == ERESTART || ret == EINTR)
464 c->flags |= CHN_F_ABORTING;
465 }
466 }
467
468 return ret;
469}
470
471#if 0
472static int
473chn_rddump(struct pcm_channel *c, unsigned int cnt)
474{
475 struct snd_dbuf *b = c->bufhard;
476
477 CHN_LOCKASSERT(c);
478#if 0
479 static u_int32_t kk = 0;
480 printf("%u: dumping %d bytes\n", ++kk, cnt);
481#endif
482 c->xruns++;
483 sndbuf_setxrun(b, sndbuf_getxrun(b) + cnt);
484 return sndbuf_dispose(b, NULL, cnt);
485}
486#endif
487
488/*
489 * Feed new data from the read buffer. Can be called in the bottom half.
490 */
491int
492chn_rdfeed(struct pcm_channel *c)
493{
494 struct snd_dbuf *b = c->bufhard;
495 struct snd_dbuf *bs = c->bufsoft;
496 unsigned int ret, amt;
497
498 CHN_LOCKASSERT(c);
499 DEB(
500 if (c->flags & CHN_F_CLOSING) {
501 sndbuf_dump(b, "b", 0x02);
502 sndbuf_dump(bs, "bs", 0x02);
503 })
504
505#if 0
506 amt = sndbuf_getready(b);
507 if (sndbuf_getfree(bs) < amt) {
508 c->xruns++;
509 amt = sndbuf_getfree(bs);
510 }
511#endif
512 amt = sndbuf_getfree(bs);
500 ret = (amt > 0) ? sndbuf_feed(b, bs, c, c->feeder, amt) : 0;
513 ret = (amt > 0) ? sndbuf_feed(b, bs, c, c->feeder, amt) : ENOSPC;
501
502 amt = sndbuf_getready(b);
503 if (amt > 0) {
504 c->xruns++;
505 sndbuf_dispose(b, NULL, amt);
506 }
507
508 if (sndbuf_getready(bs) > 0)
509 chn_wakeup(c);
510
511 return ret;
512}
513
514void
515chn_rdupdate(struct pcm_channel *c)
516{
517 int ret;
518
519 CHN_LOCKASSERT(c);
520 KASSERT(c->direction == PCMDIR_REC, ("chn_rdupdate on bad channel"));
521
514
515 amt = sndbuf_getready(b);
516 if (amt > 0) {
517 c->xruns++;
518 sndbuf_dispose(b, NULL, amt);
519 }
520
521 if (sndbuf_getready(bs) > 0)
522 chn_wakeup(c);
523
524 return ret;
525}
526
527void
528chn_rdupdate(struct pcm_channel *c)
529{
530 int ret;
531
532 CHN_LOCKASSERT(c);
533 KASSERT(c->direction == PCMDIR_REC, ("chn_rdupdate on bad channel"));
534
522 if ((c->flags & CHN_F_MAPPED) || CHN_STOPPED(c))
535 if ((c->flags & (CHN_F_MAPPED | CHN_F_VIRTUAL)) || CHN_STOPPED(c))
523 return;
524 chn_trigger(c, PCMTRIG_EMLDMARD);
525 chn_dmaupdate(c);
526 ret = chn_rdfeed(c);
527 DEB(if (ret)
528 printf("chn_rdfeed: %d\n", ret);)
529
530}
531
532/* read interrupt routine. Must be called with interrupts blocked. */
533static void
534chn_rdintr(struct pcm_channel *c)
535{
536 int ret;
537
538 CHN_LOCKASSERT(c);
539 /* tell the driver to update the primary buffer if non-dma */
540 chn_trigger(c, PCMTRIG_EMLDMARD);
541 /* update pointers in primary buffer */
542 chn_dmaupdate(c);
543 /* ...and feed from primary to secondary */
544 ret = chn_rdfeed(c);
545}
546
547/*
548 * user read routine - trigger if necessary, uiomove data from secondary buffer
549 * if blocking, sleep, rinse and repeat.
550 *
551 * called externally, so must handle locking
552 */
553
554int
555chn_read(struct pcm_channel *c, struct uio *buf)
556{
557 struct snd_dbuf *bs = c->bufsoft;
558 void *off;
559 int ret, timeout, sz, t, p;
560
561 CHN_LOCKASSERT(c);
562
563 if (CHN_STOPPED(c))
564 chn_start(c, 0);
565
566 ret = 0;
567 timeout = chn_timeout * hz;
568
569 while (ret == 0 && buf->uio_resid > 0) {
570 sz = min(buf->uio_resid, sndbuf_getready(bs));
571 if (sz > 0) {
572 /*
573 * The following assumes that the free space in
574 * the buffer can never be less around the
575 * unlock-uiomove-lock sequence.
576 */
577 while (ret == 0 && sz > 0) {
578 p = sndbuf_getreadyptr(bs);
579 t = min(sz, sndbuf_getsize(bs) - p);
580 off = sndbuf_getbufofs(bs, p);
581 CHN_UNLOCK(c);
582 ret = uiomove(off, t, buf);
583 CHN_LOCK(c);
584 sz -= t;
585 sndbuf_dispose(bs, NULL, t);
586 }
587 ret = 0;
588 } else if (c->flags & (CHN_F_NBIO | CHN_F_NOTRIGGER))
589 ret = EAGAIN;
590 else {
591 ret = chn_sleep(c, "pcmrd", timeout);
592 if (ret == EAGAIN) {
593 ret = EINVAL;
594 c->flags |= CHN_F_DEAD;
595 printf("%s: record interrupt timeout, "
596 "channel dead\n", c->name);
597 } else if (ret == ERESTART || ret == EINTR)
598 c->flags |= CHN_F_ABORTING;
599 }
600 }
601
602 return ret;
603}
604
605void
606chn_intr(struct pcm_channel *c)
607{
608 CHN_LOCK(c);
609 c->interrupts++;
610 if (c->direction == PCMDIR_PLAY)
611 chn_wrintr(c);
612 else
613 chn_rdintr(c);
614 CHN_UNLOCK(c);
615}
616
617u_int32_t
618chn_start(struct pcm_channel *c, int force)
619{
620 u_int32_t i, j;
621 struct snd_dbuf *b = c->bufhard;
622 struct snd_dbuf *bs = c->bufsoft;
623
624 CHN_LOCKASSERT(c);
625 /* if we're running, or if we're prevented from triggering, bail */
626 if (CHN_STARTED(c) || ((c->flags & CHN_F_NOTRIGGER) && !force))
627 return EINVAL;
628
629 if (force) {
630 i = 1;
631 j = 0;
632 } else {
633 if (c->direction == PCMDIR_REC) {
634 i = sndbuf_getfree(bs);
635 j = (i > 0) ? 1 : sndbuf_getready(b);
636 } else {
637 if (sndbuf_getfree(bs) == 0) {
638 i = 1;
639 j = 0;
640 } else {
641 struct snd_dbuf *pb;
642
643 pb = BUF_PARENT(c, b);
644 i = sndbuf_xbytes(sndbuf_getready(bs), bs, pb);
645 j = sndbuf_getbps(pb);
646 }
647 }
536 return;
537 chn_trigger(c, PCMTRIG_EMLDMARD);
538 chn_dmaupdate(c);
539 ret = chn_rdfeed(c);
540 DEB(if (ret)
541 printf("chn_rdfeed: %d\n", ret);)
542
543}
544
545/* read interrupt routine. Must be called with interrupts blocked. */
546static void
547chn_rdintr(struct pcm_channel *c)
548{
549 int ret;
550
551 CHN_LOCKASSERT(c);
552 /* tell the driver to update the primary buffer if non-dma */
553 chn_trigger(c, PCMTRIG_EMLDMARD);
554 /* update pointers in primary buffer */
555 chn_dmaupdate(c);
556 /* ...and feed from primary to secondary */
557 ret = chn_rdfeed(c);
558}
559
560/*
561 * user read routine - trigger if necessary, uiomove data from secondary buffer
562 * if blocking, sleep, rinse and repeat.
563 *
564 * called externally, so must handle locking
565 */
566
567int
568chn_read(struct pcm_channel *c, struct uio *buf)
569{
570 struct snd_dbuf *bs = c->bufsoft;
571 void *off;
572 int ret, timeout, sz, t, p;
573
574 CHN_LOCKASSERT(c);
575
576 if (CHN_STOPPED(c))
577 chn_start(c, 0);
578
579 ret = 0;
580 timeout = chn_timeout * hz;
581
582 while (ret == 0 && buf->uio_resid > 0) {
583 sz = min(buf->uio_resid, sndbuf_getready(bs));
584 if (sz > 0) {
585 /*
586 * The following assumes that the free space in
587 * the buffer can never be less around the
588 * unlock-uiomove-lock sequence.
589 */
590 while (ret == 0 && sz > 0) {
591 p = sndbuf_getreadyptr(bs);
592 t = min(sz, sndbuf_getsize(bs) - p);
593 off = sndbuf_getbufofs(bs, p);
594 CHN_UNLOCK(c);
595 ret = uiomove(off, t, buf);
596 CHN_LOCK(c);
597 sz -= t;
598 sndbuf_dispose(bs, NULL, t);
599 }
600 ret = 0;
601 } else if (c->flags & (CHN_F_NBIO | CHN_F_NOTRIGGER))
602 ret = EAGAIN;
603 else {
604 ret = chn_sleep(c, "pcmrd", timeout);
605 if (ret == EAGAIN) {
606 ret = EINVAL;
607 c->flags |= CHN_F_DEAD;
608 printf("%s: record interrupt timeout, "
609 "channel dead\n", c->name);
610 } else if (ret == ERESTART || ret == EINTR)
611 c->flags |= CHN_F_ABORTING;
612 }
613 }
614
615 return ret;
616}
617
618void
619chn_intr(struct pcm_channel *c)
620{
621 CHN_LOCK(c);
622 c->interrupts++;
623 if (c->direction == PCMDIR_PLAY)
624 chn_wrintr(c);
625 else
626 chn_rdintr(c);
627 CHN_UNLOCK(c);
628}
629
630u_int32_t
631chn_start(struct pcm_channel *c, int force)
632{
633 u_int32_t i, j;
634 struct snd_dbuf *b = c->bufhard;
635 struct snd_dbuf *bs = c->bufsoft;
636
637 CHN_LOCKASSERT(c);
638 /* if we're running, or if we're prevented from triggering, bail */
639 if (CHN_STARTED(c) || ((c->flags & CHN_F_NOTRIGGER) && !force))
640 return EINVAL;
641
642 if (force) {
643 i = 1;
644 j = 0;
645 } else {
646 if (c->direction == PCMDIR_REC) {
647 i = sndbuf_getfree(bs);
648 j = (i > 0) ? 1 : sndbuf_getready(b);
649 } else {
650 if (sndbuf_getfree(bs) == 0) {
651 i = 1;
652 j = 0;
653 } else {
654 struct snd_dbuf *pb;
655
656 pb = BUF_PARENT(c, b);
657 i = sndbuf_xbytes(sndbuf_getready(bs), bs, pb);
658 j = sndbuf_getbps(pb);
659 }
660 }
648 if (snd_verbose > 3 && SLIST_EMPTY(&c->children))
661 if (snd_verbose > 3 && CHN_EMPTY(c, children))
649 printf("%s: %s (%s) threshold i=%d j=%d\n",
650 __func__, CHN_DIRSTR(c),
651 (c->flags & CHN_F_VIRTUAL) ? "virtual" : "hardware",
652 i, j);
653 }
654
655 if (i >= j) {
656 c->flags |= CHN_F_TRIGGERED;
657 sndbuf_setrun(b, 1);
658 c->feedcount = (c->flags & CHN_F_CLOSING) ? 2 : 0;
659 c->interrupts = 0;
660 c->xruns = 0;
661 if (c->direction == PCMDIR_PLAY && c->parentchannel == NULL) {
662 sndbuf_fillsilence(b);
663 if (snd_verbose > 3)
664 printf("%s: %s starting! (%s) (ready=%d "
665 "force=%d i=%d j=%d intrtimeout=%u "
666 "latency=%dms)\n",
667 __func__,
668 (c->flags & CHN_F_HAS_VCHAN) ?
669 "VCHAN" : "HW",
670 (c->flags & CHN_F_CLOSING) ? "closing" :
671 "running",
672 sndbuf_getready(b),
673 force, i, j, c->timeout,
674 (sndbuf_getsize(b) * 1000) /
675 (sndbuf_getbps(b) * sndbuf_getspd(b)));
676 }
677 chn_trigger(c, PCMTRIG_START);
678 return 0;
679 }
680
681 return 0;
682}
683
684void
685chn_resetbuf(struct pcm_channel *c)
686{
687 struct snd_dbuf *b = c->bufhard;
688 struct snd_dbuf *bs = c->bufsoft;
689
690 c->blocks = 0;
691 sndbuf_reset(b);
692 sndbuf_reset(bs);
693}
694
695/*
696 * chn_sync waits until the space in the given channel goes above
697 * a threshold. The threshold is checked against fl or rl respectively.
698 * Assume that the condition can become true, do not check here...
699 */
700int
701chn_sync(struct pcm_channel *c, int threshold)
702{
703 struct snd_dbuf *b, *bs;
704 int ret, count, hcount, minflush, resid, residp, syncdelay, blksz;
705 u_int32_t cflag;
706
707 CHN_LOCKASSERT(c);
708
709 bs = c->bufsoft;
710
711 if ((c->flags & (CHN_F_DEAD | CHN_F_ABORTING)) ||
712 (threshold < 1 && sndbuf_getready(bs) < 1))
713 return 0;
714
715 if (c->direction != PCMDIR_PLAY)
716 return EINVAL;
717
718 /* if we haven't yet started and nothing is buffered, else start*/
719 if (CHN_STOPPED(c)) {
720 if (threshold > 0 || sndbuf_getready(bs) > 0) {
721 ret = chn_start(c, 1);
722 if (ret)
723 return ret;
724 } else
725 return 0;
726 }
727
728 b = BUF_PARENT(c, c->bufhard);
729
730 minflush = threshold + sndbuf_xbytes(sndbuf_getready(b), b, bs);
731
732 syncdelay = chn_syncdelay;
733
734 if (syncdelay < 0 && (threshold > 0 || sndbuf_getready(bs) > 0))
735 minflush += sndbuf_xbytes(sndbuf_getsize(b), b, bs);
736
737 /*
738 * Append (0-1000) millisecond trailing buffer (if needed)
739 * for slower / high latency hardwares (notably USB audio)
740 * to avoid audible truncation.
741 */
742 if (syncdelay > 0)
743 minflush += (sndbuf_getbps(bs) * sndbuf_getspd(bs) *
744 ((syncdelay > 1000) ? 1000 : syncdelay)) / 1000;
745
746 minflush -= minflush % sndbuf_getbps(bs);
747
748 if (minflush > 0) {
749 threshold = min(minflush, sndbuf_getfree(bs));
750 sndbuf_clear(bs, threshold);
751 sndbuf_acquire(bs, NULL, threshold);
752 minflush -= threshold;
753 }
754
755 resid = sndbuf_getready(bs);
756 residp = resid;
757 blksz = sndbuf_getblksz(b);
758 if (blksz < 1) {
759 printf("%s: WARNING: blksz < 1 ! maxsize=%d [%d/%d/%d]\n",
760 __func__, sndbuf_getmaxsize(b), sndbuf_getsize(b),
761 sndbuf_getblksz(b), sndbuf_getblkcnt(b));
762 if (sndbuf_getblkcnt(b) > 0)
763 blksz = sndbuf_getsize(b) / sndbuf_getblkcnt(b);
764 if (blksz < 1)
765 blksz = 1;
766 }
767 count = sndbuf_xbytes(minflush + resid, bs, b) / blksz;
768 hcount = count;
769 ret = 0;
770
771 if (snd_verbose > 3)
772 printf("%s: [begin] timeout=%d count=%d "
773 "minflush=%d resid=%d\n", __func__, c->timeout, count,
774 minflush, resid);
775
776 cflag = c->flags & CHN_F_CLOSING;
777 c->flags |= CHN_F_CLOSING;
778 while (count > 0 && (resid > 0 || minflush > 0)) {
779 ret = chn_sleep(c, "pcmsyn", c->timeout);
780 if (ret == ERESTART || ret == EINTR) {
781 c->flags |= CHN_F_ABORTING;
782 break;
783 }
784 if (ret == 0 || ret == EAGAIN) {
785 resid = sndbuf_getready(bs);
786 if (resid == residp) {
787 --count;
788 if (snd_verbose > 3)
789 printf("%s: [stalled] timeout=%d "
790 "count=%d hcount=%d "
791 "resid=%d minflush=%d\n",
792 __func__, c->timeout, count,
793 hcount, resid, minflush);
794 } else if (resid < residp && count < hcount) {
795 ++count;
796 if (snd_verbose > 3)
797 printf("%s: [resume] timeout=%d "
798 "count=%d hcount=%d "
799 "resid=%d minflush=%d\n",
800 __func__, c->timeout, count,
801 hcount, resid, minflush);
802 }
803 if (minflush > 0 && sndbuf_getfree(bs) > 0) {
804 threshold = min(minflush,
805 sndbuf_getfree(bs));
806 sndbuf_clear(bs, threshold);
807 sndbuf_acquire(bs, NULL, threshold);
808 resid = sndbuf_getready(bs);
809 minflush -= threshold;
810 }
811 residp = resid;
812 }
813 }
814 c->flags &= ~CHN_F_CLOSING;
815 c->flags |= cflag;
816
817 if (snd_verbose > 3)
818 printf("%s: timeout=%d count=%d hcount=%d resid=%d residp=%d "
819 "minflush=%d ret=%d\n",
820 __func__, c->timeout, count, hcount, resid, residp,
821 minflush, ret);
822
823 return 0;
824}
825
826/* called externally, handle locking */
827int
828chn_poll(struct pcm_channel *c, int ev, struct thread *td)
829{
830 struct snd_dbuf *bs = c->bufsoft;
831 int ret;
832
833 CHN_LOCKASSERT(c);
834 if (!(c->flags & (CHN_F_MAPPED | CHN_F_TRIGGERED)))
835 chn_start(c, 1);
836 ret = 0;
837 if (chn_polltrigger(c) && chn_pollreset(c))
838 ret = ev;
839 else
840 selrecord(td, sndbuf_getsel(bs));
841 return ret;
842}
843
844/*
845 * chn_abort terminates a running dma transfer. it may sleep up to 200ms.
846 * it returns the number of bytes that have not been transferred.
847 *
848 * called from: dsp_close, dsp_ioctl, with channel locked
849 */
850int
851chn_abort(struct pcm_channel *c)
852{
853 int missing = 0;
854 struct snd_dbuf *b = c->bufhard;
855 struct snd_dbuf *bs = c->bufsoft;
856
857 CHN_LOCKASSERT(c);
858 if (CHN_STOPPED(c))
859 return 0;
860 c->flags |= CHN_F_ABORTING;
861
862 c->flags &= ~CHN_F_TRIGGERED;
863 /* kill the channel */
864 chn_trigger(c, PCMTRIG_ABORT);
865 sndbuf_setrun(b, 0);
866 if (!(c->flags & CHN_F_VIRTUAL))
867 chn_dmaupdate(c);
868 missing = sndbuf_getready(bs);
869
870 c->flags &= ~CHN_F_ABORTING;
871 return missing;
872}
873
874/*
875 * this routine tries to flush the dma transfer. It is called
876 * on a close of a playback channel.
877 * first, if there is data in the buffer, but the dma has not yet
878 * begun, we need to start it.
879 * next, we wait for the play buffer to drain
880 * finally, we stop the dma.
881 *
882 * called from: dsp_close, not valid for record channels.
883 */
884
885int
886chn_flush(struct pcm_channel *c)
887{
888 struct snd_dbuf *b = c->bufhard;
889
890 CHN_LOCKASSERT(c);
891 KASSERT(c->direction == PCMDIR_PLAY, ("chn_flush on bad channel"));
892 DEB(printf("chn_flush: c->flags 0x%08x\n", c->flags));
893
894 c->flags |= CHN_F_CLOSING;
895 chn_sync(c, 0);
896 c->flags &= ~CHN_F_TRIGGERED;
897 /* kill the channel */
898 chn_trigger(c, PCMTRIG_ABORT);
899 sndbuf_setrun(b, 0);
900
901 c->flags &= ~CHN_F_CLOSING;
902 return 0;
903}
904
905int
906fmtvalid(u_int32_t fmt, u_int32_t *fmtlist)
907{
908 int i;
909
910 for (i = 0; fmtlist[i]; i++)
911 if (fmt == fmtlist[i])
912 return 1;
913 return 0;
914}
915
916static struct afmtstr_table default_afmtstr_table[] = {
917 { "alaw", AFMT_A_LAW }, { "mulaw", AFMT_MU_LAW },
918 { "u8", AFMT_U8 }, { "s8", AFMT_S8 },
919 { "s16le", AFMT_S16_LE }, { "s16be", AFMT_S16_BE },
920 { "u16le", AFMT_U16_LE }, { "u16be", AFMT_U16_BE },
921 { "s24le", AFMT_S24_LE }, { "s24be", AFMT_S24_BE },
922 { "u24le", AFMT_U24_LE }, { "u24be", AFMT_U24_BE },
923 { "s32le", AFMT_S32_LE }, { "s32be", AFMT_S32_BE },
924 { "u32le", AFMT_U32_LE }, { "u32be", AFMT_U32_BE },
925 { NULL, 0 },
926};
927
928int
929afmtstr_swap_sign(char *s)
930{
931 if (s == NULL || strlen(s) < 2) /* full length of "s8" */
932 return 0;
933 if (*s == 's')
934 *s = 'u';
935 else if (*s == 'u')
936 *s = 's';
937 else
938 return 0;
939 return 1;
940}
941
942int
943afmtstr_swap_endian(char *s)
944{
945 if (s == NULL || strlen(s) < 5) /* full length of "s16le" */
946 return 0;
947 if (s[3] == 'l')
948 s[3] = 'b';
949 else if (s[3] == 'b')
950 s[3] = 'l';
951 else
952 return 0;
953 return 1;
954}
955
956u_int32_t
957afmtstr2afmt(struct afmtstr_table *tbl, const char *s, int stereo)
958{
959 size_t fsz, sz;
960
961 sz = (s == NULL) ? 0 : strlen(s);
962
963 if (sz > 1) {
964
965 if (tbl == NULL)
966 tbl = default_afmtstr_table;
967
968 for (; tbl->fmtstr != NULL; tbl++) {
969 fsz = strlen(tbl->fmtstr);
970 if (sz < fsz)
971 continue;
972 if (strncmp(s, tbl->fmtstr, fsz) != 0)
973 continue;
974 if (fsz == sz)
975 return tbl->format |
976 ((stereo) ? AFMT_STEREO : 0);
977 if ((sz - fsz) < 2 || s[fsz] != ':')
978 break;
979 /*
980 * For now, just handle mono/stereo.
981 */
982 if ((s[fsz + 2] == '\0' && (s[fsz + 1] == 'm' ||
983 s[fsz + 1] == '1')) ||
984 strcmp(s + fsz + 1, "mono") == 0)
985 return tbl->format;
986 if ((s[fsz + 2] == '\0' && (s[fsz + 1] == 's' ||
987 s[fsz + 1] == '2')) ||
988 strcmp(s + fsz + 1, "stereo") == 0)
989 return tbl->format | AFMT_STEREO;
990 break;
991 }
992 }
993
994 return 0;
995}
996
997u_int32_t
998afmt2afmtstr(struct afmtstr_table *tbl, u_int32_t afmt, char *dst,
999 size_t len, int type, int stereo)
1000{
1001 u_int32_t fmt = 0;
1002 char *fmtstr = NULL, *tag = "";
1003
1004 if (tbl == NULL)
1005 tbl = default_afmtstr_table;
1006
1007 for (; tbl->format != 0; tbl++) {
1008 if (tbl->format == 0)
1009 break;
1010 if ((afmt & ~AFMT_STEREO) != tbl->format)
1011 continue;
1012 fmt = afmt;
1013 fmtstr = tbl->fmtstr;
1014 break;
1015 }
1016
1017 if (fmt != 0 && fmtstr != NULL && dst != NULL && len > 0) {
1018 strlcpy(dst, fmtstr, len);
1019 switch (type) {
1020 case AFMTSTR_SIMPLE:
1021 tag = (fmt & AFMT_STEREO) ? ":s" : ":m";
1022 break;
1023 case AFMTSTR_NUM:
1024 tag = (fmt & AFMT_STEREO) ? ":2" : ":1";
1025 break;
1026 case AFMTSTR_FULL:
1027 tag = (fmt & AFMT_STEREO) ? ":stereo" : ":mono";
1028 break;
1029 case AFMTSTR_NONE:
1030 default:
1031 break;
1032 }
1033 if (strlen(tag) > 0 && ((stereo && !(fmt & AFMT_STEREO)) || \
1034 (!stereo && (fmt & AFMT_STEREO))))
1035 strlcat(dst, tag, len);
1036 }
1037
1038 return fmt;
1039}
1040
1041int
1042chn_reset(struct pcm_channel *c, u_int32_t fmt)
1043{
1044 int hwspd, r;
1045
1046 CHN_LOCKASSERT(c);
1047 c->feedcount = 0;
1048 c->flags &= CHN_F_RESET;
1049 c->interrupts = 0;
1050 c->timeout = 1;
1051 c->xruns = 0;
1052
1053 r = CHANNEL_RESET(c->methods, c->devinfo);
1054 if (fmt != 0) {
1055#if 0
1056 hwspd = DSP_DEFAULT_SPEED;
1057 /* only do this on a record channel until feederbuilder works */
1058 if (c->direction == PCMDIR_REC)
1059 RANGE(hwspd, chn_getcaps(c)->minspeed, chn_getcaps(c)->maxspeed);
1060 c->speed = hwspd;
1061#endif
1062 hwspd = chn_getcaps(c)->minspeed;
1063 c->speed = hwspd;
1064
1065 if (r == 0)
1066 r = chn_setformat(c, fmt);
1067 if (r == 0)
1068 r = chn_setspeed(c, hwspd);
1069#if 0
1070 if (r == 0)
1071 r = chn_setvolume(c, 100, 100);
1072#endif
1073 }
1074 if (r == 0)
1075 r = chn_setlatency(c, chn_latency);
1076 if (r == 0) {
1077 chn_resetbuf(c);
1078 r = CHANNEL_RESETDONE(c->methods, c->devinfo);
1079 }
1080 return r;
1081}
1082
1083int
1084chn_init(struct pcm_channel *c, void *devinfo, int dir, int direction)
1085{
1086 struct feeder_class *fc;
1087 struct snd_dbuf *b, *bs;
1088 int ret;
1089
1090 if (chn_timeout < CHN_TIMEOUT_MIN || chn_timeout > CHN_TIMEOUT_MAX)
1091 chn_timeout = CHN_TIMEOUT;
1092
1093 chn_lockinit(c, dir);
1094
1095 b = NULL;
1096 bs = NULL;
662 printf("%s: %s (%s) threshold i=%d j=%d\n",
663 __func__, CHN_DIRSTR(c),
664 (c->flags & CHN_F_VIRTUAL) ? "virtual" : "hardware",
665 i, j);
666 }
667
668 if (i >= j) {
669 c->flags |= CHN_F_TRIGGERED;
670 sndbuf_setrun(b, 1);
671 c->feedcount = (c->flags & CHN_F_CLOSING) ? 2 : 0;
672 c->interrupts = 0;
673 c->xruns = 0;
674 if (c->direction == PCMDIR_PLAY && c->parentchannel == NULL) {
675 sndbuf_fillsilence(b);
676 if (snd_verbose > 3)
677 printf("%s: %s starting! (%s) (ready=%d "
678 "force=%d i=%d j=%d intrtimeout=%u "
679 "latency=%dms)\n",
680 __func__,
681 (c->flags & CHN_F_HAS_VCHAN) ?
682 "VCHAN" : "HW",
683 (c->flags & CHN_F_CLOSING) ? "closing" :
684 "running",
685 sndbuf_getready(b),
686 force, i, j, c->timeout,
687 (sndbuf_getsize(b) * 1000) /
688 (sndbuf_getbps(b) * sndbuf_getspd(b)));
689 }
690 chn_trigger(c, PCMTRIG_START);
691 return 0;
692 }
693
694 return 0;
695}
696
697void
698chn_resetbuf(struct pcm_channel *c)
699{
700 struct snd_dbuf *b = c->bufhard;
701 struct snd_dbuf *bs = c->bufsoft;
702
703 c->blocks = 0;
704 sndbuf_reset(b);
705 sndbuf_reset(bs);
706}
707
708/*
709 * chn_sync waits until the space in the given channel goes above
710 * a threshold. The threshold is checked against fl or rl respectively.
711 * Assume that the condition can become true, do not check here...
712 */
713int
714chn_sync(struct pcm_channel *c, int threshold)
715{
716 struct snd_dbuf *b, *bs;
717 int ret, count, hcount, minflush, resid, residp, syncdelay, blksz;
718 u_int32_t cflag;
719
720 CHN_LOCKASSERT(c);
721
722 bs = c->bufsoft;
723
724 if ((c->flags & (CHN_F_DEAD | CHN_F_ABORTING)) ||
725 (threshold < 1 && sndbuf_getready(bs) < 1))
726 return 0;
727
728 if (c->direction != PCMDIR_PLAY)
729 return EINVAL;
730
731 /* if we haven't yet started and nothing is buffered, else start*/
732 if (CHN_STOPPED(c)) {
733 if (threshold > 0 || sndbuf_getready(bs) > 0) {
734 ret = chn_start(c, 1);
735 if (ret)
736 return ret;
737 } else
738 return 0;
739 }
740
741 b = BUF_PARENT(c, c->bufhard);
742
743 minflush = threshold + sndbuf_xbytes(sndbuf_getready(b), b, bs);
744
745 syncdelay = chn_syncdelay;
746
747 if (syncdelay < 0 && (threshold > 0 || sndbuf_getready(bs) > 0))
748 minflush += sndbuf_xbytes(sndbuf_getsize(b), b, bs);
749
750 /*
751 * Append (0-1000) millisecond trailing buffer (if needed)
752 * for slower / high latency hardwares (notably USB audio)
753 * to avoid audible truncation.
754 */
755 if (syncdelay > 0)
756 minflush += (sndbuf_getbps(bs) * sndbuf_getspd(bs) *
757 ((syncdelay > 1000) ? 1000 : syncdelay)) / 1000;
758
759 minflush -= minflush % sndbuf_getbps(bs);
760
761 if (minflush > 0) {
762 threshold = min(minflush, sndbuf_getfree(bs));
763 sndbuf_clear(bs, threshold);
764 sndbuf_acquire(bs, NULL, threshold);
765 minflush -= threshold;
766 }
767
768 resid = sndbuf_getready(bs);
769 residp = resid;
770 blksz = sndbuf_getblksz(b);
771 if (blksz < 1) {
772 printf("%s: WARNING: blksz < 1 ! maxsize=%d [%d/%d/%d]\n",
773 __func__, sndbuf_getmaxsize(b), sndbuf_getsize(b),
774 sndbuf_getblksz(b), sndbuf_getblkcnt(b));
775 if (sndbuf_getblkcnt(b) > 0)
776 blksz = sndbuf_getsize(b) / sndbuf_getblkcnt(b);
777 if (blksz < 1)
778 blksz = 1;
779 }
780 count = sndbuf_xbytes(minflush + resid, bs, b) / blksz;
781 hcount = count;
782 ret = 0;
783
784 if (snd_verbose > 3)
785 printf("%s: [begin] timeout=%d count=%d "
786 "minflush=%d resid=%d\n", __func__, c->timeout, count,
787 minflush, resid);
788
789 cflag = c->flags & CHN_F_CLOSING;
790 c->flags |= CHN_F_CLOSING;
791 while (count > 0 && (resid > 0 || minflush > 0)) {
792 ret = chn_sleep(c, "pcmsyn", c->timeout);
793 if (ret == ERESTART || ret == EINTR) {
794 c->flags |= CHN_F_ABORTING;
795 break;
796 }
797 if (ret == 0 || ret == EAGAIN) {
798 resid = sndbuf_getready(bs);
799 if (resid == residp) {
800 --count;
801 if (snd_verbose > 3)
802 printf("%s: [stalled] timeout=%d "
803 "count=%d hcount=%d "
804 "resid=%d minflush=%d\n",
805 __func__, c->timeout, count,
806 hcount, resid, minflush);
807 } else if (resid < residp && count < hcount) {
808 ++count;
809 if (snd_verbose > 3)
810 printf("%s: [resume] timeout=%d "
811 "count=%d hcount=%d "
812 "resid=%d minflush=%d\n",
813 __func__, c->timeout, count,
814 hcount, resid, minflush);
815 }
816 if (minflush > 0 && sndbuf_getfree(bs) > 0) {
817 threshold = min(minflush,
818 sndbuf_getfree(bs));
819 sndbuf_clear(bs, threshold);
820 sndbuf_acquire(bs, NULL, threshold);
821 resid = sndbuf_getready(bs);
822 minflush -= threshold;
823 }
824 residp = resid;
825 }
826 }
827 c->flags &= ~CHN_F_CLOSING;
828 c->flags |= cflag;
829
830 if (snd_verbose > 3)
831 printf("%s: timeout=%d count=%d hcount=%d resid=%d residp=%d "
832 "minflush=%d ret=%d\n",
833 __func__, c->timeout, count, hcount, resid, residp,
834 minflush, ret);
835
836 return 0;
837}
838
839/* called externally, handle locking */
840int
841chn_poll(struct pcm_channel *c, int ev, struct thread *td)
842{
843 struct snd_dbuf *bs = c->bufsoft;
844 int ret;
845
846 CHN_LOCKASSERT(c);
847 if (!(c->flags & (CHN_F_MAPPED | CHN_F_TRIGGERED)))
848 chn_start(c, 1);
849 ret = 0;
850 if (chn_polltrigger(c) && chn_pollreset(c))
851 ret = ev;
852 else
853 selrecord(td, sndbuf_getsel(bs));
854 return ret;
855}
856
857/*
858 * chn_abort terminates a running dma transfer. it may sleep up to 200ms.
859 * it returns the number of bytes that have not been transferred.
860 *
861 * called from: dsp_close, dsp_ioctl, with channel locked
862 */
863int
864chn_abort(struct pcm_channel *c)
865{
866 int missing = 0;
867 struct snd_dbuf *b = c->bufhard;
868 struct snd_dbuf *bs = c->bufsoft;
869
870 CHN_LOCKASSERT(c);
871 if (CHN_STOPPED(c))
872 return 0;
873 c->flags |= CHN_F_ABORTING;
874
875 c->flags &= ~CHN_F_TRIGGERED;
876 /* kill the channel */
877 chn_trigger(c, PCMTRIG_ABORT);
878 sndbuf_setrun(b, 0);
879 if (!(c->flags & CHN_F_VIRTUAL))
880 chn_dmaupdate(c);
881 missing = sndbuf_getready(bs);
882
883 c->flags &= ~CHN_F_ABORTING;
884 return missing;
885}
886
887/*
888 * this routine tries to flush the dma transfer. It is called
889 * on a close of a playback channel.
890 * first, if there is data in the buffer, but the dma has not yet
891 * begun, we need to start it.
892 * next, we wait for the play buffer to drain
893 * finally, we stop the dma.
894 *
895 * called from: dsp_close, not valid for record channels.
896 */
897
898int
899chn_flush(struct pcm_channel *c)
900{
901 struct snd_dbuf *b = c->bufhard;
902
903 CHN_LOCKASSERT(c);
904 KASSERT(c->direction == PCMDIR_PLAY, ("chn_flush on bad channel"));
905 DEB(printf("chn_flush: c->flags 0x%08x\n", c->flags));
906
907 c->flags |= CHN_F_CLOSING;
908 chn_sync(c, 0);
909 c->flags &= ~CHN_F_TRIGGERED;
910 /* kill the channel */
911 chn_trigger(c, PCMTRIG_ABORT);
912 sndbuf_setrun(b, 0);
913
914 c->flags &= ~CHN_F_CLOSING;
915 return 0;
916}
917
918int
919fmtvalid(u_int32_t fmt, u_int32_t *fmtlist)
920{
921 int i;
922
923 for (i = 0; fmtlist[i]; i++)
924 if (fmt == fmtlist[i])
925 return 1;
926 return 0;
927}
928
929static struct afmtstr_table default_afmtstr_table[] = {
930 { "alaw", AFMT_A_LAW }, { "mulaw", AFMT_MU_LAW },
931 { "u8", AFMT_U8 }, { "s8", AFMT_S8 },
932 { "s16le", AFMT_S16_LE }, { "s16be", AFMT_S16_BE },
933 { "u16le", AFMT_U16_LE }, { "u16be", AFMT_U16_BE },
934 { "s24le", AFMT_S24_LE }, { "s24be", AFMT_S24_BE },
935 { "u24le", AFMT_U24_LE }, { "u24be", AFMT_U24_BE },
936 { "s32le", AFMT_S32_LE }, { "s32be", AFMT_S32_BE },
937 { "u32le", AFMT_U32_LE }, { "u32be", AFMT_U32_BE },
938 { NULL, 0 },
939};
940
941int
942afmtstr_swap_sign(char *s)
943{
944 if (s == NULL || strlen(s) < 2) /* full length of "s8" */
945 return 0;
946 if (*s == 's')
947 *s = 'u';
948 else if (*s == 'u')
949 *s = 's';
950 else
951 return 0;
952 return 1;
953}
954
955int
956afmtstr_swap_endian(char *s)
957{
958 if (s == NULL || strlen(s) < 5) /* full length of "s16le" */
959 return 0;
960 if (s[3] == 'l')
961 s[3] = 'b';
962 else if (s[3] == 'b')
963 s[3] = 'l';
964 else
965 return 0;
966 return 1;
967}
968
969u_int32_t
970afmtstr2afmt(struct afmtstr_table *tbl, const char *s, int stereo)
971{
972 size_t fsz, sz;
973
974 sz = (s == NULL) ? 0 : strlen(s);
975
976 if (sz > 1) {
977
978 if (tbl == NULL)
979 tbl = default_afmtstr_table;
980
981 for (; tbl->fmtstr != NULL; tbl++) {
982 fsz = strlen(tbl->fmtstr);
983 if (sz < fsz)
984 continue;
985 if (strncmp(s, tbl->fmtstr, fsz) != 0)
986 continue;
987 if (fsz == sz)
988 return tbl->format |
989 ((stereo) ? AFMT_STEREO : 0);
990 if ((sz - fsz) < 2 || s[fsz] != ':')
991 break;
992 /*
993 * For now, just handle mono/stereo.
994 */
995 if ((s[fsz + 2] == '\0' && (s[fsz + 1] == 'm' ||
996 s[fsz + 1] == '1')) ||
997 strcmp(s + fsz + 1, "mono") == 0)
998 return tbl->format;
999 if ((s[fsz + 2] == '\0' && (s[fsz + 1] == 's' ||
1000 s[fsz + 1] == '2')) ||
1001 strcmp(s + fsz + 1, "stereo") == 0)
1002 return tbl->format | AFMT_STEREO;
1003 break;
1004 }
1005 }
1006
1007 return 0;
1008}
1009
1010u_int32_t
1011afmt2afmtstr(struct afmtstr_table *tbl, u_int32_t afmt, char *dst,
1012 size_t len, int type, int stereo)
1013{
1014 u_int32_t fmt = 0;
1015 char *fmtstr = NULL, *tag = "";
1016
1017 if (tbl == NULL)
1018 tbl = default_afmtstr_table;
1019
1020 for (; tbl->format != 0; tbl++) {
1021 if (tbl->format == 0)
1022 break;
1023 if ((afmt & ~AFMT_STEREO) != tbl->format)
1024 continue;
1025 fmt = afmt;
1026 fmtstr = tbl->fmtstr;
1027 break;
1028 }
1029
1030 if (fmt != 0 && fmtstr != NULL && dst != NULL && len > 0) {
1031 strlcpy(dst, fmtstr, len);
1032 switch (type) {
1033 case AFMTSTR_SIMPLE:
1034 tag = (fmt & AFMT_STEREO) ? ":s" : ":m";
1035 break;
1036 case AFMTSTR_NUM:
1037 tag = (fmt & AFMT_STEREO) ? ":2" : ":1";
1038 break;
1039 case AFMTSTR_FULL:
1040 tag = (fmt & AFMT_STEREO) ? ":stereo" : ":mono";
1041 break;
1042 case AFMTSTR_NONE:
1043 default:
1044 break;
1045 }
1046 if (strlen(tag) > 0 && ((stereo && !(fmt & AFMT_STEREO)) || \
1047 (!stereo && (fmt & AFMT_STEREO))))
1048 strlcat(dst, tag, len);
1049 }
1050
1051 return fmt;
1052}
1053
1054int
1055chn_reset(struct pcm_channel *c, u_int32_t fmt)
1056{
1057 int hwspd, r;
1058
1059 CHN_LOCKASSERT(c);
1060 c->feedcount = 0;
1061 c->flags &= CHN_F_RESET;
1062 c->interrupts = 0;
1063 c->timeout = 1;
1064 c->xruns = 0;
1065
1066 r = CHANNEL_RESET(c->methods, c->devinfo);
1067 if (fmt != 0) {
1068#if 0
1069 hwspd = DSP_DEFAULT_SPEED;
1070 /* only do this on a record channel until feederbuilder works */
1071 if (c->direction == PCMDIR_REC)
1072 RANGE(hwspd, chn_getcaps(c)->minspeed, chn_getcaps(c)->maxspeed);
1073 c->speed = hwspd;
1074#endif
1075 hwspd = chn_getcaps(c)->minspeed;
1076 c->speed = hwspd;
1077
1078 if (r == 0)
1079 r = chn_setformat(c, fmt);
1080 if (r == 0)
1081 r = chn_setspeed(c, hwspd);
1082#if 0
1083 if (r == 0)
1084 r = chn_setvolume(c, 100, 100);
1085#endif
1086 }
1087 if (r == 0)
1088 r = chn_setlatency(c, chn_latency);
1089 if (r == 0) {
1090 chn_resetbuf(c);
1091 r = CHANNEL_RESETDONE(c->methods, c->devinfo);
1092 }
1093 return r;
1094}
1095
1096int
1097chn_init(struct pcm_channel *c, void *devinfo, int dir, int direction)
1098{
1099 struct feeder_class *fc;
1100 struct snd_dbuf *b, *bs;
1101 int ret;
1102
1103 if (chn_timeout < CHN_TIMEOUT_MIN || chn_timeout > CHN_TIMEOUT_MAX)
1104 chn_timeout = CHN_TIMEOUT;
1105
1106 chn_lockinit(c, dir);
1107
1108 b = NULL;
1109 bs = NULL;
1110 CHN_INIT(c, children);
1111 CHN_INIT(c, children.busy);
1097 c->devinfo = NULL;
1098 c->feeder = NULL;
1099 c->latency = -1;
1100 c->timeout = 1;
1101
1102 ret = ENOMEM;
1103 b = sndbuf_create(c->dev, c->name, "primary", c);
1104 if (b == NULL)
1105 goto out;
1106 bs = sndbuf_create(c->dev, c->name, "secondary", c);
1107 if (bs == NULL)
1108 goto out;
1109
1110 CHN_LOCK(c);
1111
1112 ret = EINVAL;
1113 fc = feeder_getclass(NULL);
1114 if (fc == NULL)
1115 goto out;
1116 if (chn_addfeeder(c, fc, NULL))
1117 goto out;
1118
1119 /*
1120 * XXX - sndbuf_setup() & sndbuf_resize() expect to be called
1121 * with the channel unlocked because they are also called
1122 * from driver methods that don't know about locking
1123 */
1124 CHN_UNLOCK(c);
1125 sndbuf_setup(bs, NULL, 0);
1126 CHN_LOCK(c);
1127 c->bufhard = b;
1128 c->bufsoft = bs;
1129 c->flags = 0;
1130 c->feederflags = 0;
1131 c->sm = NULL;
1132
1133 ret = ENODEV;
1134 CHN_UNLOCK(c); /* XXX - Unlock for CHANNEL_INIT() malloc() call */
1135 c->devinfo = CHANNEL_INIT(c->methods, devinfo, b, c, direction);
1136 CHN_LOCK(c);
1137 if (c->devinfo == NULL)
1138 goto out;
1139
1140 ret = ENOMEM;
1141 if ((sndbuf_getsize(b) == 0) && ((c->flags & CHN_F_VIRTUAL) == 0))
1142 goto out;
1143
1144 ret = chn_setdir(c, direction);
1145 if (ret)
1146 goto out;
1147
1148 ret = sndbuf_setfmt(b, AFMT_U8);
1149 if (ret)
1150 goto out;
1151
1152 ret = sndbuf_setfmt(bs, AFMT_U8);
1153 if (ret)
1154 goto out;
1155
1156 /**
1157 * @todo Should this be moved somewhere else? The primary buffer
1158 * is allocated by the driver or via DMA map setup, and tmpbuf
1159 * seems to only come into existence in sndbuf_resize().
1160 */
1161 if (c->direction == PCMDIR_PLAY) {
1162 bs->sl = sndbuf_getmaxsize(bs);
1163 bs->shadbuf = malloc(bs->sl, M_DEVBUF, M_NOWAIT);
1164 if (bs->shadbuf == NULL) {
1165 ret = ENOMEM;
1166 goto out;
1167 }
1168 }
1169
1170out:
1171 CHN_UNLOCK(c);
1172 if (ret) {
1173 if (c->devinfo) {
1174 if (CHANNEL_FREE(c->methods, c->devinfo))
1175 sndbuf_free(b);
1176 }
1177 if (bs)
1178 sndbuf_destroy(bs);
1179 if (b)
1180 sndbuf_destroy(b);
1181 c->flags |= CHN_F_DEAD;
1182 chn_lockdestroy(c);
1183
1184 return ret;
1185 }
1186
1187 return 0;
1188}
1189
1190int
1191chn_kill(struct pcm_channel *c)
1192{
1193 struct snd_dbuf *b = c->bufhard;
1194 struct snd_dbuf *bs = c->bufsoft;
1195
1112 c->devinfo = NULL;
1113 c->feeder = NULL;
1114 c->latency = -1;
1115 c->timeout = 1;
1116
1117 ret = ENOMEM;
1118 b = sndbuf_create(c->dev, c->name, "primary", c);
1119 if (b == NULL)
1120 goto out;
1121 bs = sndbuf_create(c->dev, c->name, "secondary", c);
1122 if (bs == NULL)
1123 goto out;
1124
1125 CHN_LOCK(c);
1126
1127 ret = EINVAL;
1128 fc = feeder_getclass(NULL);
1129 if (fc == NULL)
1130 goto out;
1131 if (chn_addfeeder(c, fc, NULL))
1132 goto out;
1133
1134 /*
1135 * XXX - sndbuf_setup() & sndbuf_resize() expect to be called
1136 * with the channel unlocked because they are also called
1137 * from driver methods that don't know about locking
1138 */
1139 CHN_UNLOCK(c);
1140 sndbuf_setup(bs, NULL, 0);
1141 CHN_LOCK(c);
1142 c->bufhard = b;
1143 c->bufsoft = bs;
1144 c->flags = 0;
1145 c->feederflags = 0;
1146 c->sm = NULL;
1147
1148 ret = ENODEV;
1149 CHN_UNLOCK(c); /* XXX - Unlock for CHANNEL_INIT() malloc() call */
1150 c->devinfo = CHANNEL_INIT(c->methods, devinfo, b, c, direction);
1151 CHN_LOCK(c);
1152 if (c->devinfo == NULL)
1153 goto out;
1154
1155 ret = ENOMEM;
1156 if ((sndbuf_getsize(b) == 0) && ((c->flags & CHN_F_VIRTUAL) == 0))
1157 goto out;
1158
1159 ret = chn_setdir(c, direction);
1160 if (ret)
1161 goto out;
1162
1163 ret = sndbuf_setfmt(b, AFMT_U8);
1164 if (ret)
1165 goto out;
1166
1167 ret = sndbuf_setfmt(bs, AFMT_U8);
1168 if (ret)
1169 goto out;
1170
1171 /**
1172 * @todo Should this be moved somewhere else? The primary buffer
1173 * is allocated by the driver or via DMA map setup, and tmpbuf
1174 * seems to only come into existence in sndbuf_resize().
1175 */
1176 if (c->direction == PCMDIR_PLAY) {
1177 bs->sl = sndbuf_getmaxsize(bs);
1178 bs->shadbuf = malloc(bs->sl, M_DEVBUF, M_NOWAIT);
1179 if (bs->shadbuf == NULL) {
1180 ret = ENOMEM;
1181 goto out;
1182 }
1183 }
1184
1185out:
1186 CHN_UNLOCK(c);
1187 if (ret) {
1188 if (c->devinfo) {
1189 if (CHANNEL_FREE(c->methods, c->devinfo))
1190 sndbuf_free(b);
1191 }
1192 if (bs)
1193 sndbuf_destroy(bs);
1194 if (b)
1195 sndbuf_destroy(b);
1196 c->flags |= CHN_F_DEAD;
1197 chn_lockdestroy(c);
1198
1199 return ret;
1200 }
1201
1202 return 0;
1203}
1204
1205int
1206chn_kill(struct pcm_channel *c)
1207{
1208 struct snd_dbuf *b = c->bufhard;
1209 struct snd_dbuf *bs = c->bufsoft;
1210
1196 if (CHN_STARTED(c))
1211 if (CHN_STARTED(c)) {
1212 CHN_LOCK(c);
1197 chn_trigger(c, PCMTRIG_ABORT);
1213 chn_trigger(c, PCMTRIG_ABORT);
1198 while (chn_removefeeder(c) == 0);
1214 CHN_UNLOCK(c);
1215 }
1216 while (chn_removefeeder(c) == 0)
1217 ;
1199 if (CHANNEL_FREE(c->methods, c->devinfo))
1200 sndbuf_free(b);
1201 c->flags |= CHN_F_DEAD;
1202 sndbuf_destroy(bs);
1203 sndbuf_destroy(b);
1204 chn_lockdestroy(c);
1205 return 0;
1206}
1207
1208int
1209chn_setdir(struct pcm_channel *c, int dir)
1210{
1211#ifdef DEV_ISA
1212 struct snd_dbuf *b = c->bufhard;
1213#endif
1214 int r;
1215
1216 CHN_LOCKASSERT(c);
1217 c->direction = dir;
1218 r = CHANNEL_SETDIR(c->methods, c->devinfo, c->direction);
1219#ifdef DEV_ISA
1220 if (!r && SND_DMA(b))
1221 sndbuf_dmasetdir(b, c->direction);
1222#endif
1223 return r;
1224}
1225
1226int
1227chn_setvolume(struct pcm_channel *c, int left, int right)
1228{
1229 CHN_LOCKASSERT(c);
1230 /* should add a feeder for volume changing if channel returns -1 */
1231 if (left > 100)
1232 left = 100;
1233 if (left < 0)
1234 left = 0;
1235 if (right > 100)
1236 right = 100;
1237 if (right < 0)
1238 right = 0;
1239 c->volume = left | (right << 8);
1240 return 0;
1241}
1242
1243static u_int32_t
1244round_pow2(u_int32_t v)
1245{
1246 u_int32_t ret;
1247
1248 if (v < 2)
1249 v = 2;
1250 ret = 0;
1251 while (v >> ret)
1252 ret++;
1253 ret = 1 << (ret - 1);
1254 while (ret < v)
1255 ret <<= 1;
1256 return ret;
1257}
1258
1259static u_int32_t
1260round_blksz(u_int32_t v, int round)
1261{
1262 u_int32_t ret, tmp;
1263
1264 if (round < 1)
1265 round = 1;
1266
1267 ret = min(round_pow2(v), CHN_2NDBUFMAXSIZE >> 1);
1268
1269 if (ret > v && (ret >> 1) > 0 && (ret >> 1) >= ((v * 3) >> 2))
1270 ret >>= 1;
1271
1272 tmp = ret - (ret % round);
1273 while (tmp < 16 || tmp < round) {
1274 ret <<= 1;
1275 tmp = ret - (ret % round);
1276 }
1277
1278 return ret;
1279}
1280
1281/*
1282 * 4Front call it DSP Policy, while we call it "Latency Profile". The idea
1283 * is to keep 2nd buffer short so that it doesn't cause long queue during
1284 * buffer transfer.
1285 *
1286 * Latency reference table for 48khz stereo 16bit: (PLAY)
1287 *
1288 * +---------+------------+-----------+------------+
1289 * | Latency | Blockcount | Blocksize | Buffersize |
1290 * +---------+------------+-----------+------------+
1291 * | 0 | 2 | 64 | 128 |
1292 * +---------+------------+-----------+------------+
1293 * | 1 | 4 | 128 | 512 |
1294 * +---------+------------+-----------+------------+
1295 * | 2 | 8 | 512 | 4096 |
1296 * +---------+------------+-----------+------------+
1297 * | 3 | 16 | 512 | 8192 |
1298 * +---------+------------+-----------+------------+
1299 * | 4 | 32 | 512 | 16384 |
1300 * +---------+------------+-----------+------------+
1301 * | 5 | 32 | 1024 | 32768 |
1302 * +---------+------------+-----------+------------+
1303 * | 6 | 16 | 2048 | 32768 |
1304 * +---------+------------+-----------+------------+
1305 * | 7 | 8 | 4096 | 32768 |
1306 * +---------+------------+-----------+------------+
1307 * | 8 | 4 | 8192 | 32768 |
1308 * +---------+------------+-----------+------------+
1309 * | 9 | 2 | 16384 | 32768 |
1310 * +---------+------------+-----------+------------+
1311 * | 10 | 2 | 32768 | 65536 |
1312 * +---------+------------+-----------+------------+
1313 *
1314 * Recording need a different reference table. All we care is
1315 * gobbling up everything within reasonable buffering threshold.
1316 *
1317 * Latency reference table for 48khz stereo 16bit: (REC)
1318 *
1319 * +---------+------------+-----------+------------+
1320 * | Latency | Blockcount | Blocksize | Buffersize |
1321 * +---------+------------+-----------+------------+
1322 * | 0 | 512 | 32 | 16384 |
1323 * +---------+------------+-----------+------------+
1324 * | 1 | 256 | 64 | 16384 |
1325 * +---------+------------+-----------+------------+
1326 * | 2 | 128 | 128 | 16384 |
1327 * +---------+------------+-----------+------------+
1328 * | 3 | 64 | 256 | 16384 |
1329 * +---------+------------+-----------+------------+
1330 * | 4 | 32 | 512 | 16384 |
1331 * +---------+------------+-----------+------------+
1332 * | 5 | 32 | 1024 | 32768 |
1333 * +---------+------------+-----------+------------+
1334 * | 6 | 16 | 2048 | 32768 |
1335 * +---------+------------+-----------+------------+
1336 * | 7 | 8 | 4096 | 32768 |
1337 * +---------+------------+-----------+------------+
1338 * | 8 | 4 | 8192 | 32768 |
1339 * +---------+------------+-----------+------------+
1340 * | 9 | 2 | 16384 | 32768 |
1341 * +---------+------------+-----------+------------+
1342 * | 10 | 2 | 32768 | 65536 |
1343 * +---------+------------+-----------+------------+
1344 *
1345 * Calculations for other data rate are entirely based on these reference
1346 * tables. For normal operation, Latency 5 seems give the best, well
1347 * balanced performance for typical workload. Anything below 5 will
1348 * eat up CPU to keep up with increasing context switches because of
1349 * shorter buffer space and usually require the application to handle it
1350 * aggresively through possibly real time programming technique.
1351 *
1352 */
1353#define CHN_LATENCY_PBLKCNT_REF \
1354 {{1, 2, 3, 4, 5, 5, 4, 3, 2, 1, 1}, \
1355 {1, 2, 3, 4, 5, 5, 4, 3, 2, 1, 1}}
1356#define CHN_LATENCY_PBUFSZ_REF \
1357 {{7, 9, 12, 13, 14, 15, 15, 15, 15, 15, 16}, \
1358 {11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 17}}
1359
1360#define CHN_LATENCY_RBLKCNT_REF \
1361 {{9, 8, 7, 6, 5, 5, 4, 3, 2, 1, 1}, \
1362 {9, 8, 7, 6, 5, 5, 4, 3, 2, 1, 1}}
1363#define CHN_LATENCY_RBUFSZ_REF \
1364 {{14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 16}, \
1365 {15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 17}}
1366
1367#define CHN_LATENCY_DATA_REF 192000 /* 48khz stereo 16bit ~ 48000 x 2 x 2 */
1368
1369static int
1370chn_calclatency(int dir, int latency, int bps, u_int32_t datarate,
1371 u_int32_t max, int *rblksz, int *rblkcnt)
1372{
1373 static int pblkcnts[CHN_LATENCY_PROFILE_MAX + 1][CHN_LATENCY_MAX + 1] =
1374 CHN_LATENCY_PBLKCNT_REF;
1375 static int pbufszs[CHN_LATENCY_PROFILE_MAX + 1][CHN_LATENCY_MAX + 1] =
1376 CHN_LATENCY_PBUFSZ_REF;
1377 static int rblkcnts[CHN_LATENCY_PROFILE_MAX + 1][CHN_LATENCY_MAX + 1] =
1378 CHN_LATENCY_RBLKCNT_REF;
1379 static int rbufszs[CHN_LATENCY_PROFILE_MAX + 1][CHN_LATENCY_MAX + 1] =
1380 CHN_LATENCY_RBUFSZ_REF;
1381 u_int32_t bufsz;
1382 int lprofile, blksz, blkcnt;
1383
1384 if (latency < CHN_LATENCY_MIN || latency > CHN_LATENCY_MAX ||
1385 bps < 1 || datarate < 1 ||
1386 !(dir == PCMDIR_PLAY || dir == PCMDIR_REC)) {
1387 if (rblksz != NULL)
1388 *rblksz = CHN_2NDBUFMAXSIZE >> 1;
1389 if (rblkcnt != NULL)
1390 *rblkcnt = 2;
1391 printf("%s: FAILED dir=%d latency=%d bps=%d "
1392 "datarate=%u max=%u\n",
1393 __func__, dir, latency, bps, datarate, max);
1394 return CHN_2NDBUFMAXSIZE;
1395 }
1396
1397 lprofile = chn_latency_profile;
1398
1399 if (dir == PCMDIR_PLAY) {
1400 blkcnt = pblkcnts[lprofile][latency];
1401 bufsz = pbufszs[lprofile][latency];
1402 } else {
1403 blkcnt = rblkcnts[lprofile][latency];
1404 bufsz = rbufszs[lprofile][latency];
1405 }
1406
1407 bufsz = round_pow2(snd_xbytes(1 << bufsz, CHN_LATENCY_DATA_REF,
1408 datarate));
1409 if (bufsz > max)
1410 bufsz = max;
1411 blksz = round_blksz(bufsz >> blkcnt, bps);
1412
1413 if (rblksz != NULL)
1414 *rblksz = blksz;
1415 if (rblkcnt != NULL)
1416 *rblkcnt = 1 << blkcnt;
1417
1418 return blksz << blkcnt;
1419}
1420
1421static int
1422chn_resizebuf(struct pcm_channel *c, int latency,
1423 int blkcnt, int blksz)
1424{
1425 struct snd_dbuf *b, *bs, *pb;
1426 int sblksz, sblkcnt, hblksz, hblkcnt, limit = 1;
1427 int ret;
1428
1429 CHN_LOCKASSERT(c);
1430
1431 if ((c->flags & (CHN_F_MAPPED | CHN_F_TRIGGERED)) ||
1432 !(c->direction == PCMDIR_PLAY || c->direction == PCMDIR_REC))
1433 return EINVAL;
1434
1435 if (latency == -1) {
1436 c->latency = -1;
1437 latency = chn_latency;
1438 } else if (latency == -2) {
1439 latency = c->latency;
1440 if (latency < CHN_LATENCY_MIN || latency > CHN_LATENCY_MAX)
1441 latency = chn_latency;
1442 } else if (latency < CHN_LATENCY_MIN || latency > CHN_LATENCY_MAX)
1443 return EINVAL;
1444 else {
1445 c->latency = latency;
1446 limit = 0;
1447 }
1448
1449 bs = c->bufsoft;
1450 b = c->bufhard;
1451
1452 if (!(blksz == 0 || blkcnt == -1) &&
1453 (blksz < 16 || blksz < sndbuf_getbps(bs) || blkcnt < 2 ||
1454 (blksz * blkcnt) > CHN_2NDBUFMAXSIZE))
1455 return EINVAL;
1456
1457 chn_calclatency(c->direction, latency, sndbuf_getbps(bs),
1458 sndbuf_getbps(bs) * sndbuf_getspd(bs), CHN_2NDBUFMAXSIZE,
1459 &sblksz, &sblkcnt);
1460
1461 if (blksz == 0 || blkcnt == -1) {
1462 if (blkcnt == -1)
1463 c->flags &= ~CHN_F_HAS_SIZE;
1464 if (c->flags & CHN_F_HAS_SIZE) {
1465 blksz = sndbuf_getblksz(bs);
1466 blkcnt = sndbuf_getblkcnt(bs);
1467 }
1468 } else
1469 c->flags |= CHN_F_HAS_SIZE;
1470
1471 if (c->flags & CHN_F_HAS_SIZE) {
1472 /*
1473 * The application has requested their own blksz/blkcnt.
1474 * Just obey with it, and let them toast alone. We can
1475 * clamp it to the nearest latency profile, but that would
1476 * defeat the purpose of having custom control. The least
1477 * we can do is round it to the nearest ^2 and align it.
1478 */
1479 sblksz = round_blksz(blksz, sndbuf_getbps(bs));
1480 sblkcnt = round_pow2(blkcnt);
1481 limit = 0;
1482 }
1483
1484 if (c->parentchannel != NULL) {
1485 pb = BUF_PARENT(c, NULL);
1486 CHN_UNLOCK(c);
1487 chn_notify(c->parentchannel, CHN_N_BLOCKSIZE);
1488 CHN_LOCK(c);
1489 limit = (limit != 0 && pb != NULL) ?
1490 sndbuf_xbytes(sndbuf_getsize(pb), pb, bs) : 0;
1491 c->timeout = c->parentchannel->timeout;
1492 } else {
1493 hblkcnt = 2;
1494 if (c->flags & CHN_F_HAS_SIZE) {
1495 hblksz = round_blksz(sndbuf_xbytes(sblksz, bs, b),
1496 sndbuf_getbps(b));
1497 hblkcnt = round_pow2(sndbuf_getblkcnt(bs));
1498 } else
1499 chn_calclatency(c->direction, latency,
1500 sndbuf_getbps(b),
1501 sndbuf_getbps(b) * sndbuf_getspd(b),
1502 CHN_2NDBUFMAXSIZE, &hblksz, &hblkcnt);
1503
1504 if ((hblksz << 1) > sndbuf_getmaxsize(b))
1505 hblksz = round_blksz(sndbuf_getmaxsize(b) >> 1,
1506 sndbuf_getbps(b));
1507
1508 while ((hblksz * hblkcnt) > sndbuf_getmaxsize(b)) {
1509 if (hblkcnt < 4)
1510 hblksz >>= 1;
1511 else
1512 hblkcnt >>= 1;
1513 }
1514
1515 hblksz -= hblksz % sndbuf_getbps(b);
1516
1517#if 0
1518 hblksz = sndbuf_getmaxsize(b) >> 1;
1519 hblksz -= hblksz % sndbuf_getbps(b);
1520 hblkcnt = 2;
1521#endif
1522
1523 CHN_UNLOCK(c);
1524 if (chn_usefrags == 0 ||
1525 CHANNEL_SETFRAGMENTS(c->methods, c->devinfo,
1526 hblksz, hblkcnt) < 1)
1527 sndbuf_setblksz(b, CHANNEL_SETBLOCKSIZE(c->methods,
1528 c->devinfo, hblksz));
1529 CHN_LOCK(c);
1530
1218 if (CHANNEL_FREE(c->methods, c->devinfo))
1219 sndbuf_free(b);
1220 c->flags |= CHN_F_DEAD;
1221 sndbuf_destroy(bs);
1222 sndbuf_destroy(b);
1223 chn_lockdestroy(c);
1224 return 0;
1225}
1226
1227int
1228chn_setdir(struct pcm_channel *c, int dir)
1229{
1230#ifdef DEV_ISA
1231 struct snd_dbuf *b = c->bufhard;
1232#endif
1233 int r;
1234
1235 CHN_LOCKASSERT(c);
1236 c->direction = dir;
1237 r = CHANNEL_SETDIR(c->methods, c->devinfo, c->direction);
1238#ifdef DEV_ISA
1239 if (!r && SND_DMA(b))
1240 sndbuf_dmasetdir(b, c->direction);
1241#endif
1242 return r;
1243}
1244
1245int
1246chn_setvolume(struct pcm_channel *c, int left, int right)
1247{
1248 CHN_LOCKASSERT(c);
1249 /* should add a feeder for volume changing if channel returns -1 */
1250 if (left > 100)
1251 left = 100;
1252 if (left < 0)
1253 left = 0;
1254 if (right > 100)
1255 right = 100;
1256 if (right < 0)
1257 right = 0;
1258 c->volume = left | (right << 8);
1259 return 0;
1260}
1261
1262static u_int32_t
1263round_pow2(u_int32_t v)
1264{
1265 u_int32_t ret;
1266
1267 if (v < 2)
1268 v = 2;
1269 ret = 0;
1270 while (v >> ret)
1271 ret++;
1272 ret = 1 << (ret - 1);
1273 while (ret < v)
1274 ret <<= 1;
1275 return ret;
1276}
1277
1278static u_int32_t
1279round_blksz(u_int32_t v, int round)
1280{
1281 u_int32_t ret, tmp;
1282
1283 if (round < 1)
1284 round = 1;
1285
1286 ret = min(round_pow2(v), CHN_2NDBUFMAXSIZE >> 1);
1287
1288 if (ret > v && (ret >> 1) > 0 && (ret >> 1) >= ((v * 3) >> 2))
1289 ret >>= 1;
1290
1291 tmp = ret - (ret % round);
1292 while (tmp < 16 || tmp < round) {
1293 ret <<= 1;
1294 tmp = ret - (ret % round);
1295 }
1296
1297 return ret;
1298}
1299
1300/*
1301 * 4Front call it DSP Policy, while we call it "Latency Profile". The idea
1302 * is to keep 2nd buffer short so that it doesn't cause long queue during
1303 * buffer transfer.
1304 *
1305 * Latency reference table for 48khz stereo 16bit: (PLAY)
1306 *
1307 * +---------+------------+-----------+------------+
1308 * | Latency | Blockcount | Blocksize | Buffersize |
1309 * +---------+------------+-----------+------------+
1310 * | 0 | 2 | 64 | 128 |
1311 * +---------+------------+-----------+------------+
1312 * | 1 | 4 | 128 | 512 |
1313 * +---------+------------+-----------+------------+
1314 * | 2 | 8 | 512 | 4096 |
1315 * +---------+------------+-----------+------------+
1316 * | 3 | 16 | 512 | 8192 |
1317 * +---------+------------+-----------+------------+
1318 * | 4 | 32 | 512 | 16384 |
1319 * +---------+------------+-----------+------------+
1320 * | 5 | 32 | 1024 | 32768 |
1321 * +---------+------------+-----------+------------+
1322 * | 6 | 16 | 2048 | 32768 |
1323 * +---------+------------+-----------+------------+
1324 * | 7 | 8 | 4096 | 32768 |
1325 * +---------+------------+-----------+------------+
1326 * | 8 | 4 | 8192 | 32768 |
1327 * +---------+------------+-----------+------------+
1328 * | 9 | 2 | 16384 | 32768 |
1329 * +---------+------------+-----------+------------+
1330 * | 10 | 2 | 32768 | 65536 |
1331 * +---------+------------+-----------+------------+
1332 *
1333 * Recording need a different reference table. All we care is
1334 * gobbling up everything within reasonable buffering threshold.
1335 *
1336 * Latency reference table for 48khz stereo 16bit: (REC)
1337 *
1338 * +---------+------------+-----------+------------+
1339 * | Latency | Blockcount | Blocksize | Buffersize |
1340 * +---------+------------+-----------+------------+
1341 * | 0 | 512 | 32 | 16384 |
1342 * +---------+------------+-----------+------------+
1343 * | 1 | 256 | 64 | 16384 |
1344 * +---------+------------+-----------+------------+
1345 * | 2 | 128 | 128 | 16384 |
1346 * +---------+------------+-----------+------------+
1347 * | 3 | 64 | 256 | 16384 |
1348 * +---------+------------+-----------+------------+
1349 * | 4 | 32 | 512 | 16384 |
1350 * +---------+------------+-----------+------------+
1351 * | 5 | 32 | 1024 | 32768 |
1352 * +---------+------------+-----------+------------+
1353 * | 6 | 16 | 2048 | 32768 |
1354 * +---------+------------+-----------+------------+
1355 * | 7 | 8 | 4096 | 32768 |
1356 * +---------+------------+-----------+------------+
1357 * | 8 | 4 | 8192 | 32768 |
1358 * +---------+------------+-----------+------------+
1359 * | 9 | 2 | 16384 | 32768 |
1360 * +---------+------------+-----------+------------+
1361 * | 10 | 2 | 32768 | 65536 |
1362 * +---------+------------+-----------+------------+
1363 *
1364 * Calculations for other data rate are entirely based on these reference
1365 * tables. For normal operation, Latency 5 seems give the best, well
1366 * balanced performance for typical workload. Anything below 5 will
1367 * eat up CPU to keep up with increasing context switches because of
1368 * shorter buffer space and usually require the application to handle it
1369 * aggresively through possibly real time programming technique.
1370 *
1371 */
1372#define CHN_LATENCY_PBLKCNT_REF \
1373 {{1, 2, 3, 4, 5, 5, 4, 3, 2, 1, 1}, \
1374 {1, 2, 3, 4, 5, 5, 4, 3, 2, 1, 1}}
1375#define CHN_LATENCY_PBUFSZ_REF \
1376 {{7, 9, 12, 13, 14, 15, 15, 15, 15, 15, 16}, \
1377 {11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 17}}
1378
1379#define CHN_LATENCY_RBLKCNT_REF \
1380 {{9, 8, 7, 6, 5, 5, 4, 3, 2, 1, 1}, \
1381 {9, 8, 7, 6, 5, 5, 4, 3, 2, 1, 1}}
1382#define CHN_LATENCY_RBUFSZ_REF \
1383 {{14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 16}, \
1384 {15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 17}}
1385
1386#define CHN_LATENCY_DATA_REF 192000 /* 48khz stereo 16bit ~ 48000 x 2 x 2 */
1387
1388static int
1389chn_calclatency(int dir, int latency, int bps, u_int32_t datarate,
1390 u_int32_t max, int *rblksz, int *rblkcnt)
1391{
1392 static int pblkcnts[CHN_LATENCY_PROFILE_MAX + 1][CHN_LATENCY_MAX + 1] =
1393 CHN_LATENCY_PBLKCNT_REF;
1394 static int pbufszs[CHN_LATENCY_PROFILE_MAX + 1][CHN_LATENCY_MAX + 1] =
1395 CHN_LATENCY_PBUFSZ_REF;
1396 static int rblkcnts[CHN_LATENCY_PROFILE_MAX + 1][CHN_LATENCY_MAX + 1] =
1397 CHN_LATENCY_RBLKCNT_REF;
1398 static int rbufszs[CHN_LATENCY_PROFILE_MAX + 1][CHN_LATENCY_MAX + 1] =
1399 CHN_LATENCY_RBUFSZ_REF;
1400 u_int32_t bufsz;
1401 int lprofile, blksz, blkcnt;
1402
1403 if (latency < CHN_LATENCY_MIN || latency > CHN_LATENCY_MAX ||
1404 bps < 1 || datarate < 1 ||
1405 !(dir == PCMDIR_PLAY || dir == PCMDIR_REC)) {
1406 if (rblksz != NULL)
1407 *rblksz = CHN_2NDBUFMAXSIZE >> 1;
1408 if (rblkcnt != NULL)
1409 *rblkcnt = 2;
1410 printf("%s: FAILED dir=%d latency=%d bps=%d "
1411 "datarate=%u max=%u\n",
1412 __func__, dir, latency, bps, datarate, max);
1413 return CHN_2NDBUFMAXSIZE;
1414 }
1415
1416 lprofile = chn_latency_profile;
1417
1418 if (dir == PCMDIR_PLAY) {
1419 blkcnt = pblkcnts[lprofile][latency];
1420 bufsz = pbufszs[lprofile][latency];
1421 } else {
1422 blkcnt = rblkcnts[lprofile][latency];
1423 bufsz = rbufszs[lprofile][latency];
1424 }
1425
1426 bufsz = round_pow2(snd_xbytes(1 << bufsz, CHN_LATENCY_DATA_REF,
1427 datarate));
1428 if (bufsz > max)
1429 bufsz = max;
1430 blksz = round_blksz(bufsz >> blkcnt, bps);
1431
1432 if (rblksz != NULL)
1433 *rblksz = blksz;
1434 if (rblkcnt != NULL)
1435 *rblkcnt = 1 << blkcnt;
1436
1437 return blksz << blkcnt;
1438}
1439
1440static int
1441chn_resizebuf(struct pcm_channel *c, int latency,
1442 int blkcnt, int blksz)
1443{
1444 struct snd_dbuf *b, *bs, *pb;
1445 int sblksz, sblkcnt, hblksz, hblkcnt, limit = 1;
1446 int ret;
1447
1448 CHN_LOCKASSERT(c);
1449
1450 if ((c->flags & (CHN_F_MAPPED | CHN_F_TRIGGERED)) ||
1451 !(c->direction == PCMDIR_PLAY || c->direction == PCMDIR_REC))
1452 return EINVAL;
1453
1454 if (latency == -1) {
1455 c->latency = -1;
1456 latency = chn_latency;
1457 } else if (latency == -2) {
1458 latency = c->latency;
1459 if (latency < CHN_LATENCY_MIN || latency > CHN_LATENCY_MAX)
1460 latency = chn_latency;
1461 } else if (latency < CHN_LATENCY_MIN || latency > CHN_LATENCY_MAX)
1462 return EINVAL;
1463 else {
1464 c->latency = latency;
1465 limit = 0;
1466 }
1467
1468 bs = c->bufsoft;
1469 b = c->bufhard;
1470
1471 if (!(blksz == 0 || blkcnt == -1) &&
1472 (blksz < 16 || blksz < sndbuf_getbps(bs) || blkcnt < 2 ||
1473 (blksz * blkcnt) > CHN_2NDBUFMAXSIZE))
1474 return EINVAL;
1475
1476 chn_calclatency(c->direction, latency, sndbuf_getbps(bs),
1477 sndbuf_getbps(bs) * sndbuf_getspd(bs), CHN_2NDBUFMAXSIZE,
1478 &sblksz, &sblkcnt);
1479
1480 if (blksz == 0 || blkcnt == -1) {
1481 if (blkcnt == -1)
1482 c->flags &= ~CHN_F_HAS_SIZE;
1483 if (c->flags & CHN_F_HAS_SIZE) {
1484 blksz = sndbuf_getblksz(bs);
1485 blkcnt = sndbuf_getblkcnt(bs);
1486 }
1487 } else
1488 c->flags |= CHN_F_HAS_SIZE;
1489
1490 if (c->flags & CHN_F_HAS_SIZE) {
1491 /*
1492 * The application has requested their own blksz/blkcnt.
1493 * Just obey with it, and let them toast alone. We can
1494 * clamp it to the nearest latency profile, but that would
1495 * defeat the purpose of having custom control. The least
1496 * we can do is round it to the nearest ^2 and align it.
1497 */
1498 sblksz = round_blksz(blksz, sndbuf_getbps(bs));
1499 sblkcnt = round_pow2(blkcnt);
1500 limit = 0;
1501 }
1502
1503 if (c->parentchannel != NULL) {
1504 pb = BUF_PARENT(c, NULL);
1505 CHN_UNLOCK(c);
1506 chn_notify(c->parentchannel, CHN_N_BLOCKSIZE);
1507 CHN_LOCK(c);
1508 limit = (limit != 0 && pb != NULL) ?
1509 sndbuf_xbytes(sndbuf_getsize(pb), pb, bs) : 0;
1510 c->timeout = c->parentchannel->timeout;
1511 } else {
1512 hblkcnt = 2;
1513 if (c->flags & CHN_F_HAS_SIZE) {
1514 hblksz = round_blksz(sndbuf_xbytes(sblksz, bs, b),
1515 sndbuf_getbps(b));
1516 hblkcnt = round_pow2(sndbuf_getblkcnt(bs));
1517 } else
1518 chn_calclatency(c->direction, latency,
1519 sndbuf_getbps(b),
1520 sndbuf_getbps(b) * sndbuf_getspd(b),
1521 CHN_2NDBUFMAXSIZE, &hblksz, &hblkcnt);
1522
1523 if ((hblksz << 1) > sndbuf_getmaxsize(b))
1524 hblksz = round_blksz(sndbuf_getmaxsize(b) >> 1,
1525 sndbuf_getbps(b));
1526
1527 while ((hblksz * hblkcnt) > sndbuf_getmaxsize(b)) {
1528 if (hblkcnt < 4)
1529 hblksz >>= 1;
1530 else
1531 hblkcnt >>= 1;
1532 }
1533
1534 hblksz -= hblksz % sndbuf_getbps(b);
1535
1536#if 0
1537 hblksz = sndbuf_getmaxsize(b) >> 1;
1538 hblksz -= hblksz % sndbuf_getbps(b);
1539 hblkcnt = 2;
1540#endif
1541
1542 CHN_UNLOCK(c);
1543 if (chn_usefrags == 0 ||
1544 CHANNEL_SETFRAGMENTS(c->methods, c->devinfo,
1545 hblksz, hblkcnt) < 1)
1546 sndbuf_setblksz(b, CHANNEL_SETBLOCKSIZE(c->methods,
1547 c->devinfo, hblksz));
1548 CHN_LOCK(c);
1549
1531 if (!SLIST_EMPTY(&c->children)) {
1550 if (!CHN_EMPTY(c, children)) {
1532 sblksz = round_blksz(
1533 sndbuf_xbytes(sndbuf_getsize(b) >> 1, b, bs),
1534 sndbuf_getbps(bs));
1535 sblkcnt = 2;
1536 limit = 0;
1537 } else if (limit != 0)
1538 limit = sndbuf_xbytes(sndbuf_getsize(b), b, bs);
1539
1540 /*
1541 * Interrupt timeout
1542 */
1543 c->timeout = ((u_int64_t)hz * sndbuf_getsize(b)) /
1544 ((u_int64_t)sndbuf_getspd(b) * sndbuf_getbps(b));
1545 if (c->timeout < 1)
1546 c->timeout = 1;
1547 }
1548
1549 if (limit > CHN_2NDBUFMAXSIZE)
1550 limit = CHN_2NDBUFMAXSIZE;
1551
1552#if 0
1553 while (limit > 0 && (sblksz * sblkcnt) > limit) {
1554 if (sblkcnt < 4)
1555 break;
1556 sblkcnt >>= 1;
1557 }
1558#endif
1559
1560 while ((sblksz * sblkcnt) < limit)
1561 sblkcnt <<= 1;
1562
1563 while ((sblksz * sblkcnt) > CHN_2NDBUFMAXSIZE) {
1564 if (sblkcnt < 4)
1565 sblksz >>= 1;
1566 else
1567 sblkcnt >>= 1;
1568 }
1569
1570 sblksz -= sblksz % sndbuf_getbps(bs);
1571
1572 if (sndbuf_getblkcnt(bs) != sblkcnt || sndbuf_getblksz(bs) != sblksz ||
1573 sndbuf_getsize(bs) != (sblkcnt * sblksz)) {
1574 ret = sndbuf_remalloc(bs, sblkcnt, sblksz);
1575 if (ret != 0) {
1576 printf("%s: Failed: %d %d\n", __func__,
1577 sblkcnt, sblksz);
1578 return ret;
1579 }
1580 }
1581
1582 /*
1583 * OSSv4 docs: "By default OSS will set the low water level equal
1584 * to the fragment size which is optimal in most cases."
1585 */
1586 c->lw = sndbuf_getblksz(bs);
1587 chn_resetbuf(c);
1588
1589 if (snd_verbose > 3)
1590 printf("%s: %s (%s) timeout=%u "
1591 "b[%d/%d/%d] bs[%d/%d/%d] limit=%d\n",
1592 __func__, CHN_DIRSTR(c),
1593 (c->flags & CHN_F_VIRTUAL) ? "virtual" : "hardware",
1594 c->timeout,
1595 sndbuf_getsize(b), sndbuf_getblksz(b),
1596 sndbuf_getblkcnt(b),
1597 sndbuf_getsize(bs), sndbuf_getblksz(bs),
1598 sndbuf_getblkcnt(bs), limit);
1599
1600 return 0;
1601}
1602
1603int
1604chn_setlatency(struct pcm_channel *c, int latency)
1605{
1606 CHN_LOCKASSERT(c);
1607 /* Destroy blksz/blkcnt, enforce latency profile. */
1608 return chn_resizebuf(c, latency, -1, 0);
1609}
1610
1611int
1612chn_setblocksize(struct pcm_channel *c, int blkcnt, int blksz)
1613{
1614 CHN_LOCKASSERT(c);
1615 /* Destroy latency profile, enforce blksz/blkcnt */
1616 return chn_resizebuf(c, -1, blkcnt, blksz);
1617}
1618
1619static int
1620chn_tryspeed(struct pcm_channel *c, int speed)
1621{
1622 struct pcm_feeder *f;
1623 struct snd_dbuf *b = c->bufhard;
1624 struct snd_dbuf *bs = c->bufsoft;
1625 struct snd_dbuf *x;
1626 int r, delta;
1627
1628 CHN_LOCKASSERT(c);
1629 DEB(printf("setspeed, channel %s\n", c->name));
1630 DEB(printf("want speed %d, ", speed));
1631 if (speed <= 0)
1632 return EINVAL;
1633 if (CHN_STOPPED(c)) {
1634 r = 0;
1635 c->speed = speed;
1636 sndbuf_setspd(bs, speed);
1637 RANGE(speed, chn_getcaps(c)->minspeed, chn_getcaps(c)->maxspeed);
1638 DEB(printf("try speed %d, ", speed));
1639 sndbuf_setspd(b, CHANNEL_SETSPEED(c->methods, c->devinfo, speed));
1640 DEB(printf("got speed %d\n", sndbuf_getspd(b)));
1641
1642 delta = sndbuf_getspd(b) - sndbuf_getspd(bs);
1643 if (delta < 0)
1644 delta = -delta;
1645
1646 c->feederflags &= ~(1 << FEEDER_RATE);
1647 /*
1648 * Used to be 500. It was too big!
1649 */
1650 if (delta > feeder_rate_round)
1651 c->feederflags |= 1 << FEEDER_RATE;
1652 else
1653 sndbuf_setspd(bs, sndbuf_getspd(b));
1654
1655 r = chn_buildfeeder(c);
1656 DEB(printf("r = %d\n", r));
1657 if (r)
1658 goto out;
1659
1660 if (!(c->feederflags & (1 << FEEDER_RATE)))
1661 goto out;
1662
1663 r = EINVAL;
1664 f = chn_findfeeder(c, FEEDER_RATE);
1665 DEB(printf("feedrate = %p\n", f));
1666 if (f == NULL)
1667 goto out;
1668
1669 x = (c->direction == PCMDIR_REC)? b : bs;
1670 r = FEEDER_SET(f, FEEDRATE_SRC, sndbuf_getspd(x));
1671 DEB(printf("feeder_set(FEEDRATE_SRC, %d) = %d\n", sndbuf_getspd(x), r));
1672 if (r)
1673 goto out;
1674
1675 x = (c->direction == PCMDIR_REC)? bs : b;
1676 r = FEEDER_SET(f, FEEDRATE_DST, sndbuf_getspd(x));
1677 DEB(printf("feeder_set(FEEDRATE_DST, %d) = %d\n", sndbuf_getspd(x), r));
1678out:
1679 if (!r)
1680 r = CHANNEL_SETFORMAT(c->methods, c->devinfo,
1681 sndbuf_getfmt(b));
1682 if (!r)
1683 sndbuf_setfmt(bs, c->format);
1684 if (!r)
1685 r = chn_resizebuf(c, -2, 0, 0);
1686 DEB(printf("setspeed done, r = %d\n", r));
1687 return r;
1688 } else
1689 return EINVAL;
1690}
1691
1692int
1693chn_setspeed(struct pcm_channel *c, int speed)
1694{
1695 int r, oldspeed = c->speed;
1696
1697 r = chn_tryspeed(c, speed);
1698 if (r) {
1699 if (snd_verbose > 3)
1700 printf("Failed to set speed %d falling back to %d\n",
1701 speed, oldspeed);
1702 r = chn_tryspeed(c, oldspeed);
1703 }
1704 return r;
1705}
1706
1707static int
1708chn_tryformat(struct pcm_channel *c, u_int32_t fmt)
1709{
1710 struct snd_dbuf *b = c->bufhard;
1711 struct snd_dbuf *bs = c->bufsoft;
1712 int r;
1713
1714 CHN_LOCKASSERT(c);
1715 if (CHN_STOPPED(c)) {
1716 DEB(printf("want format %d\n", fmt));
1717 c->format = fmt;
1718 r = chn_buildfeeder(c);
1719 if (r == 0) {
1720 sndbuf_setfmt(bs, c->format);
1721 chn_resetbuf(c);
1722 r = CHANNEL_SETFORMAT(c->methods, c->devinfo, sndbuf_getfmt(b));
1723 if (r == 0)
1724 r = chn_tryspeed(c, c->speed);
1725 }
1726 return r;
1727 } else
1728 return EINVAL;
1729}
1730
1731int
1732chn_setformat(struct pcm_channel *c, u_int32_t fmt)
1733{
1734 u_int32_t oldfmt = c->format;
1735 int r;
1736
1737 r = chn_tryformat(c, fmt);
1738 if (r) {
1739 if (snd_verbose > 3)
1740 printf("Format change 0x%08x failed, reverting to 0x%08x\n",
1741 fmt, oldfmt);
1742 chn_tryformat(c, oldfmt);
1743 }
1744 return r;
1745}
1746
1747int
1748chn_trigger(struct pcm_channel *c, int go)
1749{
1750#ifdef DEV_ISA
1751 struct snd_dbuf *b = c->bufhard;
1752#endif
1551 sblksz = round_blksz(
1552 sndbuf_xbytes(sndbuf_getsize(b) >> 1, b, bs),
1553 sndbuf_getbps(bs));
1554 sblkcnt = 2;
1555 limit = 0;
1556 } else if (limit != 0)
1557 limit = sndbuf_xbytes(sndbuf_getsize(b), b, bs);
1558
1559 /*
1560 * Interrupt timeout
1561 */
1562 c->timeout = ((u_int64_t)hz * sndbuf_getsize(b)) /
1563 ((u_int64_t)sndbuf_getspd(b) * sndbuf_getbps(b));
1564 if (c->timeout < 1)
1565 c->timeout = 1;
1566 }
1567
1568 if (limit > CHN_2NDBUFMAXSIZE)
1569 limit = CHN_2NDBUFMAXSIZE;
1570
1571#if 0
1572 while (limit > 0 && (sblksz * sblkcnt) > limit) {
1573 if (sblkcnt < 4)
1574 break;
1575 sblkcnt >>= 1;
1576 }
1577#endif
1578
1579 while ((sblksz * sblkcnt) < limit)
1580 sblkcnt <<= 1;
1581
1582 while ((sblksz * sblkcnt) > CHN_2NDBUFMAXSIZE) {
1583 if (sblkcnt < 4)
1584 sblksz >>= 1;
1585 else
1586 sblkcnt >>= 1;
1587 }
1588
1589 sblksz -= sblksz % sndbuf_getbps(bs);
1590
1591 if (sndbuf_getblkcnt(bs) != sblkcnt || sndbuf_getblksz(bs) != sblksz ||
1592 sndbuf_getsize(bs) != (sblkcnt * sblksz)) {
1593 ret = sndbuf_remalloc(bs, sblkcnt, sblksz);
1594 if (ret != 0) {
1595 printf("%s: Failed: %d %d\n", __func__,
1596 sblkcnt, sblksz);
1597 return ret;
1598 }
1599 }
1600
1601 /*
1602 * OSSv4 docs: "By default OSS will set the low water level equal
1603 * to the fragment size which is optimal in most cases."
1604 */
1605 c->lw = sndbuf_getblksz(bs);
1606 chn_resetbuf(c);
1607
1608 if (snd_verbose > 3)
1609 printf("%s: %s (%s) timeout=%u "
1610 "b[%d/%d/%d] bs[%d/%d/%d] limit=%d\n",
1611 __func__, CHN_DIRSTR(c),
1612 (c->flags & CHN_F_VIRTUAL) ? "virtual" : "hardware",
1613 c->timeout,
1614 sndbuf_getsize(b), sndbuf_getblksz(b),
1615 sndbuf_getblkcnt(b),
1616 sndbuf_getsize(bs), sndbuf_getblksz(bs),
1617 sndbuf_getblkcnt(bs), limit);
1618
1619 return 0;
1620}
1621
1622int
1623chn_setlatency(struct pcm_channel *c, int latency)
1624{
1625 CHN_LOCKASSERT(c);
1626 /* Destroy blksz/blkcnt, enforce latency profile. */
1627 return chn_resizebuf(c, latency, -1, 0);
1628}
1629
1630int
1631chn_setblocksize(struct pcm_channel *c, int blkcnt, int blksz)
1632{
1633 CHN_LOCKASSERT(c);
1634 /* Destroy latency profile, enforce blksz/blkcnt */
1635 return chn_resizebuf(c, -1, blkcnt, blksz);
1636}
1637
1638static int
1639chn_tryspeed(struct pcm_channel *c, int speed)
1640{
1641 struct pcm_feeder *f;
1642 struct snd_dbuf *b = c->bufhard;
1643 struct snd_dbuf *bs = c->bufsoft;
1644 struct snd_dbuf *x;
1645 int r, delta;
1646
1647 CHN_LOCKASSERT(c);
1648 DEB(printf("setspeed, channel %s\n", c->name));
1649 DEB(printf("want speed %d, ", speed));
1650 if (speed <= 0)
1651 return EINVAL;
1652 if (CHN_STOPPED(c)) {
1653 r = 0;
1654 c->speed = speed;
1655 sndbuf_setspd(bs, speed);
1656 RANGE(speed, chn_getcaps(c)->minspeed, chn_getcaps(c)->maxspeed);
1657 DEB(printf("try speed %d, ", speed));
1658 sndbuf_setspd(b, CHANNEL_SETSPEED(c->methods, c->devinfo, speed));
1659 DEB(printf("got speed %d\n", sndbuf_getspd(b)));
1660
1661 delta = sndbuf_getspd(b) - sndbuf_getspd(bs);
1662 if (delta < 0)
1663 delta = -delta;
1664
1665 c->feederflags &= ~(1 << FEEDER_RATE);
1666 /*
1667 * Used to be 500. It was too big!
1668 */
1669 if (delta > feeder_rate_round)
1670 c->feederflags |= 1 << FEEDER_RATE;
1671 else
1672 sndbuf_setspd(bs, sndbuf_getspd(b));
1673
1674 r = chn_buildfeeder(c);
1675 DEB(printf("r = %d\n", r));
1676 if (r)
1677 goto out;
1678
1679 if (!(c->feederflags & (1 << FEEDER_RATE)))
1680 goto out;
1681
1682 r = EINVAL;
1683 f = chn_findfeeder(c, FEEDER_RATE);
1684 DEB(printf("feedrate = %p\n", f));
1685 if (f == NULL)
1686 goto out;
1687
1688 x = (c->direction == PCMDIR_REC)? b : bs;
1689 r = FEEDER_SET(f, FEEDRATE_SRC, sndbuf_getspd(x));
1690 DEB(printf("feeder_set(FEEDRATE_SRC, %d) = %d\n", sndbuf_getspd(x), r));
1691 if (r)
1692 goto out;
1693
1694 x = (c->direction == PCMDIR_REC)? bs : b;
1695 r = FEEDER_SET(f, FEEDRATE_DST, sndbuf_getspd(x));
1696 DEB(printf("feeder_set(FEEDRATE_DST, %d) = %d\n", sndbuf_getspd(x), r));
1697out:
1698 if (!r)
1699 r = CHANNEL_SETFORMAT(c->methods, c->devinfo,
1700 sndbuf_getfmt(b));
1701 if (!r)
1702 sndbuf_setfmt(bs, c->format);
1703 if (!r)
1704 r = chn_resizebuf(c, -2, 0, 0);
1705 DEB(printf("setspeed done, r = %d\n", r));
1706 return r;
1707 } else
1708 return EINVAL;
1709}
1710
1711int
1712chn_setspeed(struct pcm_channel *c, int speed)
1713{
1714 int r, oldspeed = c->speed;
1715
1716 r = chn_tryspeed(c, speed);
1717 if (r) {
1718 if (snd_verbose > 3)
1719 printf("Failed to set speed %d falling back to %d\n",
1720 speed, oldspeed);
1721 r = chn_tryspeed(c, oldspeed);
1722 }
1723 return r;
1724}
1725
1726static int
1727chn_tryformat(struct pcm_channel *c, u_int32_t fmt)
1728{
1729 struct snd_dbuf *b = c->bufhard;
1730 struct snd_dbuf *bs = c->bufsoft;
1731 int r;
1732
1733 CHN_LOCKASSERT(c);
1734 if (CHN_STOPPED(c)) {
1735 DEB(printf("want format %d\n", fmt));
1736 c->format = fmt;
1737 r = chn_buildfeeder(c);
1738 if (r == 0) {
1739 sndbuf_setfmt(bs, c->format);
1740 chn_resetbuf(c);
1741 r = CHANNEL_SETFORMAT(c->methods, c->devinfo, sndbuf_getfmt(b));
1742 if (r == 0)
1743 r = chn_tryspeed(c, c->speed);
1744 }
1745 return r;
1746 } else
1747 return EINVAL;
1748}
1749
1750int
1751chn_setformat(struct pcm_channel *c, u_int32_t fmt)
1752{
1753 u_int32_t oldfmt = c->format;
1754 int r;
1755
1756 r = chn_tryformat(c, fmt);
1757 if (r) {
1758 if (snd_verbose > 3)
1759 printf("Format change 0x%08x failed, reverting to 0x%08x\n",
1760 fmt, oldfmt);
1761 chn_tryformat(c, oldfmt);
1762 }
1763 return r;
1764}
1765
1766int
1767chn_trigger(struct pcm_channel *c, int go)
1768{
1769#ifdef DEV_ISA
1770 struct snd_dbuf *b = c->bufhard;
1771#endif
1772 struct snddev_info *d = c->parentsnddev;
1753 int ret;
1754
1755 CHN_LOCKASSERT(c);
1756#ifdef DEV_ISA
1757 if (SND_DMA(b) && (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD))
1758 sndbuf_dmabounce(b);
1759#endif
1773 int ret;
1774
1775 CHN_LOCKASSERT(c);
1776#ifdef DEV_ISA
1777 if (SND_DMA(b) && (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD))
1778 sndbuf_dmabounce(b);
1779#endif
1780 if ((go == PCMTRIG_START || go == PCMTRIG_STOP ||
1781 go == PCMTRIG_ABORT) && go == c->trigger)
1782 return 0;
1783
1760 ret = CHANNEL_TRIGGER(c->methods, c->devinfo, go);
1761
1784 ret = CHANNEL_TRIGGER(c->methods, c->devinfo, go);
1785
1786 if (ret == 0) {
1787 switch (go) {
1788 case PCMTRIG_START:
1789 if (snd_verbose > 3)
1790 device_printf(c->dev,
1791 "%s() %s: calling go=0x%08x , "
1792 "prev=0x%08x\n", __func__, c->name, go,
1793 c->trigger);
1794 if (c->trigger != PCMTRIG_START) {
1795 c->trigger = go;
1796 CHN_UNLOCK(c);
1797 pcm_lock(d);
1798 CHN_INSERT_HEAD(d, c, channels.pcm.busy);
1799 pcm_unlock(d);
1800 CHN_LOCK(c);
1801 }
1802 break;
1803 case PCMTRIG_STOP:
1804 case PCMTRIG_ABORT:
1805 if (snd_verbose > 3)
1806 device_printf(c->dev,
1807 "%s() %s: calling go=0x%08x , "
1808 "prev=0x%08x\n", __func__, c->name, go,
1809 c->trigger);
1810 if (c->trigger == PCMTRIG_START) {
1811 c->trigger = go;
1812 CHN_UNLOCK(c);
1813 pcm_lock(d);
1814 CHN_REMOVE(d, c, channels.pcm.busy);
1815 pcm_unlock(d);
1816 CHN_LOCK(c);
1817 }
1818 break;
1819 default:
1820 break;
1821 }
1822 }
1823
1762 return ret;
1763}
1764
1765/**
1766 * @brief Queries sound driver for sample-aligned hardware buffer pointer index
1767 *
1768 * This function obtains the hardware pointer location, then aligns it to
1769 * the current bytes-per-sample value before returning. (E.g., a channel
1770 * running in 16 bit stereo mode would require 4 bytes per sample, so a
1771 * hwptr value ranging from 32-35 would be returned as 32.)
1772 *
1773 * @param c PCM channel context
1774 * @returns sample-aligned hardware buffer pointer index
1775 */
1776int
1777chn_getptr(struct pcm_channel *c)
1778{
1779#if 0
1780 int hwptr;
1781 int a = (1 << c->align) - 1;
1782
1783 CHN_LOCKASSERT(c);
1784 hwptr = (c->flags & CHN_F_TRIGGERED)? CHANNEL_GETPTR(c->methods, c->devinfo) : 0;
1785 /* don't allow unaligned values in the hwa ptr */
1786#if 1
1787 hwptr &= ~a ; /* Apply channel align mask */
1788#endif
1789 hwptr &= DMA_ALIGN_MASK; /* Apply DMA align mask */
1790 return hwptr;
1791#endif
1792 int hwptr;
1793
1794 CHN_LOCKASSERT(c);
1795 hwptr = (CHN_STARTED(c)) ? CHANNEL_GETPTR(c->methods, c->devinfo) : 0;
1796 return (hwptr - (hwptr % sndbuf_getbps(c->bufhard)));
1797}
1798
1799struct pcmchan_caps *
1800chn_getcaps(struct pcm_channel *c)
1801{
1802 CHN_LOCKASSERT(c);
1803 return CHANNEL_GETCAPS(c->methods, c->devinfo);
1804}
1805
1806u_int32_t
1807chn_getformats(struct pcm_channel *c)
1808{
1809 u_int32_t *fmtlist, fmts;
1810 int i;
1811
1812 fmtlist = chn_getcaps(c)->fmtlist;
1813 fmts = 0;
1814 for (i = 0; fmtlist[i]; i++)
1815 fmts |= fmtlist[i];
1816
1817 /* report software-supported formats */
1818 if (report_soft_formats)
1819 fmts |= AFMT_MU_LAW|AFMT_A_LAW|AFMT_U32_LE|AFMT_U32_BE|
1820 AFMT_S32_LE|AFMT_S32_BE|AFMT_U24_LE|AFMT_U24_BE|
1821 AFMT_S24_LE|AFMT_S24_BE|AFMT_U16_LE|AFMT_U16_BE|
1822 AFMT_S16_LE|AFMT_S16_BE|AFMT_U8|AFMT_S8;
1823
1824 return fmts;
1825}
1826
1827static int
1828chn_buildfeeder(struct pcm_channel *c)
1829{
1830 struct feeder_class *fc;
1831 struct pcm_feederdesc desc;
1832 u_int32_t tmp[2], type, flags, hwfmt, *fmtlist;
1833 int err;
1834 char fmtstr[AFMTSTR_MAXSZ];
1835
1836 CHN_LOCKASSERT(c);
1837 while (chn_removefeeder(c) == 0)
1838 ;
1839 KASSERT((c->feeder == NULL), ("feeder chain not empty"));
1840
1841 c->align = sndbuf_getalign(c->bufsoft);
1842
1824 return ret;
1825}
1826
1827/**
1828 * @brief Queries sound driver for sample-aligned hardware buffer pointer index
1829 *
1830 * This function obtains the hardware pointer location, then aligns it to
1831 * the current bytes-per-sample value before returning. (E.g., a channel
1832 * running in 16 bit stereo mode would require 4 bytes per sample, so a
1833 * hwptr value ranging from 32-35 would be returned as 32.)
1834 *
1835 * @param c PCM channel context
1836 * @returns sample-aligned hardware buffer pointer index
1837 */
1838int
1839chn_getptr(struct pcm_channel *c)
1840{
1841#if 0
1842 int hwptr;
1843 int a = (1 << c->align) - 1;
1844
1845 CHN_LOCKASSERT(c);
1846 hwptr = (c->flags & CHN_F_TRIGGERED)? CHANNEL_GETPTR(c->methods, c->devinfo) : 0;
1847 /* don't allow unaligned values in the hwa ptr */
1848#if 1
1849 hwptr &= ~a ; /* Apply channel align mask */
1850#endif
1851 hwptr &= DMA_ALIGN_MASK; /* Apply DMA align mask */
1852 return hwptr;
1853#endif
1854 int hwptr;
1855
1856 CHN_LOCKASSERT(c);
1857 hwptr = (CHN_STARTED(c)) ? CHANNEL_GETPTR(c->methods, c->devinfo) : 0;
1858 return (hwptr - (hwptr % sndbuf_getbps(c->bufhard)));
1859}
1860
1861struct pcmchan_caps *
1862chn_getcaps(struct pcm_channel *c)
1863{
1864 CHN_LOCKASSERT(c);
1865 return CHANNEL_GETCAPS(c->methods, c->devinfo);
1866}
1867
1868u_int32_t
1869chn_getformats(struct pcm_channel *c)
1870{
1871 u_int32_t *fmtlist, fmts;
1872 int i;
1873
1874 fmtlist = chn_getcaps(c)->fmtlist;
1875 fmts = 0;
1876 for (i = 0; fmtlist[i]; i++)
1877 fmts |= fmtlist[i];
1878
1879 /* report software-supported formats */
1880 if (report_soft_formats)
1881 fmts |= AFMT_MU_LAW|AFMT_A_LAW|AFMT_U32_LE|AFMT_U32_BE|
1882 AFMT_S32_LE|AFMT_S32_BE|AFMT_U24_LE|AFMT_U24_BE|
1883 AFMT_S24_LE|AFMT_S24_BE|AFMT_U16_LE|AFMT_U16_BE|
1884 AFMT_S16_LE|AFMT_S16_BE|AFMT_U8|AFMT_S8;
1885
1886 return fmts;
1887}
1888
1889static int
1890chn_buildfeeder(struct pcm_channel *c)
1891{
1892 struct feeder_class *fc;
1893 struct pcm_feederdesc desc;
1894 u_int32_t tmp[2], type, flags, hwfmt, *fmtlist;
1895 int err;
1896 char fmtstr[AFMTSTR_MAXSZ];
1897
1898 CHN_LOCKASSERT(c);
1899 while (chn_removefeeder(c) == 0)
1900 ;
1901 KASSERT((c->feeder == NULL), ("feeder chain not empty"));
1902
1903 c->align = sndbuf_getalign(c->bufsoft);
1904
1843 if (SLIST_EMPTY(&c->children)) {
1905 if (CHN_EMPTY(c, children) || c->direction == PCMDIR_REC) {
1906 /*
1907 * Virtual rec need this.
1908 */
1844 fc = feeder_getclass(NULL);
1845 KASSERT(fc != NULL, ("can't find root feeder"));
1846
1847 err = chn_addfeeder(c, fc, NULL);
1848 if (err) {
1849 DEB(printf("can't add root feeder, err %d\n", err));
1850
1851 return err;
1852 }
1853 c->feeder->desc->out = c->format;
1909 fc = feeder_getclass(NULL);
1910 KASSERT(fc != NULL, ("can't find root feeder"));
1911
1912 err = chn_addfeeder(c, fc, NULL);
1913 if (err) {
1914 DEB(printf("can't add root feeder, err %d\n", err));
1915
1916 return err;
1917 }
1918 c->feeder->desc->out = c->format;
1854 } else {
1919 } else if (c->direction == PCMDIR_PLAY) {
1855 if (c->flags & CHN_F_HAS_VCHAN) {
1856 desc.type = FEEDER_MIXER;
1857 desc.in = c->format;
1858 } else {
1859 DEB(printf("can't decide which feeder type to use!\n"));
1860 return EOPNOTSUPP;
1861 }
1862 desc.out = c->format;
1863 desc.flags = 0;
1864 fc = feeder_getclass(&desc);
1865 if (fc == NULL) {
1866 DEB(printf("can't find vchan feeder\n"));
1867
1868 return EOPNOTSUPP;
1869 }
1870
1871 err = chn_addfeeder(c, fc, &desc);
1872 if (err) {
1873 DEB(printf("can't add vchan feeder, err %d\n", err));
1874
1875 return err;
1876 }
1920 if (c->flags & CHN_F_HAS_VCHAN) {
1921 desc.type = FEEDER_MIXER;
1922 desc.in = c->format;
1923 } else {
1924 DEB(printf("can't decide which feeder type to use!\n"));
1925 return EOPNOTSUPP;
1926 }
1927 desc.out = c->format;
1928 desc.flags = 0;
1929 fc = feeder_getclass(&desc);
1930 if (fc == NULL) {
1931 DEB(printf("can't find vchan feeder\n"));
1932
1933 return EOPNOTSUPP;
1934 }
1935
1936 err = chn_addfeeder(c, fc, &desc);
1937 if (err) {
1938 DEB(printf("can't add vchan feeder, err %d\n", err));
1939
1940 return err;
1941 }
1877 }
1942 } else
1943 return EOPNOTSUPP;
1944
1878 c->feederflags &= ~(1 << FEEDER_VOLUME);
1879 if (c->direction == PCMDIR_PLAY &&
1880 !(c->flags & CHN_F_VIRTUAL) && c->parentsnddev &&
1881 (c->parentsnddev->flags & SD_F_SOFTPCMVOL) &&
1882 c->parentsnddev->mixer_dev)
1883 c->feederflags |= 1 << FEEDER_VOLUME;
1884 if (!(c->flags & CHN_F_VIRTUAL) && c->parentsnddev &&
1885 ((c->direction == PCMDIR_PLAY &&
1886 (c->parentsnddev->flags & SD_F_PSWAPLR)) ||
1887 (c->direction == PCMDIR_REC &&
1888 (c->parentsnddev->flags & SD_F_RSWAPLR))))
1889 c->feederflags |= 1 << FEEDER_SWAPLR;
1890 flags = c->feederflags;
1891 fmtlist = chn_getcaps(c)->fmtlist;
1892
1893 DEB(printf("feederflags %x\n", flags));
1894
1895 for (type = FEEDER_RATE; type < FEEDER_LAST; type++) {
1896 if (flags & (1 << type)) {
1897 desc.type = type;
1898 desc.in = 0;
1899 desc.out = 0;
1900 desc.flags = 0;
1901 DEB(printf("find feeder type %d, ", type));
1902 if (type == FEEDER_VOLUME || type == FEEDER_RATE) {
1903 if (c->feeder->desc->out & AFMT_32BIT)
1904 strlcpy(fmtstr,"s32le", sizeof(fmtstr));
1905 else if (c->feeder->desc->out & AFMT_24BIT)
1906 strlcpy(fmtstr, "s24le", sizeof(fmtstr));
1907 else {
1908 /*
1909 * 8bit doesn't provide enough headroom
1910 * for proper processing without
1911 * creating too much noises. Force to
1912 * 16bit instead.
1913 */
1914 strlcpy(fmtstr, "s16le", sizeof(fmtstr));
1915 }
1916 if (!(c->feeder->desc->out & AFMT_8BIT) &&
1917 c->feeder->desc->out & AFMT_BIGENDIAN)
1918 afmtstr_swap_endian(fmtstr);
1919 if (!(c->feeder->desc->out & (AFMT_A_LAW | AFMT_MU_LAW)) &&
1920 !(c->feeder->desc->out & AFMT_SIGNED))
1921 afmtstr_swap_sign(fmtstr);
1922 desc.in = afmtstr2afmt(NULL, fmtstr, AFMTSTR_MONO_RETURN);
1923 if (desc.in == 0)
1924 desc.in = AFMT_S16_LE;
1925 /* feeder_volume need stereo processing */
1926 if (type == FEEDER_VOLUME ||
1927 c->feeder->desc->out & AFMT_STEREO)
1928 desc.in |= AFMT_STEREO;
1929 desc.out = desc.in;
1930 } else if (type == FEEDER_SWAPLR) {
1931 desc.in = c->feeder->desc->out;
1932 desc.in |= AFMT_STEREO;
1933 desc.out = desc.in;
1934 }
1935
1936 fc = feeder_getclass(&desc);
1937 DEB(printf("got %p\n", fc));
1938 if (fc == NULL) {
1939 DEB(printf("can't find required feeder type %d\n", type));
1940
1941 return EOPNOTSUPP;
1942 }
1943
1944 if (desc.in == 0 || desc.out == 0)
1945 desc = *fc->desc;
1946
1947 DEB(printf("build fmtchain from 0x%08x to 0x%08x: ", c->feeder->desc->out, fc->desc->in));
1948 tmp[0] = desc.in;
1949 tmp[1] = 0;
1950 if (chn_fmtchain(c, tmp) == 0) {
1951 DEB(printf("failed\n"));
1952
1953 return ENODEV;
1954 }
1955 DEB(printf("ok\n"));
1956
1957 err = chn_addfeeder(c, fc, &desc);
1958 if (err) {
1959 DEB(printf("can't add feeder %p, output 0x%x, err %d\n", fc, fc->desc->out, err));
1960
1961 return err;
1962 }
1963 DEB(printf("added feeder %p, output 0x%x\n", fc, c->feeder->desc->out));
1964 }
1965 }
1966
1967 if (c->direction == PCMDIR_REC) {
1968 tmp[0] = c->format;
1969 tmp[1] = 0;
1970 hwfmt = chn_fmtchain(c, tmp);
1971 } else
1972 hwfmt = chn_fmtchain(c, fmtlist);
1973
1974 if (hwfmt == 0 || !fmtvalid(hwfmt, fmtlist)) {
1975 DEB(printf("Invalid hardware format: 0x%08x\n", hwfmt));
1976 return ENODEV;
1945 c->feederflags &= ~(1 << FEEDER_VOLUME);
1946 if (c->direction == PCMDIR_PLAY &&
1947 !(c->flags & CHN_F_VIRTUAL) && c->parentsnddev &&
1948 (c->parentsnddev->flags & SD_F_SOFTPCMVOL) &&
1949 c->parentsnddev->mixer_dev)
1950 c->feederflags |= 1 << FEEDER_VOLUME;
1951 if (!(c->flags & CHN_F_VIRTUAL) && c->parentsnddev &&
1952 ((c->direction == PCMDIR_PLAY &&
1953 (c->parentsnddev->flags & SD_F_PSWAPLR)) ||
1954 (c->direction == PCMDIR_REC &&
1955 (c->parentsnddev->flags & SD_F_RSWAPLR))))
1956 c->feederflags |= 1 << FEEDER_SWAPLR;
1957 flags = c->feederflags;
1958 fmtlist = chn_getcaps(c)->fmtlist;
1959
1960 DEB(printf("feederflags %x\n", flags));
1961
1962 for (type = FEEDER_RATE; type < FEEDER_LAST; type++) {
1963 if (flags & (1 << type)) {
1964 desc.type = type;
1965 desc.in = 0;
1966 desc.out = 0;
1967 desc.flags = 0;
1968 DEB(printf("find feeder type %d, ", type));
1969 if (type == FEEDER_VOLUME || type == FEEDER_RATE) {
1970 if (c->feeder->desc->out & AFMT_32BIT)
1971 strlcpy(fmtstr,"s32le", sizeof(fmtstr));
1972 else if (c->feeder->desc->out & AFMT_24BIT)
1973 strlcpy(fmtstr, "s24le", sizeof(fmtstr));
1974 else {
1975 /*
1976 * 8bit doesn't provide enough headroom
1977 * for proper processing without
1978 * creating too much noises. Force to
1979 * 16bit instead.
1980 */
1981 strlcpy(fmtstr, "s16le", sizeof(fmtstr));
1982 }
1983 if (!(c->feeder->desc->out & AFMT_8BIT) &&
1984 c->feeder->desc->out & AFMT_BIGENDIAN)
1985 afmtstr_swap_endian(fmtstr);
1986 if (!(c->feeder->desc->out & (AFMT_A_LAW | AFMT_MU_LAW)) &&
1987 !(c->feeder->desc->out & AFMT_SIGNED))
1988 afmtstr_swap_sign(fmtstr);
1989 desc.in = afmtstr2afmt(NULL, fmtstr, AFMTSTR_MONO_RETURN);
1990 if (desc.in == 0)
1991 desc.in = AFMT_S16_LE;
1992 /* feeder_volume need stereo processing */
1993 if (type == FEEDER_VOLUME ||
1994 c->feeder->desc->out & AFMT_STEREO)
1995 desc.in |= AFMT_STEREO;
1996 desc.out = desc.in;
1997 } else if (type == FEEDER_SWAPLR) {
1998 desc.in = c->feeder->desc->out;
1999 desc.in |= AFMT_STEREO;
2000 desc.out = desc.in;
2001 }
2002
2003 fc = feeder_getclass(&desc);
2004 DEB(printf("got %p\n", fc));
2005 if (fc == NULL) {
2006 DEB(printf("can't find required feeder type %d\n", type));
2007
2008 return EOPNOTSUPP;
2009 }
2010
2011 if (desc.in == 0 || desc.out == 0)
2012 desc = *fc->desc;
2013
2014 DEB(printf("build fmtchain from 0x%08x to 0x%08x: ", c->feeder->desc->out, fc->desc->in));
2015 tmp[0] = desc.in;
2016 tmp[1] = 0;
2017 if (chn_fmtchain(c, tmp) == 0) {
2018 DEB(printf("failed\n"));
2019
2020 return ENODEV;
2021 }
2022 DEB(printf("ok\n"));
2023
2024 err = chn_addfeeder(c, fc, &desc);
2025 if (err) {
2026 DEB(printf("can't add feeder %p, output 0x%x, err %d\n", fc, fc->desc->out, err));
2027
2028 return err;
2029 }
2030 DEB(printf("added feeder %p, output 0x%x\n", fc, c->feeder->desc->out));
2031 }
2032 }
2033
2034 if (c->direction == PCMDIR_REC) {
2035 tmp[0] = c->format;
2036 tmp[1] = 0;
2037 hwfmt = chn_fmtchain(c, tmp);
2038 } else
2039 hwfmt = chn_fmtchain(c, fmtlist);
2040
2041 if (hwfmt == 0 || !fmtvalid(hwfmt, fmtlist)) {
2042 DEB(printf("Invalid hardware format: 0x%08x\n", hwfmt));
2043 return ENODEV;
2044 } else if (c->direction == PCMDIR_REC && !CHN_EMPTY(c, children)) {
2045 /*
2046 * Kind of awkward. This whole "MIXER" concept need a
2047 * rethinking, I guess :) . Recording is the inverse
2048 * of Playback, which is why we push mixer vchan down here.
2049 */
2050 if (c->flags & CHN_F_HAS_VCHAN) {
2051 desc.type = FEEDER_MIXER;
2052 desc.in = c->format;
2053 } else
2054 return EOPNOTSUPP;
2055 desc.out = c->format;
2056 desc.flags = 0;
2057 fc = feeder_getclass(&desc);
2058 if (fc == NULL)
2059 return EOPNOTSUPP;
2060
2061 err = chn_addfeeder(c, fc, &desc);
2062 if (err != 0)
2063 return err;
1977 }
1978
1979 sndbuf_setfmt(c->bufhard, hwfmt);
1980
1981 if ((flags & (1 << FEEDER_VOLUME))) {
1982 u_int32_t parent = SOUND_MIXER_NONE;
1983 int vol, left, right;
1984
1985 vol = 100 | (100 << 8);
1986
1987 CHN_UNLOCK(c);
1988 /*
1989 * XXX This is ugly! The way mixer subs being so secretive
1990 * about its own internals force us to use this silly
1991 * monkey trick.
1992 */
1993 if (mixer_ioctl(c->parentsnddev->mixer_dev,
1994 MIXER_READ(SOUND_MIXER_PCM), (caddr_t)&vol, -1, NULL) != 0)
1995 device_printf(c->dev, "Soft PCM Volume: Failed to read default value\n");
1996 left = vol & 0x7f;
1997 right = (vol >> 8) & 0x7f;
1998 if (c->parentsnddev != NULL &&
1999 c->parentsnddev->mixer_dev != NULL &&
2000 c->parentsnddev->mixer_dev->si_drv1 != NULL)
2001 parent = mix_getparent(
2002 c->parentsnddev->mixer_dev->si_drv1,
2003 SOUND_MIXER_PCM);
2004 if (parent != SOUND_MIXER_NONE) {
2005 vol = 100 | (100 << 8);
2006 if (mixer_ioctl(c->parentsnddev->mixer_dev,
2007 MIXER_READ(parent),
2008 (caddr_t)&vol, -1, NULL) != 0)
2009 device_printf(c->dev, "Soft Volume: Failed to read parent default value\n");
2010 left = (left * (vol & 0x7f)) / 100;
2011 right = (right * ((vol >> 8) & 0x7f)) / 100;
2012 }
2013 CHN_LOCK(c);
2014 chn_setvolume(c, left, right);
2015 }
2016
2017 return 0;
2018}
2019
2020int
2021chn_notify(struct pcm_channel *c, u_int32_t flags)
2022{
2064 }
2065
2066 sndbuf_setfmt(c->bufhard, hwfmt);
2067
2068 if ((flags & (1 << FEEDER_VOLUME))) {
2069 u_int32_t parent = SOUND_MIXER_NONE;
2070 int vol, left, right;
2071
2072 vol = 100 | (100 << 8);
2073
2074 CHN_UNLOCK(c);
2075 /*
2076 * XXX This is ugly! The way mixer subs being so secretive
2077 * about its own internals force us to use this silly
2078 * monkey trick.
2079 */
2080 if (mixer_ioctl(c->parentsnddev->mixer_dev,
2081 MIXER_READ(SOUND_MIXER_PCM), (caddr_t)&vol, -1, NULL) != 0)
2082 device_printf(c->dev, "Soft PCM Volume: Failed to read default value\n");
2083 left = vol & 0x7f;
2084 right = (vol >> 8) & 0x7f;
2085 if (c->parentsnddev != NULL &&
2086 c->parentsnddev->mixer_dev != NULL &&
2087 c->parentsnddev->mixer_dev->si_drv1 != NULL)
2088 parent = mix_getparent(
2089 c->parentsnddev->mixer_dev->si_drv1,
2090 SOUND_MIXER_PCM);
2091 if (parent != SOUND_MIXER_NONE) {
2092 vol = 100 | (100 << 8);
2093 if (mixer_ioctl(c->parentsnddev->mixer_dev,
2094 MIXER_READ(parent),
2095 (caddr_t)&vol, -1, NULL) != 0)
2096 device_printf(c->dev, "Soft Volume: Failed to read parent default value\n");
2097 left = (left * (vol & 0x7f)) / 100;
2098 right = (right * ((vol >> 8) & 0x7f)) / 100;
2099 }
2100 CHN_LOCK(c);
2101 chn_setvolume(c, left, right);
2102 }
2103
2104 return 0;
2105}
2106
2107int
2108chn_notify(struct pcm_channel *c, u_int32_t flags)
2109{
2023 struct pcmchan_children *pce;
2024 struct pcm_channel *child;
2025 int run;
2026
2027 CHN_LOCK(c);
2028
2110 int run;
2111
2112 CHN_LOCK(c);
2113
2029 if (SLIST_EMPTY(&c->children)) {
2114 if (CHN_EMPTY(c, children)) {
2030 CHN_UNLOCK(c);
2031 return ENODEV;
2032 }
2033
2034 run = (CHN_STARTED(c)) ? 1 : 0;
2035 /*
2036 * if the hwchan is running, we can't change its rate, format or
2037 * blocksize
2038 */
2039 if (run)
2040 flags &= CHN_N_VOLUME | CHN_N_TRIGGER;
2041
2042 if (flags & CHN_N_RATE) {
2043 /*
2044 * we could do something here, like scan children and decide on
2045 * the most appropriate rate to mix at, but we don't for now
2046 */
2047 }
2048 if (flags & CHN_N_FORMAT) {
2049 /*
2050 * we could do something here, like scan children and decide on
2051 * the most appropriate mixer feeder to use, but we don't for now
2052 */
2053 }
2054 if (flags & CHN_N_VOLUME) {
2055 /*
2056 * we could do something here but we don't for now
2057 */
2058 }
2059 if (flags & CHN_N_BLOCKSIZE) {
2060 /*
2061 * Set to default latency profile
2062 */
2063 chn_setlatency(c, chn_latency);
2064 }
2065 if (flags & CHN_N_TRIGGER) {
2066 int nrun;
2115 CHN_UNLOCK(c);
2116 return ENODEV;
2117 }
2118
2119 run = (CHN_STARTED(c)) ? 1 : 0;
2120 /*
2121 * if the hwchan is running, we can't change its rate, format or
2122 * blocksize
2123 */
2124 if (run)
2125 flags &= CHN_N_VOLUME | CHN_N_TRIGGER;
2126
2127 if (flags & CHN_N_RATE) {
2128 /*
2129 * we could do something here, like scan children and decide on
2130 * the most appropriate rate to mix at, but we don't for now
2131 */
2132 }
2133 if (flags & CHN_N_FORMAT) {
2134 /*
2135 * we could do something here, like scan children and decide on
2136 * the most appropriate mixer feeder to use, but we don't for now
2137 */
2138 }
2139 if (flags & CHN_N_VOLUME) {
2140 /*
2141 * we could do something here but we don't for now
2142 */
2143 }
2144 if (flags & CHN_N_BLOCKSIZE) {
2145 /*
2146 * Set to default latency profile
2147 */
2148 chn_setlatency(c, chn_latency);
2149 }
2150 if (flags & CHN_N_TRIGGER) {
2151 int nrun;
2067 /*
2068 * scan the children, and figure out if any are running
2069 * if so, we need to be running, otherwise we need to be stopped
2070 * if we aren't in our target sstate, move to it
2071 */
2072 nrun = 0;
2073 SLIST_FOREACH(pce, &c->children, link) {
2074 child = pce->channel;
2075 CHN_LOCK(child);
2076 nrun = CHN_STARTED(child);
2077 CHN_UNLOCK(child);
2078 if (nrun)
2079 break;
2080 }
2152
2153 nrun = CHN_EMPTY(c, children.busy) ? 0 : 1;
2081 if (nrun && !run)
2082 chn_start(c, 1);
2083 if (!nrun && run)
2084 chn_abort(c);
2085 }
2086 CHN_UNLOCK(c);
2087 return 0;
2088}
2089
2090/**
2091 * @brief Fetch array of supported discrete sample rates
2092 *
2093 * Wrapper for CHANNEL_GETRATES. Please see channel_if.m:getrates() for
2094 * detailed information.
2095 *
2096 * @note If the operation isn't supported, this function will just return 0
2097 * (no rates in the array), and *rates will be set to NULL. Callers
2098 * should examine rates @b only if this function returns non-zero.
2099 *
2100 * @param c pcm channel to examine
2101 * @param rates pointer to array of integers; rate table will be recorded here
2102 *
2103 * @return number of rates in the array pointed to be @c rates
2104 */
2105int
2106chn_getrates(struct pcm_channel *c, int **rates)
2107{
2108 KASSERT(rates != NULL, ("rates is null"));
2109 CHN_LOCKASSERT(c);
2110 return CHANNEL_GETRATES(c->methods, c->devinfo, rates);
2111}
2112
2113/**
2114 * @brief Remove channel from a sync group, if there is one.
2115 *
2116 * This function is initially intended for the following conditions:
2117 * - Starting a syncgroup (@c SNDCTL_DSP_SYNCSTART ioctl)
2118 * - Closing a device. (A channel can't be destroyed if it's still in use.)
2119 *
2120 * @note Before calling this function, the syncgroup list mutex must be
2121 * held. (Consider pcm_channel::sm protected by the SG list mutex
2122 * whether @c c is locked or not.)
2123 *
2124 * @param c channel device to be started or closed
2125 * @returns If this channel was the only member of a group, the group ID
2126 * is returned to the caller so that the caller can release it
2127 * via free_unr() after giving up the syncgroup lock. Else it
2128 * returns 0.
2129 */
2130int
2131chn_syncdestroy(struct pcm_channel *c)
2132{
2133 struct pcmchan_syncmember *sm;
2134 struct pcmchan_syncgroup *sg;
2135 int sg_id;
2136
2137 sg_id = 0;
2138
2139 PCM_SG_LOCKASSERT(MA_OWNED);
2140
2141 if (c->sm != NULL) {
2142 sm = c->sm;
2143 sg = sm->parent;
2144 c->sm = NULL;
2145
2146 KASSERT(sg != NULL, ("syncmember has null parent"));
2147
2148 SLIST_REMOVE(&sg->members, sm, pcmchan_syncmember, link);
2149 free(sm, M_DEVBUF);
2150
2151 if (SLIST_EMPTY(&sg->members)) {
2152 SLIST_REMOVE(&snd_pcm_syncgroups, sg, pcmchan_syncgroup, link);
2153 sg_id = sg->id;
2154 free(sg, M_DEVBUF);
2155 }
2156 }
2157
2158 return sg_id;
2159}
2160
2161void
2162chn_lock(struct pcm_channel *c)
2163{
2164 CHN_LOCK(c);
2165}
2166
2167void
2168chn_unlock(struct pcm_channel *c)
2169{
2170 CHN_UNLOCK(c);
2171}
2172
2173#ifdef OSSV4_EXPERIMENT
2174int
2175chn_getpeaks(struct pcm_channel *c, int *lpeak, int *rpeak)
2176{
2177 CHN_LOCKASSERT(c);
2178 return CHANNEL_GETPEAKS(c->methods, c->devinfo, lpeak, rpeak);
2179}
2180#endif
2154 if (nrun && !run)
2155 chn_start(c, 1);
2156 if (!nrun && run)
2157 chn_abort(c);
2158 }
2159 CHN_UNLOCK(c);
2160 return 0;
2161}
2162
2163/**
2164 * @brief Fetch array of supported discrete sample rates
2165 *
2166 * Wrapper for CHANNEL_GETRATES. Please see channel_if.m:getrates() for
2167 * detailed information.
2168 *
2169 * @note If the operation isn't supported, this function will just return 0
2170 * (no rates in the array), and *rates will be set to NULL. Callers
2171 * should examine rates @b only if this function returns non-zero.
2172 *
2173 * @param c pcm channel to examine
2174 * @param rates pointer to array of integers; rate table will be recorded here
2175 *
2176 * @return number of rates in the array pointed to be @c rates
2177 */
2178int
2179chn_getrates(struct pcm_channel *c, int **rates)
2180{
2181 KASSERT(rates != NULL, ("rates is null"));
2182 CHN_LOCKASSERT(c);
2183 return CHANNEL_GETRATES(c->methods, c->devinfo, rates);
2184}
2185
2186/**
2187 * @brief Remove channel from a sync group, if there is one.
2188 *
2189 * This function is initially intended for the following conditions:
2190 * - Starting a syncgroup (@c SNDCTL_DSP_SYNCSTART ioctl)
2191 * - Closing a device. (A channel can't be destroyed if it's still in use.)
2192 *
2193 * @note Before calling this function, the syncgroup list mutex must be
2194 * held. (Consider pcm_channel::sm protected by the SG list mutex
2195 * whether @c c is locked or not.)
2196 *
2197 * @param c channel device to be started or closed
2198 * @returns If this channel was the only member of a group, the group ID
2199 * is returned to the caller so that the caller can release it
2200 * via free_unr() after giving up the syncgroup lock. Else it
2201 * returns 0.
2202 */
2203int
2204chn_syncdestroy(struct pcm_channel *c)
2205{
2206 struct pcmchan_syncmember *sm;
2207 struct pcmchan_syncgroup *sg;
2208 int sg_id;
2209
2210 sg_id = 0;
2211
2212 PCM_SG_LOCKASSERT(MA_OWNED);
2213
2214 if (c->sm != NULL) {
2215 sm = c->sm;
2216 sg = sm->parent;
2217 c->sm = NULL;
2218
2219 KASSERT(sg != NULL, ("syncmember has null parent"));
2220
2221 SLIST_REMOVE(&sg->members, sm, pcmchan_syncmember, link);
2222 free(sm, M_DEVBUF);
2223
2224 if (SLIST_EMPTY(&sg->members)) {
2225 SLIST_REMOVE(&snd_pcm_syncgroups, sg, pcmchan_syncgroup, link);
2226 sg_id = sg->id;
2227 free(sg, M_DEVBUF);
2228 }
2229 }
2230
2231 return sg_id;
2232}
2233
2234void
2235chn_lock(struct pcm_channel *c)
2236{
2237 CHN_LOCK(c);
2238}
2239
2240void
2241chn_unlock(struct pcm_channel *c)
2242{
2243 CHN_UNLOCK(c);
2244}
2245
2246#ifdef OSSV4_EXPERIMENT
2247int
2248chn_getpeaks(struct pcm_channel *c, int *lpeak, int *rpeak)
2249{
2250 CHN_LOCKASSERT(c);
2251 return CHANNEL_GETPEAKS(c->methods, c->devinfo, lpeak, rpeak);
2252}
2253#endif