4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
25 #include <sys/types.h>
27 #include <sys/errno.h>
29 #include <sys/sunddi.h>
30 #include <sys/audio/audio_oss.h>
33 #include <sys/sysmacros.h>
35 #include "audio_client.h"
37 #define OSS_FMT AFMT_S16_LE
38 #define OSS_RATE 48000
39 #define OSS_CHANNELS 2
41 typedef struct ossclient ossclient_t
;
42 typedef struct ossdev ossdev_t
;
48 { AFMT_MU_LAW
, AUDIO_FORMAT_ULAW
},
49 { AFMT_A_LAW
, AUDIO_FORMAT_ALAW
},
50 { AFMT_U8
, AUDIO_FORMAT_U8
},
51 { AFMT_S8
, AUDIO_FORMAT_S8
},
52 { AFMT_S16_BE
, AUDIO_FORMAT_S16_BE
},
53 { AFMT_S16_LE
, AUDIO_FORMAT_S16_LE
},
54 { AFMT_U16_BE
, AUDIO_FORMAT_U16_BE
},
55 { AFMT_U16_LE
, AUDIO_FORMAT_U16_LE
},
56 { AFMT_S24_BE
, AUDIO_FORMAT_S24_BE
},
57 { AFMT_S24_LE
, AUDIO_FORMAT_S24_LE
},
58 { AFMT_S32_BE
, AUDIO_FORMAT_S32_BE
},
59 { AFMT_S32_LE
, AUDIO_FORMAT_S32_LE
},
60 { AFMT_S24_PACKED
, AUDIO_FORMAT_S24_PACKED
},
61 { AFMT_AC3
, AUDIO_FORMAT_AC3
},
62 { AFMT_QUERY
, AUDIO_FORMAT_NONE
}
65 /* common structure shared between both mixer and dsp nodes */
68 audio_client_t
*o_client
;
80 uint_t d_nctrl
; /* num actual controls */
81 uint_t d_nalloc
; /* num allocated controls */
82 audio_ctrl_t
**d_ctrls
; /* array of control handles */
83 oss_mixext
*d_exts
; /* array of mixer descs */
95 oss_cnt_controls(audio_ctrl_t
*ctrl
, void *arg
)
97 int *pint
= (int *)arg
;
99 audio_ctrl_desc_t desc
;
105 if (auclnt_control_describe(ctrl
, &desc
) != 0)
106 return (AUDIO_WALK_CONTINUE
);
108 if (desc
.acd_flags
& AUDIO_CTRL_FLAG_MULTI
) {
109 for (uint64_t mask
= desc
.acd_maxvalue
; mask
; mask
>>= 1) {
117 return (AUDIO_WALK_CONTINUE
);
121 * Add one entry to the OSS user control table to internal control
124 * This is used with auimpl_walk_controls. The table must be pre-
125 * allocated before it is walk'd. This includes the root and
126 * extended control markers!
129 oss_add_control(audio_ctrl_t
*ctrl
, void *arg
)
131 ossdev_t
*odev
= arg
;
132 audio_ctrl_desc_t desc
;
141 if (auclnt_control_describe(ctrl
, &desc
))
142 return (AUDIO_WALK_CONTINUE
);
147 * Add appropriate group if not already done so.
149 if (desc
.acd_flags
& AUDIO_CTRL_FLAG_PLAY
) {
150 if (!odev
->d_play_grp
) {
151 ext
= &odev
->d_exts
[odev
->d_nctrl
];
152 ext
->ctrl
= odev
->d_nctrl
;
153 ext
->control_no
= -1;
154 ext
->type
= MIXT_GROUP
;
155 ext
->desc
= MIXEXT_SCOPE_OUTPUT
;
156 ext
->timestamp
= gethrtime();
157 (void) snprintf(ext
->id
, sizeof (ext
->id
), "PLAYBACK");
158 odev
->d_play_grp
= odev
->d_nctrl
;
161 scope
= MIXEXT_SCOPE_OUTPUT
;
162 parent
= odev
->d_play_grp
;
163 } else if (desc
.acd_flags
& AUDIO_CTRL_FLAG_REC
) {
164 if (!odev
->d_rec_grp
) {
165 ext
= &odev
->d_exts
[odev
->d_nctrl
];
166 ext
->ctrl
= odev
->d_nctrl
;
167 ext
->control_no
= -1;
168 ext
->type
= MIXT_GROUP
;
169 ext
->desc
= MIXEXT_SCOPE_INPUT
;
170 ext
->timestamp
= gethrtime();
171 (void) snprintf(ext
->id
, sizeof (ext
->id
), "RECORD");
172 odev
->d_rec_grp
= odev
->d_nctrl
;
175 scope
= MIXEXT_SCOPE_INPUT
;
176 parent
= odev
->d_rec_grp
;
177 } else if (desc
.acd_flags
& AUDIO_CTRL_FLAG_MONITOR
) {
178 if (!odev
->d_mon_grp
) {
179 ext
= &odev
->d_exts
[odev
->d_nctrl
];
180 ext
->ctrl
= odev
->d_nctrl
;
181 ext
->control_no
= -1;
182 ext
->type
= MIXT_GROUP
;
183 ext
->desc
= MIXEXT_SCOPE_MONITOR
;
184 ext
->timestamp
= gethrtime();
185 (void) snprintf(ext
->id
, sizeof (ext
->id
), "MONITOR");
186 odev
->d_mon_grp
= odev
->d_nctrl
;
189 scope
= MIXEXT_SCOPE_MONITOR
;
190 parent
= odev
->d_mon_grp
;
192 if (!odev
->d_misc_grp
) {
193 ext
= &odev
->d_exts
[odev
->d_nctrl
];
194 ext
->ctrl
= odev
->d_nctrl
;
195 ext
->control_no
= -1;
196 ext
->type
= MIXT_GROUP
;
197 ext
->desc
= MIXEXT_SCOPE_OTHER
;
198 ext
->timestamp
= gethrtime();
199 (void) snprintf(ext
->id
, sizeof (ext
->id
), "MISC");
200 odev
->d_misc_grp
= odev
->d_nctrl
;
203 scope
= MIXEXT_SCOPE_OTHER
;
204 parent
= odev
->d_misc_grp
;
207 name
= desc
.acd_name
? desc
.acd_name
: "";
209 if (desc
.acd_flags
& AUDIO_CTRL_FLAG_MULTI
) {
210 ext
= &odev
->d_exts
[odev
->d_nctrl
];
211 ext
->ctrl
= odev
->d_nctrl
;
212 ext
->control_no
= -1;
213 ext
->type
= MIXT_GROUP
;
214 ext
->timestamp
= gethrtime();
215 ext
->parent
= parent
;
217 (void) snprintf(ext
->id
, sizeof (ext
->id
), "%s", name
);
218 (void) snprintf(ext
->extname
, sizeof (ext
->extname
),
220 parent
= odev
->d_nctrl
++;
223 /* Next available open entry */
224 ext
= &odev
->d_exts
[odev
->d_nctrl
];
226 /* Record the underlying control handle */
227 odev
->d_ctrls
[odev
->d_nctrl
] = ctrl
;
230 * Now setup the oss entry
233 ext
->ctrl
= odev
->d_nctrl
;
234 ext
->control_no
= -1;
235 ext
->maxvalue
= (int)desc
.acd_maxvalue
;
236 ext
->minvalue
= (int)desc
.acd_minvalue
;
237 ext
->timestamp
= gethrtime();
238 ext
->parent
= parent
;
240 /* all controls should be pollable for now */
244 * The following flags are intended to help out applications
245 * which need to figure out where to place certain controls.
246 * A few further words of guidance:
248 * Apps that just want a single master volume control should
249 * adjust the control(s) that are labelled with MIXF_PCMVOL if
250 * present. They can fall back to adjusting all MAINVOL
251 * levels instead, if no PCMVOL is present.
253 * Controls that are one type on a certain device might be a
254 * different type on another device. For example,
255 * audiopci/ak4531 can adjust input gains for individual
256 * levels, but lacks a master record gain. AC'97, on the
257 * other hand, has individual monitor gains for inputs, but
258 * only a single master recording gain.
260 if (desc
.acd_flags
& AUDIO_CTRL_FLAG_READABLE
)
261 flags
|= MIXF_READABLE
;
262 if (desc
.acd_flags
& AUDIO_CTRL_FLAG_WRITEABLE
)
263 flags
|= MIXF_WRITEABLE
;
264 if (desc
.acd_flags
& AUDIO_CTRL_FLAG_CENTIBEL
)
265 flags
|= MIXF_CENTIBEL
;
266 if (desc
.acd_flags
& AUDIO_CTRL_FLAG_DECIBEL
)
267 flags
|= MIXF_DECIBEL
;
268 if (desc
.acd_flags
& AUDIO_CTRL_FLAG_MAINVOL
)
269 flags
|= MIXF_MAINVOL
;
270 if (desc
.acd_flags
& AUDIO_CTRL_FLAG_PCMVOL
)
271 flags
|= MIXF_PCMVOL
;
272 if (desc
.acd_flags
& AUDIO_CTRL_FLAG_RECVOL
)
273 flags
|= MIXF_RECVOL
;
274 if (desc
.acd_flags
& AUDIO_CTRL_FLAG_MONVOL
)
275 flags
|= MIXF_MONVOL
;
278 (void) snprintf(ext
->id
, sizeof (ext
->id
), "%s", name
);
281 * For now just use the same extname as the real name.
283 (void) snprintf(ext
->extname
, sizeof (ext
->extname
), name
);
286 * Now we deal with various control types.
288 switch (desc
.acd_type
) {
289 case AUDIO_CTRL_TYPE_BOOLEAN
:
290 ext
->type
= MIXT_ONOFF
;
293 case AUDIO_CTRL_TYPE_STEREO
:
294 ext
->type
= MIXT_STEREOSLIDER
;
296 case AUDIO_CTRL_TYPE_MONO
:
297 ext
->type
= MIXT_MONOSLIDER
;
299 case AUDIO_CTRL_TYPE_ENUM
:
301 if (desc
.acd_flags
& AUDIO_CTRL_FLAG_MULTI
) {
303 * We turn AUDIO_CTRL_FLAG_MULTI into a group
304 * of checkboxes, since OSS can't represent it
307 mask
= desc
.acd_maxvalue
;
311 ext
= &odev
->d_exts
[odev
->d_nctrl
];
312 (void) snprintf(ext
->extname
,
313 sizeof (ext
->extname
), "%s.%s",
314 name
, desc
.acd_enum
[bit
]);
315 (void) snprintf(ext
->id
,
316 sizeof (ext
->id
), "%s",
318 ext
->ctrl
= odev
->d_nctrl
;
319 ext
->control_no
= -1;
320 ext
->parent
= parent
;
321 ext
->timestamp
= gethrtime();
322 ext
->type
= MIXT_ONOFF
;
327 odev
->d_ctrls
[odev
->d_nctrl
] = ctrl
;
333 return (AUDIO_WALK_CONTINUE
);
336 * NB: This is sufficient only for controls
337 * with a single value. It cannot express the
338 * richer bitmask capabilities.
340 ext
->type
= MIXT_ENUM
;
344 * For an enumaration, we need to figure out
345 * which values are present, and set the
346 * appropriate mask and max value.
348 bzero(ext
->enum_present
, sizeof (ext
->enum_present
));
349 mask
= desc
.acd_maxvalue
;
353 ext
->enum_present
[bit
/ 8] |=
363 case AUDIO_CTRL_TYPE_METER
:
365 /* Its an unknown or unsupported (for now) control, skip */
366 return (AUDIO_WALK_CONTINUE
);
371 return (AUDIO_WALK_CONTINUE
);
375 * Free up an OSS user land control to internal control,
379 oss_free_controls(ossdev_t
*odev
)
381 kmem_free(odev
->d_ctrls
, sizeof (audio_ctrl_t
*) * odev
->d_nalloc
);
382 kmem_free(odev
->d_exts
, sizeof (oss_mixext
) * odev
->d_nalloc
);
388 * Allocate and fill in an OSS user land controls to internal controls
389 * helper table. This is done on one audio_dev device.
392 oss_alloc_controls(ossdev_t
*odev
)
394 audio_dev_t
*d
= odev
->d_dev
;
397 oss_mixext_root
*root_data
;
399 /* Find out who many entries we need */
400 auclnt_walk_controls(d
, oss_cnt_controls
, &nctrl
);
401 nctrl
++; /* Needs space for the device root node */
402 nctrl
++; /* Needs space for the device ext marker */
403 nctrl
++; /* Needs space for the play group */
404 nctrl
++; /* Needs space for the record group */
405 nctrl
++; /* Needs space for the monitor group */
406 nctrl
++; /* Needs space for the tone group */
407 nctrl
++; /* Needs space for the 3D group */
408 nctrl
++; /* Needs space for the misc group */
410 /* Allocate the OSS to boomer helper table */
411 odev
->d_nalloc
= nctrl
;
412 odev
->d_ctrls
= kmem_zalloc(sizeof (audio_ctrl_t
*) * nctrl
, KM_SLEEP
);
413 odev
->d_exts
= kmem_zalloc(sizeof (oss_mixext
) * nctrl
, KM_SLEEP
);
416 * Setup special case outputs to output OSS routes helper tables
420 * Root node is first, that way all others parent is this one
422 ext
= &odev
->d_exts
[odev
->d_nctrl
];
425 ext
->type
= MIXT_DEVROOT
;
426 ext
->timestamp
= gethrtime();
427 (void) snprintf(ext
->id
, sizeof (ext
->id
), "DEVROOT");
429 * Root data... nobody should be using this though.
431 root_data
= (oss_mixext_root
*)&ext
->data
;
432 (void) snprintf(root_data
->name
, sizeof (root_data
->name
), "%s",
433 auclnt_get_dev_name(d
));
434 (void) snprintf(root_data
->id
, sizeof (root_data
->id
), "%s",
435 auclnt_get_dev_name(d
));
440 * Insert an extra marker -- needed to keep layout apps hapy.
441 * This prevents some apps from assuming we are in "LEGACY" mode.
443 ext
= &odev
->d_exts
[odev
->d_nctrl
];
444 ext
->ctrl
= odev
->d_nctrl
;
445 ext
->control_no
= -1;
446 ext
->type
= MIXT_MARKER
;
447 ext
->timestamp
= gethrtime();
451 /* Fill in the complete table now */
452 auclnt_walk_controls(d
, oss_add_control
, odev
);
454 /* Update the update_counter reference counter for groups */
455 for (nctrl
= 0; nctrl
< odev
->d_nctrl
; nctrl
++) {
458 ext
= &odev
->d_exts
[nctrl
];
460 while ((i
>= 0) && (i
< odev
->d_nctrl
)) {
462 ext
= &odev
->d_exts
[i
];
463 ASSERT(ext
->parent
< i
);
464 ASSERT((ext
->type
== MIXT_GROUP
) ||
465 (ext
->type
== MIXT_DEVROOT
));
466 ext
->update_counter
++;
471 ASSERT(odev
->d_nctrl
<= odev
->d_nalloc
);
475 oss_open(audio_client_t
*c
, int oflag
)
480 audio_stream_t
*isp
, *osp
;
482 isp
= auclnt_input_stream(c
);
483 osp
= auclnt_output_stream(c
);
485 /* note that OSS always uses nonblocking open() semantics */
486 if ((rv
= auclnt_open(c
, oflag
| FNDELAY
)) != 0) {
490 if ((sc
= kmem_zalloc(sizeof (*sc
), KM_NOSLEEP
)) == NULL
) {
494 auclnt_set_private(c
, sc
);
496 odev
= auclnt_get_minor_data(c
, AUDIO_MINOR_DSP
);
498 /* set a couple of common fields */
502 /* set all default parameters */
503 if (oflag
& FWRITE
) {
504 if (((rv
= auclnt_set_format(osp
, OSS_FMT
)) != 0) ||
505 ((rv
= auclnt_set_rate(osp
, OSS_RATE
)) != 0) ||
506 ((rv
= auclnt_set_channels(osp
, OSS_CHANNELS
)) != 0)) {
509 /* default to 5 fragments to provide reasonable latency */
510 auclnt_set_latency(osp
, 5, 0);
514 if (((rv
= auclnt_set_format(isp
, OSS_FMT
)) != 0) ||
515 ((rv
= auclnt_set_rate(isp
, OSS_RATE
)) != 0) ||
516 ((rv
= auclnt_set_channels(isp
, OSS_CHANNELS
)) != 0)) {
519 /* default to 5 fragments to provide reasonable latency */
520 auclnt_set_latency(isp
, 5, 0);
531 oss_close(audio_client_t
*c
)
535 sc
= auclnt_get_private(c
);
537 if (ddi_can_receive_sig() || (ddi_get_pid() == 0)) {
538 (void) auclnt_drain(c
);
541 kmem_free(sc
, sizeof (*sc
));
547 * This is used to generate an array of names for an enumeration
550 oss_set_enum(oss_mixer_enuminfo
*ei
, ushort_t nxt
, const char *name
)
554 /* Get current entry to fill in */
556 (void) snprintf(&ei
->strings
[nxt
], ((sizeof (ei
->strings
) - nxt
) - 1),
558 ei
->strindex
[n
] = nxt
;
560 /* Adjust everything for next entry */
561 nxt
+= strnlen(name
, ((sizeof (ei
->strings
) - nxt
) - 1));
562 ei
->strings
[nxt
++] = '\0';
569 * The following two functions are used to count the number of devices
570 * in under the boomer framework.
572 * We actually report the highest "index", and then if an audio device
573 * is not found, we report a bogus removed device for it in the actual
574 * ioctls. This goofiness is required to make the OSS API happy.
577 oss_dev_walker(audio_dev_t
*d
, void *arg
)
584 index
= auclnt_get_dev_index(d
);
585 if ((index
+ 1) > cnt
) {
590 return (AUDIO_WALK_CONTINUE
);
598 auclnt_walk_devs(oss_dev_walker
, &cnt
);
603 sndctl_dsp_speed(audio_client_t
*c
, int *ratep
)
610 oflag
= auclnt_get_oflag(c
);
612 (void) auclnt_set_rate(auclnt_input_stream(c
), rate
);
613 *ratep
= auclnt_get_rate(auclnt_input_stream(c
));
616 if (oflag
& FWRITE
) {
617 (void) auclnt_set_rate(auclnt_output_stream(c
), rate
);
618 *ratep
= auclnt_get_rate(auclnt_output_stream(c
));
625 sndctl_dsp_setfmt(audio_client_t
*c
, int *fmtp
)
631 oflag
= auclnt_get_oflag(c
);
633 if (*fmtp
!= AFMT_QUERY
) {
634 /* convert from OSS */
635 for (i
= 0; oss_formats
[i
].fmt
!= AUDIO_FORMAT_NONE
; i
++) {
636 if (oss_formats
[i
].oss
== *fmtp
) {
637 fmt
= oss_formats
[i
].fmt
;
641 if (fmt
== AUDIO_FORMAT_NONE
) {
642 /* if format not known, return */
646 if (oflag
& FWRITE
) {
647 (void) auclnt_set_format(auclnt_output_stream(c
), fmt
);
651 (void) auclnt_set_format(auclnt_input_stream(c
), fmt
);
656 if (oflag
& FWRITE
) {
657 fmt
= auclnt_get_format(auclnt_output_stream(c
));
658 } else if (oflag
& FREAD
) {
659 fmt
= auclnt_get_format(auclnt_input_stream(c
));
662 /* convert back to OSS */
663 *(int *)fmtp
= AFMT_QUERY
;
664 for (i
= 0; oss_formats
[i
].fmt
!= AUDIO_FORMAT_NONE
; i
++) {
665 if (oss_formats
[i
].fmt
== fmt
) {
666 *(int *)fmtp
= oss_formats
[i
].oss
;
674 sndctl_dsp_getfmts(audio_client_t
*c
, int *fmtsp
)
679 * For now, we support all the standard ones. Later we might
680 * add in conditional support for AC3.
682 *fmtsp
= (AFMT_MU_LAW
| AFMT_A_LAW
|
684 AFMT_S16_LE
|AFMT_S16_BE
|
685 AFMT_S24_LE
| AFMT_S24_BE
|
686 AFMT_S32_LE
| AFMT_S32_BE
|
693 sndctl_dsp_channels(audio_client_t
*c
, int *chanp
)
698 oflag
= auclnt_get_oflag(c
);
702 if (oflag
& FWRITE
) {
703 (void) auclnt_set_channels(auclnt_output_stream(c
),
708 (void) auclnt_set_channels(auclnt_input_stream(c
),
713 if (oflag
& FWRITE
) {
714 nchan
= auclnt_get_channels(auclnt_output_stream(c
));
715 } else if (oflag
& FREAD
) {
716 nchan
= auclnt_get_channels(auclnt_input_stream(c
));
723 sndctl_dsp_stereo(audio_client_t
*c
, int *onoff
)
738 return (sndctl_dsp_channels(c
, &nchan
));
742 sndctl_dsp_post(audio_client_t
*c
)
744 if (auclnt_get_oflag(c
) & FWRITE
) {
745 audio_stream_t
*sp
= auclnt_output_stream(c
);
747 auclnt_clear_paused(sp
);
753 sndctl_dsp_getcaps(audio_client_t
*c
, int *capsp
)
758 ncaps
= auclnt_get_dev_capab(auclnt_get_dev(c
));
760 if (ncaps
& AUDIO_CLIENT_CAP_PLAY
)
761 osscaps
|= PCM_CAP_OUTPUT
;
762 if (ncaps
& AUDIO_CLIENT_CAP_RECORD
)
763 osscaps
|= PCM_CAP_INPUT
;
764 if (ncaps
& AUDIO_CLIENT_CAP_DUPLEX
)
765 osscaps
|= PCM_CAP_DUPLEX
;
768 osscaps
|= PCM_CAP_TRIGGER
| PCM_CAP_BATCH
;
769 if (!(ncaps
& AUDIO_CLIENT_CAP_OPAQUE
)) {
770 osscaps
|= PCM_CAP_FREERATE
| PCM_CAP_MULTI
;
773 /* This is the sndstat device! */
774 osscaps
= PCM_CAP_VIRTUAL
;
782 sndctl_dsp_gettrigger(audio_client_t
*c
, int *trigp
)
787 oflag
= auclnt_get_oflag(c
);
789 if (oflag
& FWRITE
) {
790 if (!auclnt_is_paused(auclnt_output_stream(c
))) {
791 triggers
|= PCM_ENABLE_OUTPUT
;
796 if (!auclnt_is_paused(auclnt_input_stream(c
))) {
797 triggers
|= PCM_ENABLE_INPUT
;
806 sndctl_dsp_settrigger(audio_client_t
*c
, int *trigp
)
812 oflag
= auclnt_get_oflag(c
);
815 if ((oflag
& FWRITE
) && (triggers
& PCM_ENABLE_OUTPUT
)) {
816 sp
= auclnt_output_stream(c
);
817 auclnt_clear_paused(sp
);
821 if ((oflag
& FREAD
) && (triggers
& PCM_ENABLE_INPUT
)) {
822 sp
= auclnt_input_stream(c
);
823 auclnt_clear_paused(sp
);
830 struct oss_legacy_volume
{
837 oss_legacy_volume_walker(audio_client_t
*c
, void *arg
)
839 struct oss_legacy_volume
*olv
= arg
;
841 if (auclnt_get_pid(c
) == olv
->pid
) {
842 if (olv
->ogain
<= 100) {
843 auclnt_set_gain(auclnt_output_stream(c
), olv
->ogain
);
845 if (olv
->igain
<= 100) {
846 auclnt_set_gain(auclnt_input_stream(c
), olv
->igain
);
849 return (AUDIO_WALK_CONTINUE
);
853 oss_set_legacy_volume(audio_client_t
*c
, uint8_t ogain
, uint8_t igain
)
855 struct oss_legacy_volume olv
;
857 olv
.pid
= auclnt_get_pid(c
);
860 auclnt_dev_walk_clients(auclnt_get_dev(c
),
861 oss_legacy_volume_walker
, &olv
);
865 sndctl_dsp_getplayvol(audio_client_t
*c
, int *volp
)
869 /* convert monophonic soft value to OSS stereo value */
870 vol
= auclnt_get_gain(auclnt_output_stream(c
));
871 *volp
= vol
| (vol
<< 8);
876 sndctl_dsp_setplayvol(audio_client_t
*c
, int *volp
)
885 auclnt_set_gain(auclnt_output_stream(c
), vol
);
886 *volp
= (vol
| (vol
<< 8));
892 sndctl_dsp_getrecvol(audio_client_t
*c
, int *volp
)
896 vol
= auclnt_get_gain(auclnt_input_stream(c
));
897 *volp
= (vol
| (vol
<< 8));
902 sndctl_dsp_setrecvol(audio_client_t
*c
, int *volp
)
911 auclnt_set_gain(auclnt_input_stream(c
), vol
);
912 *volp
= (vol
| (vol
<< 8));
918 sound_mixer_write_ogain(audio_client_t
*c
, int *volp
)
926 oss_set_legacy_volume(c
, vol
, 255);
927 *volp
= (vol
| (vol
<< 8));
932 sound_mixer_write_igain(audio_client_t
*c
, int *volp
)
940 oss_set_legacy_volume(c
, 255, vol
);
941 *volp
= (vol
| (vol
<< 8));
946 sndctl_dsp_readctl(audio_client_t
*c
, oss_digital_control
*ctl
)
948 /* SPDIF: need to add support with spdif */
950 _NOTE(ARGUNUSED(ctl
));
955 sndctl_dsp_writectl(audio_client_t
*c
, oss_digital_control
*ctl
)
957 /* SPDIF: need to add support with spdif */
959 _NOTE(ARGUNUSED(ctl
));
964 sndctl_dsp_cookedmode(audio_client_t
*c
, int *rvp
)
968 /* We are *always* in cooked mode -- at least until we have AC3. */
977 sndctl_dsp_silence(audio_client_t
*c
)
979 if (auclnt_get_oflag(c
) & FWRITE
) {
980 audio_stream_t
*sp
= auclnt_output_stream(c
);
981 auclnt_set_paused(sp
);
988 sndctl_dsp_skip(audio_client_t
*c
)
990 if (auclnt_get_oflag(c
) & FWRITE
) {
991 audio_stream_t
*sp
= auclnt_output_stream(c
);
992 auclnt_set_paused(sp
);
994 auclnt_clear_paused(sp
);
1000 sndctl_dsp_halt_input(audio_client_t
*c
)
1002 if (auclnt_get_oflag(c
) & FREAD
) {
1003 audio_stream_t
*sp
= auclnt_input_stream(c
);
1004 auclnt_set_paused(sp
);
1011 sndctl_dsp_halt_output(audio_client_t
*c
)
1013 if (auclnt_get_oflag(c
) & FWRITE
) {
1014 audio_stream_t
*sp
= auclnt_output_stream(c
);
1015 auclnt_set_paused(sp
);
1022 sndctl_dsp_halt(audio_client_t
*c
)
1024 (void) sndctl_dsp_halt_input(c
);
1025 (void) sndctl_dsp_halt_output(c
);
1030 sndctl_dsp_sync(audio_client_t
*c
)
1032 return (auclnt_drain(c
));
1036 sndctl_dsp_setfragment(audio_client_t
*c
, int *fragp
)
1042 nfrags
= (*fragp
) >> 16;
1043 if ((nfrags
>= 0x7fffU
) || (nfrags
< 2)) {
1044 /* use infinite setting... no change */
1048 fragsz
= (*fragp
) & 0xffff;
1050 /* basically too big, so, no change */
1053 bufsz
= (1U << fragsz
) * nfrags
;
1056 * Now we have our desired buffer size, but we have to
1057 * make sure we have a whole number of fragments >= 2, and
1058 * less than the maximum.
1060 bufsz
= ((*fragp
) >> 16) * (1U << (*fragp
));
1061 if (bufsz
>= 65536) {
1066 * We set the latency hints in terms of bytes, not fragments.
1068 auclnt_set_latency(auclnt_output_stream(c
), 0, bufsz
);
1069 auclnt_set_latency(auclnt_input_stream(c
), 0, bufsz
);
1072 * According to the OSS API documentation, the values provided
1073 * are nothing more than a "hint" and not to be relied upon
1074 * anyway. And we aren't obligated to report the actual
1081 sndctl_dsp_policy(audio_client_t
*c
, int *policy
)
1084 if ((hint
>= 2) && (hint
<= 10)) {
1085 auclnt_set_latency(auclnt_input_stream(c
), hint
, 0);
1086 auclnt_set_latency(auclnt_output_stream(c
), hint
, 0);
1092 * A word about recsrc, and playtgt ioctls: We don't allow ordinary DSP
1093 * applications to change port configurations, because these could have a
1094 * bad effect for other applications. Instead, these settings have to
1095 * be changed using the master mixer panel. In order to make applications
1096 * happy, we just present a single "default" source/target.
1099 sndctl_dsp_get_recsrc_names(audio_client_t
*c
, oss_mixer_enuminfo
*ei
)
1101 _NOTE(ARGUNUSED(c
));
1104 (void) snprintf(ei
->strings
, sizeof (ei
->strings
), "default");
1105 ei
->strindex
[0] = 0;
1111 sndctl_dsp_get_recsrc(audio_client_t
*c
, int *srcp
)
1113 _NOTE(ARGUNUSED(c
));
1119 sndctl_dsp_set_recsrc(audio_client_t
*c
, int *srcp
)
1121 _NOTE(ARGUNUSED(c
));
1127 sndctl_dsp_get_playtgt_names(audio_client_t
*c
, oss_mixer_enuminfo
*ei
)
1129 _NOTE(ARGUNUSED(c
));
1132 (void) snprintf(ei
->strings
, sizeof (ei
->strings
), "default");
1133 ei
->strindex
[0] = 0;
1139 sndctl_dsp_get_playtgt(audio_client_t
*c
, int *tgtp
)
1141 _NOTE(ARGUNUSED(c
));
1147 sndctl_dsp_set_playtgt(audio_client_t
*c
, int *tgtp
)
1149 _NOTE(ARGUNUSED(c
));
1155 sndctl_sysinfo(oss_sysinfo
*si
)
1157 bzero(si
, sizeof (*si
));
1158 (void) snprintf(si
->product
, sizeof (si
->product
), "SunOS Audio");
1159 (void) snprintf(si
->version
, sizeof (si
->version
), "4.0");
1160 si
->versionnum
= OSS_VERSION
;
1161 si
->numcards
= oss_cnt_devs();
1162 si
->nummixers
= si
->numcards
- 1;
1163 si
->numaudios
= si
->numcards
- 1;
1164 si
->numaudioengines
= si
->numaudios
;
1165 (void) snprintf(si
->license
, sizeof (si
->license
), "CDDL");
1170 sndctl_cardinfo(audio_client_t
*c
, oss_card_info
*ci
)
1178 if ((n
= ci
->card
) == -1) {
1180 d
= auclnt_get_dev(c
);
1181 n
= auclnt_get_dev_index(d
);
1184 d
= auclnt_hold_dev_by_index(n
);
1187 bzero(ci
, sizeof (*ci
));
1192 * If device removed (e.g. for DR), then
1193 * report a bogus removed entry.
1195 (void) snprintf(ci
->shortname
, sizeof (ci
->shortname
),
1197 (void) snprintf(ci
->longname
, sizeof (ci
->longname
),
1202 (void) snprintf(ci
->shortname
, sizeof (ci
->shortname
),
1203 "%s", auclnt_get_dev_name(d
));
1204 (void) snprintf(ci
->longname
, sizeof (ci
->longname
),
1205 "%s (%s)", auclnt_get_dev_description(d
),
1206 auclnt_get_dev_version(d
));
1209 while ((info
= auclnt_get_dev_hw_info(d
, &iter
)) != NULL
) {
1210 (void) strlcat(ci
->hw_info
, info
, sizeof (ci
->hw_info
));
1211 (void) strlcat(ci
->hw_info
, "\n", sizeof (ci
->hw_info
));
1215 * We don't report interrupt counts, ack counts (which are
1216 * just "read" interrupts, not spurious), or any other flags.
1217 * Nothing should be using any of this data anyway ... these
1218 * values were intended for 4Front's debugging purposes. In
1219 * Solaris, drivers should use interrupt kstats to report
1220 * interrupt related statistics.
1223 auclnt_release_dev(d
);
1228 audioinfo_walker(audio_engine_t
*e
, void *a
)
1230 oss_audioinfo
*si
= a
;
1231 int fmt
, nchan
, rate
, cap
;
1233 fmt
= auclnt_engine_get_format(e
);
1234 nchan
= auclnt_engine_get_channels(e
);
1235 rate
= auclnt_engine_get_rate(e
);
1236 cap
= auclnt_engine_get_capab(e
);
1238 for (int i
= 0; oss_formats
[i
].fmt
!= AUDIO_FORMAT_NONE
; i
++) {
1239 if (fmt
== oss_formats
[i
].fmt
) {
1240 if (cap
& AUDIO_CLIENT_CAP_PLAY
) {
1241 si
->oformats
|= oss_formats
[i
].oss
;
1243 if (cap
& AUDIO_CLIENT_CAP_RECORD
) {
1244 si
->iformats
|= oss_formats
[i
].oss
;
1249 si
->max_channels
= max(nchan
, si
->max_channels
);
1250 si
->max_rate
= max(rate
, si
->max_rate
);
1252 return (AUDIO_WALK_CONTINUE
);
1256 sndctl_audioinfo(audio_client_t
*c
, oss_audioinfo
*si
)
1264 if ((n
= si
->dev
) == -1) {
1266 d
= auclnt_get_dev(c
);
1267 n
= auclnt_get_dev_index(d
);
1270 n
++; /* skip pseudo device */
1271 d
= auclnt_hold_dev_by_index(n
);
1274 bzero(si
, sizeof (*si
));
1278 /* if device not present, forge a false entry */
1279 si
->card_number
= n
;
1280 si
->mixer_dev
= n
- 1;
1281 si
->legacy_device
= -1;
1283 (void) snprintf(si
->name
, sizeof (si
->name
), "<removed>");
1287 name
= auclnt_get_dev_name(d
);
1288 (void) snprintf(si
->name
, sizeof (si
->name
), "%s", name
);
1290 si
->legacy_device
= auclnt_get_dev_number(d
);
1293 auclnt_dev_walk_engines(d
, audioinfo_walker
, si
);
1295 cap
= auclnt_get_dev_capab(d
);
1297 if (cap
& AUDIO_CLIENT_CAP_DUPLEX
) {
1298 si
->caps
|= PCM_CAP_DUPLEX
;
1300 if (cap
& AUDIO_CLIENT_CAP_PLAY
) {
1301 si
->caps
|= PCM_CAP_OUTPUT
;
1303 if (cap
& AUDIO_CLIENT_CAP_RECORD
) {
1304 si
->caps
|= PCM_CAP_INPUT
;
1307 if (si
->caps
!= 0) {
1308 /* MMAP: we add PCM_CAP_MMAP when we we support it */
1309 si
->caps
|= PCM_CAP_TRIGGER
| PCM_CAP_BATCH
;
1311 si
->rate_source
= si
->dev
;
1313 /* we can convert and mix PCM formats */
1314 if (!(cap
& AUDIO_CLIENT_CAP_OPAQUE
)) {
1315 si
->min_channels
= min(2, si
->max_channels
);
1316 si
->min_rate
= min(5000, si
->max_rate
);
1317 si
->caps
|= PCM_CAP_FREERATE
| PCM_CAP_MULTI
;
1319 (void) snprintf(si
->devnode
, sizeof (si
->devnode
),
1320 "/dev/sound/%s:%ddsp",
1321 auclnt_get_dev_driver(d
), auclnt_get_dev_instance(d
));
1323 si
->enabled
= 0; /* stops apps from using us directly */
1324 si
->caps
= PCM_CAP_VIRTUAL
;
1325 (void) snprintf(si
->devnode
, sizeof (si
->devnode
),
1330 (void) snprintf(si
->handle
, sizeof (si
->handle
), "%s", name
);
1331 (void) snprintf(si
->label
, sizeof (si
->label
), "%s", name
);
1333 si
->card_number
= n
;
1334 si
->mixer_dev
= n
- 1;
1337 auclnt_release_dev(d
);
1343 sound_mixer_info(audio_client_t
*c
, mixer_info
*mi
)
1348 d
= auclnt_get_dev(c
);
1350 name
= auclnt_get_dev_name(d
);
1351 (void) snprintf(mi
->id
, sizeof (mi
->id
), "%s", name
);
1352 (void) snprintf(mi
->name
, sizeof (mi
->name
), "%s", name
);
1353 (void) snprintf(mi
->handle
, sizeof (mi
->handle
), "%s", name
);
1354 mi
->modify_counter
= (int)auclnt_dev_get_serial(d
);
1355 mi
->card_number
= auclnt_get_dev_index(d
);
1356 mi
->port_number
= 0;
1361 sound_mixer_read_devmask(audio_client_t
*c
, int *devmask
)
1363 _NOTE(ARGUNUSED(c
));
1364 *devmask
= SOUND_MASK_VOLUME
| SOUND_MASK_PCM
| SOUND_MASK_IGAIN
;
1369 sound_mixer_read_recmask(audio_client_t
*c
, int *recmask
)
1371 _NOTE(ARGUNUSED(c
));
1377 sound_mixer_read_recsrc(audio_client_t
*c
, int *recsrc
)
1379 _NOTE(ARGUNUSED(c
));
1385 sound_mixer_read_caps(audio_client_t
*c
, int *caps
)
1387 _NOTE(ARGUNUSED(c
));
1388 /* single recording source... sort of */
1389 *caps
= SOUND_CAP_EXCL_INPUT
;
1394 sndctl_mixerinfo(audio_client_t
*c
, oss_mixerinfo
*mi
)
1400 boolean_t release
= B_FALSE
;
1402 if ((n
= mi
->dev
) == -1) {
1404 d
= auclnt_get_dev(c
);
1405 n
= auclnt_get_dev_index(d
);
1409 d
= auclnt_hold_dev_by_index(n
);
1412 bzero(mi
, sizeof (*mi
));
1416 mi
->card_number
= n
;
1418 mi
->legacy_device
= -1;
1419 (void) snprintf(mi
->name
, sizeof (mi
->name
), "<removed>");
1420 (void) snprintf(mi
->id
, sizeof (mi
->id
), "<removed>");
1424 if ((odev
= auclnt_get_dev_minor_data(d
, AUDIO_MINOR_DSP
)) == NULL
) {
1426 auclnt_release_dev(d
);
1430 name
= auclnt_get_dev_name(d
);
1431 (void) snprintf(mi
->name
, sizeof (mi
->name
), "%s", name
);
1432 (void) snprintf(mi
->id
, sizeof (mi
->id
), "%s", name
);
1433 (void) snprintf(mi
->handle
, sizeof (mi
->handle
), "%s", name
);
1434 mi
->modify_counter
= (int)auclnt_dev_get_serial(d
);
1435 mi
->card_number
= auclnt_get_dev_index(d
);
1436 mi
->legacy_device
= auclnt_get_dev_number(d
);
1437 if (mi
->legacy_device
>= 0) {
1438 (void) snprintf(mi
->devnode
, sizeof (mi
->devnode
),
1439 "/dev/sound/%s:%dmixer",
1440 auclnt_get_dev_driver(d
), auclnt_get_dev_instance(d
));
1443 /* special nodes use generic sndstat node */
1444 (void) snprintf(mi
->devnode
, sizeof (mi
->devnode
),
1448 mi
->nrext
= odev
->d_nctrl
;
1451 auclnt_release_dev(d
);
1457 sndctl_dsp_getblksize(audio_client_t
*c
, int *fragsz
)
1459 int oflag
= auclnt_get_oflag(c
);
1462 *fragsz
= auclnt_get_fragsz(auclnt_output_stream(c
));
1463 else if (oflag
& FREAD
)
1464 *fragsz
= auclnt_get_fragsz(auclnt_input_stream(c
));
1470 sndctl_dsp_getospace(audio_client_t
*c
, audio_buf_info
*bi
)
1475 if ((auclnt_get_oflag(c
) & FWRITE
) == 0) {
1479 sp
= auclnt_output_stream(c
);
1480 n
= auclnt_get_nframes(sp
) - auclnt_get_count(sp
);
1482 bi
->fragsize
= auclnt_get_fragsz(sp
);
1483 bi
->fragstotal
= auclnt_get_nfrags(sp
);
1484 bi
->bytes
= (n
* auclnt_get_framesz(sp
));
1485 bi
->fragments
= bi
->bytes
/ bi
->fragsize
;
1491 sndctl_dsp_getispace(audio_client_t
*c
, audio_buf_info
*bi
)
1496 if ((auclnt_get_oflag(c
) & FREAD
) == 0) {
1500 sp
= auclnt_input_stream(c
);
1501 n
= auclnt_get_count(sp
);
1503 bi
->fragsize
= auclnt_get_fragsz(sp
);
1504 bi
->fragstotal
= auclnt_get_nfrags(sp
);
1505 bi
->bytes
= (n
* auclnt_get_framesz(sp
));
1506 bi
->fragments
= bi
->bytes
/ bi
->fragsize
;
1512 sndctl_dsp_getodelay(audio_client_t
*c
, int *bytes
)
1515 unsigned slen
, flen
;
1517 if (auclnt_get_oflag(c
) & FWRITE
) {
1518 audio_stream_t
*sp
= auclnt_output_stream(c
);
1519 framesz
= auclnt_get_framesz(sp
);
1520 auclnt_get_output_qlen(c
, &slen
, &flen
);
1521 *bytes
= (slen
+ flen
) * framesz
;
1529 sndctl_dsp_current_iptr(audio_client_t
*c
, oss_count_t
*count
)
1531 if (auclnt_get_oflag(c
) & FREAD
) {
1532 count
->samples
= auclnt_get_samples(auclnt_input_stream(c
));
1533 count
->fifo_samples
= 0; /* not quite accurate */
1536 count
->fifo_samples
= 0;
1542 sndctl_dsp_current_optr(audio_client_t
*c
, oss_count_t
*count
)
1544 unsigned samples
, fifo
;
1546 if (auclnt_get_oflag(c
) & FWRITE
) {
1547 auclnt_get_output_qlen(c
, &samples
, &fifo
);
1548 count
->samples
= samples
;
1549 count
->fifo_samples
= fifo
;
1552 count
->fifo_samples
= 0;
1558 sndctl_dsp_getoptr(audio_client_t
*c
, count_info
*ci
)
1564 bzero(ci
, sizeof (*ci
));
1565 if ((auclnt_get_oflag(c
) & FWRITE
) == 0) {
1568 sp
= auclnt_output_stream(c
);
1569 framesz
= auclnt_get_framesz(sp
);
1570 fragsz
= auclnt_get_fragsz(sp
);
1571 ci
->blocks
= auclnt_get_samples(sp
) * framesz
/ fragsz
;
1572 auclnt_set_samples(sp
, 0);
1573 ci
->bytes
= auclnt_get_tail(sp
) * framesz
;
1574 ci
->ptr
= auclnt_get_tidx(sp
) * framesz
;
1579 sndctl_dsp_getiptr(audio_client_t
*c
, count_info
*ci
)
1585 bzero(ci
, sizeof (*ci
));
1586 if ((auclnt_get_oflag(c
) & FREAD
) == 0) {
1589 sp
= auclnt_input_stream(c
);
1590 framesz
= auclnt_get_framesz(sp
);
1591 fragsz
= auclnt_get_fragsz(sp
);
1592 ci
->blocks
= auclnt_get_samples(sp
) * framesz
/ fragsz
;
1593 auclnt_set_samples(sp
, 0);
1594 ci
->bytes
= auclnt_get_head(sp
) * framesz
;
1595 ci
->ptr
= auclnt_get_hidx(sp
) * framesz
;
1600 sndctl_dsp_geterror(audio_client_t
*c
, audio_errinfo
*bi
)
1605 * Note: The use of this structure is unsafe... different
1606 * meanings for error codes are used by different implementations,
1607 * according to the spec. (Even different versions of the same
1608 * implementation could have different values.)
1610 * Rather than try to come up with a reliable solution here, we
1611 * don't use it. If you want to report errors, or see the result
1612 * of errors, use syslog.
1614 bzero(bi
, sizeof (*bi
));
1616 sp
= auclnt_output_stream(c
);
1617 fragsz
= max(auclnt_get_fragsz(sp
), 1);
1618 bi
->play_underruns
= (int)((auclnt_get_errors(sp
) + (fragsz
- 1)) /
1620 auclnt_set_errors(sp
, 0);
1622 sp
= auclnt_input_stream(c
);
1623 fragsz
= max(auclnt_get_fragsz(sp
), 1);
1624 bi
->rec_overruns
= (int)((auclnt_get_errors(sp
) + (fragsz
- 1)) /
1626 auclnt_set_errors(sp
, 0);
1632 sndctl_sun_send_number(audio_client_t
*c
, int *num
, cred_t
*cr
)
1637 if ((rv
= drv_priv(cr
)) != 0) {
1641 dev
= auclnt_get_dev(c
);
1642 auclnt_set_dev_number(dev
, *num
);
1647 oss_getversion(int *versp
)
1649 *versp
= OSS_VERSION
;
1654 oss_ioctl(audio_client_t
*c
, int cmd
, intptr_t arg
, int mode
, cred_t
*credp
,
1661 _NOTE(ARGUNUSED(credp
));
1663 sz
= OSSIOC_GETSZ(cmd
);
1665 if ((cmd
& (OSSIOC_IN
| OSSIOC_OUT
)) && sz
) {
1666 if ((data
= kmem_zalloc(sz
, KM_NOSLEEP
)) == NULL
) {
1673 if (cmd
& OSSIOC_IN
) {
1674 if ((rv
= ddi_copyin((void *)arg
, data
, sz
, mode
)) != 0) {
1681 * DSP specific ioctls
1683 case SNDCTL_DSP_HALT
:
1684 rv
= sndctl_dsp_halt(c
);
1687 case SNDCTL_DSP_SYNC
:
1688 rv
= sndctl_dsp_sync(c
);
1691 case SNDCTL_DSP_SPEED
:
1692 rv
= sndctl_dsp_speed(c
, (int *)data
);
1694 case SNDCTL_DSP_SETFMT
:
1695 rv
= sndctl_dsp_setfmt(c
, (int *)data
);
1697 case SNDCTL_DSP_GETFMTS
:
1698 rv
= sndctl_dsp_getfmts(c
, (int *)data
);
1700 case SNDCTL_DSP_STEREO
:
1701 rv
= sndctl_dsp_stereo(c
, (int *)data
);
1703 case SNDCTL_DSP_CHANNELS
:
1704 rv
= sndctl_dsp_channels(c
, (int *)data
);
1706 case SNDCTL_DSP_POST
:
1707 rv
= sndctl_dsp_post(c
);
1709 case SNDCTL_DSP_GETCAPS
:
1710 rv
= sndctl_dsp_getcaps(c
, (int *)data
);
1712 case SNDCTL_DSP_GETTRIGGER
:
1713 rv
= sndctl_dsp_gettrigger(c
, (int *)data
);
1715 case SNDCTL_DSP_SETTRIGGER
:
1716 rv
= sndctl_dsp_settrigger(c
, (int *)data
);
1718 case SNDCTL_DSP_GETPLAYVOL
:
1719 case SOUND_MIXER_READ_VOLUME
: /* legacy mixer on dsp */
1720 case SOUND_MIXER_READ_PCM
: /* legacy mixer on dsp */
1721 case SOUND_MIXER_READ_OGAIN
: /* legacy mixer on dsp */
1722 rv
= sndctl_dsp_getplayvol(c
, (int *)data
);
1724 case SOUND_MIXER_WRITE_VOLUME
: /* legacy mixer on dsp */
1725 case SOUND_MIXER_WRITE_PCM
: /* legacy mixer on dsp */
1726 case SOUND_MIXER_WRITE_OGAIN
: /* legacy mixer on dsp */
1727 rv
= sound_mixer_write_ogain(c
, (int *)data
);
1729 case SNDCTL_DSP_SETPLAYVOL
:
1730 rv
= sndctl_dsp_setplayvol(c
, (int *)data
);
1732 case SNDCTL_DSP_READCTL
:
1733 rv
= sndctl_dsp_readctl(c
, (oss_digital_control
*)data
);
1735 case SNDCTL_DSP_WRITECTL
:
1736 rv
= sndctl_dsp_writectl(c
, (oss_digital_control
*)data
);
1738 case SNDCTL_DSP_COOKEDMODE
:
1739 rv
= sndctl_dsp_cookedmode(c
, (int *)data
);
1741 case SNDCTL_DSP_SILENCE
:
1742 rv
= sndctl_dsp_silence(c
);
1744 case SNDCTL_DSP_SKIP
:
1745 rv
= sndctl_dsp_skip(c
);
1747 case SNDCTL_DSP_HALT_INPUT
:
1748 rv
= sndctl_dsp_halt_input(c
);
1750 case SNDCTL_DSP_HALT_OUTPUT
:
1751 rv
= sndctl_dsp_halt_output(c
);
1753 case SNDCTL_DSP_GET_RECSRC_NAMES
:
1754 rv
= sndctl_dsp_get_recsrc_names(c
, (oss_mixer_enuminfo
*)data
);
1756 case SNDCTL_DSP_SETFRAGMENT
:
1757 rv
= sndctl_dsp_setfragment(c
, (int *)data
);
1759 case SNDCTL_DSP_GET_RECSRC
:
1760 rv
= sndctl_dsp_get_recsrc(c
, (int *)data
);
1762 case SNDCTL_DSP_SET_RECSRC
:
1763 rv
= sndctl_dsp_set_recsrc(c
, (int *)data
);
1765 case SNDCTL_DSP_GET_PLAYTGT_NAMES
:
1766 rv
= sndctl_dsp_get_playtgt_names(c
,
1767 (oss_mixer_enuminfo
*)data
);
1769 case SNDCTL_DSP_GET_PLAYTGT
:
1770 rv
= sndctl_dsp_get_playtgt(c
, (int *)data
);
1772 case SNDCTL_DSP_SET_PLAYTGT
:
1773 rv
= sndctl_dsp_set_playtgt(c
, (int *)data
);
1775 case SNDCTL_DSP_GETRECVOL
:
1776 case SOUND_MIXER_READ_RECGAIN
: /* legacy mixer on dsp */
1777 case SOUND_MIXER_READ_RECLEV
: /* legacy mixer on dsp */
1778 case SOUND_MIXER_READ_IGAIN
: /* legacy mixer on dsp */
1779 rv
= sndctl_dsp_getrecvol(c
, (int *)data
);
1781 case SOUND_MIXER_WRITE_RECGAIN
: /* legacy mixer on dsp */
1782 case SOUND_MIXER_WRITE_RECLEV
: /* legacy mixer on dsp */
1783 case SOUND_MIXER_WRITE_IGAIN
: /* legacy mixer on dsp */
1784 rv
= sound_mixer_write_igain(c
, (int *)data
);
1786 case SNDCTL_DSP_SETRECVOL
:
1787 rv
= sndctl_dsp_setrecvol(c
, (int *)data
);
1789 case SNDCTL_DSP_SUBDIVIDE
: /* Ignored */
1790 case SNDCTL_DSP_SETDUPLEX
: /* Ignored */
1791 case SNDCTL_DSP_LOW_WATER
: /* Ignored */
1792 case SNDCTL_DSP_PROFILE
: /* Ignored */
1795 case SNDCTL_DSP_POLICY
:
1796 rv
= sndctl_dsp_policy(c
, (int *)data
);
1798 case SNDCTL_DSP_GETBLKSIZE
:
1799 rv
= sndctl_dsp_getblksize(c
, (int *)data
);
1801 case SNDCTL_DSP_GETOSPACE
:
1802 rv
= sndctl_dsp_getospace(c
, (audio_buf_info
*)data
);
1804 case SNDCTL_DSP_GETISPACE
:
1805 rv
= sndctl_dsp_getispace(c
, (audio_buf_info
*)data
);
1807 case SNDCTL_DSP_GETODELAY
:
1808 rv
= sndctl_dsp_getodelay(c
, (int *)data
);
1810 case SNDCTL_DSP_GETOPTR
:
1811 rv
= sndctl_dsp_getoptr(c
, (count_info
*)data
);
1813 case SNDCTL_DSP_GETIPTR
:
1814 rv
= sndctl_dsp_getiptr(c
, (count_info
*)data
);
1816 case SNDCTL_DSP_GETERROR
:
1817 rv
= sndctl_dsp_geterror(c
, (audio_errinfo
*)data
);
1819 case SNDCTL_DSP_CURRENT_IPTR
:
1820 rv
= sndctl_dsp_current_iptr(c
, (oss_count_t
*)data
);
1822 case SNDCTL_DSP_CURRENT_OPTR
:
1823 rv
= sndctl_dsp_current_optr(c
, (oss_count_t
*)data
);
1827 * Shared ioctls with /dev/mixer.
1829 case OSS_GETVERSION
:
1830 rv
= oss_getversion((int *)data
);
1832 case SNDCTL_CARDINFO
:
1833 rv
= sndctl_cardinfo(c
, (oss_card_info
*)data
);
1835 case SNDCTL_ENGINEINFO
:
1836 case SNDCTL_AUDIOINFO
:
1837 case SNDCTL_AUDIOINFO_EX
:
1838 rv
= sndctl_audioinfo(c
, (oss_audioinfo
*)data
);
1840 case SNDCTL_SYSINFO
:
1841 rv
= sndctl_sysinfo((oss_sysinfo
*)data
);
1843 case SNDCTL_MIXERINFO
:
1844 rv
= sndctl_mixerinfo(c
, (oss_mixerinfo
*)data
);
1846 case SOUND_MIXER_INFO
:
1847 rv
= sound_mixer_info(c
, (mixer_info
*)data
);
1851 * These are mixer ioctls that are virtualized for the DSP
1852 * device. They are accessible via either /dev/mixer or
1855 case SOUND_MIXER_READ_RECSRC
:
1856 case SOUND_MIXER_WRITE_RECSRC
:
1857 rv
= sound_mixer_read_recsrc(c
, (int *)data
);
1860 case SOUND_MIXER_READ_DEVMASK
:
1861 case SOUND_MIXER_READ_STEREODEVS
:
1862 rv
= sound_mixer_read_devmask(c
, (int *)data
);
1865 case SOUND_MIXER_READ_RECMASK
:
1866 rv
= sound_mixer_read_recmask(c
, (int *)data
);
1869 case SOUND_MIXER_READ_CAPS
:
1870 rv
= sound_mixer_read_caps(c
, (int *)data
);
1874 * Ioctls we have chosen not to support for now. Some
1875 * of these are of legacy interest only.
1877 case SNDCTL_SETSONG
:
1878 case SNDCTL_GETSONG
:
1879 case SNDCTL_DSP_SYNCGROUP
:
1880 case SNDCTL_DSP_SYNCSTART
:
1881 case SNDCTL_DSP_GET_CHNORDER
:
1882 case SNDCTL_DSP_SET_CHNORDER
:
1883 case SNDCTL_DSP_GETIPEAKS
:
1884 case SNDCTL_DSP_GETOPEAKS
:
1885 case SNDCTL_DSP_GETCHANNELMASK
:
1886 case SNDCTL_DSP_BIND_CHANNEL
:
1887 case SNDCTL_DSP_SETSYNCRO
:
1888 case SNDCTL_DSP_NONBLOCK
:
1894 if ((rv
== 0) && (cmd
& OSSIOC_OUT
)) {
1895 rv
= ddi_copyout(data
, (void *)arg
, sz
, mode
);
1903 kmem_free(data
, sz
);
1909 oss_output(audio_client_t
*c
)
1911 auclnt_pollwakeup(c
, POLLOUT
);
1915 oss_input(audio_client_t
*c
)
1917 auclnt_pollwakeup(c
, POLLIN
| POLLRDNORM
);
1921 ossmix_open(audio_client_t
*c
, int oflag
)
1927 _NOTE(ARGUNUSED(oflag
));
1929 if ((rv
= auclnt_open(c
, 0)) != 0) {
1933 if ((sc
= kmem_zalloc(sizeof (*sc
), KM_NOSLEEP
)) == NULL
) {
1937 if ((sc
->o_ss_buf
= kmem_zalloc(sc
->o_ss_sz
, KM_NOSLEEP
)) == NULL
) {
1938 kmem_free(sc
, sizeof (*sc
));
1941 auclnt_set_private(c
, sc
);
1943 odev
= auclnt_get_minor_data(c
, AUDIO_MINOR_DSP
);
1945 /* set a couple of common fields */
1947 sc
->o_ossdev
= odev
;
1953 ossmix_close(audio_client_t
*c
)
1957 sc
= auclnt_get_private(c
);
1959 kmem_free(sc
->o_ss_buf
, sc
->o_ss_sz
);
1960 kmem_free(sc
, sizeof (*sc
));
1966 sndctl_mix_nrext(audio_client_t
*c
, int *ncp
)
1971 d
= auclnt_get_dev(c
);
1973 if ((*ncp
!= -1) && (*ncp
!= (auclnt_get_dev_index(d
) - 1))) {
1977 if ((odev
= auclnt_get_dev_minor_data(d
, AUDIO_MINOR_DSP
)) == NULL
) {
1981 *ncp
= odev
->d_nctrl
;
1987 sndctl_mix_extinfo(audio_client_t
*c
, oss_mixext
*pext
)
1994 d
= auclnt_get_dev(c
);
1996 if (((dev
= pext
->dev
) != -1) && (dev
!= (auclnt_get_dev_index(d
) - 1)))
1999 if (((odev
= auclnt_get_dev_minor_data(d
, AUDIO_MINOR_DSP
)) == NULL
) ||
2000 (pext
->ctrl
>= odev
->d_nctrl
)) {
2004 bcopy(&odev
->d_exts
[pext
->ctrl
], pext
, sizeof (*pext
));
2012 sndctl_mix_enuminfo(audio_client_t
*c
, oss_mixer_enuminfo
*ei
)
2015 audio_ctrl_desc_t desc
;
2022 d
= auclnt_get_dev(c
);
2024 if ((ei
->dev
!= -1) && (ei
->dev
!= (auclnt_get_dev_index(d
) - 1)))
2027 if (((odev
= auclnt_get_dev_minor_data(d
, AUDIO_MINOR_DSP
)) == NULL
) ||
2028 (ei
->ctrl
>= odev
->d_nctrl
) ||
2029 (odev
->d_exts
[ei
->ctrl
].type
!= MIXT_ENUM
) ||
2030 ((ctrl
= odev
->d_ctrls
[ei
->ctrl
]) == NULL
) ||
2031 (auclnt_control_describe(ctrl
, &desc
) != 0)) {
2035 mask
= desc
.acd_maxvalue
;
2039 bzero(ei
->strings
, sizeof (ei
->strings
));
2040 bzero(ei
->strindex
, sizeof (ei
->strindex
));
2043 const char *name
= desc
.acd_enum
[bit
];
2044 nxt
= oss_set_enum(ei
, nxt
, name
? name
: "");
2053 sndctl_mix_read(audio_client_t
*c
, oss_mixer_value
*vr
)
2061 d
= auclnt_get_dev(c
);
2063 if ((vr
->dev
!= -1) && (vr
->dev
!= (auclnt_get_dev_index(d
) - 1)))
2066 if (((odev
= auclnt_get_dev_minor_data(d
, AUDIO_MINOR_DSP
)) == NULL
) ||
2067 (vr
->ctrl
>= odev
->d_nctrl
) ||
2068 ((ctrl
= odev
->d_ctrls
[vr
->ctrl
]) == NULL
)) {
2071 if ((rv
= auclnt_control_read(ctrl
, &v
)) == 0) {
2072 switch (odev
->d_exts
[vr
->ctrl
].type
) {
2074 /* translate this from an enum style bit mask */
2075 vr
->value
= ddi_ffs((unsigned long)v
) - 1;
2077 case MIXT_STEREOSLIDER
:
2078 vr
->value
= (int)ddi_swap16(v
& 0xffff);
2080 case MIXT_MONOSLIDER
:
2081 vr
->value
= (int)(v
| (v
<< 8));
2084 /* this could be simple, or could be part of a multi */
2085 if (odev
->d_exts
[vr
->ctrl
].enumbit
>= 0) {
2088 mask
<<= (odev
->d_exts
[vr
->ctrl
].enumbit
);
2089 vr
->value
= (v
& mask
) ? 1 : 0;
2091 vr
->value
= v
? 1 : 0;
2105 sndctl_mix_write(audio_client_t
*c
, oss_mixer_value
*vr
)
2113 d
= auclnt_get_dev(c
);
2115 if ((vr
->dev
!= -1) && (vr
->dev
!= (auclnt_get_dev_index(d
) - 1)))
2118 if (((odev
= auclnt_get_dev_minor_data(d
, AUDIO_MINOR_DSP
)) == NULL
) ||
2119 (vr
->ctrl
>= odev
->d_nctrl
) ||
2120 ((ctrl
= odev
->d_ctrls
[vr
->ctrl
]) == NULL
)) {
2124 switch (odev
->d_exts
[vr
->ctrl
].type
) {
2126 /* this could be standalone, or it could be part of a multi */
2127 if (odev
->d_exts
[vr
->ctrl
].enumbit
>= 0) {
2129 if ((rv
= auclnt_control_read(ctrl
, &v
)) != 0) {
2133 mask
<<= (odev
->d_exts
[vr
->ctrl
].enumbit
);
2144 /* translate this to an enum style bit mask */
2145 v
= 1U << vr
->value
;
2147 case MIXT_MONOSLIDER
:
2148 /* mask off high order bits */
2149 v
= vr
->value
& 0xff;
2151 case MIXT_STEREOSLIDER
:
2152 /* OSS uses reverse byte ordering */
2154 v
= ddi_swap16(vr
->value
& 0xffff);
2159 rv
= auclnt_control_write(ctrl
, v
);
2165 sndctl_mix_nrmix(audio_client_t
*c
, int *nmixp
)
2167 _NOTE(ARGUNUSED(c
));
2168 *nmixp
= oss_cnt_devs() - 1;
2173 ossmix_ioctl(audio_client_t
*c
, int cmd
, intptr_t arg
, int mode
, cred_t
*credp
,
2180 sz
= OSSIOC_GETSZ(cmd
);
2182 if ((cmd
& (OSSIOC_IN
| OSSIOC_OUT
)) && sz
) {
2183 if ((data
= kmem_zalloc(sz
, KM_NOSLEEP
)) == NULL
) {
2190 if (cmd
& OSSIOC_IN
) {
2191 if ((rv
= ddi_copyin((void *)arg
, data
, sz
, mode
)) != 0) {
2198 * Mixer specific ioctls
2200 case SNDCTL_MIX_NREXT
:
2201 rv
= sndctl_mix_nrext(c
, (int *)data
);
2203 case SNDCTL_MIX_EXTINFO
:
2204 rv
= sndctl_mix_extinfo(c
, (oss_mixext
*)data
);
2206 case SNDCTL_MIX_ENUMINFO
:
2207 rv
= sndctl_mix_enuminfo(c
, (oss_mixer_enuminfo
*)data
);
2209 case SNDCTL_MIX_READ
:
2210 rv
= sndctl_mix_read(c
, (oss_mixer_value
*)data
);
2212 case SNDCTL_MIX_WRITE
:
2213 rv
= sndctl_mix_write(c
, (oss_mixer_value
*)data
);
2215 case SNDCTL_MIX_NRMIX
:
2216 rv
= sndctl_mix_nrmix(c
, (int *)data
);
2220 * Legacy ioctls. These are treated as soft values only,
2221 * and do not affect global hardware state. For use by
2222 * legacy DSP applications.
2224 case SOUND_MIXER_READ_VOLUME
:
2225 case SOUND_MIXER_READ_PCM
:
2226 case SOUND_MIXER_READ_OGAIN
:
2227 rv
= sndctl_dsp_getplayvol(c
, (int *)data
);
2230 case SOUND_MIXER_WRITE_VOLUME
:
2231 case SOUND_MIXER_WRITE_PCM
:
2232 case SOUND_MIXER_WRITE_OGAIN
:
2233 rv
= sound_mixer_write_ogain(c
, (int *)data
);
2236 case SOUND_MIXER_READ_RECGAIN
:
2237 case SOUND_MIXER_READ_RECLEV
:
2238 case SOUND_MIXER_READ_IGAIN
:
2239 rv
= sndctl_dsp_getrecvol(c
, (int *)data
);
2242 case SOUND_MIXER_WRITE_RECGAIN
:
2243 case SOUND_MIXER_WRITE_RECLEV
:
2244 case SOUND_MIXER_WRITE_IGAIN
:
2245 rv
= sound_mixer_write_igain(c
, (int *)data
);
2248 case SOUND_MIXER_READ_RECSRC
:
2249 case SOUND_MIXER_WRITE_RECSRC
:
2250 rv
= sound_mixer_read_recsrc(c
, (int *)data
);
2253 case SOUND_MIXER_READ_DEVMASK
:
2254 case SOUND_MIXER_READ_STEREODEVS
:
2255 rv
= sound_mixer_read_devmask(c
, (int *)data
);
2258 case SOUND_MIXER_READ_RECMASK
:
2259 rv
= sound_mixer_read_recmask(c
, (int *)data
);
2262 case SOUND_MIXER_READ_CAPS
:
2263 rv
= sound_mixer_read_caps(c
, (int *)data
);
2267 * Common ioctls shared with DSP
2269 case OSS_GETVERSION
:
2270 rv
= oss_getversion((int *)data
);
2273 case SNDCTL_CARDINFO
:
2274 rv
= sndctl_cardinfo(c
, (oss_card_info
*)data
);
2277 case SNDCTL_ENGINEINFO
:
2278 case SNDCTL_AUDIOINFO
:
2279 case SNDCTL_AUDIOINFO_EX
:
2280 rv
= sndctl_audioinfo(c
, (oss_audioinfo
*)data
);
2283 case SNDCTL_SYSINFO
:
2284 rv
= sndctl_sysinfo((oss_sysinfo
*)data
);
2287 case SNDCTL_MIXERINFO
:
2288 rv
= sndctl_mixerinfo(c
, (oss_mixerinfo
*)data
);
2291 case SOUND_MIXER_INFO
:
2292 rv
= sound_mixer_info(c
, (mixer_info
*)data
);
2295 case SNDCTL_MIX_DESCRIPTION
: /* NOT SUPPORTED: tooltip */
2296 rv
= EIO
; /* OSS returns EIO for this one */
2300 * Special implementation-private ioctls.
2302 case SNDCTL_SUN_SEND_NUMBER
:
2303 rv
= sndctl_sun_send_number(c
, (int *)data
, credp
);
2307 * Legacy ioctls we don't support.
2309 case SOUND_MIXER_WRITE_MONGAIN
:
2310 case SOUND_MIXER_READ_MONGAIN
:
2311 case SOUND_MIXER_READ_BASS
:
2312 case SOUND_MIXER_READ_TREBLE
:
2313 case SOUND_MIXER_READ_SPEAKER
:
2314 case SOUND_MIXER_READ_LINE
:
2315 case SOUND_MIXER_READ_MIC
:
2316 case SOUND_MIXER_READ_CD
:
2317 case SOUND_MIXER_READ_IMIX
:
2318 case SOUND_MIXER_READ_ALTPCM
:
2319 case SOUND_MIXER_READ_SYNTH
:
2320 case SOUND_MIXER_READ_LINE1
:
2321 case SOUND_MIXER_READ_LINE2
:
2322 case SOUND_MIXER_READ_LINE3
:
2323 case SOUND_MIXER_WRITE_BASS
:
2324 case SOUND_MIXER_WRITE_TREBLE
:
2325 case SOUND_MIXER_WRITE_SPEAKER
:
2326 case SOUND_MIXER_WRITE_LINE
:
2327 case SOUND_MIXER_WRITE_MIC
:
2328 case SOUND_MIXER_WRITE_CD
:
2329 case SOUND_MIXER_WRITE_IMIX
:
2330 case SOUND_MIXER_WRITE_ALTPCM
:
2331 case SOUND_MIXER_WRITE_SYNTH
:
2332 case SOUND_MIXER_WRITE_LINE1
:
2333 case SOUND_MIXER_WRITE_LINE2
:
2334 case SOUND_MIXER_WRITE_LINE3
:
2336 * Additional ioctls we *could* support, but don't.
2338 case SNDCTL_SETSONG
:
2339 case SNDCTL_SETLABEL
:
2340 case SNDCTL_GETSONG
:
2341 case SNDCTL_GETLABEL
:
2342 case SNDCTL_MIDIINFO
:
2343 case SNDCTL_SETNAME
:
2349 if ((rv
== 0) && (cmd
& OSSIOC_OUT
)) {
2350 rv
= ddi_copyout(data
, (void *)arg
, sz
, mode
);
2358 kmem_free(data
, sz
);
2364 oss_dev_init(audio_dev_t
*dev
)
2368 odev
= kmem_zalloc(sizeof (*odev
), KM_SLEEP
);
2371 mutex_init(&odev
->d_mx
, NULL
, MUTEX_DRIVER
, NULL
);
2372 cv_init(&odev
->d_cv
, NULL
, CV_DRIVER
, NULL
);
2373 oss_alloc_controls(odev
);
2379 oss_dev_fini(void *arg
)
2381 ossdev_t
*odev
= arg
;
2384 oss_free_controls(odev
);
2385 mutex_destroy(&odev
->d_mx
);
2386 cv_destroy(&odev
->d_cv
);
2387 kmem_free(odev
, sizeof (*odev
));
2392 sndstat_printf(ossclient_t
*oc
, const char *fmt
, ...)
2397 (void) vsnprintf(oc
->o_ss_buf
+ oc
->o_ss_len
,
2398 oc
->o_ss_sz
- oc
->o_ss_len
, fmt
, va
);
2400 oc
->o_ss_len
= strlen(oc
->o_ss_buf
);
2404 sndstat_dev_walker(audio_dev_t
*d
, void *arg
)
2406 ossclient_t
*oc
= arg
;
2410 cap
= auclnt_get_dev_capab(d
);
2412 if (cap
& AUDIO_CLIENT_CAP_DUPLEX
) {
2414 } else if ((cap
& AUDIO_CLIENT_CAP_PLAY
) &&
2415 (cap
& AUDIO_CLIENT_CAP_RECORD
)) {
2416 capstr
= "INPUT,OUTPUT";
2417 } else if (cap
& AUDIO_CLIENT_CAP_PLAY
) {
2419 } else if (cap
& AUDIO_CLIENT_CAP_RECORD
) {
2426 return (AUDIO_WALK_CONTINUE
);
2428 sndstat_printf(oc
, "%d: %s %s, %s (%s)\n",
2429 auclnt_get_dev_number(d
), auclnt_get_dev_name(d
),
2430 auclnt_get_dev_description(d
), auclnt_get_dev_version(d
), capstr
);
2432 return (AUDIO_WALK_CONTINUE
);
2436 sndstat_mixer_walker(audio_dev_t
*d
, void *arg
)
2438 ossclient_t
*oc
= arg
;
2443 cap
= auclnt_get_dev_capab(d
);
2445 if ((cap
& (AUDIO_CLIENT_CAP_PLAY
|AUDIO_CLIENT_CAP_RECORD
)) == 0)
2446 return (AUDIO_WALK_CONTINUE
);
2448 sndstat_printf(oc
, "%d: %s %s, %s\n",
2449 auclnt_get_dev_number(d
), auclnt_get_dev_name(d
),
2450 auclnt_get_dev_description(d
), auclnt_get_dev_version(d
));
2452 while ((info
= auclnt_get_dev_hw_info(d
, &iter
)) != NULL
) {
2453 sndstat_printf(oc
, "\t%s\n", info
);
2455 return (AUDIO_WALK_CONTINUE
);
2459 ossmix_write(audio_client_t
*c
, struct uio
*uio
, cred_t
*cr
)
2461 /* write on sndstat is a no-op */
2462 _NOTE(ARGUNUSED(c
));
2463 _NOTE(ARGUNUSED(uio
));
2464 _NOTE(ARGUNUSED(cr
));
2470 ossmix_read(audio_client_t
*c
, struct uio
*uio
, cred_t
*cr
)
2476 _NOTE(ARGUNUSED(cr
));
2478 if (uio
->uio_resid
== 0) {
2482 oc
= auclnt_get_private(c
);
2484 mutex_enter(&oc
->o_ss_lock
);
2486 if (oc
->o_ss_off
== 0) {
2488 sndstat_printf(oc
, "SunOS Audio Framework\n");
2490 sndstat_printf(oc
, "\nAudio Devices:\n");
2491 auclnt_walk_devs_by_number(sndstat_dev_walker
, oc
);
2493 sndstat_printf(oc
, "\nMixers:\n");
2494 auclnt_walk_devs_by_number(sndstat_mixer_walker
, oc
);
2498 * For simplicity's sake, we implement a non-seekable device. We could
2499 * support seekability, but offsets would be rather meaningless between
2502 n
= min(uio
->uio_resid
, (oc
->o_ss_len
- oc
->o_ss_off
));
2504 rv
= uiomove(oc
->o_ss_buf
+ oc
->o_ss_off
, n
, UIO_READ
, uio
);
2512 * end-of-file reached... clear the sndstat buffer so that
2513 * subsequent reads will get the latest data.
2515 oc
->o_ss_off
= oc
->o_ss_len
= 0;
2517 mutex_exit(&oc
->o_ss_lock
);
2522 oss_read(audio_client_t
*c
, struct uio
*uio
, cred_t
*cr
)
2524 _NOTE(ARGUNUSED(cr
));
2526 auclnt_clear_paused(auclnt_input_stream(c
));
2528 return (auclnt_read(c
, uio
));
2532 oss_write(audio_client_t
*c
, struct uio
*uio
, cred_t
*cr
)
2534 _NOTE(ARGUNUSED(cr
));
2536 auclnt_clear_paused(auclnt_output_stream(c
));
2538 return (auclnt_write(c
, uio
));
2542 oss_chpoll(audio_client_t
*c
, short events
, int anyyet
, short *reventsp
,
2543 struct pollhead
**phpp
)
2545 return (auclnt_chpoll(c
, events
, anyyet
, reventsp
, phpp
));
2548 static struct audio_client_ops oss_ops
= {
2564 static struct audio_client_ops ossmix_ops
= {
2582 /* nearly the same as ossxmix; different minor name helps devfsadm */
2583 static struct audio_client_ops sndstat_ops
= {
2585 NULL
, /* dev_init */
2586 NULL
, /* dev_fini */
2602 auimpl_oss_init(void)
2604 auclnt_register_ops(AUDIO_MINOR_DSP
, &oss_ops
);
2605 auclnt_register_ops(AUDIO_MINOR_MIXER
, &ossmix_ops
);
2606 auclnt_register_ops(AUDIO_MINOR_SNDSTAT
, &sndstat_ops
);