2 * Copyright (c) 1999 Cameron Grant <cg@freebsd.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
26 * $FreeBSD: src/sys/dev/sound/pcm/dsp.c,v 1.80.2.6 2006/04/04 17:43:48 ariff Exp $
27 * $DragonFly: src/sys/dev/sound/pcm/dsp.c,v 1.17 2008/02/28 17:19:11 tgen Exp $
30 #include <sys/param.h>
31 #include <sys/queue.h>
33 #include <dev/sound/pcm/dsp.h>
34 #include <dev/sound/pcm/sound.h>
36 SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pcm/dsp.c,v 1.17 2008/02/28 17:19:11 tgen Exp $");
40 static d_open_t dsp_open
;
41 static d_close_t dsp_close
;
42 static d_read_t dsp_read
;
43 static d_write_t dsp_write
;
44 static d_ioctl_t dsp_ioctl
;
45 static d_poll_t dsp_poll
;
46 static d_mmap_t dsp_mmap
;
48 struct dev_ops dsp_cdevsw
= {
49 { "dsp", SND_CDEV_MAJOR
, 0},
50 /*.d_flags = D_NEEDGIANT,*/
61 dsp_get_info(struct cdev
*dev
)
63 struct snddev_info
*d
;
67 if (unit
>= devclass_get_maxunit(pcm_devclass
))
69 d
= devclass_get_softc(pcm_devclass
, unit
);
75 dsp_get_flags(struct cdev
*dev
)
81 if (unit
>= devclass_get_maxunit(pcm_devclass
))
83 bdev
= devclass_get_device(pcm_devclass
, unit
);
85 return pcm_getflags(bdev
);
89 dsp_set_flags(struct cdev
*dev
, u_int32_t flags
)
95 if (unit
>= devclass_get_maxunit(pcm_devclass
))
97 bdev
= devclass_get_device(pcm_devclass
, unit
);
99 pcm_setflags(bdev
, flags
);
103 * return the channels associated with an open device instance.
104 * set the priority if the device is simplex and one direction (only) is
106 * lock channels specified.
109 getchns(struct cdev
*dev
, struct pcm_channel
**rdch
, struct pcm_channel
**wrch
, u_int32_t prio
)
111 struct snddev_info
*d
;
114 flags
= dsp_get_flags(dev
);
115 d
= dsp_get_info(dev
);
118 KASSERT((flags
& SD_F_PRIO_SET
) != SD_F_PRIO_SET
, \
119 ("getchns: read and write both prioritised"));
121 if ((flags
& SD_F_PRIO_SET
) == 0 && (prio
!= (SD_F_PRIO_RD
| SD_F_PRIO_WR
))) {
122 flags
|= prio
& (SD_F_PRIO_RD
| SD_F_PRIO_WR
);
123 dsp_set_flags(dev
, flags
);
126 *rdch
= dev
->si_drv1
;
127 *wrch
= dev
->si_drv2
;
128 if ((flags
& SD_F_SIMPLEX
) && (flags
& SD_F_PRIO_SET
)) {
130 if (*rdch
&& flags
& SD_F_PRIO_WR
) {
132 *rdch
= pcm_getfakechan(d
);
133 } else if (*wrch
&& flags
& SD_F_PRIO_RD
) {
135 *wrch
= pcm_getfakechan(d
);
139 pcm_getfakechan(d
)->flags
|= CHN_F_BUSY
;
143 if (*rdch
&& *rdch
!= pcm_getfakechan(d
) && (prio
& SD_F_PRIO_RD
))
145 if (*wrch
&& *wrch
!= pcm_getfakechan(d
) && (prio
& SD_F_PRIO_WR
))
151 /* unlock specified channels */
153 relchns(struct cdev
*dev
, struct pcm_channel
*rdch
, struct pcm_channel
*wrch
, u_int32_t prio
)
155 struct snddev_info
*d
;
157 d
= dsp_get_info(dev
);
158 if (wrch
&& wrch
!= pcm_getfakechan(d
) && (prio
& SD_F_PRIO_WR
))
160 if (rdch
&& rdch
!= pcm_getfakechan(d
) && (prio
& SD_F_PRIO_RD
))
166 dsp_open(struct dev_open_args
*ap
)
168 struct cdev
*i_dev
= ap
->a_head
.a_dev
;
169 struct thread
*td
= curthread
;
170 int flags
= ap
->a_oflags
;
171 struct pcm_channel
*rdch
, *wrch
;
172 struct snddev_info
*d
= NULL
;
173 struct snddev_channel
*sce
= NULL
;
174 u_int32_t fmt
= AFMT_U8
;
183 d
= dsp_get_info(i_dev
);
184 SLIST_FOREACH(sce
, &d
->channels
, link
) {
185 if (sce
->dsp_dev
== i_dev
)
199 if ((flags
& (FREAD
| FWRITE
)) == 0) {
204 chnum
= PCMCHAN(i_dev
);
206 /* lock snddev so nobody else can monkey with it */
209 rdch
= i_dev
->si_drv1
;
210 wrch
= i_dev
->si_drv2
;
212 if (rdch
|| wrch
|| ((dsp_get_flags(i_dev
) & SD_F_SIMPLEX
) &&
213 (flags
& (FREAD
| FWRITE
)) == (FREAD
| FWRITE
))) {
214 /* simplex or not, better safe than sorry. */
221 * if we get here, the open request is valid- either:
222 * * we were previously not open
223 * * we were open for play xor record and the opener wants
224 * the non-open direction
229 error
= pcm_chnalloc(d
, &rdch
, PCMDIR_REC
, td
->td_proc
->p_pid
, chnum
);
230 if (error
!= 0 && error
!= EBUSY
&& chnum
!= -1 && (flags
& FWRITE
))
231 error
= pcm_chnalloc(d
, &rdch
, PCMDIR_REC
, td
->td_proc
->p_pid
, -1);
233 if (error
== 0 && (chn_reset(rdch
, fmt
) ||
234 (fmt
&& chn_setspeed(rdch
, DSP_DEFAULT_SPEED
))))
239 pcm_chnrelease(rdch
);
248 if (flags
& FWRITE
) {
251 error
= pcm_chnalloc(d
, &wrch
, PCMDIR_PLAY
, td
->td_proc
->p_pid
, chnum
);
252 if (error
!= 0 && error
!= EBUSY
&& chnum
!= -1 && (flags
& FREAD
))
253 error
= pcm_chnalloc(d
, &wrch
, PCMDIR_PLAY
, td
->td_proc
->p_pid
, -1);
255 if (error
== 0 && (chn_reset(wrch
, fmt
) ||
256 (fmt
&& chn_setspeed(wrch
, DSP_DEFAULT_SPEED
))))
261 pcm_chnrelease(wrch
);
264 * Lock, deref and release previously created record channel
267 pcm_chnref(rdch
, -1);
268 pcm_chnrelease(rdch
);
279 i_dev
->si_drv1
= rdch
;
280 i_dev
->si_drv2
= wrch
;
288 if (i_dev
!= NULL
&& sce
!= NULL
&& sce
->open
== 0) {
298 dsp_close(struct dev_close_args
*ap
)
300 struct cdev
*i_dev
= ap
->a_head
.a_dev
;
301 struct pcm_channel
*rdch
, *wrch
;
302 struct snddev_info
*d
;
303 struct snddev_channel
*sce
= NULL
;
306 d
= dsp_get_info(i_dev
);
308 rdch
= i_dev
->si_drv1
;
309 wrch
= i_dev
->si_drv2
;
310 i_dev
->si_drv1
= NULL
;
311 i_dev
->si_drv2
= NULL
;
313 SLIST_FOREACH(sce
, &d
->channels
, link
) {
314 if (sce
->dsp_dev
== i_dev
)
326 refs
+= pcm_chnref(rdch
, -1);
327 chn_abort(rdch
); /* won't sleep */
328 rdch
->flags
&= ~(CHN_F_RUNNING
| CHN_F_MAPPED
| CHN_F_DEAD
);
330 pcm_chnrelease(rdch
);
334 refs
+= pcm_chnref(wrch
, -1);
336 * XXX: Maybe the right behaviour is to abort on non_block.
337 * It seems that mplayer flushes the audio queue by quickly
338 * closing and re-opening. In FBSD, there's a long pause
339 * while the audio queue flushes that I presume isn't there in
342 chn_flush(wrch
); /* may sleep */
343 wrch
->flags
&= ~(CHN_F_RUNNING
| CHN_F_MAPPED
| CHN_F_DEAD
);
345 pcm_chnrelease(wrch
);
350 * If there are no more references, release the channels.
353 if (pcm_getfakechan(d
))
354 pcm_getfakechan(d
)->flags
= 0;
355 /* What is this?!? */
356 dsp_set_flags(i_dev
, dsp_get_flags(i_dev
) & ~SD_F_TRANSIENT
);
364 dsp_read(struct dev_read_args
*ap
)
366 struct cdev
*i_dev
= ap
->a_head
.a_dev
;
367 struct uio
*buf
= ap
->a_uio
;
368 int flag
= ap
->a_ioflag
;
369 struct pcm_channel
*rdch
, *wrch
;
372 getchns(i_dev
, &rdch
, &wrch
, SD_F_PRIO_RD
);
374 KASSERT(rdch
, ("dsp_read: nonexistant channel"));
375 KASSERT(rdch
->flags
& CHN_F_BUSY
, ("dsp_read: nonbusy channel"));
377 if (rdch
->flags
& (CHN_F_MAPPED
| CHN_F_DEAD
)) {
378 relchns(i_dev
, rdch
, wrch
, SD_F_PRIO_RD
);
381 if (!(rdch
->flags
& CHN_F_RUNNING
))
382 rdch
->flags
|= CHN_F_RUNNING
;
383 ret
= chn_read(rdch
, buf
, flag
);
384 relchns(i_dev
, rdch
, wrch
, SD_F_PRIO_RD
);
390 dsp_write(struct dev_write_args
*ap
)
392 struct cdev
*i_dev
= ap
->a_head
.a_dev
;
393 struct uio
*buf
= ap
->a_uio
;
394 int flag
= ap
->a_ioflag
;
395 struct pcm_channel
*rdch
, *wrch
;
398 getchns(i_dev
, &rdch
, &wrch
, SD_F_PRIO_WR
);
400 KASSERT(wrch
, ("dsp_write: nonexistant channel"));
401 KASSERT(wrch
->flags
& CHN_F_BUSY
, ("dsp_write: nonbusy channel"));
403 if (wrch
->flags
& (CHN_F_MAPPED
| CHN_F_DEAD
)) {
404 relchns(i_dev
, rdch
, wrch
, SD_F_PRIO_WR
);
407 if (!(wrch
->flags
& CHN_F_RUNNING
))
408 wrch
->flags
|= CHN_F_RUNNING
;
409 ret
= chn_write(wrch
, buf
, flag
);
410 relchns(i_dev
, rdch
, wrch
, SD_F_PRIO_WR
);
416 dsp_ioctl(struct dev_ioctl_args
*ap
)
418 struct cdev
*i_dev
= ap
->a_head
.a_dev
;
419 u_long cmd
= ap
->a_cmd
;
420 caddr_t arg
= ap
->a_data
;
421 struct pcm_channel
*chn
, *rdch
, *wrch
;
422 struct snddev_info
*d
;
424 int ret
= 0, *arg_i
= (int *)arg
, tmp
;
426 d
= dsp_get_info(i_dev
);
427 getchns(i_dev
, &rdch
, &wrch
, 0);
430 if (wrch
&& (wrch
->flags
& CHN_F_DEAD
))
432 if (rdch
&& (rdch
->flags
& CHN_F_DEAD
))
435 relchns(i_dev
, rdch
, wrch
, 0);
444 * 4Front OSS specifies that dsp devices allow mixer controls to
445 * control PCM == their volume.
447 if (IOCGROUP(cmd
) == 'M') {
449 * For now only set the channel volume for vchans, pass
450 * all others to the mixer.
452 if (wrch
!= NULL
&& wrch
->flags
& CHN_F_VIRTUAL
&&
453 (cmd
& 0xff) == SOUND_MIXER_PCM
) {
454 if ((cmd
& MIXER_WRITE(0)) == MIXER_WRITE(0)) {
455 int vol_raw
= *(int *)arg
;
456 int vol_left
, vol_right
;
458 vol_left
= min(vol_raw
& 0x00ff, 100);
459 vol_right
= min((vol_raw
& 0xff00) >> 8, 100);
460 ret
= chn_setvolume(wrch
, vol_left
, vol_right
);
462 *(int *)arg
= wrch
->volume
;
465 ap
->a_head
.a_dev
= d
->mixer_dev
;
466 ret
= mixer_ioctl(ap
);
469 relchns(i_dev
, rdch
, wrch
, 0);
476 * we start with the new ioctl interface.
478 case AIONWRITE
: /* how many bytes can write ? */
482 if (wrch && wrch->bufhard.dl)
483 while (chn_wrfeed(wrch) == 0);
485 *arg_i
= sndbuf_getfree(wrch
->bufsoft
);
493 case AIOSSIZE
: /* set the current blocksize */
495 struct snd_size
*p
= (struct snd_size
*)arg
;
501 chn_setblocksize(wrch
, 2, p
->play_size
);
502 p
->play_size
= sndbuf_getblksz(wrch
->bufsoft
);
507 chn_setblocksize(rdch
, 2, p
->rec_size
);
508 p
->rec_size
= sndbuf_getblksz(rdch
->bufsoft
);
513 case AIOGSIZE
: /* get the current blocksize */
515 struct snd_size
*p
= (struct snd_size
*)arg
;
519 p
->play_size
= sndbuf_getblksz(wrch
->bufsoft
);
524 p
->rec_size
= sndbuf_getblksz(rdch
->bufsoft
);
533 snd_chan_param
*p
= (snd_chan_param
*)arg
;
535 if (cmd
== AIOSFMT
&&
536 ((p
->play_format
!= 0 && p
->play_rate
== 0) ||
537 (p
->rec_format
!= 0 && p
->rec_rate
== 0))) {
543 if (cmd
== AIOSFMT
&& p
->play_format
!= 0) {
544 chn_setformat(wrch
, p
->play_format
);
545 chn_setspeed(wrch
, p
->play_rate
);
547 p
->play_rate
= wrch
->speed
;
548 p
->play_format
= wrch
->format
;
556 if (cmd
== AIOSFMT
&& p
->rec_format
!= 0) {
557 chn_setformat(rdch
, p
->rec_format
);
558 chn_setspeed(rdch
, p
->rec_rate
);
560 p
->rec_rate
= rdch
->speed
;
561 p
->rec_format
= rdch
->format
;
570 case AIOGCAP
: /* get capabilities */
572 snd_capabilities
*p
= (snd_capabilities
*)arg
;
573 struct pcmchan_caps
*pcaps
= NULL
, *rcaps
= NULL
;
578 rcaps
= chn_getcaps(rdch
);
582 pcaps
= chn_getcaps(wrch
);
584 p
->rate_min
= max(rcaps
? rcaps
->minspeed
: 0,
585 pcaps
? pcaps
->minspeed
: 0);
586 p
->rate_max
= min(rcaps
? rcaps
->maxspeed
: 1000000,
587 pcaps
? pcaps
->maxspeed
: 1000000);
588 p
->bufsize
= min(rdch
? sndbuf_getsize(rdch
->bufsoft
) : 1000000,
589 wrch
? sndbuf_getsize(wrch
->bufsoft
) : 1000000);
590 /* XXX bad on sb16 */
591 p
->formats
= (rdch
? chn_getformats(rdch
) : 0xffffffff) &
592 (wrch
? chn_getformats(wrch
) : 0xffffffff);
594 p
->formats
|= (dsp_get_flags(i_dev
) & SD_F_SIMPLEX
)? 0 : AFMT_FULLDUPLEX
;
596 p
->mixers
= 1; /* default: one mixer */
597 p
->inputs
= pdev
->si_drv1
? mix_getdevs(pdev
->si_drv1
) : 0;
598 p
->left
= p
->right
= 100;
607 if (*arg_i
== AIOSYNC_PLAY
&& wrch
) {
609 *arg_i
= chn_abort(wrch
);
611 } else if (*arg_i
== AIOSYNC_CAPTURE
&& rdch
) {
613 *arg_i
= chn_abort(rdch
);
616 kprintf("AIOSTOP: bad channel 0x%x\n", *arg_i
);
622 kprintf("AIOSYNC chan 0x%03lx pos %lu unimplemented\n",
623 ((snd_sync_parm
*)arg
)->chan
, ((snd_sync_parm
*)arg
)->pos
);
627 * here follow the standard ioctls (filio.h etc.)
629 case FIONREAD
: /* get # bytes to read */
632 /* if (rdch && rdch->bufhard.dl)
633 while (chn_rdfeed(rdch) == 0);
635 *arg_i
= sndbuf_getready(rdch
->bufsoft
);
643 case FIOASYNC
: /*set/clear async i/o */
644 DEB( kprintf("FIOASYNC\n") ; )
647 case SNDCTL_DSP_NONBLOCK
:
648 case FIONBIO
: /* set/clear non-blocking i/o */
652 rdch
->flags
|= CHN_F_NBIO
;
654 rdch
->flags
&= ~CHN_F_NBIO
;
660 wrch
->flags
|= CHN_F_NBIO
;
662 wrch
->flags
&= ~CHN_F_NBIO
;
668 * Finally, here is the linux-compatible ioctl interface
670 #define THE_REAL_SNDCTL_DSP_GETBLKSIZE _IOWR('P', 4, int)
671 case THE_REAL_SNDCTL_DSP_GETBLKSIZE
:
672 case SNDCTL_DSP_GETBLKSIZE
:
673 chn
= wrch
? wrch
: rdch
;
676 *arg_i
= sndbuf_getblksz(chn
->bufsoft
);
684 case SNDCTL_DSP_SETBLKSIZE
:
685 RANGE(*arg_i
, 16, 65536);
688 chn_setblocksize(wrch
, 2, *arg_i
);
693 chn_setblocksize(rdch
, 2, *arg_i
);
698 case SNDCTL_DSP_RESET
:
699 DEB(kprintf("dsp reset\n"));
714 case SNDCTL_DSP_SYNC
:
715 DEB(kprintf("dsp sync\n"));
716 /* chn_sync may sleep */
719 chn_sync(wrch
, sndbuf_getsize(wrch
->bufsoft
) - 4);
724 case SNDCTL_DSP_SPEED
:
725 /* chn_setspeed may sleep */
729 ret
= chn_setspeed(wrch
, *arg_i
);
733 if (rdch
&& ret
== 0) {
735 ret
= chn_setspeed(rdch
, *arg_i
);
743 case SOUND_PCM_READ_RATE
:
744 chn
= wrch
? wrch
: rdch
;
755 case SNDCTL_DSP_STEREO
:
757 *arg_i
= (*arg_i
)? AFMT_STEREO
: 0;
760 ret
= chn_setformat(wrch
, (wrch
->format
& ~AFMT_STEREO
) | *arg_i
);
761 tmp
= (wrch
->format
& AFMT_STEREO
)? 1 : 0;
764 if (rdch
&& ret
== 0) {
766 ret
= chn_setformat(rdch
, (rdch
->format
& ~AFMT_STEREO
) | *arg_i
);
768 tmp
= (rdch
->format
& AFMT_STEREO
)? 1 : 0;
774 case SOUND_PCM_WRITE_CHANNELS
:
775 /* case SNDCTL_DSP_CHANNELS: ( == SOUND_PCM_WRITE_CHANNELS) */
778 *arg_i
= (*arg_i
!= 1)? AFMT_STEREO
: 0;
781 ret
= chn_setformat(wrch
, (wrch
->format
& ~AFMT_STEREO
) | *arg_i
);
782 tmp
= (wrch
->format
& AFMT_STEREO
)? 2 : 1;
785 if (rdch
&& ret
== 0) {
787 ret
= chn_setformat(rdch
, (rdch
->format
& ~AFMT_STEREO
) | *arg_i
);
789 tmp
= (rdch
->format
& AFMT_STEREO
)? 2 : 1;
794 chn
= wrch
? wrch
: rdch
;
796 *arg_i
= (chn
->format
& AFMT_STEREO
) ? 2 : 1;
801 case SOUND_PCM_READ_CHANNELS
:
802 chn
= wrch
? wrch
: rdch
;
805 *arg_i
= (chn
->format
& AFMT_STEREO
) ? 2 : 1;
813 case SNDCTL_DSP_GETFMTS
: /* returns a mask of supported fmts */
814 chn
= wrch
? wrch
: rdch
;
817 *arg_i
= chn_getformats(chn
);
825 case SNDCTL_DSP_SETFMT
: /* sets _one_ format */
826 if ((*arg_i
!= AFMT_QUERY
)) {
830 ret
= chn_setformat(wrch
, (*arg_i
) | (wrch
->format
& AFMT_STEREO
));
831 tmp
= wrch
->format
& ~AFMT_STEREO
;
834 if (rdch
&& ret
== 0) {
836 ret
= chn_setformat(rdch
, (*arg_i
) | (rdch
->format
& AFMT_STEREO
));
838 tmp
= rdch
->format
& ~AFMT_STEREO
;
843 chn
= wrch
? wrch
: rdch
;
845 *arg_i
= chn
->format
& ~AFMT_STEREO
;
850 case SNDCTL_DSP_SETFRAGMENT
:
851 DEB(kprintf("SNDCTL_DSP_SETFRAGMENT 0x%08x\n", *(int *)arg
));
853 u_int32_t fragln
= (*arg_i
) & 0x0000ffff;
854 u_int32_t maxfrags
= ((*arg_i
) & 0xffff0000) >> 16;
856 u_int32_t r_maxfrags
, r_fragsz
;
858 RANGE(fragln
, 4, 16);
859 fragsz
= 1 << fragln
;
862 maxfrags
= CHN_2NDBUFMAXSIZE
/ fragsz
;
865 if (maxfrags
* fragsz
> CHN_2NDBUFMAXSIZE
)
866 maxfrags
= CHN_2NDBUFMAXSIZE
/ fragsz
;
868 DEB(kprintf("SNDCTL_DSP_SETFRAGMENT %d frags, %d sz\n", maxfrags
, fragsz
));
871 ret
= chn_setblocksize(rdch
, maxfrags
, fragsz
);
872 r_maxfrags
= sndbuf_getblkcnt(rdch
->bufsoft
);
873 r_fragsz
= sndbuf_getblksz(rdch
->bufsoft
);
876 r_maxfrags
= maxfrags
;
879 if (wrch
&& ret
== 0) {
881 ret
= chn_setblocksize(wrch
, maxfrags
, fragsz
);
882 maxfrags
= sndbuf_getblkcnt(wrch
->bufsoft
);
883 fragsz
= sndbuf_getblksz(wrch
->bufsoft
);
885 } else { /* use whatever came from the read channel */
886 maxfrags
= r_maxfrags
;
895 *arg_i
= (maxfrags
<< 16) | fragln
;
899 case SNDCTL_DSP_GETISPACE
:
900 /* return the size of data available in the input queue */
902 audio_buf_info
*a
= (audio_buf_info
*)arg
;
904 struct snd_dbuf
*bs
= rdch
->bufsoft
;
907 a
->bytes
= sndbuf_getready(bs
);
908 a
->fragments
= a
->bytes
/ sndbuf_getblksz(bs
);
909 a
->fragstotal
= sndbuf_getblkcnt(bs
);
910 a
->fragsize
= sndbuf_getblksz(bs
);
916 case SNDCTL_DSP_GETOSPACE
:
917 /* return space available in the output queue */
919 audio_buf_info
*a
= (audio_buf_info
*)arg
;
921 struct snd_dbuf
*bs
= wrch
->bufsoft
;
924 /* XXX abusive DMA update: chn_wrupdate(wrch); */
925 a
->bytes
= sndbuf_getfree(bs
);
926 a
->fragments
= a
->bytes
/ sndbuf_getblksz(bs
);
927 a
->fragstotal
= sndbuf_getblkcnt(bs
);
928 a
->fragsize
= sndbuf_getblksz(bs
);
934 case SNDCTL_DSP_GETIPTR
:
936 count_info
*a
= (count_info
*)arg
;
938 struct snd_dbuf
*bs
= rdch
->bufsoft
;
941 /* XXX abusive DMA update: chn_rdupdate(rdch); */
942 a
->bytes
= sndbuf_gettotal(bs
);
943 a
->blocks
= sndbuf_getblocks(bs
) - rdch
->blocks
;
944 a
->ptr
= sndbuf_getreadyptr(bs
);
945 rdch
->blocks
= sndbuf_getblocks(bs
);
952 case SNDCTL_DSP_GETOPTR
:
954 count_info
*a
= (count_info
*)arg
;
956 struct snd_dbuf
*bs
= wrch
->bufsoft
;
959 /* XXX abusive DMA update: chn_wrupdate(wrch); */
960 a
->bytes
= sndbuf_gettotal(bs
);
961 a
->blocks
= sndbuf_getblocks(bs
) - wrch
->blocks
;
962 a
->ptr
= sndbuf_getreadyptr(bs
);
963 wrch
->blocks
= sndbuf_getblocks(bs
);
970 case SNDCTL_DSP_GETCAPS
:
971 *arg_i
= DSP_CAP_REALTIME
| DSP_CAP_MMAP
| DSP_CAP_TRIGGER
;
972 if (rdch
&& wrch
&& !(dsp_get_flags(i_dev
) & SD_F_SIMPLEX
))
973 *arg_i
|= DSP_CAP_DUPLEX
;
976 case SOUND_PCM_READ_BITS
:
977 chn
= wrch
? wrch
: rdch
;
980 if (chn
->format
& AFMT_8BIT
)
982 else if (chn
->format
& AFMT_16BIT
)
984 else if (chn
->format
& AFMT_24BIT
)
986 else if (chn
->format
& AFMT_32BIT
)
997 case SNDCTL_DSP_SETTRIGGER
:
1000 rdch
->flags
&= ~(CHN_F_TRIGGERED
| CHN_F_NOTRIGGER
);
1001 if (*arg_i
& PCM_ENABLE_INPUT
)
1004 rdch
->flags
|= CHN_F_NOTRIGGER
;
1009 wrch
->flags
&= ~(CHN_F_TRIGGERED
| CHN_F_NOTRIGGER
);
1010 if (*arg_i
& PCM_ENABLE_OUTPUT
)
1013 wrch
->flags
|= CHN_F_NOTRIGGER
;
1018 case SNDCTL_DSP_GETTRIGGER
:
1022 if (wrch
->flags
& CHN_F_TRIGGERED
)
1023 *arg_i
|= PCM_ENABLE_OUTPUT
;
1028 if (rdch
->flags
& CHN_F_TRIGGERED
)
1029 *arg_i
|= PCM_ENABLE_INPUT
;
1034 case SNDCTL_DSP_GETODELAY
:
1036 struct snd_dbuf
*b
= wrch
->bufhard
;
1037 struct snd_dbuf
*bs
= wrch
->bufsoft
;
1040 /* XXX abusive DMA update: chn_wrupdate(wrch); */
1041 *arg_i
= sndbuf_getready(b
) + sndbuf_getready(bs
);
1047 case SNDCTL_DSP_POST
:
1050 wrch
->flags
&= ~CHN_F_NOTRIGGER
;
1056 case SNDCTL_DSP_SETDUPLEX
:
1058 * switch to full-duplex mode if card is in half-duplex
1059 * mode and is able to work in full-duplex mode
1061 if (rdch
&& wrch
&& (dsp_get_flags(i_dev
) & SD_F_SIMPLEX
))
1062 dsp_set_flags(i_dev
, dsp_get_flags(i_dev
)^SD_F_SIMPLEX
);
1065 case SNDCTL_DSP_MAPINBUF
:
1066 case SNDCTL_DSP_MAPOUTBUF
:
1067 case SNDCTL_DSP_SETSYNCRO
:
1070 case SNDCTL_DSP_SUBDIVIDE
:
1071 case SOUND_PCM_WRITE_FILTER
:
1072 case SOUND_PCM_READ_FILTER
:
1073 /* dunno what these do, don't sound important */
1076 DEB(kprintf("default ioctl fn 0x%08lx fail\n", cmd
));
1080 relchns(i_dev
, rdch
, wrch
, 0);
1085 dsp_poll(struct dev_poll_args
*ap
)
1087 struct cdev
*i_dev
= ap
->a_head
.a_dev
;
1088 int events
= ap
->a_events
;
1089 struct thread
*td
= curthread
;
1090 struct pcm_channel
*wrch
= NULL
, *rdch
= NULL
;
1094 getchns(i_dev
, &rdch
, &wrch
, SD_F_PRIO_RD
| SD_F_PRIO_WR
);
1097 e
= (events
& (POLLOUT
| POLLWRNORM
));
1099 ret
|= chn_poll(wrch
, e
, td
);
1102 e
= (events
& (POLLIN
| POLLRDNORM
));
1104 ret
|= chn_poll(rdch
, e
, td
);
1106 relchns(i_dev
, rdch
, wrch
, SD_F_PRIO_RD
| SD_F_PRIO_WR
);
1113 dsp_mmap(struct dev_mmap_args
*ap
)
1115 struct cdev
*i_dev
= ap
->a_head
.a_dev
;
1116 vm_offset_t offset
= ap
->a_offset
;
1117 int nprot
= ap
->a_nprot
;
1118 struct pcm_channel
*wrch
= NULL
, *rdch
= NULL
, *c
;
1120 if (nprot
& PROT_EXEC
)
1123 getchns(i_dev
, &rdch
, &wrch
, SD_F_PRIO_RD
| SD_F_PRIO_WR
);
1126 * XXX the linux api uses the nprot to select read/write buffer
1127 * our vm system doesn't allow this, so force write buffer
1130 if (wrch
&& (nprot
& PROT_WRITE
)) {
1132 } else if (rdch
&& (nprot
& PROT_READ
)) {
1142 relchns(i_dev
, rdch
, wrch
, SD_F_PRIO_RD
| SD_F_PRIO_WR
);
1146 if (offset
>= sndbuf_getsize(c
->bufsoft
)) {
1147 relchns(i_dev
, rdch
, wrch
, SD_F_PRIO_RD
| SD_F_PRIO_WR
);
1151 if (!(c
->flags
& CHN_F_MAPPED
))
1152 c
->flags
|= CHN_F_MAPPED
;
1154 ap
->a_result
= vtophys(sndbuf_getbufofs(c
->bufsoft
, offset
));
1155 relchns(i_dev
, rdch
, wrch
, SD_F_PRIO_RD
| SD_F_PRIO_WR
);
1161 * for i = 0 to channels of device N
1162 * if dspN.i isn't busy and in the right dir, create a dev_t and return it
1165 dsp_clone(struct dev_clone_args
*ap
)
1167 struct cdev
*i_dev
= ap
->a_head
.a_dev
;
1169 struct snddev_info
*pcm_dev
;
1170 struct snddev_channel
*pcm_chan
;
1171 struct pcm_channel
*c
;
1175 pcm_dev
= dsp_get_info(i_dev
);
1177 if (pcm_dev
== NULL
)
1180 dir
= ap
->a_mode
& FWRITE
? PCMDIR_PLAY
: PCMDIR_REC
;
1183 SLIST_FOREACH(pcm_chan
, &pcm_dev
->channels
, link
) {
1184 c
= pcm_chan
->channel
;
1186 pdev
= pcm_chan
->dsp_dev
;
1189 * Make sure that the channel has not been assigned
1190 * to a device yet (and vice versa).
1191 * The direction has to match and the channel may not
1193 * dsp_open will use exactly this channel number to
1194 * avoid (possible?) races between clone and open.
1196 if (pdev
== NULL
&& c
->direction
== dir
&&
1197 !(c
->flags
& CHN_F_BUSY
)) {
1200 pcm_chan
->dsp_dev
= make_only_dev(&dsp_cdevsw
,
1201 PCMMKMINOR(PCMUNIT(i_dev
), pcm_chan
->chan_num
),
1202 UID_ROOT
, GID_WHEEL
,
1206 pcm_chan
->chan_num
);
1207 pcm_unlock(pcm_dev
);
1209 ap
->a_dev
= pcm_chan
->dsp_dev
;
1215 if ((pdev
!= NULL
) && (pdev
->si_drv1
== NULL
) && (pdev
->si_drv2
== NULL
)) {
1216 kprintf("%s: dangling device\n", devtoname(pdev
));
1221 /* no channel available, create vchannel */
1222 if (dir
== PCMDIR_PLAY
&&
1223 pcm_dev
->vchancount
> 0 &&
1224 pcm_dev
->vchancount
< snd_maxautovchans
&&
1225 pcm_dev
->devcount
< PCMMAXCHAN
) {
1226 err
= pcm_setvchans(pcm_dev
, pcm_dev
->vchancount
+ 1);
1228 goto retry_chnalloc
;
1230 * If we can't use vchans, because the main output is
1231 * blocked for something else, we should not return
1232 * any vchan create error, but the more descriptive
1234 * After all, the user didn't ask us to clone, but
1235 * only opened /dev/dsp.