Merge branch 'vendor/OPENSSH'
[dragonfly.git] / 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  * $FreeBSD: src/sys/dev/sound/pcm/dsp.c,v 1.80.2.6 2006/04/04 17:43:48 ariff Exp $
27  */
28
29 #include <sys/param.h>
30 #include <sys/queue.h>
31 #include <sys/event.h>
32
33 #include <dev/sound/pcm/dsp.h>
34 #include <dev/sound/pcm/sound.h>
35
36
37 #define OLDPCM_IOCTL
38
39 static d_open_t dsp_open;
40 static d_close_t dsp_close;
41 static d_read_t dsp_read;
42 static d_write_t dsp_write;
43 static d_ioctl_t dsp_ioctl;
44 static d_kqfilter_t dsp_kqfilter;
45 static d_mmap_t dsp_mmap;
46
47 static void dsp_filter_detach(struct knote *);
48 static int dsp_filter_read(struct knote *, long);
49 static int dsp_filter_write(struct knote *, long);
50
51 struct dev_ops dsp_ops = {
52         { "dsp", 0, 0},
53         /*.d_flags =    D_NEEDGIANT,*/
54         .d_open =       dsp_open,
55         .d_close =      dsp_close,
56         .d_read =       dsp_read,
57         .d_write =      dsp_write,
58         .d_ioctl =      dsp_ioctl,
59         .d_kqfilter =   dsp_kqfilter,
60         .d_mmap =       dsp_mmap,
61 };
62
63 struct snddev_info *
64 dsp_get_info(struct cdev *dev)
65 {
66         struct snddev_info *d;
67         int unit;
68
69         unit = PCMUNIT(dev);
70         if (unit >= devclass_get_maxunit(pcm_devclass))
71                 return NULL;
72         d = devclass_get_softc(pcm_devclass, unit);
73
74         return d;
75 }
76
77 static u_int32_t
78 dsp_get_flags(struct cdev *dev)
79 {
80         device_t bdev;
81         int unit;
82
83         unit = PCMUNIT(dev);
84         if (unit >= devclass_get_maxunit(pcm_devclass))
85                 return 0xffffffff;
86         bdev = devclass_get_device(pcm_devclass, unit);
87
88         return pcm_getflags(bdev);
89 }
90
91 static void
92 dsp_set_flags(struct cdev *dev, u_int32_t flags)
93 {
94         device_t bdev;
95         int unit;
96
97         unit = PCMUNIT(dev);
98         if (unit >= devclass_get_maxunit(pcm_devclass))
99                 return;
100         bdev = devclass_get_device(pcm_devclass, unit);
101
102         pcm_setflags(bdev, flags);
103 }
104
105 /*
106  * return the channels associated with an open device instance.
107  * set the priority if the device is simplex and one direction (only) is
108  * specified.
109  * lock channels specified.
110  */
111 static int
112 getchns(struct cdev *dev, struct pcm_channel **rdch, struct pcm_channel **wrch, u_int32_t prio)
113 {
114         struct snddev_info *d;
115         u_int32_t flags;
116
117         flags = dsp_get_flags(dev);
118         d = dsp_get_info(dev);
119         pcm_inprog(d, 1);
120         pcm_lock(d);
121         KASSERT((flags & SD_F_PRIO_SET) != SD_F_PRIO_SET, \
122                 ("getchns: read and write both prioritised"));
123
124         if ((flags & SD_F_PRIO_SET) == 0 && (prio != (SD_F_PRIO_RD | SD_F_PRIO_WR))) {
125                 flags |= prio & (SD_F_PRIO_RD | SD_F_PRIO_WR);
126                 dsp_set_flags(dev, flags);
127         }
128
129         *rdch = dev->si_drv1;
130         *wrch = dev->si_drv2;
131         if ((flags & SD_F_SIMPLEX) && (flags & SD_F_PRIO_SET)) {
132                 if (prio) {
133                         if (*rdch && flags & SD_F_PRIO_WR) {
134                                 dev->si_drv1 = NULL;
135                                 *rdch = pcm_getfakechan(d);
136                         } else if (*wrch && flags & SD_F_PRIO_RD) {
137                                 dev->si_drv2 = NULL;
138                                 *wrch = pcm_getfakechan(d);
139                         }
140                 }
141
142                 pcm_getfakechan(d)->flags |= CHN_F_BUSY;
143         }
144         pcm_unlock(d);
145
146         if (*rdch && *rdch != pcm_getfakechan(d) && (prio & SD_F_PRIO_RD))
147                 CHN_LOCK(*rdch);
148         if (*wrch && *wrch != pcm_getfakechan(d) && (prio & SD_F_PRIO_WR))
149                 CHN_LOCK(*wrch);
150
151         return 0;
152 }
153
154 /* unlock specified channels */
155 static void
156 relchns(struct cdev *dev, struct pcm_channel *rdch, struct pcm_channel *wrch, u_int32_t prio)
157 {
158         struct snddev_info *d;
159
160         d = dsp_get_info(dev);
161         if (wrch && wrch != pcm_getfakechan(d) && (prio & SD_F_PRIO_WR))
162                 CHN_UNLOCK(wrch);
163         if (rdch && rdch != pcm_getfakechan(d) && (prio & SD_F_PRIO_RD))
164                 CHN_UNLOCK(rdch);
165         pcm_inprog(d, -1);
166 }
167
168 static int
169 dsp_open(struct dev_open_args *ap)
170 {
171         struct cdev *i_dev = ap->a_head.a_dev;
172         struct thread *td = curthread;
173         int flags = ap->a_oflags;
174         struct pcm_channel *rdch, *wrch;
175         struct snddev_info *d = NULL;
176         struct snddev_channel *sce = NULL;
177         u_int32_t fmt = AFMT_U8;
178         int error;
179         int chnum;
180
181         if (i_dev == NULL) {
182                 error = ENODEV;
183                 goto out;
184         }
185
186         d = dsp_get_info(i_dev);
187         SLIST_FOREACH(sce, &d->channels, link) {
188                 if (sce->dsp_dev == i_dev)
189                         break;
190         }
191
192         if (sce == NULL) {
193                 error = ENODEV;
194                 goto out;
195         }
196
197         if (td == NULL) {
198                 error = ENODEV;
199                 goto out;
200         }
201
202         if ((flags & (FREAD | FWRITE)) == 0) {
203                 error = EINVAL;
204                 goto out;
205         }
206
207         chnum = PCMCHAN(i_dev);
208
209         /* lock snddev so nobody else can monkey with it */
210         pcm_lock(d);
211
212         rdch = i_dev->si_drv1;
213         wrch = i_dev->si_drv2;
214
215         if (rdch || wrch || ((dsp_get_flags(i_dev) & SD_F_SIMPLEX) &&
216                     (flags & (FREAD | FWRITE)) == (FREAD | FWRITE))) {
217                 /* simplex or not, better safe than sorry. */
218                 pcm_unlock(d);
219                 error = EBUSY;
220                 goto out;
221         }
222
223         /*
224          * if we get here, the open request is valid- either:
225          *   * we were previously not open
226          *   * we were open for play xor record and the opener wants
227          *     the non-open direction
228          */
229         if (flags & FREAD) {
230                 /* open for read */
231                 pcm_unlock(d);
232                 error = pcm_chnalloc(d, &rdch, PCMDIR_REC, td->td_proc->p_pid, chnum);
233                 if (error != 0 && error != EBUSY && chnum != -1 && (flags & FWRITE))
234                         error = pcm_chnalloc(d, &rdch, PCMDIR_REC, td->td_proc->p_pid, -1);
235
236                 if (error == 0 && (chn_reset(rdch, fmt) ||
237                                 (fmt && chn_setspeed(rdch, DSP_DEFAULT_SPEED))))
238                         error = ENODEV;
239
240                 if (error != 0) {
241                         if (rdch)
242                                 pcm_chnrelease(rdch);
243                         goto out;
244                 }
245
246                 pcm_chnref(rdch, 1);
247                 CHN_UNLOCK(rdch);
248                 pcm_lock(d);
249         }
250
251         if (flags & FWRITE) {
252             /* open for write */
253             pcm_unlock(d);
254             error = pcm_chnalloc(d, &wrch, PCMDIR_PLAY, td->td_proc->p_pid, chnum);
255             if (error != 0 && error != EBUSY && chnum != -1 && (flags & FREAD))
256                 error = pcm_chnalloc(d, &wrch, PCMDIR_PLAY, td->td_proc->p_pid, -1);
257
258             if (error == 0 && (chn_reset(wrch, fmt) ||
259                         (fmt && chn_setspeed(wrch, DSP_DEFAULT_SPEED))))
260                 error = ENODEV;
261
262             if (error != 0) {
263                 if (wrch)
264                     pcm_chnrelease(wrch);
265                 if (rdch) {
266                     /*
267                      * Lock, deref and release previously created record channel
268                      */
269                     CHN_LOCK(rdch);
270                     pcm_chnref(rdch, -1);
271                     pcm_chnrelease(rdch);
272                 }
273
274                 goto out;
275             }
276
277             pcm_chnref(wrch, 1);
278             CHN_UNLOCK(wrch);
279             pcm_lock(d);
280         }
281
282         i_dev->si_drv1 = rdch;
283         i_dev->si_drv2 = wrch;
284
285         sce->open++;
286
287         pcm_unlock(d);
288         return 0;
289
290 out:
291         if (i_dev != NULL && sce != NULL && sce->open == 0) {
292                 pcm_lock(d);
293                 destroy_dev(i_dev);
294                 sce->dsp_dev = NULL;
295                 pcm_unlock(d);
296         }
297         return (error);
298 }
299
300 static int
301 dsp_close(struct dev_close_args *ap)
302 {
303         struct cdev *i_dev = ap->a_head.a_dev;
304         struct pcm_channel *rdch, *wrch;
305         struct snddev_info *d;
306         struct snddev_channel *sce = NULL;
307         int refs;
308
309         d = dsp_get_info(i_dev);
310         pcm_lock(d);
311         rdch = i_dev->si_drv1;
312         wrch = i_dev->si_drv2;
313         i_dev->si_drv1 = NULL;
314         i_dev->si_drv2 = NULL;
315
316         SLIST_FOREACH(sce, &d->channels, link) {
317                 if (sce->dsp_dev == i_dev)
318                         break;
319         }
320         sce->dsp_dev = NULL;
321         destroy_dev(i_dev);
322
323         pcm_unlock(d);
324
325         if (rdch || wrch) {
326                 refs = 0;
327                 if (rdch) {
328                         CHN_LOCK(rdch);
329                         refs += pcm_chnref(rdch, -1);
330                         chn_abort(rdch); /* won't sleep */
331                         rdch->flags &= ~(CHN_F_RUNNING | CHN_F_MAPPED | CHN_F_DEAD);
332                         chn_reset(rdch, 0);
333                         pcm_chnrelease(rdch);
334                 }
335                 if (wrch) {
336                         CHN_LOCK(wrch);
337                         refs += pcm_chnref(wrch, -1);
338                         /*
339                          * XXX: Maybe the right behaviour is to abort on non_block.
340                          * It seems that mplayer flushes the audio queue by quickly
341                          * closing and re-opening.  In FBSD, there's a long pause
342                          * while the audio queue flushes that I presume isn't there in
343                          * linux.
344                          */
345                         chn_flush(wrch); /* may sleep */
346                         wrch->flags &= ~(CHN_F_RUNNING | CHN_F_MAPPED | CHN_F_DEAD);
347                         chn_reset(wrch, 0);
348                         pcm_chnrelease(wrch);
349                 }
350
351                 pcm_lock(d);
352                 /*
353                  * If there are no more references, release the channels.
354                  */
355                 if (refs == 0) {
356                         if (pcm_getfakechan(d))
357                                 pcm_getfakechan(d)->flags = 0;
358                         /* What is this?!? */
359                         dsp_set_flags(i_dev, dsp_get_flags(i_dev) & ~SD_F_TRANSIENT);
360                 }
361                 pcm_unlock(d);
362         }
363         return 0;
364 }
365
366 static int
367 dsp_read(struct dev_read_args *ap)
368 {
369         struct cdev *i_dev = ap->a_head.a_dev;
370         struct uio *buf = ap->a_uio;
371         int flag = ap->a_ioflag;
372         struct pcm_channel *rdch, *wrch;
373         int ret;
374
375         getchns(i_dev, &rdch, &wrch, SD_F_PRIO_RD);
376
377         KASSERT(rdch, ("dsp_read: nonexistant channel"));
378         KASSERT(rdch->flags & CHN_F_BUSY, ("dsp_read: nonbusy channel"));
379
380         if (rdch->flags & (CHN_F_MAPPED | CHN_F_DEAD)) {
381                 relchns(i_dev, rdch, wrch, SD_F_PRIO_RD);
382                 return EINVAL;
383         }
384         if (!(rdch->flags & CHN_F_RUNNING))
385                 rdch->flags |= CHN_F_RUNNING;
386         ret = chn_read(rdch, buf, flag);
387         relchns(i_dev, rdch, wrch, SD_F_PRIO_RD);
388
389         return ret;
390 }
391
392 static int
393 dsp_write(struct dev_write_args *ap)
394 {
395         struct cdev *i_dev = ap->a_head.a_dev;
396         struct uio *buf = ap->a_uio;
397         int flag = ap->a_ioflag;
398         struct pcm_channel *rdch, *wrch;
399         int ret;
400
401         getchns(i_dev, &rdch, &wrch, SD_F_PRIO_WR);
402
403         KASSERT(wrch, ("dsp_write: nonexistant channel"));
404         KASSERT(wrch->flags & CHN_F_BUSY, ("dsp_write: nonbusy channel"));
405
406         if (wrch->flags & (CHN_F_MAPPED | CHN_F_DEAD)) {
407                 relchns(i_dev, rdch, wrch, SD_F_PRIO_WR);
408                 return EINVAL;
409         }
410         if (!(wrch->flags & CHN_F_RUNNING))
411                 wrch->flags |= CHN_F_RUNNING;
412         ret = chn_write(wrch, buf, flag);
413         relchns(i_dev, rdch, wrch, SD_F_PRIO_WR);
414
415         return ret;
416 }
417
418 static int
419 dsp_ioctl(struct dev_ioctl_args *ap)
420 {
421         struct cdev *i_dev = ap->a_head.a_dev;
422         u_long cmd = ap->a_cmd;
423         caddr_t arg = ap->a_data;
424         struct pcm_channel *chn, *rdch, *wrch;
425         struct snddev_info *d;
426         int kill;
427         int ret = 0, *arg_i = (int *)arg, tmp;
428
429         d = dsp_get_info(i_dev);
430         getchns(i_dev, &rdch, &wrch, 0);
431
432         kill = 0;
433         if (wrch && (wrch->flags & CHN_F_DEAD))
434                 kill |= 1;
435         if (rdch && (rdch->flags & CHN_F_DEAD))
436                 kill |= 2;
437         if (kill == 3) {
438                 relchns(i_dev, rdch, wrch, 0);
439                 return EINVAL;
440         }
441         if (kill & 1)
442                 wrch = NULL;
443         if (kill & 2)
444                 rdch = NULL;
445
446         /*
447          * 4Front OSS specifies that dsp devices allow mixer controls to
448          * control PCM == their volume.
449          */
450         if (IOCGROUP(cmd) == 'M') {
451                 /*
452                  * For now only set the channel volume for vchans, pass
453                  * all others to the mixer.
454                  */
455                 if (wrch != NULL && wrch->flags & CHN_F_VIRTUAL &&
456                     (cmd & 0xff) == SOUND_MIXER_PCM) {
457                         if ((cmd & MIXER_WRITE(0)) == MIXER_WRITE(0)) {
458                                 int vol_raw = *(int *)arg;
459                                 int vol_left, vol_right;
460
461                                 vol_left = min(vol_raw & 0x00ff, 100);
462                                 vol_right = min((vol_raw & 0xff00) >> 8, 100);
463                                 ret = chn_setvolume(wrch, vol_left, vol_right);
464                         } else {
465                                 *(int *)arg = wrch->volume;
466                         }
467                 } else {
468                         ap->a_head.a_dev = d->mixer_dev;
469                         ret = mixer_ioctl(ap);
470                 }
471
472                 relchns(i_dev, rdch, wrch, 0);
473                 return ret;
474         }
475         
476         switch(cmd) {
477 #ifdef OLDPCM_IOCTL
478         /*
479          * we start with the new ioctl interface.
480          */
481         case AIONWRITE: /* how many bytes can write ? */
482                 if (wrch) {
483                         CHN_LOCK(wrch);
484 /*
485                 if (wrch && wrch->bufhard.dl)
486                         while (chn_wrfeed(wrch) == 0);
487 */
488                         *arg_i = sndbuf_getfree(wrch->bufsoft);
489                         CHN_UNLOCK(wrch);
490                 } else {
491                         *arg_i = 0;
492                         ret = EINVAL;
493                 }
494                 break;
495
496         case AIOSSIZE:     /* set the current blocksize */
497                 {
498                         struct snd_size *p = (struct snd_size *)arg;
499
500                         p->play_size = 0;
501                         p->rec_size = 0;
502                         if (wrch) {
503                                 CHN_LOCK(wrch);
504                                 chn_setblocksize(wrch, 2, p->play_size);
505                                 p->play_size = sndbuf_getblksz(wrch->bufsoft);
506                                 CHN_UNLOCK(wrch);
507                         }
508                         if (rdch) {
509                                 CHN_LOCK(rdch);
510                                 chn_setblocksize(rdch, 2, p->rec_size);
511                                 p->rec_size = sndbuf_getblksz(rdch->bufsoft);
512                                 CHN_UNLOCK(rdch);
513                         }
514                 }
515                 break;
516         case AIOGSIZE:  /* get the current blocksize */
517                 {
518                         struct snd_size *p = (struct snd_size *)arg;
519
520                         if (wrch) {
521                                 CHN_LOCK(wrch);
522                                 p->play_size = sndbuf_getblksz(wrch->bufsoft);
523                                 CHN_UNLOCK(wrch);
524                         }
525                         if (rdch) {
526                                 CHN_LOCK(rdch);
527                                 p->rec_size = sndbuf_getblksz(rdch->bufsoft);
528                                 CHN_UNLOCK(rdch);
529                         }
530                 }
531                 break;
532
533         case AIOSFMT:
534         case AIOGFMT:
535                 {
536                         snd_chan_param *p = (snd_chan_param *)arg;
537
538                         if (cmd == AIOSFMT &&
539                             ((p->play_format != 0 && p->play_rate == 0) ||
540                             (p->rec_format != 0 && p->rec_rate == 0))) {
541                                 ret = EINVAL;
542                                 break;
543                         }
544                         if (wrch) {
545                                 CHN_LOCK(wrch);
546                                 if (cmd == AIOSFMT && p->play_format != 0) {
547                                         chn_setformat(wrch, p->play_format);
548                                         chn_setspeed(wrch, p->play_rate);
549                                 }
550                                 p->play_rate = wrch->speed;
551                                 p->play_format = wrch->format;
552                                 CHN_UNLOCK(wrch);
553                         } else {
554                                 p->play_rate = 0;
555                                 p->play_format = 0;
556                         }
557                         if (rdch) {
558                                 CHN_LOCK(rdch);
559                                 if (cmd == AIOSFMT && p->rec_format != 0) {
560                                         chn_setformat(rdch, p->rec_format);
561                                         chn_setspeed(rdch, p->rec_rate);
562                                 }
563                                 p->rec_rate = rdch->speed;
564                                 p->rec_format = rdch->format;
565                                 CHN_UNLOCK(rdch);
566                         } else {
567                                 p->rec_rate = 0;
568                                 p->rec_format = 0;
569                         }
570                 }
571                 break;
572
573         case AIOGCAP:     /* get capabilities */
574                 {
575                         snd_capabilities *p = (snd_capabilities *)arg;
576                         struct pcmchan_caps *pcaps = NULL, *rcaps = NULL;
577                         struct cdev *pdev;
578
579                         if (rdch) {
580                                 CHN_LOCK(rdch);
581                                 rcaps = chn_getcaps(rdch);
582                         }
583                         if (wrch) {
584                                 CHN_LOCK(wrch);
585                                 pcaps = chn_getcaps(wrch);
586                         }
587                         p->rate_min = max(rcaps? rcaps->minspeed : 0,
588                                           pcaps? pcaps->minspeed : 0);
589                         p->rate_max = min(rcaps? rcaps->maxspeed : 1000000,
590                                           pcaps? pcaps->maxspeed : 1000000);
591                         p->bufsize = min(rdch? sndbuf_getsize(rdch->bufsoft) : 1000000,
592                                          wrch? sndbuf_getsize(wrch->bufsoft) : 1000000);
593                         /* XXX bad on sb16 */
594                         p->formats = (rdch? chn_getformats(rdch) : 0xffffffff) &
595                                      (wrch? chn_getformats(wrch) : 0xffffffff);
596                         if (rdch && wrch)
597                                 p->formats |= (dsp_get_flags(i_dev) & SD_F_SIMPLEX)? 0 : AFMT_FULLDUPLEX;
598                         pdev = d->mixer_dev;
599                         p->mixers = 1; /* default: one mixer */
600                         p->inputs = pdev->si_drv1? mix_getdevs(pdev->si_drv1) : 0;
601                         p->left = p->right = 100;
602                         if (rdch)
603                                 CHN_UNLOCK(rdch);
604                         if (wrch)
605                                 CHN_UNLOCK(wrch);
606                 }
607                 break;
608
609         case AIOSTOP:
610                 if (*arg_i == AIOSYNC_PLAY && wrch) {
611                         CHN_LOCK(wrch);
612                         *arg_i = chn_abort(wrch);
613                         CHN_UNLOCK(wrch);
614                 } else if (*arg_i == AIOSYNC_CAPTURE && rdch) {
615                         CHN_LOCK(rdch);
616                         *arg_i = chn_abort(rdch);
617                         CHN_UNLOCK(rdch);
618                 } else {
619                         kprintf("AIOSTOP: bad channel 0x%x\n", *arg_i);
620                         *arg_i = 0;
621                 }
622                 break;
623
624         case AIOSYNC:
625                 kprintf("AIOSYNC chan 0x%03lx pos %lu unimplemented\n",
626                         ((snd_sync_parm *)arg)->chan, ((snd_sync_parm *)arg)->pos);
627                 break;
628 #endif
629         /*
630          * here follow the standard ioctls (filio.h etc.)
631          */
632         case FIONREAD: /* get # bytes to read */
633                 if (rdch) {
634                         CHN_LOCK(rdch);
635 /*                      if (rdch && rdch->bufhard.dl)
636                                 while (chn_rdfeed(rdch) == 0);
637 */
638                         *arg_i = sndbuf_getready(rdch->bufsoft);
639                         CHN_UNLOCK(rdch);
640                 } else {
641                         *arg_i = 0;
642                         ret = EINVAL;
643                 }
644                 break;
645
646         case FIOASYNC: /*set/clear async i/o */
647                 DEB( kprintf("FIOASYNC\n") ; )
648                 break;
649
650         case SNDCTL_DSP_NONBLOCK:
651         case FIONBIO: /* set/clear non-blocking i/o */
652                 if (rdch) {
653                         CHN_LOCK(rdch);
654                         if (*arg_i)
655                                 rdch->flags |= CHN_F_NBIO;
656                         else
657                                 rdch->flags &= ~CHN_F_NBIO;
658                         CHN_UNLOCK(rdch);
659                 }
660                 if (wrch) {
661                         CHN_LOCK(wrch);
662                         if (*arg_i)
663                                 wrch->flags |= CHN_F_NBIO;
664                         else
665                                 wrch->flags &= ~CHN_F_NBIO;
666                         CHN_UNLOCK(wrch);
667                 }
668                 break;
669
670         /*
671          * Finally, here is the linux-compatible ioctl interface
672          */
673 #define THE_REAL_SNDCTL_DSP_GETBLKSIZE _IOWR('P', 4, int)
674         case THE_REAL_SNDCTL_DSP_GETBLKSIZE:
675         case SNDCTL_DSP_GETBLKSIZE:
676                 chn = wrch ? wrch : rdch;
677                 if (chn) {
678                         CHN_LOCK(chn);
679                         *arg_i = sndbuf_getblksz(chn->bufsoft);
680                         CHN_UNLOCK(chn);
681                 } else {
682                         *arg_i = 0;
683                         ret = EINVAL;
684                 }
685                 break ;
686
687         case SNDCTL_DSP_SETBLKSIZE:
688                 RANGE(*arg_i, 16, 65536);
689                 if (wrch) {
690                         CHN_LOCK(wrch);
691                         chn_setblocksize(wrch, 2, *arg_i);
692                         CHN_UNLOCK(wrch);
693                 }
694                 if (rdch) {
695                         CHN_LOCK(rdch);
696                         chn_setblocksize(rdch, 2, *arg_i);
697                         CHN_UNLOCK(rdch);
698                 }
699                 break;
700
701         case SNDCTL_DSP_RESET:
702                 DEB(kprintf("dsp reset\n"));
703                 if (wrch) {
704                         CHN_LOCK(wrch);
705                         chn_abort(wrch);
706                         chn_resetbuf(wrch);
707                         CHN_UNLOCK(wrch);
708                 }
709                 if (rdch) {
710                         CHN_LOCK(rdch);
711                         chn_abort(rdch);
712                         chn_resetbuf(rdch);
713                         CHN_UNLOCK(rdch);
714                 }
715                 break;
716
717         case SNDCTL_DSP_SYNC:
718                 DEB(kprintf("dsp sync\n"));
719                 /* chn_sync may sleep */
720                 if (wrch) {
721                         CHN_LOCK(wrch);
722                         chn_sync(wrch, sndbuf_getsize(wrch->bufsoft) - 4);
723                         CHN_UNLOCK(wrch);
724                 }
725                 break;
726
727         case SNDCTL_DSP_SPEED:
728                 /* chn_setspeed may sleep */
729                 tmp = 0;
730                 if (wrch) {
731                         CHN_LOCK(wrch);
732                         ret = chn_setspeed(wrch, *arg_i);
733                         tmp = wrch->speed;
734                         CHN_UNLOCK(wrch);
735                 }
736                 if (rdch && ret == 0) {
737                         CHN_LOCK(rdch);
738                         ret = chn_setspeed(rdch, *arg_i);
739                         if (tmp == 0)
740                                 tmp = rdch->speed;
741                         CHN_UNLOCK(rdch);
742                 }
743                 *arg_i = tmp;
744                 break;
745
746         case SOUND_PCM_READ_RATE:
747                 chn = wrch ? wrch : rdch;
748                 if (chn) {
749                         CHN_LOCK(chn);
750                         *arg_i = chn->speed;
751                         CHN_UNLOCK(chn);
752                 } else {
753                         *arg_i = 0;
754                         ret = EINVAL;
755                 }
756                 break;
757
758         case SNDCTL_DSP_STEREO:
759                 tmp = -1;
760                 *arg_i = (*arg_i)? AFMT_STEREO : 0;
761                 if (wrch) {
762                         CHN_LOCK(wrch);
763                         ret = chn_setformat(wrch, (wrch->format & ~AFMT_STEREO) | *arg_i);
764                         tmp = (wrch->format & AFMT_STEREO)? 1 : 0;
765                         CHN_UNLOCK(wrch);
766                 }
767                 if (rdch && ret == 0) {
768                         CHN_LOCK(rdch);
769                         ret = chn_setformat(rdch, (rdch->format & ~AFMT_STEREO) | *arg_i);
770                         if (tmp == -1)
771                                 tmp = (rdch->format & AFMT_STEREO)? 1 : 0;
772                         CHN_UNLOCK(rdch);
773                 }
774                 *arg_i = tmp;
775                 break;
776
777         case SOUND_PCM_WRITE_CHANNELS:
778 /*      case SNDCTL_DSP_CHANNELS: ( == SOUND_PCM_WRITE_CHANNELS) */
779                 if (*arg_i != 0) {
780                         tmp = 0;
781                         *arg_i = (*arg_i != 1)? AFMT_STEREO : 0;
782                         if (wrch) {
783                                 CHN_LOCK(wrch);
784                                 ret = chn_setformat(wrch, (wrch->format & ~AFMT_STEREO) | *arg_i);
785                                 tmp = (wrch->format & AFMT_STEREO)? 2 : 1;
786                                 CHN_UNLOCK(wrch);
787                         }
788                         if (rdch && ret == 0) {
789                                 CHN_LOCK(rdch);
790                                 ret = chn_setformat(rdch, (rdch->format & ~AFMT_STEREO) | *arg_i);
791                                 if (tmp == 0)
792                                         tmp = (rdch->format & AFMT_STEREO)? 2 : 1;
793                                 CHN_UNLOCK(rdch);
794                         }
795                         *arg_i = tmp;
796                 } else {
797                         chn = wrch ? wrch : rdch;
798                         CHN_LOCK(chn);
799                         *arg_i = (chn->format & AFMT_STEREO) ? 2 : 1;
800                         CHN_UNLOCK(chn);
801                 }
802                 break;
803
804         case SOUND_PCM_READ_CHANNELS:
805                 chn = wrch ? wrch : rdch;
806                 if (chn) {
807                         CHN_LOCK(chn);
808                         *arg_i = (chn->format & AFMT_STEREO) ? 2 : 1;
809                         CHN_UNLOCK(chn);
810                 } else {
811                         *arg_i = 0;
812                         ret = EINVAL;
813                 }
814                 break;
815
816         case SNDCTL_DSP_GETFMTS:        /* returns a mask of supported fmts */
817                 chn = wrch ? wrch : rdch;
818                 if (chn) {
819                         CHN_LOCK(chn);
820                         *arg_i = chn_getformats(chn);
821                         CHN_UNLOCK(chn);
822                 } else {
823                         *arg_i = 0;
824                         ret = EINVAL;
825                 }
826                 break ;
827
828         case SNDCTL_DSP_SETFMT: /* sets _one_ format */
829                 if ((*arg_i != AFMT_QUERY)) {
830                         tmp = 0;
831                         if (wrch) {
832                                 CHN_LOCK(wrch);
833                                 ret = chn_setformat(wrch, (*arg_i) | (wrch->format & AFMT_STEREO));
834                                 tmp = wrch->format & ~AFMT_STEREO;
835                                 CHN_UNLOCK(wrch);
836                         }
837                         if (rdch && ret == 0) {
838                                 CHN_LOCK(rdch);
839                                 ret = chn_setformat(rdch, (*arg_i) | (rdch->format & AFMT_STEREO));
840                                 if (tmp == 0)
841                                         tmp = rdch->format & ~AFMT_STEREO;
842                                 CHN_UNLOCK(rdch);
843                         }
844                         *arg_i = tmp;
845                 } else {
846                         chn = wrch ? wrch : rdch;
847                         CHN_LOCK(chn);
848                         *arg_i = chn->format & ~AFMT_STEREO;
849                         CHN_UNLOCK(chn);
850                 }
851                 break;
852
853         case SNDCTL_DSP_SETFRAGMENT:
854                 DEB(kprintf("SNDCTL_DSP_SETFRAGMENT 0x%08x\n", *(int *)arg));
855                 {
856                         u_int32_t fragln = (*arg_i) & 0x0000ffff;
857                         u_int32_t maxfrags = ((*arg_i) & 0xffff0000) >> 16;
858                         u_int32_t fragsz;
859                         u_int32_t r_maxfrags, r_fragsz;
860
861                         RANGE(fragln, 4, 16);
862                         fragsz = 1 << fragln;
863
864                         if (maxfrags == 0)
865                                 maxfrags = CHN_2NDBUFMAXSIZE / fragsz;
866                         if (maxfrags < 2)
867                                 maxfrags = 2;
868                         if (maxfrags * fragsz > CHN_2NDBUFMAXSIZE)
869                                 maxfrags = CHN_2NDBUFMAXSIZE / fragsz;
870
871                         DEB(kprintf("SNDCTL_DSP_SETFRAGMENT %d frags, %d sz\n", maxfrags, fragsz));
872                         if (rdch) {
873                                 CHN_LOCK(rdch);
874                                 ret = chn_setblocksize(rdch, maxfrags, fragsz);
875                                 r_maxfrags = sndbuf_getblkcnt(rdch->bufsoft);
876                                 r_fragsz = sndbuf_getblksz(rdch->bufsoft);
877                                 CHN_UNLOCK(rdch);
878                         } else {
879                                 r_maxfrags = maxfrags;
880                                 r_fragsz = fragsz;
881                         }
882                         if (wrch && ret == 0) {
883                                 CHN_LOCK(wrch);
884                                 ret = chn_setblocksize(wrch, maxfrags, fragsz);
885                                 maxfrags = sndbuf_getblkcnt(wrch->bufsoft);
886                                 fragsz = sndbuf_getblksz(wrch->bufsoft);
887                                 CHN_UNLOCK(wrch);
888                         } else { /* use whatever came from the read channel */
889                                 maxfrags = r_maxfrags;
890                                 fragsz = r_fragsz;
891                         }
892
893                         fragln = 0;
894                         while (fragsz > 1) {
895                                 fragln++;
896                                 fragsz >>= 1;
897                         }
898                         *arg_i = (maxfrags << 16) | fragln;
899                 }
900                 break;
901
902         case SNDCTL_DSP_GETISPACE:
903                 /* return the size of data available in the input queue */
904                 {
905                         audio_buf_info *a = (audio_buf_info *)arg;
906                         if (rdch) {
907                                 struct snd_dbuf *bs = rdch->bufsoft;
908
909                                 CHN_LOCK(rdch);
910                                 a->bytes = sndbuf_getready(bs);
911                                 a->fragments = a->bytes / sndbuf_getblksz(bs);
912                                 a->fragstotal = sndbuf_getblkcnt(bs);
913                                 a->fragsize = sndbuf_getblksz(bs);
914                                 CHN_UNLOCK(rdch);
915                         }
916                 }
917                 break;
918
919         case SNDCTL_DSP_GETOSPACE:
920                 /* return space available in the output queue */
921                 {
922                         audio_buf_info *a = (audio_buf_info *)arg;
923                         if (wrch) {
924                                 struct snd_dbuf *bs = wrch->bufsoft;
925
926                                 CHN_LOCK(wrch);
927                                 /* XXX abusive DMA update: chn_wrupdate(wrch); */
928                                 a->bytes = sndbuf_getfree(bs);
929                                 a->fragments = a->bytes / sndbuf_getblksz(bs);
930                                 a->fragstotal = sndbuf_getblkcnt(bs);
931                                 a->fragsize = sndbuf_getblksz(bs);
932                                 CHN_UNLOCK(wrch);
933                         }
934                 }
935                 break;
936
937         case SNDCTL_DSP_GETIPTR:
938                 {
939                         count_info *a = (count_info *)arg;
940                         if (rdch) {
941                                 struct snd_dbuf *bs = rdch->bufsoft;
942
943                                 CHN_LOCK(rdch);
944                                 /* XXX abusive DMA update: chn_rdupdate(rdch); */
945                                 a->bytes = sndbuf_gettotal(bs);
946                                 a->blocks = sndbuf_getblocks(bs) - rdch->blocks;
947                                 a->ptr = sndbuf_getreadyptr(bs);
948                                 rdch->blocks = sndbuf_getblocks(bs);
949                                 CHN_UNLOCK(rdch);
950                         } else
951                                 ret = EINVAL;
952                 }
953                 break;
954
955         case SNDCTL_DSP_GETOPTR:
956                 {
957                         count_info *a = (count_info *)arg;
958                         if (wrch) {
959                                 struct snd_dbuf *bs = wrch->bufsoft;
960
961                                 CHN_LOCK(wrch);
962                                 /* XXX abusive DMA update: chn_wrupdate(wrch); */
963                                 a->bytes = sndbuf_gettotal(bs);
964                                 a->blocks = sndbuf_getblocks(bs) - wrch->blocks;
965                                 a->ptr = sndbuf_getreadyptr(bs);
966                                 wrch->blocks = sndbuf_getblocks(bs);
967                                 CHN_UNLOCK(wrch);
968                         } else
969                                 ret = EINVAL;
970                 }
971                 break;
972
973         case SNDCTL_DSP_GETCAPS:
974                 *arg_i = DSP_CAP_REALTIME | DSP_CAP_MMAP | DSP_CAP_TRIGGER;
975                 if (rdch && wrch && !(dsp_get_flags(i_dev) & SD_F_SIMPLEX))
976                         *arg_i |= DSP_CAP_DUPLEX;
977                 break;
978
979         case SOUND_PCM_READ_BITS:
980                 chn = wrch ? wrch : rdch;
981                 if (chn) {
982                         CHN_LOCK(chn);
983                         if (chn->format & AFMT_8BIT)
984                                 *arg_i = 8;
985                         else if (chn->format & AFMT_16BIT)
986                                 *arg_i = 16;
987                         else if (chn->format & AFMT_24BIT)
988                                 *arg_i = 24;
989                         else if (chn->format & AFMT_32BIT)
990                                 *arg_i = 32;
991                         else
992                                 ret = EINVAL;
993                         CHN_UNLOCK(chn);
994                 } else {
995                         *arg_i = 0;
996                         ret = EINVAL;
997                 }
998                 break;
999
1000         case SNDCTL_DSP_SETTRIGGER:
1001                 if (rdch) {
1002                         CHN_LOCK(rdch);
1003                         rdch->flags &= ~(CHN_F_TRIGGERED | CHN_F_NOTRIGGER);
1004                         if (*arg_i & PCM_ENABLE_INPUT)
1005                                 chn_start(rdch, 1);
1006                         else
1007                                 rdch->flags |= CHN_F_NOTRIGGER;
1008                         CHN_UNLOCK(rdch);
1009                 }
1010                 if (wrch) {
1011                         CHN_LOCK(wrch);
1012                         wrch->flags &= ~(CHN_F_TRIGGERED | CHN_F_NOTRIGGER);
1013                         if (*arg_i & PCM_ENABLE_OUTPUT)
1014                                 chn_start(wrch, 1);
1015                         else
1016                                 wrch->flags |= CHN_F_NOTRIGGER;
1017                         CHN_UNLOCK(wrch);
1018                 }
1019                 break;
1020
1021         case SNDCTL_DSP_GETTRIGGER:
1022                 *arg_i = 0;
1023                 if (wrch) {
1024                         CHN_LOCK(wrch);
1025                         if (wrch->flags & CHN_F_TRIGGERED)
1026                                 *arg_i |= PCM_ENABLE_OUTPUT;
1027                         CHN_UNLOCK(wrch);
1028                 }
1029                 if (rdch) {
1030                         CHN_LOCK(rdch);
1031                         if (rdch->flags & CHN_F_TRIGGERED)
1032                                 *arg_i |= PCM_ENABLE_INPUT;
1033                         CHN_UNLOCK(rdch);
1034                 }
1035                 break;
1036
1037         case SNDCTL_DSP_GETODELAY:
1038                 if (wrch) {
1039                         struct snd_dbuf *b = wrch->bufhard;
1040                         struct snd_dbuf *bs = wrch->bufsoft;
1041
1042                         CHN_LOCK(wrch);
1043                         /* XXX abusive DMA update: chn_wrupdate(wrch); */
1044                         *arg_i = sndbuf_getready(b) + sndbuf_getready(bs);
1045                         CHN_UNLOCK(wrch);
1046                 } else
1047                         ret = EINVAL;
1048                 break;
1049
1050         case SNDCTL_DSP_POST:
1051                 if (wrch) {
1052                         CHN_LOCK(wrch);
1053                         wrch->flags &= ~CHN_F_NOTRIGGER;
1054                         chn_start(wrch, 1);
1055                         CHN_UNLOCK(wrch);
1056                 }
1057                 break;
1058
1059         case SNDCTL_DSP_SETDUPLEX:
1060                 /*
1061                  * switch to full-duplex mode if card is in half-duplex
1062                  * mode and is able to work in full-duplex mode
1063                  */
1064                 if (rdch && wrch && (dsp_get_flags(i_dev) & SD_F_SIMPLEX))
1065                         dsp_set_flags(i_dev, dsp_get_flags(i_dev)^SD_F_SIMPLEX);
1066                 break;
1067
1068         case SNDCTL_DSP_MAPINBUF:
1069         case SNDCTL_DSP_MAPOUTBUF:
1070         case SNDCTL_DSP_SETSYNCRO:
1071                 /* undocumented */
1072
1073         case SNDCTL_DSP_SUBDIVIDE:
1074         case SOUND_PCM_WRITE_FILTER:
1075         case SOUND_PCM_READ_FILTER:
1076                 /* dunno what these do, don't sound important */
1077
1078         default:
1079                 DEB(kprintf("default ioctl fn 0x%08lx fail\n", cmd));
1080                 ret = EINVAL;
1081                 break;
1082         }
1083         relchns(i_dev, rdch, wrch, 0);
1084         return ret;
1085 }
1086
1087 static struct filterops dsp_read_filtops =
1088         { FILTEROP_ISFD, NULL, dsp_filter_detach, dsp_filter_read };
1089 static struct filterops dsp_write_filtops =
1090         { FILTEROP_ISFD, NULL, dsp_filter_detach, dsp_filter_write };
1091
1092 static int
1093 dsp_kqfilter(struct dev_kqfilter_args *ap)
1094 {
1095         struct knote *kn = ap->a_kn;
1096         struct klist *klist;
1097         struct cdev *i_dev = ap->a_head.a_dev;
1098         struct pcm_channel *wrch = NULL, *rdch = NULL;
1099         struct snd_dbuf *bs = NULL;
1100
1101         getchns(i_dev, &rdch, &wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
1102
1103         switch (kn->kn_filter) {
1104         case EVFILT_READ:
1105                 if (rdch) {
1106                         kn->kn_fop = &dsp_read_filtops;
1107                         kn->kn_hook = (caddr_t)rdch;
1108                         bs = rdch->bufsoft;
1109                         ap->a_result = 0;
1110                 }
1111                 break;
1112         case EVFILT_WRITE:
1113                 if (wrch) {
1114                         kn->kn_fop = &dsp_write_filtops;
1115                         kn->kn_hook = (caddr_t)wrch;
1116                         bs = wrch->bufsoft;
1117                         ap->a_result = 0;
1118                 }
1119                 break;
1120         default:
1121                 ap->a_result = EOPNOTSUPP;
1122                 break;
1123         }
1124
1125         if (ap->a_result == 0) {
1126                 klist = &sndbuf_getkq(bs)->ki_note;
1127                 knote_insert(klist, kn);
1128         }
1129
1130         relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
1131
1132         return (0);
1133 }
1134
1135 static void
1136 dsp_filter_detach(struct knote *kn)
1137 {
1138         struct pcm_channel *ch = (struct pcm_channel *)kn->kn_hook;
1139         struct snd_dbuf *bs = ch->bufsoft;
1140         struct klist *klist;
1141
1142         CHN_LOCK(ch);
1143         klist = &sndbuf_getkq(bs)->ki_note;
1144         knote_remove(klist, kn);
1145         CHN_UNLOCK(ch);
1146 }
1147
1148 static int
1149 dsp_filter_read(struct knote *kn, long hint)
1150 {
1151         struct pcm_channel *rdch = (struct pcm_channel *)kn->kn_hook;
1152         struct thread *td = curthread;
1153         int ready;
1154
1155         CHN_LOCK(rdch);
1156         ready = chn_poll(rdch, 1, td);
1157         CHN_UNLOCK(rdch);
1158
1159         return (ready);
1160 }
1161
1162 static int
1163 dsp_filter_write(struct knote *kn, long hint)
1164 {
1165         struct pcm_channel *wrch = (struct pcm_channel *)kn->kn_hook;
1166         struct thread *td = curthread;
1167         int ready;
1168
1169         CHN_LOCK(wrch);
1170         ready = chn_poll(wrch, 1, td);
1171         CHN_UNLOCK(wrch);
1172
1173         return (ready);
1174 }
1175
1176 static int
1177 dsp_mmap(struct dev_mmap_args *ap)
1178 {
1179         struct cdev *i_dev = ap->a_head.a_dev;
1180         vm_offset_t offset = ap->a_offset;
1181         int nprot = ap->a_nprot;
1182         struct pcm_channel *wrch = NULL, *rdch = NULL, *c;
1183
1184         if (nprot & PROT_EXEC)
1185                 return -1;
1186
1187         getchns(i_dev, &rdch, &wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
1188 #if 0
1189         /*
1190          * XXX the linux api uses the nprot to select read/write buffer
1191          * our vm system doesn't allow this, so force write buffer
1192          */
1193
1194         if (wrch && (nprot & PROT_WRITE)) {
1195                 c = wrch;
1196         } else if (rdch && (nprot & PROT_READ)) {
1197                 c = rdch;
1198         } else {
1199                 return -1;
1200         }
1201 #else
1202         c = wrch;
1203 #endif
1204
1205         if (c == NULL) {
1206                 relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
1207                 return -1;
1208         }
1209
1210         if (offset >= sndbuf_getsize(c->bufsoft)) {
1211                 relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
1212                 return -1;
1213         }
1214
1215         if (!(c->flags & CHN_F_MAPPED))
1216                 c->flags |= CHN_F_MAPPED;
1217
1218         ap->a_result = atop(vtophys(sndbuf_getbufofs(c->bufsoft, offset)));
1219         relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
1220
1221         return (0);
1222 }
1223
1224 /*
1225  *    for i = 0 to channels of device N
1226  *      if dspN.i isn't busy and in the right dir, create a dev_t and return it
1227  */
1228 int
1229 dsp_clone(struct dev_clone_args *ap)
1230 {
1231         struct cdev *i_dev = ap->a_head.a_dev;
1232         struct cdev *pdev;
1233         struct snddev_info *pcm_dev;
1234         struct snddev_channel *pcm_chan;
1235         struct pcm_channel *c;
1236         int err = EBUSY;
1237         int dir;
1238
1239         pcm_dev = dsp_get_info(i_dev);
1240
1241         if (pcm_dev == NULL)
1242                 return (ENODEV);
1243
1244         dir = ap->a_mode & FWRITE ? PCMDIR_PLAY : PCMDIR_REC;
1245
1246 retry_chnalloc:
1247         SLIST_FOREACH(pcm_chan, &pcm_dev->channels, link) {
1248                 c = pcm_chan->channel;
1249                 CHN_LOCK(c);
1250                 pdev = pcm_chan->dsp_dev;
1251
1252                 /*
1253                  * Make sure that the channel has not been assigned
1254                  * to a device yet (and vice versa).
1255                  * The direction has to match and the channel may not
1256                  * be busy.
1257                  * dsp_open will use exactly this channel number to
1258                  * avoid (possible?) races between clone and open.
1259                  */
1260                 if (pdev == NULL && c->direction == dir &&
1261                     !(c->flags & CHN_F_BUSY)) {
1262                         CHN_UNLOCK(c);
1263                         pcm_lock(pcm_dev);
1264                         pcm_chan->dsp_dev = make_only_dev(&dsp_ops,
1265                                 PCMMKMINOR(PCMUNIT(i_dev), pcm_chan->chan_num),
1266                                 UID_ROOT, GID_WHEEL,
1267                                 0666,
1268                                 "%s.%d",
1269                                 devtoname(i_dev),
1270                                 pcm_chan->chan_num);
1271                         pcm_unlock(pcm_dev);
1272
1273                         ap->a_dev = pcm_chan->dsp_dev;
1274                         return (0);
1275                 }
1276                 CHN_UNLOCK(c);
1277
1278 #if DEBUG
1279                 if ((pdev != NULL) && (pdev->si_drv1 == NULL) && (pdev->si_drv2 == NULL)) {
1280                         kprintf("%s: dangling device\n", devtoname(pdev));
1281                 }
1282 #endif
1283         }
1284
1285         /* no channel available, create vchannel */
1286         if (dir == PCMDIR_PLAY &&
1287             pcm_dev->vchancount > 0 &&
1288             pcm_dev->vchancount < snd_maxautovchans &&
1289             pcm_dev->devcount < PCMMAXCHAN) {
1290                 err = pcm_setvchans(pcm_dev, pcm_dev->vchancount + 1);
1291                 if (err == 0)
1292                         goto retry_chnalloc;
1293                 /*
1294                  * If we can't use vchans, because the main output is
1295                  * blocked for something else, we should not return
1296                  * any vchan create error, but the more descriptive
1297                  * EBUSY.
1298                  * After all, the user didn't ask us to clone, but
1299                  * only opened /dev/dsp.
1300                  */
1301                 err = EBUSY;
1302         }
1303
1304         return (err);
1305 }