FreeBSD/Linux Kernel Cross Reference
sys/dev/sound/pcm/dsp.c
1 /*-
2 * Copyright (c) 1999 Cameron Grant <cg@freebsd.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27 #include <dev/sound/pcm/sound.h>
28 #include <sys/ctype.h>
29
30 #include <vm/vm.h>
31 #include <vm/vm_object.h>
32 #include <vm/vm_page.h>
33 #include <vm/vm_pager.h>
34
35 SND_DECLARE_FILE("$FreeBSD$");
36
37 static int dsp_mmap_allow_prot_exec = 0;
38 SYSCTL_INT(_hw_snd, OID_AUTO, compat_linux_mmap, CTLFLAG_RW,
39 &dsp_mmap_allow_prot_exec, 0, "linux mmap compatibility");
40
41 struct dsp_cdevinfo {
42 struct pcm_channel *rdch, *wrch;
43 int busy, simplex;
44 TAILQ_ENTRY(dsp_cdevinfo) link;
45 };
46
47 #define PCM_RDCH(x) (((struct dsp_cdevinfo *)(x)->si_drv1)->rdch)
48 #define PCM_WRCH(x) (((struct dsp_cdevinfo *)(x)->si_drv1)->wrch)
49 #define PCM_SIMPLEX(x) (((struct dsp_cdevinfo *)(x)->si_drv1)->simplex)
50
51 #define DSP_CDEVINFO_CACHESIZE 8
52
53 #define DSP_REGISTERED(x, y) (PCM_REGISTERED(x) && \
54 (y) != NULL && (y)->si_drv1 != NULL)
55
56 #define OLDPCM_IOCTL
57
58 static d_open_t dsp_open;
59 static d_close_t dsp_close;
60 static d_read_t dsp_read;
61 static d_write_t dsp_write;
62 static d_ioctl_t dsp_ioctl;
63 static d_poll_t dsp_poll;
64 static d_mmap_t dsp_mmap;
65 static d_mmap_single_t dsp_mmap_single;
66
67 struct cdevsw dsp_cdevsw = {
68 .d_version = D_VERSION,
69 .d_open = dsp_open,
70 .d_close = dsp_close,
71 .d_read = dsp_read,
72 .d_write = dsp_write,
73 .d_ioctl = dsp_ioctl,
74 .d_poll = dsp_poll,
75 .d_mmap = dsp_mmap,
76 .d_mmap_single = dsp_mmap_single,
77 .d_name = "dsp",
78 };
79
80 #ifdef USING_DEVFS
81 static eventhandler_tag dsp_ehtag = NULL;
82 static int dsp_umax = -1;
83 static int dsp_cmax = -1;
84 #endif
85
86 static int dsp_oss_syncgroup(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_syncgroup *group);
87 static int dsp_oss_syncstart(int sg_id);
88 static int dsp_oss_policy(struct pcm_channel *wrch, struct pcm_channel *rdch, int policy);
89 #ifdef OSSV4_EXPERIMENT
90 static int dsp_oss_cookedmode(struct pcm_channel *wrch, struct pcm_channel *rdch, int enabled);
91 static int dsp_oss_getchnorder(struct pcm_channel *wrch, struct pcm_channel *rdch, unsigned long long *map);
92 static int dsp_oss_setchnorder(struct pcm_channel *wrch, struct pcm_channel *rdch, unsigned long long *map);
93 static int dsp_oss_getlabel(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_label_t *label);
94 static int dsp_oss_setlabel(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_label_t *label);
95 static int dsp_oss_getsong(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *song);
96 static int dsp_oss_setsong(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *song);
97 static int dsp_oss_setname(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *name);
98 #endif
99
100 static struct snddev_info *
101 dsp_get_info(struct cdev *dev)
102 {
103 return (devclass_get_softc(pcm_devclass, PCMUNIT(dev)));
104 }
105
106 static uint32_t
107 dsp_get_flags(struct cdev *dev)
108 {
109 device_t bdev;
110
111 bdev = devclass_get_device(pcm_devclass, PCMUNIT(dev));
112
113 return ((bdev != NULL) ? pcm_getflags(bdev) : 0xffffffff);
114 }
115
116 static void
117 dsp_set_flags(struct cdev *dev, uint32_t flags)
118 {
119 device_t bdev;
120
121 bdev = devclass_get_device(pcm_devclass, PCMUNIT(dev));
122
123 if (bdev != NULL)
124 pcm_setflags(bdev, flags);
125 }
126
127 /*
128 * return the channels associated with an open device instance.
129 * lock channels specified.
130 */
131 static int
132 getchns(struct cdev *dev, struct pcm_channel **rdch, struct pcm_channel **wrch,
133 uint32_t prio)
134 {
135 struct snddev_info *d;
136 struct pcm_channel *ch;
137 uint32_t flags;
138
139 if (PCM_SIMPLEX(dev) != 0) {
140 d = dsp_get_info(dev);
141 if (!PCM_REGISTERED(d))
142 return (ENXIO);
143 pcm_lock(d);
144 PCM_WAIT(d);
145 PCM_ACQUIRE(d);
146 /*
147 * Note: order is important -
148 * pcm flags -> prio query flags -> wild guess
149 */
150 ch = NULL;
151 flags = dsp_get_flags(dev);
152 if (flags & SD_F_PRIO_WR) {
153 ch = PCM_RDCH(dev);
154 PCM_RDCH(dev) = NULL;
155 } else if (flags & SD_F_PRIO_RD) {
156 ch = PCM_WRCH(dev);
157 PCM_WRCH(dev) = NULL;
158 } else if (prio & SD_F_PRIO_WR) {
159 ch = PCM_RDCH(dev);
160 PCM_RDCH(dev) = NULL;
161 flags |= SD_F_PRIO_WR;
162 } else if (prio & SD_F_PRIO_RD) {
163 ch = PCM_WRCH(dev);
164 PCM_WRCH(dev) = NULL;
165 flags |= SD_F_PRIO_RD;
166 } else if (PCM_WRCH(dev) != NULL) {
167 ch = PCM_RDCH(dev);
168 PCM_RDCH(dev) = NULL;
169 flags |= SD_F_PRIO_WR;
170 } else if (PCM_RDCH(dev) != NULL) {
171 ch = PCM_WRCH(dev);
172 PCM_WRCH(dev) = NULL;
173 flags |= SD_F_PRIO_RD;
174 }
175 PCM_SIMPLEX(dev) = 0;
176 dsp_set_flags(dev, flags);
177 if (ch != NULL) {
178 CHN_LOCK(ch);
179 pcm_chnref(ch, -1);
180 pcm_chnrelease(ch);
181 }
182 PCM_RELEASE(d);
183 pcm_unlock(d);
184 }
185
186 *rdch = PCM_RDCH(dev);
187 *wrch = PCM_WRCH(dev);
188
189 if (*rdch != NULL && (prio & SD_F_PRIO_RD))
190 CHN_LOCK(*rdch);
191 if (*wrch != NULL && (prio & SD_F_PRIO_WR))
192 CHN_LOCK(*wrch);
193
194 return (0);
195 }
196
197 /* unlock specified channels */
198 static void
199 relchns(struct cdev *dev, struct pcm_channel *rdch, struct pcm_channel *wrch,
200 uint32_t prio)
201 {
202 if (wrch != NULL && (prio & SD_F_PRIO_WR))
203 CHN_UNLOCK(wrch);
204 if (rdch != NULL && (prio & SD_F_PRIO_RD))
205 CHN_UNLOCK(rdch);
206 }
207
208 static void
209 dsp_cdevinfo_alloc(struct cdev *dev,
210 struct pcm_channel *rdch, struct pcm_channel *wrch)
211 {
212 struct snddev_info *d;
213 struct dsp_cdevinfo *cdi;
214 int simplex;
215
216 d = dsp_get_info(dev);
217
218 KASSERT(PCM_REGISTERED(d) && dev != NULL && dev->si_drv1 == NULL &&
219 rdch != wrch,
220 ("bogus %s(), what are you trying to accomplish here?", __func__));
221 PCM_BUSYASSERT(d);
222 mtx_assert(d->lock, MA_OWNED);
223
224 simplex = (dsp_get_flags(dev) & SD_F_SIMPLEX) ? 1 : 0;
225
226 /*
227 * Scan for free instance entry and put it into the end of list.
228 * Create new one if necessary.
229 */
230 TAILQ_FOREACH(cdi, &d->dsp_cdevinfo_pool, link) {
231 if (cdi->busy != 0)
232 break;
233 cdi->rdch = rdch;
234 cdi->wrch = wrch;
235 cdi->simplex = simplex;
236 cdi->busy = 1;
237 TAILQ_REMOVE(&d->dsp_cdevinfo_pool, cdi, link);
238 TAILQ_INSERT_TAIL(&d->dsp_cdevinfo_pool, cdi, link);
239 dev->si_drv1 = cdi;
240 return;
241 }
242 pcm_unlock(d);
243 cdi = malloc(sizeof(*cdi), M_DEVBUF, M_WAITOK | M_ZERO);
244 pcm_lock(d);
245 cdi->rdch = rdch;
246 cdi->wrch = wrch;
247 cdi->simplex = simplex;
248 cdi->busy = 1;
249 TAILQ_INSERT_TAIL(&d->dsp_cdevinfo_pool, cdi, link);
250 dev->si_drv1 = cdi;
251 }
252
253 static void
254 dsp_cdevinfo_free(struct cdev *dev)
255 {
256 struct snddev_info *d;
257 struct dsp_cdevinfo *cdi, *tmp;
258 uint32_t flags;
259 int i;
260
261 d = dsp_get_info(dev);
262
263 KASSERT(PCM_REGISTERED(d) && dev != NULL && dev->si_drv1 != NULL &&
264 PCM_RDCH(dev) == NULL && PCM_WRCH(dev) == NULL,
265 ("bogus %s(), what are you trying to accomplish here?", __func__));
266 PCM_BUSYASSERT(d);
267 mtx_assert(d->lock, MA_OWNED);
268
269 cdi = dev->si_drv1;
270 dev->si_drv1 = NULL;
271 cdi->rdch = NULL;
272 cdi->wrch = NULL;
273 cdi->simplex = 0;
274 cdi->busy = 0;
275
276 /*
277 * Once it is free, move it back to the beginning of list for
278 * faster new entry allocation.
279 */
280 TAILQ_REMOVE(&d->dsp_cdevinfo_pool, cdi, link);
281 TAILQ_INSERT_HEAD(&d->dsp_cdevinfo_pool, cdi, link);
282
283 /*
284 * Scan the list, cache free entries up to DSP_CDEVINFO_CACHESIZE.
285 * Reset simplex flags.
286 */
287 flags = dsp_get_flags(dev) & ~SD_F_PRIO_SET;
288 i = DSP_CDEVINFO_CACHESIZE;
289 TAILQ_FOREACH_SAFE(cdi, &d->dsp_cdevinfo_pool, link, tmp) {
290 if (cdi->busy != 0) {
291 if (cdi->simplex == 0) {
292 if (cdi->rdch != NULL)
293 flags |= SD_F_PRIO_RD;
294 if (cdi->wrch != NULL)
295 flags |= SD_F_PRIO_WR;
296 }
297 } else {
298 if (i == 0) {
299 TAILQ_REMOVE(&d->dsp_cdevinfo_pool, cdi, link);
300 free(cdi, M_DEVBUF);
301 } else
302 i--;
303 }
304 }
305 dsp_set_flags(dev, flags);
306 }
307
308 void
309 dsp_cdevinfo_init(struct snddev_info *d)
310 {
311 struct dsp_cdevinfo *cdi;
312 int i;
313
314 KASSERT(d != NULL, ("NULL snddev_info"));
315 PCM_BUSYASSERT(d);
316 mtx_assert(d->lock, MA_NOTOWNED);
317
318 TAILQ_INIT(&d->dsp_cdevinfo_pool);
319 for (i = 0; i < DSP_CDEVINFO_CACHESIZE; i++) {
320 cdi = malloc(sizeof(*cdi), M_DEVBUF, M_WAITOK | M_ZERO);
321 TAILQ_INSERT_HEAD(&d->dsp_cdevinfo_pool, cdi, link);
322 }
323 }
324
325 void
326 dsp_cdevinfo_flush(struct snddev_info *d)
327 {
328 struct dsp_cdevinfo *cdi, *tmp;
329
330 KASSERT(d != NULL, ("NULL snddev_info"));
331 PCM_BUSYASSERT(d);
332 mtx_assert(d->lock, MA_NOTOWNED);
333
334 cdi = TAILQ_FIRST(&d->dsp_cdevinfo_pool);
335 while (cdi != NULL) {
336 tmp = TAILQ_NEXT(cdi, link);
337 free(cdi, M_DEVBUF);
338 cdi = tmp;
339 }
340 TAILQ_INIT(&d->dsp_cdevinfo_pool);
341 }
342
343 /* duplex / simplex cdev type */
344 enum {
345 DSP_CDEV_TYPE_RDONLY, /* simplex read-only (record) */
346 DSP_CDEV_TYPE_WRONLY, /* simplex write-only (play) */
347 DSP_CDEV_TYPE_RDWR, /* duplex read, write, or both */
348 };
349
350 #define DSP_F_VALID(x) ((x) & (FREAD | FWRITE))
351 #define DSP_F_DUPLEX(x) (((x) & (FREAD | FWRITE)) == (FREAD | FWRITE))
352 #define DSP_F_SIMPLEX(x) (!DSP_F_DUPLEX(x))
353 #define DSP_F_READ(x) ((x) & FREAD)
354 #define DSP_F_WRITE(x) ((x) & FWRITE)
355
356 static const struct {
357 int type;
358 char *name;
359 char *sep;
360 int use_sep;
361 int hw;
362 int max;
363 uint32_t fmt, spd;
364 int query;
365 } dsp_cdevs[] = {
366 { SND_DEV_DSP, "dsp", ".", 0, 0, 0,
367 AFMT_U8, DSP_DEFAULT_SPEED, DSP_CDEV_TYPE_RDWR },
368 { SND_DEV_AUDIO, "audio", ".", 0, 0, 0,
369 AFMT_MU_LAW, DSP_DEFAULT_SPEED, DSP_CDEV_TYPE_RDWR },
370 { SND_DEV_DSP16, "dspW", ".", 0, 0, 0,
371 AFMT_S16_LE, DSP_DEFAULT_SPEED, DSP_CDEV_TYPE_RDWR },
372 { SND_DEV_DSPHW_PLAY, "dsp", ".p", 1, 1, SND_MAXHWCHAN,
373 AFMT_S16_LE | AFMT_STEREO, 48000, DSP_CDEV_TYPE_WRONLY },
374 { SND_DEV_DSPHW_VPLAY, "dsp", ".vp", 1, 1, SND_MAXVCHANS,
375 AFMT_S16_LE | AFMT_STEREO, 48000, DSP_CDEV_TYPE_WRONLY },
376 { SND_DEV_DSPHW_REC, "dsp", ".r", 1, 1, SND_MAXHWCHAN,
377 AFMT_S16_LE | AFMT_STEREO, 48000, DSP_CDEV_TYPE_RDONLY },
378 { SND_DEV_DSPHW_VREC, "dsp", ".vr", 1, 1, SND_MAXVCHANS,
379 AFMT_S16_LE | AFMT_STEREO, 48000, DSP_CDEV_TYPE_RDONLY },
380 { SND_DEV_DSPHW_CD, "dspcd", ".", 0, 0, 0,
381 AFMT_S16_LE | AFMT_STEREO, 44100, DSP_CDEV_TYPE_RDWR },
382 { SND_DEV_DSP_MMAP, "dsp_mmap", ".", 0, 0, 0,
383 AFMT_S16_LE | AFMT_STEREO, 48000, DSP_CDEV_TYPE_RDWR },
384 };
385
386 #define DSP_FIXUP_ERROR() do { \
387 prio = dsp_get_flags(i_dev); \
388 if (!DSP_F_VALID(flags)) \
389 error = EINVAL; \
390 if (!DSP_F_DUPLEX(flags) && \
391 ((DSP_F_READ(flags) && d->reccount == 0) || \
392 (DSP_F_WRITE(flags) && d->playcount == 0))) \
393 error = ENOTSUP; \
394 else if (!DSP_F_DUPLEX(flags) && (prio & SD_F_SIMPLEX) && \
395 ((DSP_F_READ(flags) && (prio & SD_F_PRIO_WR)) || \
396 (DSP_F_WRITE(flags) && (prio & SD_F_PRIO_RD)))) \
397 error = EBUSY; \
398 else if (DSP_REGISTERED(d, i_dev)) \
399 error = EBUSY; \
400 } while(0)
401
402 static int
403 dsp_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
404 {
405 struct pcm_channel *rdch, *wrch;
406 struct snddev_info *d;
407 uint32_t fmt, spd, prio;
408 int i, error, rderror, wrerror, devtype, wdevunit, rdevunit;
409
410 /* Kind of impossible.. */
411 if (i_dev == NULL || td == NULL)
412 return (ENODEV);
413
414 d = dsp_get_info(i_dev);
415 if (!PCM_REGISTERED(d))
416 return (EBADF);
417
418 PCM_GIANT_ENTER(d);
419
420 /* Lock snddev so nobody else can monkey with it. */
421 pcm_lock(d);
422 PCM_WAIT(d);
423
424 /*
425 * Try to acquire cloned device before someone else pick it.
426 * ENODEV means this is not a cloned droids.
427 */
428 error = snd_clone_acquire(i_dev);
429 if (!(error == 0 || error == ENODEV)) {
430 DSP_FIXUP_ERROR();
431 pcm_unlock(d);
432 PCM_GIANT_EXIT(d);
433 return (error);
434 }
435
436 error = 0;
437 DSP_FIXUP_ERROR();
438
439 if (error != 0) {
440 (void)snd_clone_release(i_dev);
441 pcm_unlock(d);
442 PCM_GIANT_EXIT(d);
443 return (error);
444 }
445
446 /*
447 * That is just enough. Acquire and unlock pcm lock so
448 * the other will just have to wait until we finish doing
449 * everything.
450 */
451 PCM_ACQUIRE(d);
452 pcm_unlock(d);
453
454 devtype = PCMDEV(i_dev);
455 wdevunit = -1;
456 rdevunit = -1;
457 fmt = 0;
458 spd = 0;
459
460 for (i = 0; i < (sizeof(dsp_cdevs) / sizeof(dsp_cdevs[0])); i++) {
461 if (devtype != dsp_cdevs[i].type)
462 continue;
463 if (DSP_F_SIMPLEX(flags) &&
464 ((dsp_cdevs[i].query == DSP_CDEV_TYPE_WRONLY &&
465 DSP_F_READ(flags)) ||
466 (dsp_cdevs[i].query == DSP_CDEV_TYPE_RDONLY &&
467 DSP_F_WRITE(flags)))) {
468 /*
469 * simplex, opposite direction? Please be gone..
470 */
471 (void)snd_clone_release(i_dev);
472 PCM_RELEASE_QUICK(d);
473 PCM_GIANT_EXIT(d);
474 return (ENOTSUP);
475 }
476 if (dsp_cdevs[i].query == DSP_CDEV_TYPE_WRONLY)
477 wdevunit = dev2unit(i_dev);
478 else if (dsp_cdevs[i].query == DSP_CDEV_TYPE_RDONLY)
479 rdevunit = dev2unit(i_dev);
480 fmt = dsp_cdevs[i].fmt;
481 spd = dsp_cdevs[i].spd;
482 break;
483 }
484
485 /* No matching devtype? */
486 if (fmt == 0 || spd == 0)
487 panic("impossible devtype %d", devtype);
488
489 rdch = NULL;
490 wrch = NULL;
491 rderror = 0;
492 wrerror = 0;
493
494 /*
495 * if we get here, the open request is valid- either:
496 * * we were previously not open
497 * * we were open for play xor record and the opener wants
498 * the non-open direction
499 */
500 if (DSP_F_READ(flags)) {
501 /* open for read */
502 rderror = pcm_chnalloc(d, &rdch, PCMDIR_REC,
503 td->td_proc->p_pid, rdevunit);
504
505 if (rderror == 0 && (chn_reset(rdch, fmt) != 0 ||
506 (chn_setspeed(rdch, spd) != 0)))
507 rderror = ENXIO;
508
509 if (rderror != 0) {
510 if (rdch != NULL)
511 pcm_chnrelease(rdch);
512 if (!DSP_F_DUPLEX(flags)) {
513 (void)snd_clone_release(i_dev);
514 PCM_RELEASE_QUICK(d);
515 PCM_GIANT_EXIT(d);
516 return (rderror);
517 }
518 rdch = NULL;
519 } else {
520 if (flags & O_NONBLOCK)
521 rdch->flags |= CHN_F_NBIO;
522 pcm_chnref(rdch, 1);
523 CHN_UNLOCK(rdch);
524 }
525 }
526
527 if (DSP_F_WRITE(flags)) {
528 /* open for write */
529 wrerror = pcm_chnalloc(d, &wrch, PCMDIR_PLAY,
530 td->td_proc->p_pid, wdevunit);
531
532 if (wrerror == 0 && (chn_reset(wrch, fmt) != 0 ||
533 (chn_setspeed(wrch, spd) != 0)))
534 wrerror = ENXIO;
535
536 if (wrerror != 0) {
537 if (wrch != NULL)
538 pcm_chnrelease(wrch);
539 if (!DSP_F_DUPLEX(flags)) {
540 if (rdch != NULL) {
541 /*
542 * Lock, deref and release previously
543 * created record channel
544 */
545 CHN_LOCK(rdch);
546 pcm_chnref(rdch, -1);
547 pcm_chnrelease(rdch);
548 }
549 (void)snd_clone_release(i_dev);
550 PCM_RELEASE_QUICK(d);
551 PCM_GIANT_EXIT(d);
552 return (wrerror);
553 }
554 wrch = NULL;
555 } else {
556 if (flags & O_NONBLOCK)
557 wrch->flags |= CHN_F_NBIO;
558 pcm_chnref(wrch, 1);
559 CHN_UNLOCK(wrch);
560 }
561 }
562
563 if (rdch == NULL && wrch == NULL) {
564 (void)snd_clone_release(i_dev);
565 PCM_RELEASE_QUICK(d);
566 PCM_GIANT_EXIT(d);
567 return ((wrerror != 0) ? wrerror : rderror);
568 }
569
570 pcm_lock(d);
571
572 /*
573 * We're done. Allocate channels information for this cdev.
574 */
575 dsp_cdevinfo_alloc(i_dev, rdch, wrch);
576
577 /*
578 * Increase clone refcount for its automatic garbage collector.
579 */
580 (void)snd_clone_ref(i_dev);
581
582 PCM_RELEASE(d);
583 pcm_unlock(d);
584
585 PCM_GIANT_LEAVE(d);
586
587 return (0);
588 }
589
590 static int
591 dsp_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
592 {
593 struct pcm_channel *rdch, *wrch;
594 struct snddev_info *d;
595 int sg_ids, refs;
596
597 d = dsp_get_info(i_dev);
598 if (!DSP_REGISTERED(d, i_dev))
599 return (EBADF);
600
601 PCM_GIANT_ENTER(d);
602
603 pcm_lock(d);
604 PCM_WAIT(d);
605
606 rdch = PCM_RDCH(i_dev);
607 wrch = PCM_WRCH(i_dev);
608
609 if (rdch || wrch) {
610 PCM_ACQUIRE(d);
611 pcm_unlock(d);
612
613 refs = 0;
614 if (rdch) {
615 /*
616 * The channel itself need not be locked because:
617 * a) Adding a channel to a syncgroup happens only in dsp_ioctl(),
618 * which cannot run concurrently to dsp_close().
619 * b) The syncmember pointer (sm) is protected by the global
620 * syncgroup list lock.
621 * c) A channel can't just disappear, invalidating pointers,
622 * unless it's closed/dereferenced first.
623 */
624 PCM_SG_LOCK();
625 sg_ids = chn_syncdestroy(rdch);
626 PCM_SG_UNLOCK();
627 if (sg_ids != 0)
628 free_unr(pcmsg_unrhdr, sg_ids);
629
630 CHN_LOCK(rdch);
631 refs += pcm_chnref(rdch, -1);
632 chn_abort(rdch); /* won't sleep */
633 rdch->flags &= ~(CHN_F_RUNNING | CHN_F_MAPPED | CHN_F_DEAD);
634 chn_reset(rdch, 0);
635 pcm_chnrelease(rdch);
636 PCM_RDCH(i_dev) = NULL;
637 }
638 if (wrch) {
639 /*
640 * Please see block above.
641 */
642 PCM_SG_LOCK();
643 sg_ids = chn_syncdestroy(wrch);
644 PCM_SG_UNLOCK();
645 if (sg_ids != 0)
646 free_unr(pcmsg_unrhdr, sg_ids);
647
648 CHN_LOCK(wrch);
649 refs += pcm_chnref(wrch, -1);
650 chn_flush(wrch); /* may sleep */
651 wrch->flags &= ~(CHN_F_RUNNING | CHN_F_MAPPED | CHN_F_DEAD);
652 chn_reset(wrch, 0);
653 pcm_chnrelease(wrch);
654 PCM_WRCH(i_dev) = NULL;
655 }
656
657 pcm_lock(d);
658 /*
659 * If there are no more references, release the channels.
660 */
661 if (refs == 0 && PCM_RDCH(i_dev) == NULL &&
662 PCM_WRCH(i_dev) == NULL) {
663 dsp_cdevinfo_free(i_dev);
664 /*
665 * Release clone busy state and unref it
666 * so the automatic garbage collector will
667 * get the hint and do the remaining cleanup
668 * process.
669 */
670 (void)snd_clone_release(i_dev);
671
672 /*
673 * destroy_dev() might sleep, so release pcm lock
674 * here and rely on pcm cv serialization.
675 */
676 pcm_unlock(d);
677 (void)snd_clone_unref(i_dev);
678 pcm_lock(d);
679 }
680 PCM_RELEASE(d);
681 }
682
683 pcm_unlock(d);
684
685 PCM_GIANT_LEAVE(d);
686
687 return (0);
688 }
689
690 static __inline int
691 dsp_io_ops(struct cdev *i_dev, struct uio *buf)
692 {
693 struct snddev_info *d;
694 struct pcm_channel **ch, *rdch, *wrch;
695 int (*chn_io)(struct pcm_channel *, struct uio *);
696 int prio, ret;
697 pid_t runpid;
698
699 KASSERT(i_dev != NULL && buf != NULL &&
700 (buf->uio_rw == UIO_READ || buf->uio_rw == UIO_WRITE),
701 ("%s(): io train wreck!", __func__));
702
703 d = dsp_get_info(i_dev);
704 if (!DSP_REGISTERED(d, i_dev))
705 return (EBADF);
706
707 PCM_GIANT_ENTER(d);
708
709 switch (buf->uio_rw) {
710 case UIO_READ:
711 prio = SD_F_PRIO_RD;
712 ch = &rdch;
713 chn_io = chn_read;
714 break;
715 case UIO_WRITE:
716 prio = SD_F_PRIO_WR;
717 ch = &wrch;
718 chn_io = chn_write;
719 break;
720 default:
721 panic("invalid/corrupted uio direction: %d", buf->uio_rw);
722 break;
723 }
724
725 rdch = NULL;
726 wrch = NULL;
727 runpid = buf->uio_td->td_proc->p_pid;
728
729 getchns(i_dev, &rdch, &wrch, prio);
730
731 if (*ch == NULL || !((*ch)->flags & CHN_F_BUSY)) {
732 PCM_GIANT_EXIT(d);
733 return (EBADF);
734 }
735
736 if (((*ch)->flags & (CHN_F_MAPPED | CHN_F_DEAD)) ||
737 (((*ch)->flags & CHN_F_RUNNING) && (*ch)->pid != runpid)) {
738 relchns(i_dev, rdch, wrch, prio);
739 PCM_GIANT_EXIT(d);
740 return (EINVAL);
741 } else if (!((*ch)->flags & CHN_F_RUNNING)) {
742 (*ch)->flags |= CHN_F_RUNNING;
743 (*ch)->pid = runpid;
744 }
745
746 /*
747 * chn_read/write must give up channel lock in order to copy bytes
748 * from/to userland, so up the "in progress" counter to make sure
749 * someone else doesn't come along and muss up the buffer.
750 */
751 ++(*ch)->inprog;
752 ret = chn_io(*ch, buf);
753 --(*ch)->inprog;
754
755 CHN_BROADCAST(&(*ch)->cv);
756
757 relchns(i_dev, rdch, wrch, prio);
758
759 PCM_GIANT_LEAVE(d);
760
761 return (ret);
762 }
763
764 static int
765 dsp_read(struct cdev *i_dev, struct uio *buf, int flag)
766 {
767 return (dsp_io_ops(i_dev, buf));
768 }
769
770 static int
771 dsp_write(struct cdev *i_dev, struct uio *buf, int flag)
772 {
773 return (dsp_io_ops(i_dev, buf));
774 }
775
776 static int
777 dsp_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, struct thread *td)
778 {
779 struct pcm_channel *chn, *rdch, *wrch;
780 struct snddev_info *d;
781 u_long xcmd;
782 int *arg_i, ret, kill, tmp;
783
784 d = dsp_get_info(i_dev);
785 if (!DSP_REGISTERED(d, i_dev))
786 return (EBADF);
787
788 PCM_GIANT_ENTER(d);
789
790 arg_i = (int *)arg;
791 ret = 0;
792 xcmd = 0;
793
794 /*
795 * this is an evil hack to allow broken apps to perform mixer ioctls
796 * on dsp devices.
797 */
798 if (IOCGROUP(cmd) == 'M') {
799 /*
800 * This is at least, a bug to bug compatible with OSS.
801 */
802 if (d->mixer_dev != NULL) {
803 PCM_ACQUIRE_QUICK(d);
804 ret = mixer_ioctl_cmd(d->mixer_dev, cmd, arg, -1, td,
805 MIXER_CMD_DIRECT);
806 PCM_RELEASE_QUICK(d);
807 } else
808 ret = EBADF;
809
810 PCM_GIANT_EXIT(d);
811
812 return (ret);
813 }
814
815 /*
816 * Certain ioctls may be made on any type of device (audio, mixer,
817 * and MIDI). Handle those special cases here.
818 */
819 if (IOCGROUP(cmd) == 'X') {
820 PCM_ACQUIRE_QUICK(d);
821 switch(cmd) {
822 case SNDCTL_SYSINFO:
823 sound_oss_sysinfo((oss_sysinfo *)arg);
824 break;
825 case SNDCTL_AUDIOINFO:
826 ret = dsp_oss_audioinfo(i_dev, (oss_audioinfo *)arg);
827 break;
828 case SNDCTL_MIXERINFO:
829 ret = mixer_oss_mixerinfo(i_dev, (oss_mixerinfo *)arg);
830 break;
831 default:
832 ret = EINVAL;
833 }
834 PCM_RELEASE_QUICK(d);
835 PCM_GIANT_EXIT(d);
836 return (ret);
837 }
838
839 getchns(i_dev, &rdch, &wrch, 0);
840
841 kill = 0;
842 if (wrch && (wrch->flags & CHN_F_DEAD))
843 kill |= 1;
844 if (rdch && (rdch->flags & CHN_F_DEAD))
845 kill |= 2;
846 if (kill == 3) {
847 relchns(i_dev, rdch, wrch, 0);
848 PCM_GIANT_EXIT(d);
849 return (EINVAL);
850 }
851 if (kill & 1)
852 wrch = NULL;
853 if (kill & 2)
854 rdch = NULL;
855
856 if (wrch == NULL && rdch == NULL) {
857 relchns(i_dev, rdch, wrch, 0);
858 PCM_GIANT_EXIT(d);
859 return (EINVAL);
860 }
861
862 switch(cmd) {
863 #ifdef OLDPCM_IOCTL
864 /*
865 * we start with the new ioctl interface.
866 */
867 case AIONWRITE: /* how many bytes can write ? */
868 if (wrch) {
869 CHN_LOCK(wrch);
870 /*
871 if (wrch && wrch->bufhard.dl)
872 while (chn_wrfeed(wrch) == 0);
873 */
874 *arg_i = sndbuf_getfree(wrch->bufsoft);
875 CHN_UNLOCK(wrch);
876 } else {
877 *arg_i = 0;
878 ret = EINVAL;
879 }
880 break;
881
882 case AIOSSIZE: /* set the current blocksize */
883 {
884 struct snd_size *p = (struct snd_size *)arg;
885
886 p->play_size = 0;
887 p->rec_size = 0;
888 PCM_ACQUIRE_QUICK(d);
889 if (wrch) {
890 CHN_LOCK(wrch);
891 chn_setblocksize(wrch, 2, p->play_size);
892 p->play_size = sndbuf_getblksz(wrch->bufsoft);
893 CHN_UNLOCK(wrch);
894 }
895 if (rdch) {
896 CHN_LOCK(rdch);
897 chn_setblocksize(rdch, 2, p->rec_size);
898 p->rec_size = sndbuf_getblksz(rdch->bufsoft);
899 CHN_UNLOCK(rdch);
900 }
901 PCM_RELEASE_QUICK(d);
902 }
903 break;
904 case AIOGSIZE: /* get the current blocksize */
905 {
906 struct snd_size *p = (struct snd_size *)arg;
907
908 if (wrch) {
909 CHN_LOCK(wrch);
910 p->play_size = sndbuf_getblksz(wrch->bufsoft);
911 CHN_UNLOCK(wrch);
912 }
913 if (rdch) {
914 CHN_LOCK(rdch);
915 p->rec_size = sndbuf_getblksz(rdch->bufsoft);
916 CHN_UNLOCK(rdch);
917 }
918 }
919 break;
920
921 case AIOSFMT:
922 case AIOGFMT:
923 {
924 snd_chan_param *p = (snd_chan_param *)arg;
925
926 if (cmd == AIOSFMT &&
927 ((p->play_format != 0 && p->play_rate == 0) ||
928 (p->rec_format != 0 && p->rec_rate == 0))) {
929 ret = EINVAL;
930 break;
931 }
932 PCM_ACQUIRE_QUICK(d);
933 if (wrch) {
934 CHN_LOCK(wrch);
935 if (cmd == AIOSFMT && p->play_format != 0) {
936 chn_setformat(wrch, p->play_format);
937 chn_setspeed(wrch, p->play_rate);
938 }
939 p->play_rate = wrch->speed;
940 p->play_format = wrch->format;
941 CHN_UNLOCK(wrch);
942 } else {
943 p->play_rate = 0;
944 p->play_format = 0;
945 }
946 if (rdch) {
947 CHN_LOCK(rdch);
948 if (cmd == AIOSFMT && p->rec_format != 0) {
949 chn_setformat(rdch, p->rec_format);
950 chn_setspeed(rdch, p->rec_rate);
951 }
952 p->rec_rate = rdch->speed;
953 p->rec_format = rdch->format;
954 CHN_UNLOCK(rdch);
955 } else {
956 p->rec_rate = 0;
957 p->rec_format = 0;
958 }
959 PCM_RELEASE_QUICK(d);
960 }
961 break;
962
963 case AIOGCAP: /* get capabilities */
964 {
965 snd_capabilities *p = (snd_capabilities *)arg;
966 struct pcmchan_caps *pcaps = NULL, *rcaps = NULL;
967 struct cdev *pdev;
968
969 pcm_lock(d);
970 if (rdch) {
971 CHN_LOCK(rdch);
972 rcaps = chn_getcaps(rdch);
973 }
974 if (wrch) {
975 CHN_LOCK(wrch);
976 pcaps = chn_getcaps(wrch);
977 }
978 p->rate_min = max(rcaps? rcaps->minspeed : 0,
979 pcaps? pcaps->minspeed : 0);
980 p->rate_max = min(rcaps? rcaps->maxspeed : 1000000,
981 pcaps? pcaps->maxspeed : 1000000);
982 p->bufsize = min(rdch? sndbuf_getsize(rdch->bufsoft) : 1000000,
983 wrch? sndbuf_getsize(wrch->bufsoft) : 1000000);
984 /* XXX bad on sb16 */
985 p->formats = (rdch? chn_getformats(rdch) : 0xffffffff) &
986 (wrch? chn_getformats(wrch) : 0xffffffff);
987 if (rdch && wrch)
988 p->formats |= (dsp_get_flags(i_dev) & SD_F_SIMPLEX)? 0 : AFMT_FULLDUPLEX;
989 pdev = d->mixer_dev;
990 p->mixers = 1; /* default: one mixer */
991 p->inputs = pdev->si_drv1? mix_getdevs(pdev->si_drv1) : 0;
992 p->left = p->right = 100;
993 if (wrch)
994 CHN_UNLOCK(wrch);
995 if (rdch)
996 CHN_UNLOCK(rdch);
997 pcm_unlock(d);
998 }
999 break;
1000
1001 case AIOSTOP:
1002 if (*arg_i == AIOSYNC_PLAY && wrch) {
1003 CHN_LOCK(wrch);
1004 *arg_i = chn_abort(wrch);
1005 CHN_UNLOCK(wrch);
1006 } else if (*arg_i == AIOSYNC_CAPTURE && rdch) {
1007 CHN_LOCK(rdch);
1008 *arg_i = chn_abort(rdch);
1009 CHN_UNLOCK(rdch);
1010 } else {
1011 printf("AIOSTOP: bad channel 0x%x\n", *arg_i);
1012 *arg_i = 0;
1013 }
1014 break;
1015
1016 case AIOSYNC:
1017 printf("AIOSYNC chan 0x%03lx pos %lu unimplemented\n",
1018 ((snd_sync_parm *)arg)->chan, ((snd_sync_parm *)arg)->pos);
1019 break;
1020 #endif
1021 /*
1022 * here follow the standard ioctls (filio.h etc.)
1023 */
1024 case FIONREAD: /* get # bytes to read */
1025 if (rdch) {
1026 CHN_LOCK(rdch);
1027 /* if (rdch && rdch->bufhard.dl)
1028 while (chn_rdfeed(rdch) == 0);
1029 */
1030 *arg_i = sndbuf_getready(rdch->bufsoft);
1031 CHN_UNLOCK(rdch);
1032 } else {
1033 *arg_i = 0;
1034 ret = EINVAL;
1035 }
1036 break;
1037
1038 case FIOASYNC: /*set/clear async i/o */
1039 DEB( printf("FIOASYNC\n") ; )
1040 break;
1041
1042 case SNDCTL_DSP_NONBLOCK: /* set non-blocking i/o */
1043 case FIONBIO: /* set/clear non-blocking i/o */
1044 if (rdch) {
1045 CHN_LOCK(rdch);
1046 if (cmd == SNDCTL_DSP_NONBLOCK || *arg_i)
1047 rdch->flags |= CHN_F_NBIO;
1048 else
1049 rdch->flags &= ~CHN_F_NBIO;
1050 CHN_UNLOCK(rdch);
1051 }
1052 if (wrch) {
1053 CHN_LOCK(wrch);
1054 if (cmd == SNDCTL_DSP_NONBLOCK || *arg_i)
1055 wrch->flags |= CHN_F_NBIO;
1056 else
1057 wrch->flags &= ~CHN_F_NBIO;
1058 CHN_UNLOCK(wrch);
1059 }
1060 break;
1061
1062 /*
1063 * Finally, here is the linux-compatible ioctl interface
1064 */
1065 #define THE_REAL_SNDCTL_DSP_GETBLKSIZE _IOWR('P', 4, int)
1066 case THE_REAL_SNDCTL_DSP_GETBLKSIZE:
1067 case SNDCTL_DSP_GETBLKSIZE:
1068 chn = wrch ? wrch : rdch;
1069 if (chn) {
1070 CHN_LOCK(chn);
1071 *arg_i = sndbuf_getblksz(chn->bufsoft);
1072 CHN_UNLOCK(chn);
1073 } else {
1074 *arg_i = 0;
1075 ret = EINVAL;
1076 }
1077 break;
1078
1079 case SNDCTL_DSP_SETBLKSIZE:
1080 RANGE(*arg_i, 16, 65536);
1081 PCM_ACQUIRE_QUICK(d);
1082 if (wrch) {
1083 CHN_LOCK(wrch);
1084 chn_setblocksize(wrch, 2, *arg_i);
1085 CHN_UNLOCK(wrch);
1086 }
1087 if (rdch) {
1088 CHN_LOCK(rdch);
1089 chn_setblocksize(rdch, 2, *arg_i);
1090 CHN_UNLOCK(rdch);
1091 }
1092 PCM_RELEASE_QUICK(d);
1093 break;
1094
1095 case SNDCTL_DSP_RESET:
1096 DEB(printf("dsp reset\n"));
1097 if (wrch) {
1098 CHN_LOCK(wrch);
1099 chn_abort(wrch);
1100 chn_resetbuf(wrch);
1101 CHN_UNLOCK(wrch);
1102 }
1103 if (rdch) {
1104 CHN_LOCK(rdch);
1105 chn_abort(rdch);
1106 chn_resetbuf(rdch);
1107 CHN_UNLOCK(rdch);
1108 }
1109 break;
1110
1111 case SNDCTL_DSP_SYNC:
1112 DEB(printf("dsp sync\n"));
1113 /* chn_sync may sleep */
1114 if (wrch) {
1115 CHN_LOCK(wrch);
1116 chn_sync(wrch, 0);
1117 CHN_UNLOCK(wrch);
1118 }
1119 break;
1120
1121 case SNDCTL_DSP_SPEED:
1122 /* chn_setspeed may sleep */
1123 tmp = 0;
1124 PCM_ACQUIRE_QUICK(d);
1125 if (wrch) {
1126 CHN_LOCK(wrch);
1127 ret = chn_setspeed(wrch, *arg_i);
1128 tmp = wrch->speed;
1129 CHN_UNLOCK(wrch);
1130 }
1131 if (rdch && ret == 0) {
1132 CHN_LOCK(rdch);
1133 ret = chn_setspeed(rdch, *arg_i);
1134 if (tmp == 0)
1135 tmp = rdch->speed;
1136 CHN_UNLOCK(rdch);
1137 }
1138 PCM_RELEASE_QUICK(d);
1139 *arg_i = tmp;
1140 break;
1141
1142 case SOUND_PCM_READ_RATE:
1143 chn = wrch ? wrch : rdch;
1144 if (chn) {
1145 CHN_LOCK(chn);
1146 *arg_i = chn->speed;
1147 CHN_UNLOCK(chn);
1148 } else {
1149 *arg_i = 0;
1150 ret = EINVAL;
1151 }
1152 break;
1153
1154 case SNDCTL_DSP_STEREO:
1155 tmp = -1;
1156 *arg_i = (*arg_i)? AFMT_STEREO : 0;
1157 PCM_ACQUIRE_QUICK(d);
1158 if (wrch) {
1159 CHN_LOCK(wrch);
1160 ret = chn_setformat(wrch, (wrch->format & ~AFMT_STEREO) | *arg_i);
1161 tmp = (wrch->format & AFMT_STEREO)? 1 : 0;
1162 CHN_UNLOCK(wrch);
1163 }
1164 if (rdch && ret == 0) {
1165 CHN_LOCK(rdch);
1166 ret = chn_setformat(rdch, (rdch->format & ~AFMT_STEREO) | *arg_i);
1167 if (tmp == -1)
1168 tmp = (rdch->format & AFMT_STEREO)? 1 : 0;
1169 CHN_UNLOCK(rdch);
1170 }
1171 PCM_RELEASE_QUICK(d);
1172 *arg_i = tmp;
1173 break;
1174
1175 case SOUND_PCM_WRITE_CHANNELS:
1176 /* case SNDCTL_DSP_CHANNELS: ( == SOUND_PCM_WRITE_CHANNELS) */
1177 if (*arg_i != 0) {
1178 tmp = 0;
1179 *arg_i = (*arg_i != 1)? AFMT_STEREO : 0;
1180 PCM_ACQUIRE_QUICK(d);
1181 if (wrch) {
1182 CHN_LOCK(wrch);
1183 ret = chn_setformat(wrch, (wrch->format & ~AFMT_STEREO) | *arg_i);
1184 tmp = (wrch->format & AFMT_STEREO)? 2 : 1;
1185 CHN_UNLOCK(wrch);
1186 }
1187 if (rdch && ret == 0) {
1188 CHN_LOCK(rdch);
1189 ret = chn_setformat(rdch, (rdch->format & ~AFMT_STEREO) | *arg_i);
1190 if (tmp == 0)
1191 tmp = (rdch->format & AFMT_STEREO)? 2 : 1;
1192 CHN_UNLOCK(rdch);
1193 }
1194 PCM_RELEASE_QUICK(d);
1195 *arg_i = tmp;
1196 } else {
1197 chn = wrch ? wrch : rdch;
1198 CHN_LOCK(chn);
1199 *arg_i = (chn->format & AFMT_STEREO) ? 2 : 1;
1200 CHN_UNLOCK(chn);
1201 }
1202 break;
1203
1204 case SOUND_PCM_READ_CHANNELS:
1205 chn = wrch ? wrch : rdch;
1206 if (chn) {
1207 CHN_LOCK(chn);
1208 *arg_i = (chn->format & AFMT_STEREO) ? 2 : 1;
1209 CHN_UNLOCK(chn);
1210 } else {
1211 *arg_i = 0;
1212 ret = EINVAL;
1213 }
1214 break;
1215
1216 case SNDCTL_DSP_GETFMTS: /* returns a mask of supported fmts */
1217 chn = wrch ? wrch : rdch;
1218 if (chn) {
1219 CHN_LOCK(chn);
1220 *arg_i = chn_getformats(chn);
1221 CHN_UNLOCK(chn);
1222 } else {
1223 *arg_i = 0;
1224 ret = EINVAL;
1225 }
1226 break;
1227
1228 case SNDCTL_DSP_SETFMT: /* sets _one_ format */
1229 if ((*arg_i != AFMT_QUERY)) {
1230 tmp = 0;
1231 PCM_ACQUIRE_QUICK(d);
1232 if (wrch) {
1233 CHN_LOCK(wrch);
1234 ret = chn_setformat(wrch, (*arg_i) | (wrch->format & AFMT_STEREO));
1235 tmp = wrch->format & ~AFMT_STEREO;
1236 CHN_UNLOCK(wrch);
1237 }
1238 if (rdch && ret == 0) {
1239 CHN_LOCK(rdch);
1240 ret = chn_setformat(rdch, (*arg_i) | (rdch->format & AFMT_STEREO));
1241 if (tmp == 0)
1242 tmp = rdch->format & ~AFMT_STEREO;
1243 CHN_UNLOCK(rdch);
1244 }
1245 PCM_RELEASE_QUICK(d);
1246 *arg_i = tmp;
1247 } else {
1248 chn = wrch ? wrch : rdch;
1249 CHN_LOCK(chn);
1250 *arg_i = chn->format & ~AFMT_STEREO;
1251 CHN_UNLOCK(chn);
1252 }
1253 break;
1254
1255 case SNDCTL_DSP_SETFRAGMENT:
1256 DEB(printf("SNDCTL_DSP_SETFRAGMENT 0x%08x\n", *(int *)arg));
1257 {
1258 uint32_t fragln = (*arg_i) & 0x0000ffff;
1259 uint32_t maxfrags = ((*arg_i) & 0xffff0000) >> 16;
1260 uint32_t fragsz;
1261 uint32_t r_maxfrags, r_fragsz;
1262
1263 RANGE(fragln, 4, 16);
1264 fragsz = 1 << fragln;
1265
1266 if (maxfrags == 0)
1267 maxfrags = CHN_2NDBUFMAXSIZE / fragsz;
1268 if (maxfrags < 2)
1269 maxfrags = 2;
1270 if (maxfrags * fragsz > CHN_2NDBUFMAXSIZE)
1271 maxfrags = CHN_2NDBUFMAXSIZE / fragsz;
1272
1273 DEB(printf("SNDCTL_DSP_SETFRAGMENT %d frags, %d sz\n", maxfrags, fragsz));
1274 PCM_ACQUIRE_QUICK(d);
1275 if (rdch) {
1276 CHN_LOCK(rdch);
1277 ret = chn_setblocksize(rdch, maxfrags, fragsz);
1278 r_maxfrags = sndbuf_getblkcnt(rdch->bufsoft);
1279 r_fragsz = sndbuf_getblksz(rdch->bufsoft);
1280 CHN_UNLOCK(rdch);
1281 } else {
1282 r_maxfrags = maxfrags;
1283 r_fragsz = fragsz;
1284 }
1285 if (wrch && ret == 0) {
1286 CHN_LOCK(wrch);
1287 ret = chn_setblocksize(wrch, maxfrags, fragsz);
1288 maxfrags = sndbuf_getblkcnt(wrch->bufsoft);
1289 fragsz = sndbuf_getblksz(wrch->bufsoft);
1290 CHN_UNLOCK(wrch);
1291 } else { /* use whatever came from the read channel */
1292 maxfrags = r_maxfrags;
1293 fragsz = r_fragsz;
1294 }
1295 PCM_RELEASE_QUICK(d);
1296
1297 fragln = 0;
1298 while (fragsz > 1) {
1299 fragln++;
1300 fragsz >>= 1;
1301 }
1302 *arg_i = (maxfrags << 16) | fragln;
1303 }
1304 break;
1305
1306 case SNDCTL_DSP_GETISPACE:
1307 /* return the size of data available in the input queue */
1308 {
1309 audio_buf_info *a = (audio_buf_info *)arg;
1310 if (rdch) {
1311 struct snd_dbuf *bs = rdch->bufsoft;
1312
1313 CHN_LOCK(rdch);
1314 a->bytes = sndbuf_getready(bs);
1315 a->fragments = a->bytes / sndbuf_getblksz(bs);
1316 a->fragstotal = sndbuf_getblkcnt(bs);
1317 a->fragsize = sndbuf_getblksz(bs);
1318 CHN_UNLOCK(rdch);
1319 } else
1320 ret = EINVAL;
1321 }
1322 break;
1323
1324 case SNDCTL_DSP_GETOSPACE:
1325 /* return space available in the output queue */
1326 {
1327 audio_buf_info *a = (audio_buf_info *)arg;
1328 if (wrch) {
1329 struct snd_dbuf *bs = wrch->bufsoft;
1330
1331 CHN_LOCK(wrch);
1332 /* XXX abusive DMA update: chn_wrupdate(wrch); */
1333 a->bytes = sndbuf_getfree(bs);
1334 a->fragments = a->bytes / sndbuf_getblksz(bs);
1335 a->fragstotal = sndbuf_getblkcnt(bs);
1336 a->fragsize = sndbuf_getblksz(bs);
1337 CHN_UNLOCK(wrch);
1338 } else
1339 ret = EINVAL;
1340 }
1341 break;
1342
1343 case SNDCTL_DSP_GETIPTR:
1344 {
1345 count_info *a = (count_info *)arg;
1346 if (rdch) {
1347 struct snd_dbuf *bs = rdch->bufsoft;
1348
1349 CHN_LOCK(rdch);
1350 /* XXX abusive DMA update: chn_rdupdate(rdch); */
1351 a->bytes = sndbuf_gettotal(bs);
1352 a->blocks = sndbuf_getblocks(bs) - rdch->blocks;
1353 a->ptr = sndbuf_getfreeptr(bs);
1354 rdch->blocks = sndbuf_getblocks(bs);
1355 CHN_UNLOCK(rdch);
1356 } else
1357 ret = EINVAL;
1358 }
1359 break;
1360
1361 case SNDCTL_DSP_GETOPTR:
1362 {
1363 count_info *a = (count_info *)arg;
1364 if (wrch) {
1365 struct snd_dbuf *bs = wrch->bufsoft;
1366
1367 CHN_LOCK(wrch);
1368 /* XXX abusive DMA update: chn_wrupdate(wrch); */
1369 a->bytes = sndbuf_gettotal(bs);
1370 a->blocks = sndbuf_getblocks(bs) - wrch->blocks;
1371 a->ptr = sndbuf_getreadyptr(bs);
1372 wrch->blocks = sndbuf_getblocks(bs);
1373 CHN_UNLOCK(wrch);
1374 } else
1375 ret = EINVAL;
1376 }
1377 break;
1378
1379 case SNDCTL_DSP_GETCAPS:
1380 pcm_lock(d);
1381 *arg_i = DSP_CAP_REALTIME | DSP_CAP_MMAP | DSP_CAP_TRIGGER;
1382 if (rdch && wrch && !(dsp_get_flags(i_dev) & SD_F_SIMPLEX))
1383 *arg_i |= DSP_CAP_DUPLEX;
1384 pcm_unlock(d);
1385 break;
1386
1387 case SOUND_PCM_READ_BITS:
1388 chn = wrch ? wrch : rdch;
1389 if (chn) {
1390 CHN_LOCK(chn);
1391 if (chn->format & AFMT_8BIT)
1392 *arg_i = 8;
1393 else if (chn->format & AFMT_16BIT)
1394 *arg_i = 16;
1395 else if (chn->format & AFMT_24BIT)
1396 *arg_i = 24;
1397 else if (chn->format & AFMT_32BIT)
1398 *arg_i = 32;
1399 else
1400 ret = EINVAL;
1401 CHN_UNLOCK(chn);
1402 } else {
1403 *arg_i = 0;
1404 ret = EINVAL;
1405 }
1406 break;
1407
1408 case SNDCTL_DSP_SETTRIGGER:
1409 if (rdch) {
1410 CHN_LOCK(rdch);
1411 rdch->flags &= ~(CHN_F_TRIGGERED | CHN_F_NOTRIGGER);
1412 if (*arg_i & PCM_ENABLE_INPUT)
1413 chn_start(rdch, 1);
1414 else
1415 rdch->flags |= CHN_F_NOTRIGGER;
1416 CHN_UNLOCK(rdch);
1417 }
1418 if (wrch) {
1419 CHN_LOCK(wrch);
1420 wrch->flags &= ~(CHN_F_TRIGGERED | CHN_F_NOTRIGGER);
1421 if (*arg_i & PCM_ENABLE_OUTPUT)
1422 chn_start(wrch, 1);
1423 else
1424 wrch->flags |= CHN_F_NOTRIGGER;
1425 CHN_UNLOCK(wrch);
1426 }
1427 break;
1428
1429 case SNDCTL_DSP_GETTRIGGER:
1430 *arg_i = 0;
1431 if (wrch) {
1432 CHN_LOCK(wrch);
1433 if (wrch->flags & CHN_F_TRIGGERED)
1434 *arg_i |= PCM_ENABLE_OUTPUT;
1435 CHN_UNLOCK(wrch);
1436 }
1437 if (rdch) {
1438 CHN_LOCK(rdch);
1439 if (rdch->flags & CHN_F_TRIGGERED)
1440 *arg_i |= PCM_ENABLE_INPUT;
1441 CHN_UNLOCK(rdch);
1442 }
1443 break;
1444
1445 case SNDCTL_DSP_GETODELAY:
1446 if (wrch) {
1447 struct snd_dbuf *bs = wrch->bufsoft;
1448
1449 CHN_LOCK(wrch);
1450 /* XXX abusive DMA update: chn_wrupdate(wrch); */
1451 *arg_i = sndbuf_getready(bs);
1452 CHN_UNLOCK(wrch);
1453 } else
1454 ret = EINVAL;
1455 break;
1456
1457 case SNDCTL_DSP_POST:
1458 if (wrch) {
1459 CHN_LOCK(wrch);
1460 wrch->flags &= ~CHN_F_NOTRIGGER;
1461 chn_start(wrch, 1);
1462 CHN_UNLOCK(wrch);
1463 }
1464 break;
1465
1466 case SNDCTL_DSP_SETDUPLEX:
1467 /*
1468 * switch to full-duplex mode if card is in half-duplex
1469 * mode and is able to work in full-duplex mode
1470 */
1471 pcm_lock(d);
1472 if (rdch && wrch && (dsp_get_flags(i_dev) & SD_F_SIMPLEX))
1473 dsp_set_flags(i_dev, dsp_get_flags(i_dev)^SD_F_SIMPLEX);
1474 pcm_unlock(d);
1475 break;
1476
1477 /*
1478 * The following four ioctls are simple wrappers around mixer_ioctl
1479 * with no further processing. xcmd is short for "translated
1480 * command".
1481 */
1482 case SNDCTL_DSP_GETRECVOL:
1483 if (xcmd == 0)
1484 xcmd = SOUND_MIXER_READ_RECLEV;
1485 /* FALLTHROUGH */
1486 case SNDCTL_DSP_SETRECVOL:
1487 if (xcmd == 0)
1488 xcmd = SOUND_MIXER_WRITE_RECLEV;
1489 /* FALLTHROUGH */
1490 case SNDCTL_DSP_GETPLAYVOL:
1491 if (xcmd == 0)
1492 xcmd = SOUND_MIXER_READ_PCM;
1493 /* FALLTHROUGH */
1494 case SNDCTL_DSP_SETPLAYVOL:
1495 if (xcmd == 0)
1496 xcmd = SOUND_MIXER_WRITE_PCM;
1497
1498 if (d->mixer_dev != NULL) {
1499 PCM_ACQUIRE_QUICK(d);
1500 ret = mixer_ioctl_cmd(d->mixer_dev, xcmd, arg, -1, td,
1501 MIXER_CMD_DIRECT);
1502 PCM_RELEASE_QUICK(d);
1503 } else
1504 ret = ENOTSUP;
1505 break;
1506
1507 case SNDCTL_DSP_GET_RECSRC_NAMES:
1508 case SNDCTL_DSP_GET_RECSRC:
1509 case SNDCTL_DSP_SET_RECSRC:
1510 if (d->mixer_dev != NULL) {
1511 PCM_ACQUIRE_QUICK(d);
1512 ret = mixer_ioctl_cmd(d->mixer_dev, cmd, arg, -1, td,
1513 MIXER_CMD_DIRECT);
1514 PCM_RELEASE_QUICK(d);
1515 } else
1516 ret = ENOTSUP;
1517 break;
1518
1519 /*
1520 * The following 3 ioctls aren't very useful at the moment. For
1521 * now, only a single channel is associated with a cdev (/dev/dspN
1522 * instance), so there's only a single output routing to use (i.e.,
1523 * the wrch bound to this cdev).
1524 */
1525 case SNDCTL_DSP_GET_PLAYTGT_NAMES:
1526 {
1527 oss_mixer_enuminfo *ei;
1528 ei = (oss_mixer_enuminfo *)arg;
1529 ei->dev = 0;
1530 ei->ctrl = 0;
1531 ei->version = 0; /* static for now */
1532 ei->strindex[0] = 0;
1533
1534 if (wrch != NULL) {
1535 ei->nvalues = 1;
1536 strlcpy(ei->strings, wrch->name,
1537 sizeof(ei->strings));
1538 } else {
1539 ei->nvalues = 0;
1540 ei->strings[0] = '\0';
1541 }
1542 }
1543 break;
1544 case SNDCTL_DSP_GET_PLAYTGT:
1545 case SNDCTL_DSP_SET_PLAYTGT: /* yes, they are the same for now */
1546 /*
1547 * Re: SET_PLAYTGT
1548 * OSSv4: "The value that was accepted by the device will
1549 * be returned back in the variable pointed by the
1550 * argument."
1551 */
1552 if (wrch != NULL)
1553 *arg_i = 0;
1554 else
1555 ret = EINVAL;
1556 break;
1557
1558 case SNDCTL_DSP_SILENCE:
1559 /*
1560 * Flush the software (pre-feed) buffer, but try to minimize playback
1561 * interruption. (I.e., record unplayed samples with intent to
1562 * restore by SNDCTL_DSP_SKIP.) Intended for application "pause"
1563 * functionality.
1564 */
1565 if (wrch == NULL)
1566 ret = EINVAL;
1567 else {
1568 struct snd_dbuf *bs;
1569 CHN_LOCK(wrch);
1570 while (wrch->inprog != 0)
1571 cv_wait(&wrch->cv, wrch->lock);
1572 bs = wrch->bufsoft;
1573 if ((bs->shadbuf != NULL) && (sndbuf_getready(bs) > 0)) {
1574 bs->sl = sndbuf_getready(bs);
1575 sndbuf_dispose(bs, bs->shadbuf, sndbuf_getready(bs));
1576 sndbuf_fillsilence(bs);
1577 chn_start(wrch, 0);
1578 }
1579 CHN_UNLOCK(wrch);
1580 }
1581 break;
1582
1583 case SNDCTL_DSP_SKIP:
1584 /*
1585 * OSSv4 docs: "This ioctl call discards all unplayed samples in the
1586 * playback buffer by moving the current write position immediately
1587 * before the point where the device is currently reading the samples."
1588 */
1589 if (wrch == NULL)
1590 ret = EINVAL;
1591 else {
1592 struct snd_dbuf *bs;
1593 CHN_LOCK(wrch);
1594 while (wrch->inprog != 0)
1595 cv_wait(&wrch->cv, wrch->lock);
1596 bs = wrch->bufsoft;
1597 if ((bs->shadbuf != NULL) && (bs->sl > 0)) {
1598 sndbuf_softreset(bs);
1599 sndbuf_acquire(bs, bs->shadbuf, bs->sl);
1600 bs->sl = 0;
1601 chn_start(wrch, 0);
1602 }
1603 CHN_UNLOCK(wrch);
1604 }
1605 break;
1606
1607 case SNDCTL_DSP_CURRENT_OPTR:
1608 case SNDCTL_DSP_CURRENT_IPTR:
1609 /**
1610 * @note Changing formats resets the buffer counters, which differs
1611 * from the 4Front drivers. However, I don't expect this to be
1612 * much of a problem.
1613 *
1614 * @note In a test where @c CURRENT_OPTR is called immediately after write
1615 * returns, this driver is about 32K samples behind whereas
1616 * 4Front's is about 8K samples behind. Should determine source
1617 * of discrepancy, even if only out of curiosity.
1618 *
1619 * @todo Actually test SNDCTL_DSP_CURRENT_IPTR.
1620 */
1621 chn = (cmd == SNDCTL_DSP_CURRENT_OPTR) ? wrch : rdch;
1622 if (chn == NULL)
1623 ret = EINVAL;
1624 else {
1625 struct snd_dbuf *bs;
1626 /* int tmp; */
1627
1628 oss_count_t *oc = (oss_count_t *)arg;
1629
1630 CHN_LOCK(chn);
1631 bs = chn->bufsoft;
1632 #if 0
1633 tmp = (sndbuf_getsize(b) + chn_getptr(chn) - sndbuf_gethwptr(b)) % sndbuf_getsize(b);
1634 oc->samples = (sndbuf_gettotal(b) + tmp) / sndbuf_getbps(b);
1635 oc->fifo_samples = (sndbuf_getready(b) - tmp) / sndbuf_getbps(b);
1636 #else
1637 oc->samples = sndbuf_gettotal(bs) / sndbuf_getbps(bs);
1638 oc->fifo_samples = sndbuf_getready(bs) / sndbuf_getbps(bs);
1639 #endif
1640 CHN_UNLOCK(chn);
1641 }
1642 break;
1643
1644 case SNDCTL_DSP_HALT_OUTPUT:
1645 case SNDCTL_DSP_HALT_INPUT:
1646 chn = (cmd == SNDCTL_DSP_HALT_OUTPUT) ? wrch : rdch;
1647 if (chn == NULL)
1648 ret = EINVAL;
1649 else {
1650 CHN_LOCK(chn);
1651 chn_abort(chn);
1652 CHN_UNLOCK(chn);
1653 }
1654 break;
1655
1656 case SNDCTL_DSP_LOW_WATER:
1657 /*
1658 * Set the number of bytes required to attract attention by
1659 * select/poll.
1660 */
1661 if (wrch != NULL) {
1662 CHN_LOCK(wrch);
1663 wrch->lw = (*arg_i > 1) ? *arg_i : 1;
1664 CHN_UNLOCK(wrch);
1665 }
1666 if (rdch != NULL) {
1667 CHN_LOCK(rdch);
1668 rdch->lw = (*arg_i > 1) ? *arg_i : 1;
1669 CHN_UNLOCK(rdch);
1670 }
1671 break;
1672
1673 case SNDCTL_DSP_GETERROR:
1674 /*
1675 * OSSv4 docs: "All errors and counters will automatically be
1676 * cleared to zeroes after the call so each call will return only
1677 * the errors that occurred after the previous invocation. ... The
1678 * play_underruns and rec_overrun fields are the only usefull fields
1679 * returned by OSS 4.0."
1680 */
1681 {
1682 audio_errinfo *ei = (audio_errinfo *)arg;
1683
1684 bzero((void *)ei, sizeof(*ei));
1685
1686 if (wrch != NULL) {
1687 CHN_LOCK(wrch);
1688 ei->play_underruns = wrch->xruns;
1689 wrch->xruns = 0;
1690 CHN_UNLOCK(wrch);
1691 }
1692 if (rdch != NULL) {
1693 CHN_LOCK(rdch);
1694 ei->rec_overruns = rdch->xruns;
1695 rdch->xruns = 0;
1696 CHN_UNLOCK(rdch);
1697 }
1698 }
1699 break;
1700
1701 case SNDCTL_DSP_SYNCGROUP:
1702 PCM_ACQUIRE_QUICK(d);
1703 ret = dsp_oss_syncgroup(wrch, rdch, (oss_syncgroup *)arg);
1704 PCM_RELEASE_QUICK(d);
1705 break;
1706
1707 case SNDCTL_DSP_SYNCSTART:
1708 PCM_ACQUIRE_QUICK(d);
1709 ret = dsp_oss_syncstart(*arg_i);
1710 PCM_RELEASE_QUICK(d);
1711 break;
1712
1713 case SNDCTL_DSP_POLICY:
1714 PCM_ACQUIRE_QUICK(d);
1715 ret = dsp_oss_policy(wrch, rdch, *arg_i);
1716 PCM_RELEASE_QUICK(d);
1717 break;
1718
1719 #ifdef OSSV4_EXPERIMENT
1720 /*
1721 * XXX The following ioctls are not yet supported and just return
1722 * EINVAL.
1723 */
1724 case SNDCTL_DSP_GETOPEAKS:
1725 case SNDCTL_DSP_GETIPEAKS:
1726 chn = (cmd == SNDCTL_DSP_GETOPEAKS) ? wrch : rdch;
1727 if (chn == NULL)
1728 ret = EINVAL;
1729 else {
1730 oss_peaks_t *op = (oss_peaks_t *)arg;
1731 int lpeak, rpeak;
1732
1733 CHN_LOCK(chn);
1734 ret = chn_getpeaks(chn, &lpeak, &rpeak);
1735 if (ret == -1)
1736 ret = EINVAL;
1737 else {
1738 (*op)[0] = lpeak;
1739 (*op)[1] = rpeak;
1740 }
1741 CHN_UNLOCK(chn);
1742 }
1743 break;
1744
1745 /*
1746 * XXX Once implemented, revisit this for proper cv protection
1747 * (if necessary).
1748 */
1749 case SNDCTL_DSP_COOKEDMODE:
1750 ret = dsp_oss_cookedmode(wrch, rdch, *arg_i);
1751 break;
1752 case SNDCTL_DSP_GET_CHNORDER:
1753 ret = dsp_oss_getchnorder(wrch, rdch, (unsigned long long *)arg);
1754 break;
1755 case SNDCTL_DSP_SET_CHNORDER:
1756 ret = dsp_oss_setchnorder(wrch, rdch, (unsigned long long *)arg);
1757 break;
1758 case SNDCTL_GETLABEL:
1759 ret = dsp_oss_getlabel(wrch, rdch, (oss_label_t *)arg);
1760 break;
1761 case SNDCTL_SETLABEL:
1762 ret = dsp_oss_setlabel(wrch, rdch, (oss_label_t *)arg);
1763 break;
1764 case SNDCTL_GETSONG:
1765 ret = dsp_oss_getsong(wrch, rdch, (oss_longname_t *)arg);
1766 break;
1767 case SNDCTL_SETSONG:
1768 ret = dsp_oss_setsong(wrch, rdch, (oss_longname_t *)arg);
1769 break;
1770 case SNDCTL_SETNAME:
1771 ret = dsp_oss_setname(wrch, rdch, (oss_longname_t *)arg);
1772 break;
1773 #if 0
1774 /**
1775 * @note The SNDCTL_CARDINFO ioctl was omitted per 4Front developer
1776 * documentation. "The usability of this call is very limited. It's
1777 * provided only for completeness of the API. OSS API doesn't have
1778 * any concept of card. Any information returned by this ioctl calld
1779 * is reserved exclusively for the utility programs included in the
1780 * OSS package. Applications should not try to use for this
1781 * information in any ways."
1782 */
1783 case SNDCTL_CARDINFO:
1784 ret = EINVAL;
1785 break;
1786 /**
1787 * @note The S/PDIF interface ioctls, @c SNDCTL_DSP_READCTL and
1788 * @c SNDCTL_DSP_WRITECTL have been omitted at the suggestion of
1789 * 4Front Technologies.
1790 */
1791 case SNDCTL_DSP_READCTL:
1792 case SNDCTL_DSP_WRITECTL:
1793 ret = EINVAL;
1794 break;
1795 #endif /* !0 (explicitly omitted ioctls) */
1796
1797 #endif /* !OSSV4_EXPERIMENT */
1798 case SNDCTL_DSP_MAPINBUF:
1799 case SNDCTL_DSP_MAPOUTBUF:
1800 case SNDCTL_DSP_SETSYNCRO:
1801 /* undocumented */
1802
1803 case SNDCTL_DSP_SUBDIVIDE:
1804 case SOUND_PCM_WRITE_FILTER:
1805 case SOUND_PCM_READ_FILTER:
1806 /* dunno what these do, don't sound important */
1807
1808 default:
1809 DEB(printf("default ioctl fn 0x%08lx fail\n", cmd));
1810 ret = EINVAL;
1811 break;
1812 }
1813
1814 relchns(i_dev, rdch, wrch, 0);
1815
1816 PCM_GIANT_LEAVE(d);
1817
1818 return (ret);
1819 }
1820
1821 static int
1822 dsp_poll(struct cdev *i_dev, int events, struct thread *td)
1823 {
1824 struct snddev_info *d;
1825 struct pcm_channel *wrch, *rdch;
1826 int ret, e;
1827
1828 d = dsp_get_info(i_dev);
1829 if (!DSP_REGISTERED(d, i_dev))
1830 return (EBADF);
1831
1832 PCM_GIANT_ENTER(d);
1833
1834 wrch = NULL;
1835 rdch = NULL;
1836 ret = 0;
1837
1838 getchns(i_dev, &rdch, &wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
1839
1840 if (wrch != NULL && !(wrch->flags & CHN_F_DEAD)) {
1841 e = (events & (POLLOUT | POLLWRNORM));
1842 if (e)
1843 ret |= chn_poll(wrch, e, td);
1844 }
1845
1846 if (rdch != NULL && !(rdch->flags & CHN_F_DEAD)) {
1847 e = (events & (POLLIN | POLLRDNORM));
1848 if (e)
1849 ret |= chn_poll(rdch, e, td);
1850 }
1851
1852 relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
1853
1854 PCM_GIANT_LEAVE(d);
1855
1856 return (ret);
1857 }
1858
1859 static int
1860 dsp_mmap(struct cdev *i_dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot)
1861 {
1862
1863 *paddr = vtophys(offset);
1864 return (0);
1865 }
1866
1867 static int
1868 dsp_mmap_single(struct cdev *i_dev, vm_ooffset_t *offset,
1869 vm_size_t size, struct vm_object **object, int nprot)
1870 {
1871 struct snddev_info *d;
1872 struct pcm_channel *wrch, *rdch, *c;
1873
1874 /*
1875 * Reject PROT_EXEC by default. It just doesn't makes sense.
1876 * Unfortunately, we have to give up this one due to linux_mmap
1877 * changes.
1878 *
1879 * http://lists.freebsd.org/pipermail/freebsd-emulation/2007-June/003698.html
1880 *
1881 */
1882 if ((nprot & PROT_EXEC) && dsp_mmap_allow_prot_exec == 0)
1883 return (EINVAL);
1884
1885 /*
1886 * PROT_READ (alone) selects the input buffer.
1887 * PROT_WRITE (alone) selects the output buffer.
1888 * PROT_WRITE|PROT_READ together select the output buffer.
1889 */
1890 if ((nprot & (PROT_READ | PROT_WRITE)) == 0)
1891 return (EINVAL);
1892
1893 d = dsp_get_info(i_dev);
1894 if (!DSP_REGISTERED(d, i_dev))
1895 return (EINVAL);
1896
1897 PCM_GIANT_ENTER(d);
1898
1899 getchns(i_dev, &rdch, &wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
1900
1901 c = ((nprot & PROT_WRITE) != 0) ? wrch : rdch;
1902 if (c == NULL || (c->flags & CHN_F_MMAP_INVALID) ||
1903 (*offset + size) > sndbuf_getsize(c->bufsoft) ||
1904 (wrch != NULL && (wrch->flags & CHN_F_MMAP_INVALID)) ||
1905 (rdch != NULL && (rdch->flags & CHN_F_MMAP_INVALID))) {
1906 relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
1907 PCM_GIANT_EXIT(d);
1908 return (EINVAL);
1909 }
1910
1911 if (wrch != NULL)
1912 wrch->flags |= CHN_F_MAPPED;
1913 if (rdch != NULL)
1914 rdch->flags |= CHN_F_MAPPED;
1915
1916 *offset = (uintptr_t)sndbuf_getbufofs(c->bufsoft, *offset);
1917 relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
1918 *object = vm_pager_allocate(OBJT_DEVICE, i_dev,
1919 size, nprot, *offset);
1920
1921 PCM_GIANT_LEAVE(d);
1922
1923 if (*object == NULL)
1924 return (EINVAL);
1925 return (0);
1926 }
1927
1928 #ifdef USING_DEVFS
1929
1930 /* So much for dev_stdclone() */
1931 static int
1932 dsp_stdclone(char *name, char *namep, char *sep, int use_sep, int *u, int *c)
1933 {
1934 size_t len;
1935
1936 len = strlen(namep);
1937
1938 if (bcmp(name, namep, len) != 0)
1939 return (ENODEV);
1940
1941 name += len;
1942
1943 if (isdigit(*name) == 0)
1944 return (ENODEV);
1945
1946 len = strlen(sep);
1947
1948 if (*name == '' && !(name[1] == '\0' || bcmp(name + 1, sep, len) == 0))
1949 return (ENODEV);
1950
1951 for (*u = 0; isdigit(*name) != 0; name++) {
1952 *u *= 10;
1953 *u += *name - '';
1954 if (*u > dsp_umax)
1955 return (ENODEV);
1956 }
1957
1958 if (*name == '\0')
1959 return ((use_sep == 0) ? 0 : ENODEV);
1960
1961 if (bcmp(name, sep, len) != 0 || isdigit(name[len]) == 0)
1962 return (ENODEV);
1963
1964 name += len;
1965
1966 if (*name == '' && name[1] != '\0')
1967 return (ENODEV);
1968
1969 for (*c = 0; isdigit(*name) != 0; name++) {
1970 *c *= 10;
1971 *c += *name - '';
1972 if (*c > dsp_cmax)
1973 return (ENODEV);
1974 }
1975
1976 if (*name != '\0')
1977 return (ENODEV);
1978
1979 return (0);
1980 }
1981
1982 static void
1983 dsp_clone(void *arg,
1984 #if __FreeBSD_version >= 600034
1985 struct ucred *cred,
1986 #endif
1987 char *name, int namelen, struct cdev **dev)
1988 {
1989 struct snddev_info *d;
1990 struct snd_clone_entry *ce;
1991 struct pcm_channel *c;
1992 int i, unit, udcmask, cunit, devtype, devhw, devcmax, tumax;
1993 char *devname, *devsep;
1994
1995 KASSERT(dsp_umax >= 0 && dsp_cmax >= 0, ("Uninitialized unit!"));
1996
1997 if (*dev != NULL)
1998 return;
1999
2000 unit = -1;
2001 cunit = -1;
2002 devtype = -1;
2003 devhw = 0;
2004 devcmax = -1;
2005 tumax = -1;
2006 devname = NULL;
2007 devsep = NULL;
2008
2009 for (i = 0; unit == -1 &&
2010 i < (sizeof(dsp_cdevs) / sizeof(dsp_cdevs[0])); i++) {
2011 devtype = dsp_cdevs[i].type;
2012 devname = dsp_cdevs[i].name;
2013 devsep = dsp_cdevs[i].sep;
2014 devhw = dsp_cdevs[i].hw;
2015 devcmax = dsp_cdevs[i].max - 1;
2016 if (strcmp(name, devname) == 0)
2017 unit = snd_unit;
2018 else if (dsp_stdclone(name, devname, devsep,
2019 dsp_cdevs[i].use_sep, &unit, &cunit) != 0) {
2020 unit = -1;
2021 cunit = -1;
2022 }
2023 }
2024
2025 d = devclass_get_softc(pcm_devclass, unit);
2026 if (!PCM_REGISTERED(d) || d->clones == NULL)
2027 return;
2028
2029 /* XXX Need Giant magic entry ??? */
2030
2031 pcm_lock(d);
2032 if (snd_clone_disabled(d->clones)) {
2033 pcm_unlock(d);
2034 return;
2035 }
2036
2037 PCM_WAIT(d);
2038 PCM_ACQUIRE(d);
2039 pcm_unlock(d);
2040
2041 udcmask = snd_u2unit(unit) | snd_d2unit(devtype);
2042
2043 if (devhw != 0) {
2044 KASSERT(devcmax <= dsp_cmax,
2045 ("overflow: devcmax=%d, dsp_cmax=%d", devcmax, dsp_cmax));
2046 if (cunit > devcmax) {
2047 PCM_RELEASE_QUICK(d);
2048 return;
2049 }
2050 udcmask |= snd_c2unit(cunit);
2051 CHN_FOREACH(c, d, channels.pcm) {
2052 CHN_LOCK(c);
2053 if (c->unit != udcmask) {
2054 CHN_UNLOCK(c);
2055 continue;
2056 }
2057 CHN_UNLOCK(c);
2058 udcmask &= ~snd_c2unit(cunit);
2059 /*
2060 * Temporarily increase clone maxunit to overcome
2061 * vchan flexibility.
2062 *
2063 * # sysctl dev.pcm.0.play.vchans=256
2064 * dev.pcm.0.play.vchans: 1 -> 256
2065 * # cat /dev/zero > /dev/dsp0.vp255 &
2066 * [1] 17296
2067 * # sysctl dev.pcm.0.play.vchans=0
2068 * dev.pcm.0.play.vchans: 256 -> 1
2069 * # fg
2070 * [1] + running cat /dev/zero > /dev/dsp0.vp255
2071 * ^C
2072 * # cat /dev/zero > /dev/dsp0.vp255
2073 * zsh: operation not supported: /dev/dsp0.vp255
2074 */
2075 tumax = snd_clone_getmaxunit(d->clones);
2076 if (cunit > tumax)
2077 snd_clone_setmaxunit(d->clones, cunit);
2078 else
2079 tumax = -1;
2080 goto dsp_clone_alloc;
2081 }
2082 /*
2083 * Ok, so we're requesting unallocated vchan, but still
2084 * within maximum vchan limit.
2085 */
2086 if (((devtype == SND_DEV_DSPHW_VPLAY && d->pvchancount > 0) ||
2087 (devtype == SND_DEV_DSPHW_VREC && d->rvchancount > 0)) &&
2088 cunit < snd_maxautovchans) {
2089 udcmask &= ~snd_c2unit(cunit);
2090 tumax = snd_clone_getmaxunit(d->clones);
2091 if (cunit > tumax)
2092 snd_clone_setmaxunit(d->clones, cunit);
2093 else
2094 tumax = -1;
2095 goto dsp_clone_alloc;
2096 }
2097 PCM_RELEASE_QUICK(d);
2098 return;
2099 }
2100
2101 dsp_clone_alloc:
2102 ce = snd_clone_alloc(d->clones, dev, &cunit, udcmask);
2103 if (tumax != -1)
2104 snd_clone_setmaxunit(d->clones, tumax);
2105 if (ce != NULL) {
2106 udcmask |= snd_c2unit(cunit);
2107 *dev = make_dev(&dsp_cdevsw, unit2minor(udcmask),
2108 UID_ROOT, GID_WHEEL, 0666, "%s%d%s%d",
2109 devname, unit, devsep, cunit);
2110 snd_clone_register(ce, *dev);
2111 }
2112
2113 PCM_RELEASE_QUICK(d);
2114
2115 if (*dev != NULL)
2116 dev_ref(*dev);
2117 }
2118
2119 static void
2120 dsp_sysinit(void *p)
2121 {
2122 if (dsp_ehtag != NULL)
2123 return;
2124 /* initialize unit numbering */
2125 snd_unit_init();
2126 dsp_umax = PCMMAXUNIT;
2127 dsp_cmax = PCMMAXCHAN;
2128 dsp_ehtag = EVENTHANDLER_REGISTER(dev_clone, dsp_clone, 0, 1000);
2129 }
2130
2131 static void
2132 dsp_sysuninit(void *p)
2133 {
2134 if (dsp_ehtag == NULL)
2135 return;
2136 EVENTHANDLER_DEREGISTER(dev_clone, dsp_ehtag);
2137 dsp_ehtag = NULL;
2138 }
2139
2140 SYSINIT(dsp_sysinit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, dsp_sysinit, NULL);
2141 SYSUNINIT(dsp_sysuninit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, dsp_sysuninit, NULL);
2142 #endif
2143
2144 char *
2145 dsp_unit2name(char *buf, size_t len, int unit)
2146 {
2147 int i, dtype;
2148
2149 KASSERT(buf != NULL && len != 0,
2150 ("bogus buf=%p len=%ju", buf, (uintmax_t)len));
2151
2152 dtype = snd_unit2d(unit);
2153
2154 for (i = 0; i < (sizeof(dsp_cdevs) / sizeof(dsp_cdevs[0])); i++) {
2155 if (dtype != dsp_cdevs[i].type)
2156 continue;
2157 snprintf(buf, len, "%s%d%s%d", dsp_cdevs[i].name,
2158 snd_unit2u(unit), dsp_cdevs[i].sep, snd_unit2c(unit));
2159 return (buf);
2160 }
2161
2162 return (NULL);
2163 }
2164
2165 /**
2166 * @brief Handler for SNDCTL_AUDIOINFO.
2167 *
2168 * Gathers information about the audio device specified in ai->dev. If
2169 * ai->dev == -1, then this function gathers information about the current
2170 * device. If the call comes in on a non-audio device and ai->dev == -1,
2171 * return EINVAL.
2172 *
2173 * This routine is supposed to go practically straight to the hardware,
2174 * getting capabilities directly from the sound card driver, side-stepping
2175 * the intermediate channel interface.
2176 *
2177 * Note, however, that the usefulness of this command is significantly
2178 * decreased when requesting info about any device other than the one serving
2179 * the request. While each snddev_channel refers to a specific device node,
2180 * the converse is *not* true. Currently, when a sound device node is opened,
2181 * the sound subsystem scans for an available audio channel (or channels, if
2182 * opened in read+write) and then assigns them to the si_drv[12] private
2183 * data fields. As a result, any information returned linking a channel to
2184 * a specific character device isn't necessarily accurate.
2185 *
2186 * @note
2187 * Calling threads must not hold any snddev_info or pcm_channel locks.
2188 *
2189 * @param dev device on which the ioctl was issued
2190 * @param ai ioctl request data container
2191 *
2192 * @retval 0 success
2193 * @retval EINVAL ai->dev specifies an invalid device
2194 *
2195 * @todo Verify correctness of Doxygen tags. ;)
2196 */
2197 int
2198 dsp_oss_audioinfo(struct cdev *i_dev, oss_audioinfo *ai)
2199 {
2200 struct pcmchan_caps *caps;
2201 struct pcm_channel *ch;
2202 struct snddev_info *d;
2203 uint32_t fmts;
2204 int i, nchan, *rates, minch, maxch;
2205 char *devname, buf[CHN_NAMELEN];
2206
2207 /*
2208 * If probing the device that received the ioctl, make sure it's a
2209 * DSP device. (Users may use this ioctl with /dev/mixer and
2210 * /dev/midi.)
2211 */
2212 if (ai->dev == -1 && i_dev->si_devsw != &dsp_cdevsw)
2213 return (EINVAL);
2214
2215 ch = NULL;
2216 devname = NULL;
2217 nchan = 0;
2218 bzero(buf, sizeof(buf));
2219
2220 /*
2221 * Search for the requested audio device (channel). Start by
2222 * iterating over pcm devices.
2223 */
2224 for (i = 0; pcm_devclass != NULL &&
2225 i < devclass_get_maxunit(pcm_devclass); i++) {
2226 d = devclass_get_softc(pcm_devclass, i);
2227 if (!PCM_REGISTERED(d))
2228 continue;
2229
2230 /* XXX Need Giant magic entry ??? */
2231
2232 /* See the note in function docblock */
2233 mtx_assert(d->lock, MA_NOTOWNED);
2234 pcm_lock(d);
2235
2236 CHN_FOREACH(ch, d, channels.pcm) {
2237 mtx_assert(ch->lock, MA_NOTOWNED);
2238 CHN_LOCK(ch);
2239 if (ai->dev == -1) {
2240 if (DSP_REGISTERED(d, i_dev) &&
2241 (ch == PCM_RDCH(i_dev) || /* record ch */
2242 ch == PCM_WRCH(i_dev))) { /* playback ch */
2243 devname = dsp_unit2name(buf,
2244 sizeof(buf), ch->unit);
2245 }
2246 } else if (ai->dev == nchan) {
2247 devname = dsp_unit2name(buf, sizeof(buf),
2248 ch->unit);
2249 }
2250 if (devname != NULL)
2251 break;
2252 CHN_UNLOCK(ch);
2253 ++nchan;
2254 }
2255
2256 if (devname != NULL) {
2257 /*
2258 * At this point, the following synchronization stuff
2259 * has happened:
2260 * - a specific PCM device is locked.
2261 * - a specific audio channel has been locked, so be
2262 * sure to unlock when exiting;
2263 */
2264
2265 caps = chn_getcaps(ch);
2266
2267 /*
2268 * With all handles collected, zero out the user's
2269 * container and begin filling in its fields.
2270 */
2271 bzero((void *)ai, sizeof(oss_audioinfo));
2272
2273 ai->dev = nchan;
2274 strlcpy(ai->name, ch->name, sizeof(ai->name));
2275
2276 if ((ch->flags & CHN_F_BUSY) == 0)
2277 ai->busy = 0;
2278 else
2279 ai->busy = (ch->direction == PCMDIR_PLAY) ? OPEN_WRITE : OPEN_READ;
2280
2281 /**
2282 * @note
2283 * @c cmd - OSSv4 docs: "Only supported under Linux at
2284 * this moment." Cop-out, I know, but I'll save
2285 * running around in the process table for later.
2286 * Is there a risk of leaking information?
2287 */
2288 ai->pid = ch->pid;
2289
2290 /*
2291 * These flags stolen from SNDCTL_DSP_GETCAPS handler.
2292 * Note, however, that a single channel operates in
2293 * only one direction, so DSP_CAP_DUPLEX is out.
2294 */
2295 /**
2296 * @todo @c SNDCTL_AUDIOINFO::caps - Make drivers keep
2297 * these in pcmchan::caps?
2298 */
2299 ai->caps = DSP_CAP_REALTIME | DSP_CAP_MMAP | DSP_CAP_TRIGGER;
2300
2301 /*
2302 * Collect formats supported @b natively by the
2303 * device. Also determine min/max channels. (I.e.,
2304 * mono, stereo, or both?)
2305 *
2306 * If any channel is stereo, maxch = 2;
2307 * if all channels are stereo, minch = 2, too;
2308 * if any channel is mono, minch = 1;
2309 * and if all channels are mono, maxch = 1.
2310 */
2311 minch = 0;
2312 maxch = 0;
2313 fmts = 0;
2314 for (i = 0; caps->fmtlist[i]; i++) {
2315 fmts |= caps->fmtlist[i];
2316 if (caps->fmtlist[i] & AFMT_STEREO) {
2317 minch = (minch == 0) ? 2 : minch;
2318 maxch = 2;
2319 } else {
2320 minch = 1;
2321 maxch = (maxch == 0) ? 1 : maxch;
2322 }
2323 }
2324
2325 if (ch->direction == PCMDIR_PLAY)
2326 ai->oformats = fmts;
2327 else
2328 ai->iformats = fmts;
2329
2330 /**
2331 * @note
2332 * @c magic - OSSv4 docs: "Reserved for internal use
2333 * by OSS."
2334 *
2335 * @par
2336 * @c card_number - OSSv4 docs: "Number of the sound
2337 * card where this device belongs or -1 if this
2338 * information is not available. Applications
2339 * should normally not use this field for any
2340 * purpose."
2341 */
2342 ai->card_number = -1;
2343 /**
2344 * @todo @c song_name - depends first on
2345 * SNDCTL_[GS]ETSONG @todo @c label - depends
2346 * on SNDCTL_[GS]ETLABEL
2347 * @todo @c port_number - routing information?
2348 */
2349 ai->port_number = -1;
2350 ai->mixer_dev = (d->mixer_dev != NULL) ? PCMUNIT(d->mixer_dev) : -1;
2351 /**
2352 * @note
2353 * @c real_device - OSSv4 docs: "Obsolete."
2354 */
2355 ai->real_device = -1;
2356 strlcpy(ai->devnode, devname, sizeof(ai->devnode));
2357 ai->enabled = device_is_attached(d->dev) ? 1 : 0;
2358 /**
2359 * @note
2360 * @c flags - OSSv4 docs: "Reserved for future use."
2361 *
2362 * @note
2363 * @c binding - OSSv4 docs: "Reserved for future use."
2364 *
2365 * @todo @c handle - haven't decided how to generate
2366 * this yet; bus, vendor, device IDs?
2367 */
2368 ai->min_rate = caps->minspeed;
2369 ai->max_rate = caps->maxspeed;
2370
2371 ai->min_channels = minch;
2372 ai->max_channels = maxch;
2373
2374 ai->nrates = chn_getrates(ch, &rates);
2375 if (ai->nrates > OSS_MAX_SAMPLE_RATES)
2376 ai->nrates = OSS_MAX_SAMPLE_RATES;
2377
2378 for (i = 0; i < ai->nrates; i++)
2379 ai->rates[i] = rates[i];
2380
2381 CHN_UNLOCK(ch);
2382 }
2383
2384 pcm_unlock(d);
2385
2386 if (devname != NULL)
2387 return (0);
2388 }
2389
2390 /* Exhausted the search -- nothing is locked, so return. */
2391 return (EINVAL);
2392 }
2393
2394 /**
2395 * @brief Assigns a PCM channel to a sync group.
2396 *
2397 * Sync groups are used to enable audio operations on multiple devices
2398 * simultaneously. They may be used with any number of devices and may
2399 * span across applications. Devices are added to groups with
2400 * the SNDCTL_DSP_SYNCGROUP ioctl, and operations are triggered with the
2401 * SNDCTL_DSP_SYNCSTART ioctl.
2402 *
2403 * If the @c id field of the @c group parameter is set to zero, then a new
2404 * sync group is created. Otherwise, wrch and rdch (if set) are added to
2405 * the group specified.
2406 *
2407 * @todo As far as memory allocation, should we assume that things are
2408 * okay and allocate with M_WAITOK before acquiring channel locks,
2409 * freeing later if not?
2410 *
2411 * @param wrch output channel associated w/ device (if any)
2412 * @param rdch input channel associated w/ device (if any)
2413 * @param group Sync group parameters
2414 *
2415 * @retval 0 success
2416 * @retval non-zero error to be propagated upstream
2417 */
2418 static int
2419 dsp_oss_syncgroup(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_syncgroup *group)
2420 {
2421 struct pcmchan_syncmember *smrd, *smwr;
2422 struct pcmchan_syncgroup *sg;
2423 int ret, sg_ids[3];
2424
2425 smrd = NULL;
2426 smwr = NULL;
2427 sg = NULL;
2428 ret = 0;
2429
2430 /*
2431 * Free_unr() may sleep, so store released syncgroup IDs until after
2432 * all locks are released.
2433 */
2434 sg_ids[0] = sg_ids[1] = sg_ids[2] = 0;
2435
2436 PCM_SG_LOCK();
2437
2438 /*
2439 * - Insert channel(s) into group's member list.
2440 * - Set CHN_F_NOTRIGGER on channel(s).
2441 * - Stop channel(s).
2442 */
2443
2444 /*
2445 * If device's channels are already mapped to a group, unmap them.
2446 */
2447 if (wrch) {
2448 CHN_LOCK(wrch);
2449 sg_ids[0] = chn_syncdestroy(wrch);
2450 }
2451
2452 if (rdch) {
2453 CHN_LOCK(rdch);
2454 sg_ids[1] = chn_syncdestroy(rdch);
2455 }
2456
2457 /*
2458 * Verify that mode matches character device properites.
2459 * - Bail if PCM_ENABLE_OUTPUT && wrch == NULL.
2460 * - Bail if PCM_ENABLE_INPUT && rdch == NULL.
2461 */
2462 if (((wrch == NULL) && (group->mode & PCM_ENABLE_OUTPUT)) ||
2463 ((rdch == NULL) && (group->mode & PCM_ENABLE_INPUT))) {
2464 ret = EINVAL;
2465 goto out;
2466 }
2467
2468 /*
2469 * An id of zero indicates the user wants to create a new
2470 * syncgroup.
2471 */
2472 if (group->id == 0) {
2473 sg = (struct pcmchan_syncgroup *)malloc(sizeof(*sg), M_DEVBUF, M_NOWAIT);
2474 if (sg != NULL) {
2475 SLIST_INIT(&sg->members);
2476 sg->id = alloc_unr(pcmsg_unrhdr);
2477
2478 group->id = sg->id;
2479 SLIST_INSERT_HEAD(&snd_pcm_syncgroups, sg, link);
2480 } else
2481 ret = ENOMEM;
2482 } else {
2483 SLIST_FOREACH(sg, &snd_pcm_syncgroups, link) {
2484 if (sg->id == group->id)
2485 break;
2486 }
2487 if (sg == NULL)
2488 ret = EINVAL;
2489 }
2490
2491 /* Couldn't create or find a syncgroup. Fail. */
2492 if (sg == NULL)
2493 goto out;
2494
2495 /*
2496 * Allocate a syncmember, assign it and a channel together, and
2497 * insert into syncgroup.
2498 */
2499 if (group->mode & PCM_ENABLE_INPUT) {
2500 smrd = (struct pcmchan_syncmember *)malloc(sizeof(*smrd), M_DEVBUF, M_NOWAIT);
2501 if (smrd == NULL) {
2502 ret = ENOMEM;
2503 goto out;
2504 }
2505
2506 SLIST_INSERT_HEAD(&sg->members, smrd, link);
2507 smrd->parent = sg;
2508 smrd->ch = rdch;
2509
2510 chn_abort(rdch);
2511 rdch->flags |= CHN_F_NOTRIGGER;
2512 rdch->sm = smrd;
2513 }
2514
2515 if (group->mode & PCM_ENABLE_OUTPUT) {
2516 smwr = (struct pcmchan_syncmember *)malloc(sizeof(*smwr), M_DEVBUF, M_NOWAIT);
2517 if (smwr == NULL) {
2518 ret = ENOMEM;
2519 goto out;
2520 }
2521
2522 SLIST_INSERT_HEAD(&sg->members, smwr, link);
2523 smwr->parent = sg;
2524 smwr->ch = wrch;
2525
2526 chn_abort(wrch);
2527 wrch->flags |= CHN_F_NOTRIGGER;
2528 wrch->sm = smwr;
2529 }
2530
2531
2532 out:
2533 if (ret != 0) {
2534 if (smrd != NULL)
2535 free(smrd, M_DEVBUF);
2536 if ((sg != NULL) && SLIST_EMPTY(&sg->members)) {
2537 sg_ids[2] = sg->id;
2538 SLIST_REMOVE(&snd_pcm_syncgroups, sg, pcmchan_syncgroup, link);
2539 free(sg, M_DEVBUF);
2540 }
2541
2542 if (wrch)
2543 wrch->sm = NULL;
2544 if (rdch)
2545 rdch->sm = NULL;
2546 }
2547
2548 if (wrch)
2549 CHN_UNLOCK(wrch);
2550 if (rdch)
2551 CHN_UNLOCK(rdch);
2552
2553 PCM_SG_UNLOCK();
2554
2555 if (sg_ids[0])
2556 free_unr(pcmsg_unrhdr, sg_ids[0]);
2557 if (sg_ids[1])
2558 free_unr(pcmsg_unrhdr, sg_ids[1]);
2559 if (sg_ids[2])
2560 free_unr(pcmsg_unrhdr, sg_ids[2]);
2561
2562 return (ret);
2563 }
2564
2565 /**
2566 * @brief Launch a sync group into action
2567 *
2568 * Sync groups are established via SNDCTL_DSP_SYNCGROUP. This function
2569 * iterates over all members, triggering them along the way.
2570 *
2571 * @note Caller must not hold any channel locks.
2572 *
2573 * @param sg_id sync group identifier
2574 *
2575 * @retval 0 success
2576 * @retval non-zero error worthy of propagating upstream to user
2577 */
2578 static int
2579 dsp_oss_syncstart(int sg_id)
2580 {
2581 struct pcmchan_syncmember *sm, *sm_tmp;
2582 struct pcmchan_syncgroup *sg;
2583 struct pcm_channel *c;
2584 int ret, needlocks;
2585
2586 /* Get the synclists lock */
2587 PCM_SG_LOCK();
2588
2589 do {
2590 ret = 0;
2591 needlocks = 0;
2592
2593 /* Search for syncgroup by ID */
2594 SLIST_FOREACH(sg, &snd_pcm_syncgroups, link) {
2595 if (sg->id == sg_id)
2596 break;
2597 }
2598
2599 /* Return EINVAL if not found */
2600 if (sg == NULL) {
2601 ret = EINVAL;
2602 break;
2603 }
2604
2605 /* Any removals resulting in an empty group should've handled this */
2606 KASSERT(!SLIST_EMPTY(&sg->members), ("found empty syncgroup"));
2607
2608 /*
2609 * Attempt to lock all member channels - if any are already
2610 * locked, unlock those acquired, sleep for a bit, and try
2611 * again.
2612 */
2613 SLIST_FOREACH(sm, &sg->members, link) {
2614 if (CHN_TRYLOCK(sm->ch) == 0) {
2615 int timo = hz * 5/1000;
2616 if (timo < 1)
2617 timo = 1;
2618
2619 /* Release all locked channels so far, retry */
2620 SLIST_FOREACH(sm_tmp, &sg->members, link) {
2621 /* sm is the member already locked */
2622 if (sm == sm_tmp)
2623 break;
2624 CHN_UNLOCK(sm_tmp->ch);
2625 }
2626
2627 /** @todo Is PRIBIO correct/ */
2628 ret = msleep(sm, &snd_pcm_syncgroups_mtx,
2629 PRIBIO | PCATCH, "pcmsg", timo);
2630 if (ret == EINTR || ret == ERESTART)
2631 break;
2632
2633 needlocks = 1;
2634 ret = 0; /* Assumes ret == EAGAIN... */
2635 }
2636 }
2637 } while (needlocks && ret == 0);
2638
2639 /* Proceed only if no errors encountered. */
2640 if (ret == 0) {
2641 /* Launch channels */
2642 while((sm = SLIST_FIRST(&sg->members)) != NULL) {
2643 SLIST_REMOVE_HEAD(&sg->members, link);
2644
2645 c = sm->ch;
2646 c->sm = NULL;
2647 chn_start(c, 1);
2648 c->flags &= ~CHN_F_NOTRIGGER;
2649 CHN_UNLOCK(c);
2650
2651 free(sm, M_DEVBUF);
2652 }
2653
2654 SLIST_REMOVE(&snd_pcm_syncgroups, sg, pcmchan_syncgroup, link);
2655 free(sg, M_DEVBUF);
2656 }
2657
2658 PCM_SG_UNLOCK();
2659
2660 /*
2661 * Free_unr() may sleep, so be sure to give up the syncgroup lock
2662 * first.
2663 */
2664 if (ret == 0)
2665 free_unr(pcmsg_unrhdr, sg_id);
2666
2667 return (ret);
2668 }
2669
2670 /**
2671 * @brief Handler for SNDCTL_DSP_POLICY
2672 *
2673 * The SNDCTL_DSP_POLICY ioctl is a simpler interface to control fragment
2674 * size and count like with SNDCTL_DSP_SETFRAGMENT. Instead of the user
2675 * specifying those two parameters, s/he simply selects a number from 0..10
2676 * which corresponds to a buffer size. Smaller numbers request smaller
2677 * buffers with lower latencies (at greater overhead from more frequent
2678 * interrupts), while greater numbers behave in the opposite manner.
2679 *
2680 * The 4Front spec states that a value of 5 should be the default. However,
2681 * this implementation deviates slightly by using a linear scale without
2682 * consulting drivers. I.e., even though drivers may have different default
2683 * buffer sizes, a policy argument of 5 will have the same result across
2684 * all drivers.
2685 *
2686 * See http://manuals.opensound.com/developer/SNDCTL_DSP_POLICY.html for
2687 * more information.
2688 *
2689 * @todo When SNDCTL_DSP_COOKEDMODE is supported, it'll be necessary to
2690 * work with hardware drivers directly.
2691 *
2692 * @note PCM channel arguments must not be locked by caller.
2693 *
2694 * @param wrch Pointer to opened playback channel (optional; may be NULL)
2695 * @param rdch " recording channel (optional; may be NULL)
2696 * @param policy Integer from [0:10]
2697 *
2698 * @retval 0 constant (for now)
2699 */
2700 static int
2701 dsp_oss_policy(struct pcm_channel *wrch, struct pcm_channel *rdch, int policy)
2702 {
2703 int ret;
2704
2705 if (policy < CHN_POLICY_MIN || policy > CHN_POLICY_MAX)
2706 return (EIO);
2707
2708 /* Default: success */
2709 ret = 0;
2710
2711 if (rdch) {
2712 CHN_LOCK(rdch);
2713 ret = chn_setlatency(rdch, policy);
2714 CHN_UNLOCK(rdch);
2715 }
2716
2717 if (wrch && ret == 0) {
2718 CHN_LOCK(wrch);
2719 ret = chn_setlatency(wrch, policy);
2720 CHN_UNLOCK(wrch);
2721 }
2722
2723 if (ret)
2724 ret = EIO;
2725
2726 return (ret);
2727 }
2728
2729 #ifdef OSSV4_EXPERIMENT
2730 /**
2731 * @brief Enable or disable "cooked" mode
2732 *
2733 * This is a handler for @c SNDCTL_DSP_COOKEDMODE. When in cooked mode, which
2734 * is the default, the sound system handles rate and format conversions
2735 * automatically (ex: user writing 11025Hz/8 bit/unsigned but card only
2736 * operates with 44100Hz/16bit/signed samples).
2737 *
2738 * Disabling cooked mode is intended for applications wanting to mmap()
2739 * a sound card's buffer space directly, bypassing the FreeBSD 2-stage
2740 * feeder architecture, presumably to gain as much control over audio
2741 * hardware as possible.
2742 *
2743 * See @c http://manuals.opensound.com/developer/SNDCTL_DSP_COOKEDMODE.html
2744 * for more details.
2745 *
2746 * @note Currently, this function is just a stub that always returns EINVAL.
2747 *
2748 * @todo Figure out how to and actually implement this.
2749 *
2750 * @param wrch playback channel (optional; may be NULL)
2751 * @param rdch recording channel (optional; may be NULL)
2752 * @param enabled 0 = raw mode, 1 = cooked mode
2753 *
2754 * @retval EINVAL Operation not yet supported.
2755 */
2756 static int
2757 dsp_oss_cookedmode(struct pcm_channel *wrch, struct pcm_channel *rdch, int enabled)
2758 {
2759 return (EINVAL);
2760 }
2761
2762 /**
2763 * @brief Retrieve channel interleaving order
2764 *
2765 * This is the handler for @c SNDCTL_DSP_GET_CHNORDER.
2766 *
2767 * See @c http://manuals.opensound.com/developer/SNDCTL_DSP_GET_CHNORDER.html
2768 * for more details.
2769 *
2770 * @note As the ioctl definition is still under construction, FreeBSD
2771 * does not currently support SNDCTL_DSP_GET_CHNORDER.
2772 *
2773 * @param wrch playback channel (optional; may be NULL)
2774 * @param rdch recording channel (optional; may be NULL)
2775 * @param map channel map (result will be stored there)
2776 *
2777 * @retval EINVAL Operation not yet supported.
2778 */
2779 static int
2780 dsp_oss_getchnorder(struct pcm_channel *wrch, struct pcm_channel *rdch, unsigned long long *map)
2781 {
2782 return (EINVAL);
2783 }
2784
2785 /**
2786 * @brief Specify channel interleaving order
2787 *
2788 * This is the handler for @c SNDCTL_DSP_SET_CHNORDER.
2789 *
2790 * @note As the ioctl definition is still under construction, FreeBSD
2791 * does not currently support @c SNDCTL_DSP_SET_CHNORDER.
2792 *
2793 * @param wrch playback channel (optional; may be NULL)
2794 * @param rdch recording channel (optional; may be NULL)
2795 * @param map channel map
2796 *
2797 * @retval EINVAL Operation not yet supported.
2798 */
2799 static int
2800 dsp_oss_setchnorder(struct pcm_channel *wrch, struct pcm_channel *rdch, unsigned long long *map)
2801 {
2802 return (EINVAL);
2803 }
2804
2805 /**
2806 * @brief Retrieve an audio device's label
2807 *
2808 * This is a handler for the @c SNDCTL_GETLABEL ioctl.
2809 *
2810 * See @c http://manuals.opensound.com/developer/SNDCTL_GETLABEL.html
2811 * for more details.
2812 *
2813 * From Hannu@4Front: "For example ossxmix (just like some HW mixer
2814 * consoles) can show variable "labels" for certain controls. By default
2815 * the application name (say quake) is shown as the label but
2816 * applications may change the labels themselves."
2817 *
2818 * @note As the ioctl definition is still under construction, FreeBSD
2819 * does not currently support @c SNDCTL_GETLABEL.
2820 *
2821 * @param wrch playback channel (optional; may be NULL)
2822 * @param rdch recording channel (optional; may be NULL)
2823 * @param label label gets copied here
2824 *
2825 * @retval EINVAL Operation not yet supported.
2826 */
2827 static int
2828 dsp_oss_getlabel(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_label_t *label)
2829 {
2830 return (EINVAL);
2831 }
2832
2833 /**
2834 * @brief Specify an audio device's label
2835 *
2836 * This is a handler for the @c SNDCTL_SETLABEL ioctl. Please see the
2837 * comments for @c dsp_oss_getlabel immediately above.
2838 *
2839 * See @c http://manuals.opensound.com/developer/SNDCTL_GETLABEL.html
2840 * for more details.
2841 *
2842 * @note As the ioctl definition is still under construction, FreeBSD
2843 * does not currently support SNDCTL_SETLABEL.
2844 *
2845 * @param wrch playback channel (optional; may be NULL)
2846 * @param rdch recording channel (optional; may be NULL)
2847 * @param label label gets copied from here
2848 *
2849 * @retval EINVAL Operation not yet supported.
2850 */
2851 static int
2852 dsp_oss_setlabel(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_label_t *label)
2853 {
2854 return (EINVAL);
2855 }
2856
2857 /**
2858 * @brief Retrieve name of currently played song
2859 *
2860 * This is a handler for the @c SNDCTL_GETSONG ioctl. Audio players could
2861 * tell the system the name of the currently playing song, which would be
2862 * visible in @c /dev/sndstat.
2863 *
2864 * See @c http://manuals.opensound.com/developer/SNDCTL_GETSONG.html
2865 * for more details.
2866 *
2867 * @note As the ioctl definition is still under construction, FreeBSD
2868 * does not currently support SNDCTL_GETSONG.
2869 *
2870 * @param wrch playback channel (optional; may be NULL)
2871 * @param rdch recording channel (optional; may be NULL)
2872 * @param song song name gets copied here
2873 *
2874 * @retval EINVAL Operation not yet supported.
2875 */
2876 static int
2877 dsp_oss_getsong(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *song)
2878 {
2879 return (EINVAL);
2880 }
2881
2882 /**
2883 * @brief Retrieve name of currently played song
2884 *
2885 * This is a handler for the @c SNDCTL_SETSONG ioctl. Audio players could
2886 * tell the system the name of the currently playing song, which would be
2887 * visible in @c /dev/sndstat.
2888 *
2889 * See @c http://manuals.opensound.com/developer/SNDCTL_SETSONG.html
2890 * for more details.
2891 *
2892 * @note As the ioctl definition is still under construction, FreeBSD
2893 * does not currently support SNDCTL_SETSONG.
2894 *
2895 * @param wrch playback channel (optional; may be NULL)
2896 * @param rdch recording channel (optional; may be NULL)
2897 * @param song song name gets copied from here
2898 *
2899 * @retval EINVAL Operation not yet supported.
2900 */
2901 static int
2902 dsp_oss_setsong(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *song)
2903 {
2904 return (EINVAL);
2905 }
2906
2907 /**
2908 * @brief Rename a device
2909 *
2910 * This is a handler for the @c SNDCTL_SETNAME ioctl.
2911 *
2912 * See @c http://manuals.opensound.com/developer/SNDCTL_SETNAME.html for
2913 * more details.
2914 *
2915 * From Hannu@4Front: "This call is used to change the device name
2916 * reported in /dev/sndstat and ossinfo. So instead of using some generic
2917 * 'OSS loopback audio (MIDI) driver' the device may be given a meaningfull
2918 * name depending on the current context (for example 'OSS virtual wave table
2919 * synth' or 'VoIP link to London')."
2920 *
2921 * @note As the ioctl definition is still under construction, FreeBSD
2922 * does not currently support SNDCTL_SETNAME.
2923 *
2924 * @param wrch playback channel (optional; may be NULL)
2925 * @param rdch recording channel (optional; may be NULL)
2926 * @param name new device name gets copied from here
2927 *
2928 * @retval EINVAL Operation not yet supported.
2929 */
2930 static int
2931 dsp_oss_setname(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *name)
2932 {
2933 return (EINVAL);
2934 }
2935 #endif /* !OSSV4_EXPERIMENT */
Cache object: 13b080abefbcc1c00c19e924ebee2ae7
|