188447a05SGarrett D'Amore /*
288447a05SGarrett D'Amore * CDDL HEADER START
388447a05SGarrett D'Amore *
488447a05SGarrett D'Amore * The contents of this file are subject to the terms of the
588447a05SGarrett D'Amore * Common Development and Distribution License (the "License").
688447a05SGarrett D'Amore * You may not use this file except in compliance with the License.
788447a05SGarrett D'Amore *
888447a05SGarrett D'Amore * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
988447a05SGarrett D'Amore * or http://www.opensolaris.org/os/licensing.
1088447a05SGarrett D'Amore * See the License for the specific language governing permissions
1188447a05SGarrett D'Amore * and limitations under the License.
1288447a05SGarrett D'Amore *
1388447a05SGarrett D'Amore * When distributing Covered Code, include this CDDL HEADER in each
1488447a05SGarrett D'Amore * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1588447a05SGarrett D'Amore * If applicable, add the following below this CDDL HEADER, with the
1688447a05SGarrett D'Amore * fields enclosed by brackets "[]" replaced with your own identifying
1788447a05SGarrett D'Amore * information: Portions Copyright [yyyy] [name of copyright owner]
1888447a05SGarrett D'Amore *
1988447a05SGarrett D'Amore * CDDL HEADER END
2088447a05SGarrett D'Amore */
2188447a05SGarrett D'Amore /*
22*2c30fa45SGarrett D'Amore * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
2388447a05SGarrett D'Amore */
2488447a05SGarrett D'Amore
2588447a05SGarrett D'Amore #include <sys/types.h>
2688447a05SGarrett D'Amore #include <sys/open.h>
2788447a05SGarrett D'Amore #include <sys/errno.h>
2888447a05SGarrett D'Amore #include <sys/ddi.h>
2988447a05SGarrett D'Amore #include <sys/sunddi.h>
3088447a05SGarrett D'Amore #include <sys/audio/audio_oss.h>
3188447a05SGarrett D'Amore #include <sys/file.h>
3288447a05SGarrett D'Amore #include <sys/note.h>
3388447a05SGarrett D'Amore #include <sys/sysmacros.h>
3488447a05SGarrett D'Amore #include <sys/list.h>
3588447a05SGarrett D'Amore #include "audio_client.h"
3688447a05SGarrett D'Amore
3788447a05SGarrett D'Amore #define OSS_FMT AFMT_S16_LE
3888447a05SGarrett D'Amore #define OSS_RATE 48000
3988447a05SGarrett D'Amore #define OSS_CHANNELS 2
4088447a05SGarrett D'Amore
4188447a05SGarrett D'Amore typedef struct ossclient ossclient_t;
4288447a05SGarrett D'Amore typedef struct ossdev ossdev_t;
4388447a05SGarrett D'Amore
4488447a05SGarrett D'Amore static const struct {
4588447a05SGarrett D'Amore int oss;
4688447a05SGarrett D'Amore int fmt;
4788447a05SGarrett D'Amore } oss_formats[] = {
4888447a05SGarrett D'Amore { AFMT_MU_LAW, AUDIO_FORMAT_ULAW },
4988447a05SGarrett D'Amore { AFMT_A_LAW, AUDIO_FORMAT_ALAW },
5088447a05SGarrett D'Amore { AFMT_U8, AUDIO_FORMAT_U8 },
5188447a05SGarrett D'Amore { AFMT_S8, AUDIO_FORMAT_S8 },
5288447a05SGarrett D'Amore { AFMT_S16_BE, AUDIO_FORMAT_S16_BE },
5388447a05SGarrett D'Amore { AFMT_S16_LE, AUDIO_FORMAT_S16_LE },
5488447a05SGarrett D'Amore { AFMT_U16_BE, AUDIO_FORMAT_U16_BE },
5588447a05SGarrett D'Amore { AFMT_U16_LE, AUDIO_FORMAT_U16_LE },
5688447a05SGarrett D'Amore { AFMT_S24_BE, AUDIO_FORMAT_S24_BE },
5788447a05SGarrett D'Amore { AFMT_S24_LE, AUDIO_FORMAT_S24_LE },
5888447a05SGarrett D'Amore { AFMT_S32_BE, AUDIO_FORMAT_S32_BE },
5988447a05SGarrett D'Amore { AFMT_S32_LE, AUDIO_FORMAT_S32_LE },
6088447a05SGarrett D'Amore { AFMT_S24_PACKED, AUDIO_FORMAT_S24_PACKED },
6188447a05SGarrett D'Amore { AFMT_AC3, AUDIO_FORMAT_AC3 },
6288447a05SGarrett D'Amore { AFMT_QUERY, AUDIO_FORMAT_NONE }
6388447a05SGarrett D'Amore };
6488447a05SGarrett D'Amore
6588447a05SGarrett D'Amore /* common structure shared between both mixer and dsp nodes */
6688447a05SGarrett D'Amore struct ossclient {
6788447a05SGarrett D'Amore ossdev_t *o_ossdev;
6888447a05SGarrett D'Amore audio_client_t *o_client;
6988447a05SGarrett D'Amore /* sndstat */
7088447a05SGarrett D'Amore kmutex_t o_ss_lock;
7188447a05SGarrett D'Amore char *o_ss_buf;
7288447a05SGarrett D'Amore size_t o_ss_len;
7388447a05SGarrett D'Amore size_t o_ss_sz;
7488447a05SGarrett D'Amore size_t o_ss_off;
7588447a05SGarrett D'Amore };
7688447a05SGarrett D'Amore
7788447a05SGarrett D'Amore struct ossdev {
7888447a05SGarrett D'Amore audio_dev_t *d_dev;
7988447a05SGarrett D'Amore
8088447a05SGarrett D'Amore uint_t d_nctrl; /* num actual controls */
8188447a05SGarrett D'Amore uint_t d_nalloc; /* num allocated controls */
8288447a05SGarrett D'Amore audio_ctrl_t **d_ctrls; /* array of control handles */
8388447a05SGarrett D'Amore oss_mixext *d_exts; /* array of mixer descs */
8488447a05SGarrett D'Amore
8588447a05SGarrett D'Amore int d_play_grp;
8688447a05SGarrett D'Amore int d_rec_grp;
8788447a05SGarrett D'Amore int d_mon_grp;
8888447a05SGarrett D'Amore int d_misc_grp;
8988447a05SGarrett D'Amore
9088447a05SGarrett D'Amore kmutex_t d_mx;
9188447a05SGarrett D'Amore kcondvar_t d_cv;
9288447a05SGarrett D'Amore };
9388447a05SGarrett D'Amore
9488447a05SGarrett D'Amore static int
oss_cnt_controls(audio_ctrl_t * ctrl,void * arg)9588447a05SGarrett D'Amore oss_cnt_controls(audio_ctrl_t *ctrl, void *arg)
9688447a05SGarrett D'Amore {
9788447a05SGarrett D'Amore int *pint = (int *)arg;
9888447a05SGarrett D'Amore int cnt;
9988447a05SGarrett D'Amore audio_ctrl_desc_t desc;
10088447a05SGarrett D'Amore
10188447a05SGarrett D'Amore cnt = *pint;
10288447a05SGarrett D'Amore cnt++;
10388447a05SGarrett D'Amore *pint = cnt;
10488447a05SGarrett D'Amore
10588447a05SGarrett D'Amore if (auclnt_control_describe(ctrl, &desc) != 0)
10688447a05SGarrett D'Amore return (AUDIO_WALK_CONTINUE);
10788447a05SGarrett D'Amore
10888447a05SGarrett D'Amore if (desc.acd_flags & AUDIO_CTRL_FLAG_MULTI) {
10988447a05SGarrett D'Amore for (uint64_t mask = desc.acd_maxvalue; mask; mask >>= 1) {
11088447a05SGarrett D'Amore if (mask & 1) {
11188447a05SGarrett D'Amore cnt++;
11288447a05SGarrett D'Amore }
11388447a05SGarrett D'Amore }
11488447a05SGarrett D'Amore *pint = cnt;
11588447a05SGarrett D'Amore }
11688447a05SGarrett D'Amore
11788447a05SGarrett D'Amore return (AUDIO_WALK_CONTINUE);
11888447a05SGarrett D'Amore }
11988447a05SGarrett D'Amore
12088447a05SGarrett D'Amore /*
12188447a05SGarrett D'Amore * Add one entry to the OSS user control table to internal control
12288447a05SGarrett D'Amore * helper table.
12388447a05SGarrett D'Amore *
12488447a05SGarrett D'Amore * This is used with auimpl_walk_controls. The table must be pre-
12588447a05SGarrett D'Amore * allocated before it is walk'd. This includes the root and
12688447a05SGarrett D'Amore * extended control markers!
12788447a05SGarrett D'Amore */
12888447a05SGarrett D'Amore static int
oss_add_control(audio_ctrl_t * ctrl,void * arg)12988447a05SGarrett D'Amore oss_add_control(audio_ctrl_t *ctrl, void *arg)
13088447a05SGarrett D'Amore {
13188447a05SGarrett D'Amore ossdev_t *odev = arg;
13288447a05SGarrett D'Amore audio_ctrl_desc_t desc;
13388447a05SGarrett D'Amore oss_mixext *ext;
13488447a05SGarrett D'Amore int bit;
13588447a05SGarrett D'Amore uint64_t mask;
13688447a05SGarrett D'Amore const char *name;
13788447a05SGarrett D'Amore int parent;
13888447a05SGarrett D'Amore int flags;
13988447a05SGarrett D'Amore unsigned scope;
14088447a05SGarrett D'Amore
14188447a05SGarrett D'Amore if (auclnt_control_describe(ctrl, &desc))
14288447a05SGarrett D'Amore return (AUDIO_WALK_CONTINUE);
14388447a05SGarrett D'Amore
14488447a05SGarrett D'Amore parent = 0;
14588447a05SGarrett D'Amore
14688447a05SGarrett D'Amore /*
14788447a05SGarrett D'Amore * Add appropriate group if not already done so.
14888447a05SGarrett D'Amore */
14988447a05SGarrett D'Amore if (desc.acd_flags & AUDIO_CTRL_FLAG_PLAY) {
15088447a05SGarrett D'Amore if (!odev->d_play_grp) {
15188447a05SGarrett D'Amore ext = &odev->d_exts[odev->d_nctrl];
15288447a05SGarrett D'Amore ext->ctrl = odev->d_nctrl;
15388447a05SGarrett D'Amore ext->control_no = -1;
15488447a05SGarrett D'Amore ext->type = MIXT_GROUP;
15588447a05SGarrett D'Amore ext->desc = MIXEXT_SCOPE_OUTPUT;
15688447a05SGarrett D'Amore ext->timestamp = gethrtime();
15788447a05SGarrett D'Amore (void) snprintf(ext->id, sizeof (ext->id), "PLAYBACK");
15888447a05SGarrett D'Amore odev->d_play_grp = odev->d_nctrl;
15988447a05SGarrett D'Amore odev->d_nctrl++;
16088447a05SGarrett D'Amore }
16188447a05SGarrett D'Amore scope = MIXEXT_SCOPE_OUTPUT;
16288447a05SGarrett D'Amore parent = odev->d_play_grp;
16388447a05SGarrett D'Amore } else if (desc.acd_flags & AUDIO_CTRL_FLAG_REC) {
16488447a05SGarrett D'Amore if (!odev->d_rec_grp) {
16588447a05SGarrett D'Amore ext = &odev->d_exts[odev->d_nctrl];
16688447a05SGarrett D'Amore ext->ctrl = odev->d_nctrl;
16788447a05SGarrett D'Amore ext->control_no = -1;
16888447a05SGarrett D'Amore ext->type = MIXT_GROUP;
16988447a05SGarrett D'Amore ext->desc = MIXEXT_SCOPE_INPUT;
17088447a05SGarrett D'Amore ext->timestamp = gethrtime();
17188447a05SGarrett D'Amore (void) snprintf(ext->id, sizeof (ext->id), "RECORD");
17288447a05SGarrett D'Amore odev->d_rec_grp = odev->d_nctrl;
17388447a05SGarrett D'Amore odev->d_nctrl++;
17488447a05SGarrett D'Amore }
17588447a05SGarrett D'Amore scope = MIXEXT_SCOPE_INPUT;
17688447a05SGarrett D'Amore parent = odev->d_rec_grp;
17788447a05SGarrett D'Amore } else if (desc.acd_flags & AUDIO_CTRL_FLAG_MONITOR) {
17888447a05SGarrett D'Amore if (!odev->d_mon_grp) {
17988447a05SGarrett D'Amore ext = &odev->d_exts[odev->d_nctrl];
18088447a05SGarrett D'Amore ext->ctrl = odev->d_nctrl;
18188447a05SGarrett D'Amore ext->control_no = -1;
18288447a05SGarrett D'Amore ext->type = MIXT_GROUP;
18388447a05SGarrett D'Amore ext->desc = MIXEXT_SCOPE_MONITOR;
18488447a05SGarrett D'Amore ext->timestamp = gethrtime();
18588447a05SGarrett D'Amore (void) snprintf(ext->id, sizeof (ext->id), "MONITOR");
18688447a05SGarrett D'Amore odev->d_mon_grp = odev->d_nctrl;
18788447a05SGarrett D'Amore odev->d_nctrl++;
18888447a05SGarrett D'Amore }
18988447a05SGarrett D'Amore scope = MIXEXT_SCOPE_MONITOR;
19088447a05SGarrett D'Amore parent = odev->d_mon_grp;
19188447a05SGarrett D'Amore } else {
19288447a05SGarrett D'Amore if (!odev->d_misc_grp) {
19388447a05SGarrett D'Amore ext = &odev->d_exts[odev->d_nctrl];
19488447a05SGarrett D'Amore ext->ctrl = odev->d_nctrl;
19588447a05SGarrett D'Amore ext->control_no = -1;
19688447a05SGarrett D'Amore ext->type = MIXT_GROUP;
19788447a05SGarrett D'Amore ext->desc = MIXEXT_SCOPE_OTHER;
19888447a05SGarrett D'Amore ext->timestamp = gethrtime();
19988447a05SGarrett D'Amore (void) snprintf(ext->id, sizeof (ext->id), "MISC");
20088447a05SGarrett D'Amore odev->d_misc_grp = odev->d_nctrl;
20188447a05SGarrett D'Amore odev->d_nctrl++;
20288447a05SGarrett D'Amore }
20388447a05SGarrett D'Amore scope = MIXEXT_SCOPE_OTHER;
20488447a05SGarrett D'Amore parent = odev->d_misc_grp;
20588447a05SGarrett D'Amore }
20688447a05SGarrett D'Amore
20788447a05SGarrett D'Amore name = desc.acd_name ? desc.acd_name : "";
20888447a05SGarrett D'Amore
20988447a05SGarrett D'Amore if (desc.acd_flags & AUDIO_CTRL_FLAG_MULTI) {
21088447a05SGarrett D'Amore ext = &odev->d_exts[odev->d_nctrl];
21188447a05SGarrett D'Amore ext->ctrl = odev->d_nctrl;
21288447a05SGarrett D'Amore ext->control_no = -1;
21388447a05SGarrett D'Amore ext->type = MIXT_GROUP;
21488447a05SGarrett D'Amore ext->timestamp = gethrtime();
21588447a05SGarrett D'Amore ext->parent = parent;
21688447a05SGarrett D'Amore ext->desc = scope;
21788447a05SGarrett D'Amore (void) snprintf(ext->id, sizeof (ext->id), "%s", name);
21888447a05SGarrett D'Amore (void) snprintf(ext->extname, sizeof (ext->extname),
21988447a05SGarrett D'Amore "%s", name);
22088447a05SGarrett D'Amore parent = odev->d_nctrl++;
22188447a05SGarrett D'Amore }
22288447a05SGarrett D'Amore
22388447a05SGarrett D'Amore /* Next available open entry */
22488447a05SGarrett D'Amore ext = &odev->d_exts[odev->d_nctrl];
22588447a05SGarrett D'Amore
22688447a05SGarrett D'Amore /* Record the underlying control handle */
22788447a05SGarrett D'Amore odev->d_ctrls[odev->d_nctrl] = ctrl;
22888447a05SGarrett D'Amore
22988447a05SGarrett D'Amore /*
23088447a05SGarrett D'Amore * Now setup the oss entry
23188447a05SGarrett D'Amore */
23288447a05SGarrett D'Amore
23388447a05SGarrett D'Amore ext->ctrl = odev->d_nctrl;
23488447a05SGarrett D'Amore ext->control_no = -1;
23588447a05SGarrett D'Amore ext->maxvalue = (int)desc.acd_maxvalue;
23688447a05SGarrett D'Amore ext->minvalue = (int)desc.acd_minvalue;
23788447a05SGarrett D'Amore ext->timestamp = gethrtime();
23888447a05SGarrett D'Amore ext->parent = parent;
23988447a05SGarrett D'Amore ext->desc = scope;
24088447a05SGarrett D'Amore /* all controls should be pollable for now */
24188447a05SGarrett D'Amore flags = MIXF_POLL;
24288447a05SGarrett D'Amore
24388447a05SGarrett D'Amore /*
24488447a05SGarrett D'Amore * The following flags are intended to help out applications
24588447a05SGarrett D'Amore * which need to figure out where to place certain controls.
24688447a05SGarrett D'Amore * A few further words of guidance:
24788447a05SGarrett D'Amore *
24888447a05SGarrett D'Amore * Apps that just want a single master volume control should
24988447a05SGarrett D'Amore * adjust the control(s) that are labelled with MIXF_PCMVOL if
25088447a05SGarrett D'Amore * present. They can fall back to adjusting all MAINVOL
25188447a05SGarrett D'Amore * levels instead, if no PCMVOL is present.
25288447a05SGarrett D'Amore *
25388447a05SGarrett D'Amore * Controls that are one type on a certain device might be a
25488447a05SGarrett D'Amore * different type on another device. For example,
25588447a05SGarrett D'Amore * audiopci/ak4531 can adjust input gains for individual
25688447a05SGarrett D'Amore * levels, but lacks a master record gain. AC'97, on the
25788447a05SGarrett D'Amore * other hand, has individual monitor gains for inputs, but
25888447a05SGarrett D'Amore * only a single master recording gain.
25988447a05SGarrett D'Amore */
26088447a05SGarrett D'Amore if (desc.acd_flags & AUDIO_CTRL_FLAG_READABLE)
26188447a05SGarrett D'Amore flags |= MIXF_READABLE;
26288447a05SGarrett D'Amore if (desc.acd_flags & AUDIO_CTRL_FLAG_WRITEABLE)
26388447a05SGarrett D'Amore flags |= MIXF_WRITEABLE;
26488447a05SGarrett D'Amore if (desc.acd_flags & AUDIO_CTRL_FLAG_CENTIBEL)
26588447a05SGarrett D'Amore flags |= MIXF_CENTIBEL;
26688447a05SGarrett D'Amore if (desc.acd_flags & AUDIO_CTRL_FLAG_DECIBEL)
26788447a05SGarrett D'Amore flags |= MIXF_DECIBEL;
26888447a05SGarrett D'Amore if (desc.acd_flags & AUDIO_CTRL_FLAG_MAINVOL)
26988447a05SGarrett D'Amore flags |= MIXF_MAINVOL;
27088447a05SGarrett D'Amore if (desc.acd_flags & AUDIO_CTRL_FLAG_PCMVOL)
27188447a05SGarrett D'Amore flags |= MIXF_PCMVOL;
27288447a05SGarrett D'Amore if (desc.acd_flags & AUDIO_CTRL_FLAG_RECVOL)
27388447a05SGarrett D'Amore flags |= MIXF_RECVOL;
27488447a05SGarrett D'Amore if (desc.acd_flags & AUDIO_CTRL_FLAG_MONVOL)
27588447a05SGarrett D'Amore flags |= MIXF_MONVOL;
27688447a05SGarrett D'Amore ext->flags = flags;
27788447a05SGarrett D'Amore
27888447a05SGarrett D'Amore (void) snprintf(ext->id, sizeof (ext->id), "%s", name);
27988447a05SGarrett D'Amore
28088447a05SGarrett D'Amore /*
28188447a05SGarrett D'Amore * For now just use the same extname as the real name.
28288447a05SGarrett D'Amore */
28388447a05SGarrett D'Amore (void) snprintf(ext->extname, sizeof (ext->extname), name);
28488447a05SGarrett D'Amore
28588447a05SGarrett D'Amore /*
28688447a05SGarrett D'Amore * Now we deal with various control types.
28788447a05SGarrett D'Amore */
28888447a05SGarrett D'Amore switch (desc.acd_type) {
28988447a05SGarrett D'Amore case AUDIO_CTRL_TYPE_BOOLEAN:
29088447a05SGarrett D'Amore ext->type = MIXT_ONOFF;
29188447a05SGarrett D'Amore ext->enumbit = -1;
29288447a05SGarrett D'Amore break;
29388447a05SGarrett D'Amore case AUDIO_CTRL_TYPE_STEREO:
29488447a05SGarrett D'Amore ext->type = MIXT_STEREOSLIDER;
29588447a05SGarrett D'Amore break;
29688447a05SGarrett D'Amore case AUDIO_CTRL_TYPE_MONO:
29788447a05SGarrett D'Amore ext->type = MIXT_MONOSLIDER;
29888447a05SGarrett D'Amore break;
29988447a05SGarrett D'Amore case AUDIO_CTRL_TYPE_ENUM:
30088447a05SGarrett D'Amore
30188447a05SGarrett D'Amore if (desc.acd_flags & AUDIO_CTRL_FLAG_MULTI) {
30288447a05SGarrett D'Amore /*
30388447a05SGarrett D'Amore * We turn AUDIO_CTRL_FLAG_MULTI into a group
30488447a05SGarrett D'Amore * of checkboxes, since OSS can't represent it
30588447a05SGarrett D'Amore * natively.
30688447a05SGarrett D'Amore */
30788447a05SGarrett D'Amore mask = desc.acd_maxvalue;
30888447a05SGarrett D'Amore bit = 0;
30988447a05SGarrett D'Amore while (mask) {
31088447a05SGarrett D'Amore if (mask & 1) {
31188447a05SGarrett D'Amore ext = &odev->d_exts[odev->d_nctrl];
31288447a05SGarrett D'Amore (void) snprintf(ext->extname,
31388447a05SGarrett D'Amore sizeof (ext->extname), "%s.%s",
31488447a05SGarrett D'Amore name, desc.acd_enum[bit]);
31588447a05SGarrett D'Amore (void) snprintf(ext->id,
31688447a05SGarrett D'Amore sizeof (ext->id), "%s",
31788447a05SGarrett D'Amore desc.acd_enum[bit]);
31888447a05SGarrett D'Amore ext->ctrl = odev->d_nctrl;
31988447a05SGarrett D'Amore ext->control_no = -1;
32088447a05SGarrett D'Amore ext->parent = parent;
32188447a05SGarrett D'Amore ext->timestamp = gethrtime();
32288447a05SGarrett D'Amore ext->type = MIXT_ONOFF;
32388447a05SGarrett D'Amore ext->minvalue = 0;
32488447a05SGarrett D'Amore ext->maxvalue = 1;
32588447a05SGarrett D'Amore ext->enumbit = bit;
32688447a05SGarrett D'Amore ext->flags = flags;
32788447a05SGarrett D'Amore odev->d_ctrls[odev->d_nctrl] = ctrl;
32888447a05SGarrett D'Amore odev->d_nctrl++;
32988447a05SGarrett D'Amore }
33088447a05SGarrett D'Amore bit++;
33188447a05SGarrett D'Amore mask >>= 1;
33288447a05SGarrett D'Amore }
33388447a05SGarrett D'Amore return (AUDIO_WALK_CONTINUE);
33488447a05SGarrett D'Amore } else {
33588447a05SGarrett D'Amore /*
33688447a05SGarrett D'Amore * NB: This is sufficient only for controls
33788447a05SGarrett D'Amore * with a single value. It cannot express the
33888447a05SGarrett D'Amore * richer bitmask capabilities.
33988447a05SGarrett D'Amore */
34088447a05SGarrett D'Amore ext->type = MIXT_ENUM;
34188447a05SGarrett D'Amore ext->minvalue = 0;
34288447a05SGarrett D'Amore
34388447a05SGarrett D'Amore /*
34488447a05SGarrett D'Amore * For an enumaration, we need to figure out
34588447a05SGarrett D'Amore * which values are present, and set the
34688447a05SGarrett D'Amore * appropriate mask and max value.
34788447a05SGarrett D'Amore */
34888447a05SGarrett D'Amore bzero(ext->enum_present, sizeof (ext->enum_present));
34988447a05SGarrett D'Amore mask = desc.acd_maxvalue;
35088447a05SGarrett D'Amore bit = 0;
35188447a05SGarrett D'Amore while (mask) {
35288447a05SGarrett D'Amore if (mask & 1) {
35388447a05SGarrett D'Amore ext->enum_present[bit / 8] |=
35488447a05SGarrett D'Amore (1 << (bit % 8));
35588447a05SGarrett D'Amore }
35688447a05SGarrett D'Amore mask >>= 1;
35788447a05SGarrett D'Amore bit++;
35888447a05SGarrett D'Amore }
35988447a05SGarrett D'Amore ext->maxvalue = bit;
36088447a05SGarrett D'Amore }
36188447a05SGarrett D'Amore break;
36288447a05SGarrett D'Amore
36388447a05SGarrett D'Amore case AUDIO_CTRL_TYPE_METER:
36488447a05SGarrett D'Amore default:
36588447a05SGarrett D'Amore /* Its an unknown or unsupported (for now) control, skip */
36688447a05SGarrett D'Amore return (AUDIO_WALK_CONTINUE);
36788447a05SGarrett D'Amore }
36888447a05SGarrett D'Amore
36988447a05SGarrett D'Amore odev->d_nctrl++;
37088447a05SGarrett D'Amore
37188447a05SGarrett D'Amore return (AUDIO_WALK_CONTINUE);
37288447a05SGarrett D'Amore }
37388447a05SGarrett D'Amore
37488447a05SGarrett D'Amore /*
37588447a05SGarrett D'Amore * Free up an OSS user land control to internal control,
37688447a05SGarrett D'Amore * helper table.
37788447a05SGarrett D'Amore */
37888447a05SGarrett D'Amore static void
oss_free_controls(ossdev_t * odev)37988447a05SGarrett D'Amore oss_free_controls(ossdev_t *odev)
38088447a05SGarrett D'Amore {
38188447a05SGarrett D'Amore kmem_free(odev->d_ctrls, sizeof (audio_ctrl_t *) * odev->d_nalloc);
38288447a05SGarrett D'Amore kmem_free(odev->d_exts, sizeof (oss_mixext) * odev->d_nalloc);
38388447a05SGarrett D'Amore odev->d_nctrl = 0;
38488447a05SGarrett D'Amore odev->d_nalloc = 0;
38588447a05SGarrett D'Amore }
38688447a05SGarrett D'Amore
38788447a05SGarrett D'Amore /*
38888447a05SGarrett D'Amore * Allocate and fill in an OSS user land controls to internal controls
38988447a05SGarrett D'Amore * helper table. This is done on one audio_dev device.
39088447a05SGarrett D'Amore */
39188447a05SGarrett D'Amore static void
oss_alloc_controls(ossdev_t * odev)39288447a05SGarrett D'Amore oss_alloc_controls(ossdev_t *odev)
39388447a05SGarrett D'Amore {
39488447a05SGarrett D'Amore audio_dev_t *d = odev->d_dev;
39588447a05SGarrett D'Amore int nctrl = 0;
39688447a05SGarrett D'Amore oss_mixext *ext;
39788447a05SGarrett D'Amore oss_mixext_root *root_data;
39888447a05SGarrett D'Amore
39988447a05SGarrett D'Amore /* Find out who many entries we need */
40088447a05SGarrett D'Amore auclnt_walk_controls(d, oss_cnt_controls, &nctrl);
40188447a05SGarrett D'Amore nctrl++; /* Needs space for the device root node */
40288447a05SGarrett D'Amore nctrl++; /* Needs space for the device ext marker */
40388447a05SGarrett D'Amore nctrl++; /* Needs space for the play group */
40488447a05SGarrett D'Amore nctrl++; /* Needs space for the record group */
40588447a05SGarrett D'Amore nctrl++; /* Needs space for the monitor group */
40688447a05SGarrett D'Amore nctrl++; /* Needs space for the tone group */
40788447a05SGarrett D'Amore nctrl++; /* Needs space for the 3D group */
40888447a05SGarrett D'Amore nctrl++; /* Needs space for the misc group */
40988447a05SGarrett D'Amore
41088447a05SGarrett D'Amore /* Allocate the OSS to boomer helper table */
41188447a05SGarrett D'Amore odev->d_nalloc = nctrl;
41288447a05SGarrett D'Amore odev->d_ctrls = kmem_zalloc(sizeof (audio_ctrl_t *) * nctrl, KM_SLEEP);
41388447a05SGarrett D'Amore odev->d_exts = kmem_zalloc(sizeof (oss_mixext) * nctrl, KM_SLEEP);
41488447a05SGarrett D'Amore
41588447a05SGarrett D'Amore /*
41688447a05SGarrett D'Amore * Setup special case outputs to output OSS routes helper tables
41788447a05SGarrett D'Amore */
41888447a05SGarrett D'Amore
41988447a05SGarrett D'Amore /*
42088447a05SGarrett D'Amore * Root node is first, that way all others parent is this one
42188447a05SGarrett D'Amore */
42288447a05SGarrett D'Amore ext = &odev->d_exts[odev->d_nctrl];
42388447a05SGarrett D'Amore ext->ctrl = 0;
42488447a05SGarrett D'Amore ext->parent = -1;
42588447a05SGarrett D'Amore ext->type = MIXT_DEVROOT;
42688447a05SGarrett D'Amore ext->timestamp = gethrtime();
42788447a05SGarrett D'Amore (void) snprintf(ext->id, sizeof (ext->id), "DEVROOT");
42888447a05SGarrett D'Amore /*
42988447a05SGarrett D'Amore * Root data... nobody should be using this though.
43088447a05SGarrett D'Amore */
43188447a05SGarrett D'Amore root_data = (oss_mixext_root *)&ext->data;
43288447a05SGarrett D'Amore (void) snprintf(root_data->name, sizeof (root_data->name), "%s",
43388447a05SGarrett D'Amore auclnt_get_dev_name(d));
43488447a05SGarrett D'Amore (void) snprintf(root_data->id, sizeof (root_data->id), "%s",
43588447a05SGarrett D'Amore auclnt_get_dev_name(d));
43688447a05SGarrett D'Amore
43788447a05SGarrett D'Amore odev->d_nctrl++;
43888447a05SGarrett D'Amore
43988447a05SGarrett D'Amore /*
44088447a05SGarrett D'Amore * Insert an extra marker -- needed to keep layout apps hapy.
44188447a05SGarrett D'Amore * This prevents some apps from assuming we are in "LEGACY" mode.
44288447a05SGarrett D'Amore */
44388447a05SGarrett D'Amore ext = &odev->d_exts[odev->d_nctrl];
44488447a05SGarrett D'Amore ext->ctrl = odev->d_nctrl;
44588447a05SGarrett D'Amore ext->control_no = -1;
44688447a05SGarrett D'Amore ext->type = MIXT_MARKER;
44788447a05SGarrett D'Amore ext->timestamp = gethrtime();
44888447a05SGarrett D'Amore ext->parent = 0;
44988447a05SGarrett D'Amore odev->d_nctrl++;
45088447a05SGarrett D'Amore
45188447a05SGarrett D'Amore /* Fill in the complete table now */
45288447a05SGarrett D'Amore auclnt_walk_controls(d, oss_add_control, odev);
45388447a05SGarrett D'Amore
45488447a05SGarrett D'Amore /* Update the update_counter reference counter for groups */
45588447a05SGarrett D'Amore for (nctrl = 0; nctrl < odev->d_nctrl; nctrl++) {
45688447a05SGarrett D'Amore int i;
45788447a05SGarrett D'Amore
45888447a05SGarrett D'Amore ext = &odev->d_exts[nctrl];
45988447a05SGarrett D'Amore i = ext->parent;
46088447a05SGarrett D'Amore while ((i >= 0) && (i < odev->d_nctrl)) {
46188447a05SGarrett D'Amore
46288447a05SGarrett D'Amore ext = &odev->d_exts[i];
46388447a05SGarrett D'Amore ASSERT(ext->parent < i);
46488447a05SGarrett D'Amore ASSERT((ext->type == MIXT_GROUP) ||
46588447a05SGarrett D'Amore (ext->type == MIXT_DEVROOT));
46688447a05SGarrett D'Amore ext->update_counter++;
46788447a05SGarrett D'Amore i = ext->parent;
46888447a05SGarrett D'Amore }
46988447a05SGarrett D'Amore }
47088447a05SGarrett D'Amore
47188447a05SGarrett D'Amore ASSERT(odev->d_nctrl <= odev->d_nalloc);
47288447a05SGarrett D'Amore }
47388447a05SGarrett D'Amore
47488447a05SGarrett D'Amore static int
oss_open(audio_client_t * c,int oflag)47588447a05SGarrett D'Amore oss_open(audio_client_t *c, int oflag)
47688447a05SGarrett D'Amore {
47788447a05SGarrett D'Amore int rv;
47888447a05SGarrett D'Amore ossdev_t *odev;
47988447a05SGarrett D'Amore ossclient_t *sc;
48088447a05SGarrett D'Amore audio_stream_t *isp, *osp;
48188447a05SGarrett D'Amore
48288447a05SGarrett D'Amore isp = auclnt_input_stream(c);
48388447a05SGarrett D'Amore osp = auclnt_output_stream(c);
48488447a05SGarrett D'Amore
48588447a05SGarrett D'Amore /* note that OSS always uses nonblocking open() semantics */
486*2c30fa45SGarrett D'Amore if ((rv = auclnt_open(c, oflag | FNDELAY)) != 0) {
48788447a05SGarrett D'Amore return (rv);
48888447a05SGarrett D'Amore }
48988447a05SGarrett D'Amore
49088447a05SGarrett D'Amore if ((sc = kmem_zalloc(sizeof (*sc), KM_NOSLEEP)) == NULL) {
49188447a05SGarrett D'Amore auclnt_close(c);
49288447a05SGarrett D'Amore return (ENOMEM);
49388447a05SGarrett D'Amore }
49488447a05SGarrett D'Amore auclnt_set_private(c, sc);
49588447a05SGarrett D'Amore
49688447a05SGarrett D'Amore odev = auclnt_get_minor_data(c, AUDIO_MINOR_DSP);
49788447a05SGarrett D'Amore
49888447a05SGarrett D'Amore /* set a couple of common fields */
49988447a05SGarrett D'Amore sc->o_client = c;
50088447a05SGarrett D'Amore sc->o_ossdev = odev;
50188447a05SGarrett D'Amore
50288447a05SGarrett D'Amore /* set all default parameters */
50388447a05SGarrett D'Amore if (oflag & FWRITE) {
50488447a05SGarrett D'Amore if (((rv = auclnt_set_format(osp, OSS_FMT)) != 0) ||
50588447a05SGarrett D'Amore ((rv = auclnt_set_rate(osp, OSS_RATE)) != 0) ||
50688447a05SGarrett D'Amore ((rv = auclnt_set_channels(osp, OSS_CHANNELS)) != 0)) {
50788447a05SGarrett D'Amore goto failed;
50888447a05SGarrett D'Amore }
509a702341cSGarrett D'Amore /* default to 5 fragments to provide reasonable latency */
510a702341cSGarrett D'Amore auclnt_set_latency(osp, 5, 0);
51188447a05SGarrett D'Amore }
51288447a05SGarrett D'Amore
51388447a05SGarrett D'Amore if (oflag & FREAD) {
51488447a05SGarrett D'Amore if (((rv = auclnt_set_format(isp, OSS_FMT)) != 0) ||
51588447a05SGarrett D'Amore ((rv = auclnt_set_rate(isp, OSS_RATE)) != 0) ||
51688447a05SGarrett D'Amore ((rv = auclnt_set_channels(isp, OSS_CHANNELS)) != 0)) {
51788447a05SGarrett D'Amore goto failed;
51888447a05SGarrett D'Amore }
519a702341cSGarrett D'Amore /* default to 5 fragments to provide reasonable latency */
520a702341cSGarrett D'Amore auclnt_set_latency(isp, 5, 0);
52188447a05SGarrett D'Amore }
52288447a05SGarrett D'Amore
52388447a05SGarrett D'Amore return (0);
52488447a05SGarrett D'Amore
52588447a05SGarrett D'Amore failed:
52688447a05SGarrett D'Amore auclnt_close(c);
52788447a05SGarrett D'Amore return (rv);
52888447a05SGarrett D'Amore }
52988447a05SGarrett D'Amore
53088447a05SGarrett D'Amore static void
oss_close(audio_client_t * c)53188447a05SGarrett D'Amore oss_close(audio_client_t *c)
53288447a05SGarrett D'Amore {
53388447a05SGarrett D'Amore ossclient_t *sc;
53488447a05SGarrett D'Amore
53588447a05SGarrett D'Amore sc = auclnt_get_private(c);
53688447a05SGarrett D'Amore
53788447a05SGarrett D'Amore if (ddi_can_receive_sig() || (ddi_get_pid() == 0)) {
53888447a05SGarrett D'Amore (void) auclnt_drain(c);
53988447a05SGarrett D'Amore }
54088447a05SGarrett D'Amore
54188447a05SGarrett D'Amore kmem_free(sc, sizeof (*sc));
54288447a05SGarrett D'Amore
54388447a05SGarrett D'Amore auclnt_close(c);
54488447a05SGarrett D'Amore }
54588447a05SGarrett D'Amore
54688447a05SGarrett D'Amore /*
54788447a05SGarrett D'Amore * This is used to generate an array of names for an enumeration
54888447a05SGarrett D'Amore */
54988447a05SGarrett D'Amore static ushort_t
oss_set_enum(oss_mixer_enuminfo * ei,ushort_t nxt,const char * name)55088447a05SGarrett D'Amore oss_set_enum(oss_mixer_enuminfo *ei, ushort_t nxt, const char *name)
55188447a05SGarrett D'Amore {
55288447a05SGarrett D'Amore uint32_t n;
55388447a05SGarrett D'Amore
55488447a05SGarrett D'Amore /* Get current entry to fill in */
55588447a05SGarrett D'Amore n = ei->nvalues;
55688447a05SGarrett D'Amore (void) snprintf(&ei->strings[nxt], ((sizeof (ei->strings) - nxt) - 1),
55788447a05SGarrett D'Amore "%s", name);
55888447a05SGarrett D'Amore ei->strindex[n] = nxt;
55988447a05SGarrett D'Amore
56088447a05SGarrett D'Amore /* Adjust everything for next entry */
56188447a05SGarrett D'Amore nxt += strnlen(name, ((sizeof (ei->strings) - nxt) - 1));
56288447a05SGarrett D'Amore ei->strings[nxt++] = '\0';
56388447a05SGarrett D'Amore
56488447a05SGarrett D'Amore ei->nvalues++;
56588447a05SGarrett D'Amore return (nxt);
56688447a05SGarrett D'Amore }
56788447a05SGarrett D'Amore
56888447a05SGarrett D'Amore /*
56988447a05SGarrett D'Amore * The following two functions are used to count the number of devices
57088447a05SGarrett D'Amore * in under the boomer framework.
57188447a05SGarrett D'Amore *
57288447a05SGarrett D'Amore * We actually report the highest "index", and then if an audio device
57388447a05SGarrett D'Amore * is not found, we report a bogus removed device for it in the actual
57488447a05SGarrett D'Amore * ioctls. This goofiness is required to make the OSS API happy.
57588447a05SGarrett D'Amore */
57688447a05SGarrett D'Amore int
oss_dev_walker(audio_dev_t * d,void * arg)57788447a05SGarrett D'Amore oss_dev_walker(audio_dev_t *d, void *arg)
57888447a05SGarrett D'Amore {
57988447a05SGarrett D'Amore int *pcnt = arg;
58088447a05SGarrett D'Amore int cnt;
58188447a05SGarrett D'Amore int index;
58288447a05SGarrett D'Amore
58388447a05SGarrett D'Amore cnt = *pcnt;
58488447a05SGarrett D'Amore index = auclnt_get_dev_index(d);
58588447a05SGarrett D'Amore if ((index + 1) > cnt) {
58688447a05SGarrett D'Amore cnt = index + 1;
58788447a05SGarrett D'Amore *pcnt = cnt;
58888447a05SGarrett D'Amore }
58988447a05SGarrett D'Amore
59088447a05SGarrett D'Amore return (AUDIO_WALK_CONTINUE);
59188447a05SGarrett D'Amore }
59288447a05SGarrett D'Amore
59388447a05SGarrett D'Amore static int
oss_cnt_devs(void)59488447a05SGarrett D'Amore oss_cnt_devs(void)
59588447a05SGarrett D'Amore {
59688447a05SGarrett D'Amore int cnt = 0;
59788447a05SGarrett D'Amore
59888447a05SGarrett D'Amore auclnt_walk_devs(oss_dev_walker, &cnt);
59988447a05SGarrett D'Amore return (cnt);
60088447a05SGarrett D'Amore }
60188447a05SGarrett D'Amore
60288447a05SGarrett D'Amore static int
sndctl_dsp_speed(audio_client_t * c,int * ratep)60388447a05SGarrett D'Amore sndctl_dsp_speed(audio_client_t *c, int *ratep)
60488447a05SGarrett D'Amore {
60588447a05SGarrett D'Amore int rate;
60688447a05SGarrett D'Amore int oflag;
60788447a05SGarrett D'Amore
60888447a05SGarrett D'Amore rate = *ratep;
60988447a05SGarrett D'Amore
61088447a05SGarrett D'Amore oflag = auclnt_get_oflag(c);
61188447a05SGarrett D'Amore if (oflag & FREAD) {
61226025630SGarrett D'Amore (void) auclnt_set_rate(auclnt_input_stream(c), rate);
61326025630SGarrett D'Amore *ratep = auclnt_get_rate(auclnt_input_stream(c));
61488447a05SGarrett D'Amore }
61588447a05SGarrett D'Amore
61688447a05SGarrett D'Amore if (oflag & FWRITE) {
61726025630SGarrett D'Amore (void) auclnt_set_rate(auclnt_output_stream(c), rate);
61826025630SGarrett D'Amore *ratep = auclnt_get_rate(auclnt_output_stream(c));
61988447a05SGarrett D'Amore }
62088447a05SGarrett D'Amore
62188447a05SGarrett D'Amore return (0);
62288447a05SGarrett D'Amore }
62388447a05SGarrett D'Amore
62488447a05SGarrett D'Amore static int
sndctl_dsp_setfmt(audio_client_t * c,int * fmtp)62588447a05SGarrett D'Amore sndctl_dsp_setfmt(audio_client_t *c, int *fmtp)
62688447a05SGarrett D'Amore {
62788447a05SGarrett D'Amore int fmt;
62888447a05SGarrett D'Amore int i;
62988447a05SGarrett D'Amore int oflag;
63088447a05SGarrett D'Amore
63188447a05SGarrett D'Amore oflag = auclnt_get_oflag(c);
63288447a05SGarrett D'Amore
63388447a05SGarrett D'Amore if (*fmtp != AFMT_QUERY) {
63488447a05SGarrett D'Amore /* convert from OSS */
63588447a05SGarrett D'Amore for (i = 0; oss_formats[i].fmt != AUDIO_FORMAT_NONE; i++) {
63688447a05SGarrett D'Amore if (oss_formats[i].oss == *fmtp) {
63788447a05SGarrett D'Amore fmt = oss_formats[i].fmt;
63888447a05SGarrett D'Amore break;
63988447a05SGarrett D'Amore }
64088447a05SGarrett D'Amore }
64188447a05SGarrett D'Amore if (fmt == AUDIO_FORMAT_NONE) {
64226025630SGarrett D'Amore /* if format not known, return */
64326025630SGarrett D'Amore goto done;
64488447a05SGarrett D'Amore }
64588447a05SGarrett D'Amore
64688447a05SGarrett D'Amore if (oflag & FWRITE) {
64726025630SGarrett D'Amore (void) auclnt_set_format(auclnt_output_stream(c), fmt);
64888447a05SGarrett D'Amore }
64988447a05SGarrett D'Amore
65088447a05SGarrett D'Amore if (oflag & FREAD) {
65126025630SGarrett D'Amore (void) auclnt_set_format(auclnt_input_stream(c), fmt);
65288447a05SGarrett D'Amore }
65388447a05SGarrett D'Amore }
65488447a05SGarrett D'Amore
65526025630SGarrett D'Amore done:
65688447a05SGarrett D'Amore if (oflag & FWRITE) {
65788447a05SGarrett D'Amore fmt = auclnt_get_format(auclnt_output_stream(c));
65888447a05SGarrett D'Amore } else if (oflag & FREAD) {
65988447a05SGarrett D'Amore fmt = auclnt_get_format(auclnt_input_stream(c));
66088447a05SGarrett D'Amore }
66188447a05SGarrett D'Amore
66288447a05SGarrett D'Amore /* convert back to OSS */
66388447a05SGarrett D'Amore *(int *)fmtp = AFMT_QUERY;
66488447a05SGarrett D'Amore for (i = 0; oss_formats[i].fmt != AUDIO_FORMAT_NONE; i++) {
66588447a05SGarrett D'Amore if (oss_formats[i].fmt == fmt) {
66688447a05SGarrett D'Amore *(int *)fmtp = oss_formats[i].oss;
66788447a05SGarrett D'Amore }
66888447a05SGarrett D'Amore }
66988447a05SGarrett D'Amore
67088447a05SGarrett D'Amore return (0);
67188447a05SGarrett D'Amore }
67288447a05SGarrett D'Amore
67388447a05SGarrett D'Amore static int
sndctl_dsp_getfmts(audio_client_t * c,int * fmtsp)67488447a05SGarrett D'Amore sndctl_dsp_getfmts(audio_client_t *c, int *fmtsp)
67588447a05SGarrett D'Amore {
67688447a05SGarrett D'Amore _NOTE(ARGUNUSED(c));
67788447a05SGarrett D'Amore
67888447a05SGarrett D'Amore /*
67988447a05SGarrett D'Amore * For now, we support all the standard ones. Later we might
68088447a05SGarrett D'Amore * add in conditional support for AC3.
68188447a05SGarrett D'Amore */
68288447a05SGarrett D'Amore *fmtsp = (AFMT_MU_LAW | AFMT_A_LAW |
68388447a05SGarrett D'Amore AFMT_U8 | AFMT_S8 |
68488447a05SGarrett D'Amore AFMT_S16_LE |AFMT_S16_BE |
68588447a05SGarrett D'Amore AFMT_S24_LE | AFMT_S24_BE |
68688447a05SGarrett D'Amore AFMT_S32_LE | AFMT_S32_BE |
68788447a05SGarrett D'Amore AFMT_S24_PACKED);
68888447a05SGarrett D'Amore
68988447a05SGarrett D'Amore return (0);
69088447a05SGarrett D'Amore }
69188447a05SGarrett D'Amore
69288447a05SGarrett D'Amore static int
sndctl_dsp_channels(audio_client_t * c,int * chanp)69388447a05SGarrett D'Amore sndctl_dsp_channels(audio_client_t *c, int *chanp)
69488447a05SGarrett D'Amore {
69588447a05SGarrett D'Amore int nchan;
69688447a05SGarrett D'Amore int oflag;
69788447a05SGarrett D'Amore
69888447a05SGarrett D'Amore oflag = auclnt_get_oflag(c);
69988447a05SGarrett D'Amore
70088447a05SGarrett D'Amore nchan = *chanp;
70188447a05SGarrett D'Amore if (nchan != 0) {
70288447a05SGarrett D'Amore if (oflag & FWRITE) {
70326025630SGarrett D'Amore (void) auclnt_set_channels(auclnt_output_stream(c),
70488447a05SGarrett D'Amore nchan);
70588447a05SGarrett D'Amore }
70688447a05SGarrett D'Amore
70788447a05SGarrett D'Amore if (oflag & FREAD) {
70826025630SGarrett D'Amore (void) auclnt_set_channels(auclnt_input_stream(c),
70926025630SGarrett D'Amore nchan);
71088447a05SGarrett D'Amore }
71188447a05SGarrett D'Amore }
71288447a05SGarrett D'Amore
71388447a05SGarrett D'Amore if (oflag & FWRITE) {
71488447a05SGarrett D'Amore nchan = auclnt_get_channels(auclnt_output_stream(c));
71588447a05SGarrett D'Amore } else if (oflag & FREAD) {
71688447a05SGarrett D'Amore nchan = auclnt_get_channels(auclnt_input_stream(c));
71788447a05SGarrett D'Amore }
71888447a05SGarrett D'Amore *chanp = nchan;
71988447a05SGarrett D'Amore return (0);
72088447a05SGarrett D'Amore }
72188447a05SGarrett D'Amore
72288447a05SGarrett D'Amore static int
sndctl_dsp_stereo(audio_client_t * c,int * onoff)72388447a05SGarrett D'Amore sndctl_dsp_stereo(audio_client_t *c, int *onoff)
72488447a05SGarrett D'Amore {
72588447a05SGarrett D'Amore int nchan;
72688447a05SGarrett D'Amore
72788447a05SGarrett D'Amore switch (*onoff) {
72888447a05SGarrett D'Amore case 0:
72988447a05SGarrett D'Amore nchan = 1;
73088447a05SGarrett D'Amore break;
73188447a05SGarrett D'Amore case 1:
73288447a05SGarrett D'Amore nchan = 2;
73388447a05SGarrett D'Amore break;
73488447a05SGarrett D'Amore default:
73588447a05SGarrett D'Amore return (EINVAL);
73688447a05SGarrett D'Amore }
73788447a05SGarrett D'Amore
73888447a05SGarrett D'Amore return (sndctl_dsp_channels(c, &nchan));
73988447a05SGarrett D'Amore }
74088447a05SGarrett D'Amore
74188447a05SGarrett D'Amore static int
sndctl_dsp_post(audio_client_t * c)74288447a05SGarrett D'Amore sndctl_dsp_post(audio_client_t *c)
74388447a05SGarrett D'Amore {
74488447a05SGarrett D'Amore if (auclnt_get_oflag(c) & FWRITE) {
74588447a05SGarrett D'Amore audio_stream_t *sp = auclnt_output_stream(c);
74688447a05SGarrett D'Amore auclnt_flush(sp);
74788447a05SGarrett D'Amore auclnt_clear_paused(sp);
74888447a05SGarrett D'Amore }
74988447a05SGarrett D'Amore return (0);
75088447a05SGarrett D'Amore }
75188447a05SGarrett D'Amore
75288447a05SGarrett D'Amore static int
sndctl_dsp_getcaps(audio_client_t * c,int * capsp)75388447a05SGarrett D'Amore sndctl_dsp_getcaps(audio_client_t *c, int *capsp)
75488447a05SGarrett D'Amore {
75588447a05SGarrett D'Amore int ncaps;
75688447a05SGarrett D'Amore int osscaps = 0;
75788447a05SGarrett D'Amore
75888447a05SGarrett D'Amore ncaps = auclnt_get_dev_capab(auclnt_get_dev(c));
75988447a05SGarrett D'Amore
76088447a05SGarrett D'Amore if (ncaps & AUDIO_CLIENT_CAP_PLAY)
76188447a05SGarrett D'Amore osscaps |= PCM_CAP_OUTPUT;
76288447a05SGarrett D'Amore if (ncaps & AUDIO_CLIENT_CAP_RECORD)
76388447a05SGarrett D'Amore osscaps |= PCM_CAP_INPUT;
76488447a05SGarrett D'Amore if (ncaps & AUDIO_CLIENT_CAP_DUPLEX)
76588447a05SGarrett D'Amore osscaps |= PCM_CAP_DUPLEX;
76688447a05SGarrett D'Amore
76726025630SGarrett D'Amore if (osscaps != 0) {
76826025630SGarrett D'Amore osscaps |= PCM_CAP_TRIGGER | PCM_CAP_BATCH;
76926025630SGarrett D'Amore if (!(ncaps & AUDIO_CLIENT_CAP_OPAQUE)) {
77026025630SGarrett D'Amore osscaps |= PCM_CAP_FREERATE | PCM_CAP_MULTI;
77126025630SGarrett D'Amore }
77226025630SGarrett D'Amore } else {
77326025630SGarrett D'Amore /* This is the sndstat device! */
77426025630SGarrett D'Amore osscaps = PCM_CAP_VIRTUAL;
77526025630SGarrett D'Amore }
77626025630SGarrett D'Amore
77788447a05SGarrett D'Amore *capsp = osscaps;
77888447a05SGarrett D'Amore return (0);
77988447a05SGarrett D'Amore }
78088447a05SGarrett D'Amore
78188447a05SGarrett D'Amore static int
sndctl_dsp_gettrigger(audio_client_t * c,int * trigp)78288447a05SGarrett D'Amore sndctl_dsp_gettrigger(audio_client_t *c, int *trigp)
78388447a05SGarrett D'Amore {
78488447a05SGarrett D'Amore int triggers = 0;
78588447a05SGarrett D'Amore int oflag;
78688447a05SGarrett D'Amore
78788447a05SGarrett D'Amore oflag = auclnt_get_oflag(c);
78888447a05SGarrett D'Amore
78988447a05SGarrett D'Amore if (oflag & FWRITE) {
79088447a05SGarrett D'Amore if (!auclnt_is_paused(auclnt_output_stream(c))) {
79188447a05SGarrett D'Amore triggers |= PCM_ENABLE_OUTPUT;
79288447a05SGarrett D'Amore }
79388447a05SGarrett D'Amore }
79488447a05SGarrett D'Amore
79588447a05SGarrett D'Amore if (oflag & FREAD) {
79688447a05SGarrett D'Amore if (!auclnt_is_paused(auclnt_input_stream(c))) {
79788447a05SGarrett D'Amore triggers |= PCM_ENABLE_INPUT;
79888447a05SGarrett D'Amore }
79988447a05SGarrett D'Amore }
80088447a05SGarrett D'Amore *trigp = triggers;
80188447a05SGarrett D'Amore
80288447a05SGarrett D'Amore return (0);
80388447a05SGarrett D'Amore }
80488447a05SGarrett D'Amore
80588447a05SGarrett D'Amore static int
sndctl_dsp_settrigger(audio_client_t * c,int * trigp)80688447a05SGarrett D'Amore sndctl_dsp_settrigger(audio_client_t *c, int *trigp)
80788447a05SGarrett D'Amore {
80888447a05SGarrett D'Amore int triggers;
80988447a05SGarrett D'Amore int oflag;
8109556c422SGarrett D'Amore audio_stream_t *sp;
81188447a05SGarrett D'Amore
81288447a05SGarrett D'Amore oflag = auclnt_get_oflag(c);
81388447a05SGarrett D'Amore triggers = *trigp;
81488447a05SGarrett D'Amore
81588447a05SGarrett D'Amore if ((oflag & FWRITE) && (triggers & PCM_ENABLE_OUTPUT)) {
8169556c422SGarrett D'Amore sp = auclnt_output_stream(c);
8179556c422SGarrett D'Amore auclnt_clear_paused(sp);
8189556c422SGarrett D'Amore auclnt_start(sp);
81988447a05SGarrett D'Amore }
82088447a05SGarrett D'Amore
82188447a05SGarrett D'Amore if ((oflag & FREAD) && (triggers & PCM_ENABLE_INPUT)) {
8229556c422SGarrett D'Amore sp = auclnt_input_stream(c);
8239556c422SGarrett D'Amore auclnt_clear_paused(sp);
8249556c422SGarrett D'Amore auclnt_start(sp);
82588447a05SGarrett D'Amore }
82688447a05SGarrett D'Amore
82788447a05SGarrett D'Amore return (0);
82888447a05SGarrett D'Amore }
82988447a05SGarrett D'Amore
83088447a05SGarrett D'Amore struct oss_legacy_volume {
83188447a05SGarrett D'Amore pid_t pid;
83288447a05SGarrett D'Amore uint8_t ogain;
83388447a05SGarrett D'Amore uint8_t igain;
83488447a05SGarrett D'Amore };
83588447a05SGarrett D'Amore
83688447a05SGarrett D'Amore static int
oss_legacy_volume_walker(audio_client_t * c,void * arg)83788447a05SGarrett D'Amore oss_legacy_volume_walker(audio_client_t *c, void *arg)
83888447a05SGarrett D'Amore {
83988447a05SGarrett D'Amore struct oss_legacy_volume *olv = arg;
84088447a05SGarrett D'Amore
84188447a05SGarrett D'Amore if (auclnt_get_pid(c) == olv->pid) {
84288447a05SGarrett D'Amore if (olv->ogain <= 100) {
84388447a05SGarrett D'Amore auclnt_set_gain(auclnt_output_stream(c), olv->ogain);
84488447a05SGarrett D'Amore }
84588447a05SGarrett D'Amore if (olv->igain <= 100) {
84688447a05SGarrett D'Amore auclnt_set_gain(auclnt_input_stream(c), olv->igain);
84788447a05SGarrett D'Amore }
84888447a05SGarrett D'Amore }
84988447a05SGarrett D'Amore return (AUDIO_WALK_CONTINUE);
85088447a05SGarrett D'Amore }
85188447a05SGarrett D'Amore
85288447a05SGarrett D'Amore static void
oss_set_legacy_volume(audio_client_t * c,uint8_t ogain,uint8_t igain)85388447a05SGarrett D'Amore oss_set_legacy_volume(audio_client_t *c, uint8_t ogain, uint8_t igain)
85488447a05SGarrett D'Amore {
85588447a05SGarrett D'Amore struct oss_legacy_volume olv;
85688447a05SGarrett D'Amore
85788447a05SGarrett D'Amore olv.pid = auclnt_get_pid(c);
85888447a05SGarrett D'Amore olv.ogain = ogain;
85988447a05SGarrett D'Amore olv.igain = igain;
86088447a05SGarrett D'Amore auclnt_dev_walk_clients(auclnt_get_dev(c),
86188447a05SGarrett D'Amore oss_legacy_volume_walker, &olv);
86288447a05SGarrett D'Amore }
86388447a05SGarrett D'Amore
86488447a05SGarrett D'Amore static int
sndctl_dsp_getplayvol(audio_client_t * c,int * volp)86588447a05SGarrett D'Amore sndctl_dsp_getplayvol(audio_client_t *c, int *volp)
86688447a05SGarrett D'Amore {
86788447a05SGarrett D'Amore int vol;
86888447a05SGarrett D'Amore
86988447a05SGarrett D'Amore /* convert monophonic soft value to OSS stereo value */
87088447a05SGarrett D'Amore vol = auclnt_get_gain(auclnt_output_stream(c));
87188447a05SGarrett D'Amore *volp = vol | (vol << 8);
87288447a05SGarrett D'Amore return (0);
87388447a05SGarrett D'Amore }
87488447a05SGarrett D'Amore
87588447a05SGarrett D'Amore static int
sndctl_dsp_setplayvol(audio_client_t * c,int * volp)87688447a05SGarrett D'Amore sndctl_dsp_setplayvol(audio_client_t *c, int *volp)
87788447a05SGarrett D'Amore {
87888447a05SGarrett D'Amore uint8_t vol;
87988447a05SGarrett D'Amore
88088447a05SGarrett D'Amore vol = *volp & 0xff;
88188447a05SGarrett D'Amore if (vol > 100) {
88288447a05SGarrett D'Amore return (EINVAL);
88388447a05SGarrett D'Amore }
88488447a05SGarrett D'Amore
88588447a05SGarrett D'Amore auclnt_set_gain(auclnt_output_stream(c), vol);
88688447a05SGarrett D'Amore *volp = (vol | (vol << 8));
88788447a05SGarrett D'Amore
88888447a05SGarrett D'Amore return (0);
88988447a05SGarrett D'Amore }
89088447a05SGarrett D'Amore
89188447a05SGarrett D'Amore static int
sndctl_dsp_getrecvol(audio_client_t * c,int * volp)89288447a05SGarrett D'Amore sndctl_dsp_getrecvol(audio_client_t *c, int *volp)
89388447a05SGarrett D'Amore {
89488447a05SGarrett D'Amore int vol;
89588447a05SGarrett D'Amore
89688447a05SGarrett D'Amore vol = auclnt_get_gain(auclnt_input_stream(c));
89788447a05SGarrett D'Amore *volp = (vol | (vol << 8));
89888447a05SGarrett D'Amore return (0);
89988447a05SGarrett D'Amore }
90088447a05SGarrett D'Amore
90188447a05SGarrett D'Amore static int
sndctl_dsp_setrecvol(audio_client_t * c,int * volp)90288447a05SGarrett D'Amore sndctl_dsp_setrecvol(audio_client_t *c, int *volp)
90388447a05SGarrett D'Amore {
90488447a05SGarrett D'Amore uint8_t vol;
90588447a05SGarrett D'Amore
90688447a05SGarrett D'Amore vol = *volp & 0xff;
90788447a05SGarrett D'Amore if (vol > 100) {
90888447a05SGarrett D'Amore return (EINVAL);
90988447a05SGarrett D'Amore }
91088447a05SGarrett D'Amore
91188447a05SGarrett D'Amore auclnt_set_gain(auclnt_input_stream(c), vol);
91288447a05SGarrett D'Amore *volp = (vol | (vol << 8));
91388447a05SGarrett D'Amore
91488447a05SGarrett D'Amore return (0);
91588447a05SGarrett D'Amore }
91688447a05SGarrett D'Amore
91788447a05SGarrett D'Amore static int
sound_mixer_write_ogain(audio_client_t * c,int * volp)91888447a05SGarrett D'Amore sound_mixer_write_ogain(audio_client_t *c, int *volp)
91988447a05SGarrett D'Amore {
92088447a05SGarrett D'Amore uint8_t vol;
92188447a05SGarrett D'Amore
92288447a05SGarrett D'Amore vol = *volp & 0xff;
92388447a05SGarrett D'Amore if (vol > 100) {
92488447a05SGarrett D'Amore return (EINVAL);
92588447a05SGarrett D'Amore }
92688447a05SGarrett D'Amore oss_set_legacy_volume(c, vol, 255);
92788447a05SGarrett D'Amore *volp = (vol | (vol << 8));
92888447a05SGarrett D'Amore return (0);
92988447a05SGarrett D'Amore }
93088447a05SGarrett D'Amore
93188447a05SGarrett D'Amore static int
sound_mixer_write_igain(audio_client_t * c,int * volp)93288447a05SGarrett D'Amore sound_mixer_write_igain(audio_client_t *c, int *volp)
93388447a05SGarrett D'Amore {
93488447a05SGarrett D'Amore uint8_t vol;
93588447a05SGarrett D'Amore
93688447a05SGarrett D'Amore vol = *volp & 0xff;
93788447a05SGarrett D'Amore if (vol > 100) {
93888447a05SGarrett D'Amore return (EINVAL);
93988447a05SGarrett D'Amore }
94088447a05SGarrett D'Amore oss_set_legacy_volume(c, 255, vol);
94188447a05SGarrett D'Amore *volp = (vol | (vol << 8));
94288447a05SGarrett D'Amore return (0);
94388447a05SGarrett D'Amore }
94488447a05SGarrett D'Amore
94588447a05SGarrett D'Amore static int
sndctl_dsp_readctl(audio_client_t * c,oss_digital_control * ctl)94688447a05SGarrett D'Amore sndctl_dsp_readctl(audio_client_t *c, oss_digital_control *ctl)
94788447a05SGarrett D'Amore {
94888447a05SGarrett D'Amore /* SPDIF: need to add support with spdif */
94988447a05SGarrett D'Amore _NOTE(ARGUNUSED(c));
95088447a05SGarrett D'Amore _NOTE(ARGUNUSED(ctl));
95188447a05SGarrett D'Amore return (ENOTSUP);
95288447a05SGarrett D'Amore }
95388447a05SGarrett D'Amore
95488447a05SGarrett D'Amore static int
sndctl_dsp_writectl(audio_client_t * c,oss_digital_control * ctl)95588447a05SGarrett D'Amore sndctl_dsp_writectl(audio_client_t *c, oss_digital_control *ctl)
95688447a05SGarrett D'Amore {
95788447a05SGarrett D'Amore /* SPDIF: need to add support with spdif */
95888447a05SGarrett D'Amore _NOTE(ARGUNUSED(c));
95988447a05SGarrett D'Amore _NOTE(ARGUNUSED(ctl));
96088447a05SGarrett D'Amore return (ENOTSUP);
96188447a05SGarrett D'Amore }
96288447a05SGarrett D'Amore
96388447a05SGarrett D'Amore static int
sndctl_dsp_cookedmode(audio_client_t * c,int * rvp)96488447a05SGarrett D'Amore sndctl_dsp_cookedmode(audio_client_t *c, int *rvp)
96588447a05SGarrett D'Amore {
96688447a05SGarrett D'Amore _NOTE(ARGUNUSED(c));
96788447a05SGarrett D'Amore
96888447a05SGarrett D'Amore /* We are *always* in cooked mode -- at least until we have AC3. */
96988447a05SGarrett D'Amore if (*rvp == 0) {
97088447a05SGarrett D'Amore return (ENOTSUP);
97188447a05SGarrett D'Amore } else {
97288447a05SGarrett D'Amore return (0);
97388447a05SGarrett D'Amore }
97488447a05SGarrett D'Amore }
97588447a05SGarrett D'Amore
97688447a05SGarrett D'Amore static int
sndctl_dsp_silence(audio_client_t * c)97788447a05SGarrett D'Amore sndctl_dsp_silence(audio_client_t *c)
97888447a05SGarrett D'Amore {
97988447a05SGarrett D'Amore if (auclnt_get_oflag(c) & FWRITE) {
98088447a05SGarrett D'Amore audio_stream_t *sp = auclnt_output_stream(c);
98188447a05SGarrett D'Amore auclnt_set_paused(sp);
98288447a05SGarrett D'Amore auclnt_flush(sp);
98388447a05SGarrett D'Amore }
98488447a05SGarrett D'Amore return (0);
98588447a05SGarrett D'Amore }
98688447a05SGarrett D'Amore
98788447a05SGarrett D'Amore static int
sndctl_dsp_skip(audio_client_t * c)98888447a05SGarrett D'Amore sndctl_dsp_skip(audio_client_t *c)
98988447a05SGarrett D'Amore {
99088447a05SGarrett D'Amore if (auclnt_get_oflag(c) & FWRITE) {
99188447a05SGarrett D'Amore audio_stream_t *sp = auclnt_output_stream(c);
99288447a05SGarrett D'Amore auclnt_set_paused(sp);
99388447a05SGarrett D'Amore auclnt_flush(sp);
99488447a05SGarrett D'Amore auclnt_clear_paused(sp);
99588447a05SGarrett D'Amore }
99688447a05SGarrett D'Amore return (0);
99788447a05SGarrett D'Amore }
99888447a05SGarrett D'Amore
99988447a05SGarrett D'Amore static int
sndctl_dsp_halt_input(audio_client_t * c)100088447a05SGarrett D'Amore sndctl_dsp_halt_input(audio_client_t *c)
100188447a05SGarrett D'Amore {
100288447a05SGarrett D'Amore if (auclnt_get_oflag(c) & FREAD) {
100388447a05SGarrett D'Amore audio_stream_t *sp = auclnt_input_stream(c);
100488447a05SGarrett D'Amore auclnt_set_paused(sp);
100588447a05SGarrett D'Amore auclnt_flush(sp);
100688447a05SGarrett D'Amore }
100788447a05SGarrett D'Amore return (0);
100888447a05SGarrett D'Amore }
100988447a05SGarrett D'Amore
101088447a05SGarrett D'Amore static int
sndctl_dsp_halt_output(audio_client_t * c)101188447a05SGarrett D'Amore sndctl_dsp_halt_output(audio_client_t *c)
101288447a05SGarrett D'Amore {
101388447a05SGarrett D'Amore if (auclnt_get_oflag(c) & FWRITE) {
101488447a05SGarrett D'Amore audio_stream_t *sp = auclnt_output_stream(c);
101588447a05SGarrett D'Amore auclnt_set_paused(sp);
101688447a05SGarrett D'Amore auclnt_flush(sp);
101788447a05SGarrett D'Amore }
101888447a05SGarrett D'Amore return (0);
101988447a05SGarrett D'Amore }
102088447a05SGarrett D'Amore
102188447a05SGarrett D'Amore static int
sndctl_dsp_halt(audio_client_t * c)102288447a05SGarrett D'Amore sndctl_dsp_halt(audio_client_t *c)
102388447a05SGarrett D'Amore {
102488447a05SGarrett D'Amore (void) sndctl_dsp_halt_input(c);
102588447a05SGarrett D'Amore (void) sndctl_dsp_halt_output(c);
102688447a05SGarrett D'Amore return (0);
102788447a05SGarrett D'Amore }
102888447a05SGarrett D'Amore
102988447a05SGarrett D'Amore static int
sndctl_dsp_sync(audio_client_t * c)103088447a05SGarrett D'Amore sndctl_dsp_sync(audio_client_t *c)
103188447a05SGarrett D'Amore {
103288447a05SGarrett D'Amore return (auclnt_drain(c));
103388447a05SGarrett D'Amore }
103488447a05SGarrett D'Amore
103588447a05SGarrett D'Amore static int
sndctl_dsp_setfragment(audio_client_t * c,int * fragp)103688447a05SGarrett D'Amore sndctl_dsp_setfragment(audio_client_t *c, int *fragp)
103788447a05SGarrett D'Amore {
1038a702341cSGarrett D'Amore int bufsz;
1039a702341cSGarrett D'Amore int nfrags;
1040a702341cSGarrett D'Amore int fragsz;
1041a702341cSGarrett D'Amore
1042a702341cSGarrett D'Amore nfrags = (*fragp) >> 16;
1043a702341cSGarrett D'Amore if ((nfrags >= 0x7fffU) || (nfrags < 2)) {
1044a702341cSGarrett D'Amore /* use infinite setting... no change */
1045a702341cSGarrett D'Amore return (0);
1046a702341cSGarrett D'Amore }
1047a702341cSGarrett D'Amore
1048a702341cSGarrett D'Amore fragsz = (*fragp) & 0xffff;
1049a702341cSGarrett D'Amore if (fragsz > 16) {
1050a702341cSGarrett D'Amore /* basically too big, so, no change */
1051a702341cSGarrett D'Amore return (0);
1052a702341cSGarrett D'Amore }
1053a702341cSGarrett D'Amore bufsz = (1U << fragsz) * nfrags;
1054a702341cSGarrett D'Amore
1055a702341cSGarrett D'Amore /*
1056a702341cSGarrett D'Amore * Now we have our desired buffer size, but we have to
1057a702341cSGarrett D'Amore * make sure we have a whole number of fragments >= 2, and
1058a702341cSGarrett D'Amore * less than the maximum.
1059a702341cSGarrett D'Amore */
1060a702341cSGarrett D'Amore bufsz = ((*fragp) >> 16) * (1U << (*fragp));
1061a702341cSGarrett D'Amore if (bufsz >= 65536) {
1062a702341cSGarrett D'Amore return (0);
1063a702341cSGarrett D'Amore }
1064a702341cSGarrett D'Amore
1065a702341cSGarrett D'Amore /*
1066a702341cSGarrett D'Amore * We set the latency hints in terms of bytes, not fragments.
1067a702341cSGarrett D'Amore */
1068a702341cSGarrett D'Amore auclnt_set_latency(auclnt_output_stream(c), 0, bufsz);
1069a702341cSGarrett D'Amore auclnt_set_latency(auclnt_input_stream(c), 0, bufsz);
1070a702341cSGarrett D'Amore
107188447a05SGarrett D'Amore /*
107288447a05SGarrett D'Amore * According to the OSS API documentation, the values provided
107388447a05SGarrett D'Amore * are nothing more than a "hint" and not to be relied upon
107488447a05SGarrett D'Amore * anyway. And we aren't obligated to report the actual
107588447a05SGarrett D'Amore * values back!
107688447a05SGarrett D'Amore */
107788447a05SGarrett D'Amore return (0);
107888447a05SGarrett D'Amore }
107988447a05SGarrett D'Amore
1080a702341cSGarrett D'Amore static int
sndctl_dsp_policy(audio_client_t * c,int * policy)1081a702341cSGarrett D'Amore sndctl_dsp_policy(audio_client_t *c, int *policy)
1082a702341cSGarrett D'Amore {
1083a702341cSGarrett D'Amore int hint = *policy;
1084a702341cSGarrett D'Amore if ((hint >= 2) && (hint <= 10)) {
1085a702341cSGarrett D'Amore auclnt_set_latency(auclnt_input_stream(c), hint, 0);
1086a702341cSGarrett D'Amore auclnt_set_latency(auclnt_output_stream(c), hint, 0);
1087a702341cSGarrett D'Amore }
1088a702341cSGarrett D'Amore return (0);
1089a702341cSGarrett D'Amore }
1090a702341cSGarrett D'Amore
109188447a05SGarrett D'Amore /*
109288447a05SGarrett D'Amore * A word about recsrc, and playtgt ioctls: We don't allow ordinary DSP
109388447a05SGarrett D'Amore * applications to change port configurations, because these could have a
109488447a05SGarrett D'Amore * bad effect for other applications. Instead, these settings have to
109588447a05SGarrett D'Amore * be changed using the master mixer panel. In order to make applications
109688447a05SGarrett D'Amore * happy, we just present a single "default" source/target.
109788447a05SGarrett D'Amore */
109888447a05SGarrett D'Amore static int
sndctl_dsp_get_recsrc_names(audio_client_t * c,oss_mixer_enuminfo * ei)109988447a05SGarrett D'Amore sndctl_dsp_get_recsrc_names(audio_client_t *c, oss_mixer_enuminfo *ei)
110088447a05SGarrett D'Amore {
110188447a05SGarrett D'Amore _NOTE(ARGUNUSED(c));
110288447a05SGarrett D'Amore
110388447a05SGarrett D'Amore ei->nvalues = 1;
110488447a05SGarrett D'Amore (void) snprintf(ei->strings, sizeof (ei->strings), "default");
110588447a05SGarrett D'Amore ei->strindex[0] = 0;
110688447a05SGarrett D'Amore
110788447a05SGarrett D'Amore return (0);
110888447a05SGarrett D'Amore }
110988447a05SGarrett D'Amore
111088447a05SGarrett D'Amore static int
sndctl_dsp_get_recsrc(audio_client_t * c,int * srcp)111188447a05SGarrett D'Amore sndctl_dsp_get_recsrc(audio_client_t *c, int *srcp)
111288447a05SGarrett D'Amore {
111388447a05SGarrett D'Amore _NOTE(ARGUNUSED(c));
111488447a05SGarrett D'Amore *srcp = 0;
111588447a05SGarrett D'Amore return (0);
111688447a05SGarrett D'Amore }
111788447a05SGarrett D'Amore
111888447a05SGarrett D'Amore static int
sndctl_dsp_set_recsrc(audio_client_t * c,int * srcp)111988447a05SGarrett D'Amore sndctl_dsp_set_recsrc(audio_client_t *c, int *srcp)
112088447a05SGarrett D'Amore {
112188447a05SGarrett D'Amore _NOTE(ARGUNUSED(c));
112288447a05SGarrett D'Amore *srcp = 0;
112388447a05SGarrett D'Amore return (0);
112488447a05SGarrett D'Amore }
112588447a05SGarrett D'Amore
112688447a05SGarrett D'Amore static int
sndctl_dsp_get_playtgt_names(audio_client_t * c,oss_mixer_enuminfo * ei)112788447a05SGarrett D'Amore sndctl_dsp_get_playtgt_names(audio_client_t *c, oss_mixer_enuminfo *ei)
112888447a05SGarrett D'Amore {
112988447a05SGarrett D'Amore _NOTE(ARGUNUSED(c));
113088447a05SGarrett D'Amore
113188447a05SGarrett D'Amore ei->nvalues = 1;
113288447a05SGarrett D'Amore (void) snprintf(ei->strings, sizeof (ei->strings), "default");
113388447a05SGarrett D'Amore ei->strindex[0] = 0;
113488447a05SGarrett D'Amore
113588447a05SGarrett D'Amore return (0);
113688447a05SGarrett D'Amore }
113788447a05SGarrett D'Amore
113888447a05SGarrett D'Amore static int
sndctl_dsp_get_playtgt(audio_client_t * c,int * tgtp)113988447a05SGarrett D'Amore sndctl_dsp_get_playtgt(audio_client_t *c, int *tgtp)
114088447a05SGarrett D'Amore {
114188447a05SGarrett D'Amore _NOTE(ARGUNUSED(c));
114288447a05SGarrett D'Amore *tgtp = 0;
114388447a05SGarrett D'Amore return (0);
114488447a05SGarrett D'Amore }
114588447a05SGarrett D'Amore
114688447a05SGarrett D'Amore static int
sndctl_dsp_set_playtgt(audio_client_t * c,int * tgtp)114788447a05SGarrett D'Amore sndctl_dsp_set_playtgt(audio_client_t *c, int *tgtp)
114888447a05SGarrett D'Amore {
114988447a05SGarrett D'Amore _NOTE(ARGUNUSED(c));
115088447a05SGarrett D'Amore *tgtp = 0;
115188447a05SGarrett D'Amore return (0);
115288447a05SGarrett D'Amore }
115388447a05SGarrett D'Amore
115488447a05SGarrett D'Amore static int
sndctl_sysinfo(oss_sysinfo * si)115588447a05SGarrett D'Amore sndctl_sysinfo(oss_sysinfo *si)
115688447a05SGarrett D'Amore {
115788447a05SGarrett D'Amore bzero(si, sizeof (*si));
115888447a05SGarrett D'Amore (void) snprintf(si->product, sizeof (si->product), "SunOS Audio");
115988447a05SGarrett D'Amore (void) snprintf(si->version, sizeof (si->version), "4.0");
116088447a05SGarrett D'Amore si->versionnum = OSS_VERSION;
116188447a05SGarrett D'Amore si->numcards = oss_cnt_devs();
116288447a05SGarrett D'Amore si->nummixers = si->numcards - 1;
116388447a05SGarrett D'Amore si->numaudios = si->numcards - 1;
116488447a05SGarrett D'Amore si->numaudioengines = si->numaudios;
116588447a05SGarrett D'Amore (void) snprintf(si->license, sizeof (si->license), "CDDL");
116688447a05SGarrett D'Amore return (0);
116788447a05SGarrett D'Amore }
116888447a05SGarrett D'Amore
116988447a05SGarrett D'Amore static int
sndctl_cardinfo(audio_client_t * c,oss_card_info * ci)117088447a05SGarrett D'Amore sndctl_cardinfo(audio_client_t *c, oss_card_info *ci)
117188447a05SGarrett D'Amore {
117288447a05SGarrett D'Amore audio_dev_t *d;
117388447a05SGarrett D'Amore void *iter;
117488447a05SGarrett D'Amore const char *info;
117588447a05SGarrett D'Amore int n;
117688447a05SGarrett D'Amore boolean_t release;
117788447a05SGarrett D'Amore
117888447a05SGarrett D'Amore if ((n = ci->card) == -1) {
117988447a05SGarrett D'Amore release = B_FALSE;
118088447a05SGarrett D'Amore d = auclnt_get_dev(c);
118188447a05SGarrett D'Amore n = auclnt_get_dev_index(d);
118288447a05SGarrett D'Amore } else {
118388447a05SGarrett D'Amore release = B_TRUE;
118488447a05SGarrett D'Amore d = auclnt_hold_dev_by_index(n);
118588447a05SGarrett D'Amore }
118688447a05SGarrett D'Amore
118788447a05SGarrett D'Amore bzero(ci, sizeof (*ci));
118888447a05SGarrett D'Amore ci->card = n;
118988447a05SGarrett D'Amore
119088447a05SGarrett D'Amore if (d == NULL) {
119188447a05SGarrett D'Amore /*
119288447a05SGarrett D'Amore * If device removed (e.g. for DR), then
119388447a05SGarrett D'Amore * report a bogus removed entry.
119488447a05SGarrett D'Amore */
119588447a05SGarrett D'Amore (void) snprintf(ci->shortname, sizeof (ci->shortname),
119688447a05SGarrett D'Amore "<removed>");
119788447a05SGarrett D'Amore (void) snprintf(ci->longname, sizeof (ci->longname),
119888447a05SGarrett D'Amore "<removed>");
119988447a05SGarrett D'Amore return (0);
120088447a05SGarrett D'Amore }
120188447a05SGarrett D'Amore
120288447a05SGarrett D'Amore (void) snprintf(ci->shortname, sizeof (ci->shortname),
120388447a05SGarrett D'Amore "%s", auclnt_get_dev_name(d));
120488447a05SGarrett D'Amore (void) snprintf(ci->longname, sizeof (ci->longname),
120588447a05SGarrett D'Amore "%s (%s)", auclnt_get_dev_description(d),
120688447a05SGarrett D'Amore auclnt_get_dev_version(d));
120788447a05SGarrett D'Amore
120888447a05SGarrett D'Amore iter = NULL;
120988447a05SGarrett D'Amore while ((info = auclnt_get_dev_hw_info(d, &iter)) != NULL) {
121088447a05SGarrett D'Amore (void) strlcat(ci->hw_info, info, sizeof (ci->hw_info));
121188447a05SGarrett D'Amore (void) strlcat(ci->hw_info, "\n", sizeof (ci->hw_info));
121288447a05SGarrett D'Amore }
121388447a05SGarrett D'Amore
121488447a05SGarrett D'Amore /*
121588447a05SGarrett D'Amore * We don't report interrupt counts, ack counts (which are
121688447a05SGarrett D'Amore * just "read" interrupts, not spurious), or any other flags.
121788447a05SGarrett D'Amore * Nothing should be using any of this data anyway ... these
121888447a05SGarrett D'Amore * values were intended for 4Front's debugging purposes. In
121988447a05SGarrett D'Amore * Solaris, drivers should use interrupt kstats to report
122088447a05SGarrett D'Amore * interrupt related statistics.
122188447a05SGarrett D'Amore */
122288447a05SGarrett D'Amore if (release)
122388447a05SGarrett D'Amore auclnt_release_dev(d);
122488447a05SGarrett D'Amore return (0);
122588447a05SGarrett D'Amore }
122688447a05SGarrett D'Amore
122788447a05SGarrett D'Amore static int
audioinfo_walker(audio_engine_t * e,void * a)122888447a05SGarrett D'Amore audioinfo_walker(audio_engine_t *e, void *a)
122988447a05SGarrett D'Amore {
123088447a05SGarrett D'Amore oss_audioinfo *si = a;
123188447a05SGarrett D'Amore int fmt, nchan, rate, cap;
123288447a05SGarrett D'Amore
123388447a05SGarrett D'Amore fmt = auclnt_engine_get_format(e);
123488447a05SGarrett D'Amore nchan = auclnt_engine_get_channels(e);
123588447a05SGarrett D'Amore rate = auclnt_engine_get_rate(e);
123688447a05SGarrett D'Amore cap = auclnt_engine_get_capab(e);
123788447a05SGarrett D'Amore
123888447a05SGarrett D'Amore for (int i = 0; oss_formats[i].fmt != AUDIO_FORMAT_NONE; i++) {
123988447a05SGarrett D'Amore if (fmt == oss_formats[i].fmt) {
124088447a05SGarrett D'Amore if (cap & AUDIO_CLIENT_CAP_PLAY) {
124188447a05SGarrett D'Amore si->oformats |= oss_formats[i].oss;
124288447a05SGarrett D'Amore }
124388447a05SGarrett D'Amore if (cap & AUDIO_CLIENT_CAP_RECORD) {
124488447a05SGarrett D'Amore si->iformats |= oss_formats[i].oss;
124588447a05SGarrett D'Amore }
124688447a05SGarrett D'Amore break;
124788447a05SGarrett D'Amore }
124888447a05SGarrett D'Amore }
124988447a05SGarrett D'Amore si->max_channels = max(nchan, si->max_channels);
125088447a05SGarrett D'Amore si->max_rate = max(rate, si->max_rate);
125188447a05SGarrett D'Amore
125288447a05SGarrett D'Amore return (AUDIO_WALK_CONTINUE);
125388447a05SGarrett D'Amore }
125488447a05SGarrett D'Amore
125588447a05SGarrett D'Amore static int
sndctl_audioinfo(audio_client_t * c,oss_audioinfo * si)125688447a05SGarrett D'Amore sndctl_audioinfo(audio_client_t *c, oss_audioinfo *si)
125788447a05SGarrett D'Amore {
125888447a05SGarrett D'Amore audio_dev_t *d;
125988447a05SGarrett D'Amore const char *name;
126088447a05SGarrett D'Amore int n;
126188447a05SGarrett D'Amore boolean_t release;
126288447a05SGarrett D'Amore unsigned cap;
126388447a05SGarrett D'Amore
126488447a05SGarrett D'Amore if ((n = si->dev) == -1) {
126588447a05SGarrett D'Amore release = B_FALSE;
126688447a05SGarrett D'Amore d = auclnt_get_dev(c);
126788447a05SGarrett D'Amore n = auclnt_get_dev_index(d);
126888447a05SGarrett D'Amore } else {
126988447a05SGarrett D'Amore release = B_TRUE;
127088447a05SGarrett D'Amore n++; /* skip pseudo device */
127188447a05SGarrett D'Amore d = auclnt_hold_dev_by_index(n);
127288447a05SGarrett D'Amore }
127388447a05SGarrett D'Amore
127488447a05SGarrett D'Amore bzero(si, sizeof (*si));
127588447a05SGarrett D'Amore si->dev = n - 1;
127688447a05SGarrett D'Amore
127788447a05SGarrett D'Amore if (d == NULL) {
127888447a05SGarrett D'Amore /* if device not present, forge a false entry */
127988447a05SGarrett D'Amore si->card_number = n;
128088447a05SGarrett D'Amore si->mixer_dev = n - 1;
128188447a05SGarrett D'Amore si->legacy_device = -1;
128288447a05SGarrett D'Amore si->enabled = 0;
128388447a05SGarrett D'Amore (void) snprintf(si->name, sizeof (si->name), "<removed>");
128488447a05SGarrett D'Amore return (0);
128588447a05SGarrett D'Amore }
128688447a05SGarrett D'Amore
128788447a05SGarrett D'Amore name = auclnt_get_dev_name(d);
128888447a05SGarrett D'Amore (void) snprintf(si->name, sizeof (si->name), "%s", name);
128988447a05SGarrett D'Amore
129088447a05SGarrett D'Amore si->legacy_device = auclnt_get_dev_number(d);
129188447a05SGarrett D'Amore si->caps = 0;
129288447a05SGarrett D'Amore
129388447a05SGarrett D'Amore auclnt_dev_walk_engines(d, audioinfo_walker, si);
129488447a05SGarrett D'Amore
129588447a05SGarrett D'Amore cap = auclnt_get_dev_capab(d);
129688447a05SGarrett D'Amore
129788447a05SGarrett D'Amore if (cap & AUDIO_CLIENT_CAP_DUPLEX) {
129888447a05SGarrett D'Amore si->caps |= PCM_CAP_DUPLEX;
129988447a05SGarrett D'Amore }
130088447a05SGarrett D'Amore if (cap & AUDIO_CLIENT_CAP_PLAY) {
130188447a05SGarrett D'Amore si->caps |= PCM_CAP_OUTPUT;
130288447a05SGarrett D'Amore }
130388447a05SGarrett D'Amore if (cap & AUDIO_CLIENT_CAP_RECORD) {
130488447a05SGarrett D'Amore si->caps |= PCM_CAP_INPUT;
130588447a05SGarrett D'Amore }
130688447a05SGarrett D'Amore
130788447a05SGarrett D'Amore if (si->caps != 0) {
130888447a05SGarrett D'Amore /* MMAP: we add PCM_CAP_MMAP when we we support it */
130926025630SGarrett D'Amore si->caps |= PCM_CAP_TRIGGER | PCM_CAP_BATCH;
131088447a05SGarrett D'Amore si->enabled = 1;
131188447a05SGarrett D'Amore si->rate_source = si->dev;
131288447a05SGarrett D'Amore
131326025630SGarrett D'Amore /* we can convert and mix PCM formats */
131426025630SGarrett D'Amore if (!(cap & AUDIO_CLIENT_CAP_OPAQUE)) {
131588447a05SGarrett D'Amore si->min_channels = min(2, si->max_channels);
131688447a05SGarrett D'Amore si->min_rate = min(5000, si->max_rate);
131726025630SGarrett D'Amore si->caps |= PCM_CAP_FREERATE | PCM_CAP_MULTI;
131888447a05SGarrett D'Amore }
131988447a05SGarrett D'Amore (void) snprintf(si->devnode, sizeof (si->devnode),
132088447a05SGarrett D'Amore "/dev/sound/%s:%ddsp",
132188447a05SGarrett D'Amore auclnt_get_dev_driver(d), auclnt_get_dev_instance(d));
132288447a05SGarrett D'Amore } else {
132388447a05SGarrett D'Amore si->enabled = 0; /* stops apps from using us directly */
132488447a05SGarrett D'Amore si->caps = PCM_CAP_VIRTUAL;
132588447a05SGarrett D'Amore (void) snprintf(si->devnode, sizeof (si->devnode),
132688447a05SGarrett D'Amore "/dev/sndstat");
132788447a05SGarrett D'Amore }
132888447a05SGarrett D'Amore
132988447a05SGarrett D'Amore si->pid = -1;
133088447a05SGarrett D'Amore (void) snprintf(si->handle, sizeof (si->handle), "%s", name);
133188447a05SGarrett D'Amore (void) snprintf(si->label, sizeof (si->label), "%s", name);
133288447a05SGarrett D'Amore si->latency = -1;
133388447a05SGarrett D'Amore si->card_number = n;
133488447a05SGarrett D'Amore si->mixer_dev = n - 1;
133588447a05SGarrett D'Amore
133688447a05SGarrett D'Amore if (release)
133788447a05SGarrett D'Amore auclnt_release_dev(d);
133888447a05SGarrett D'Amore
133988447a05SGarrett D'Amore return (0);
134088447a05SGarrett D'Amore }
134188447a05SGarrett D'Amore
134288447a05SGarrett D'Amore static int
sound_mixer_info(audio_client_t * c,mixer_info * mi)134388447a05SGarrett D'Amore sound_mixer_info(audio_client_t *c, mixer_info *mi)
134488447a05SGarrett D'Amore {
134588447a05SGarrett D'Amore audio_dev_t *d;
134688447a05SGarrett D'Amore const char *name;
134788447a05SGarrett D'Amore
134888447a05SGarrett D'Amore d = auclnt_get_dev(c);
134988447a05SGarrett D'Amore
135088447a05SGarrett D'Amore name = auclnt_get_dev_name(d);
135188447a05SGarrett D'Amore (void) snprintf(mi->id, sizeof (mi->id), "%s", name);
135288447a05SGarrett D'Amore (void) snprintf(mi->name, sizeof (mi->name), "%s", name);
135388447a05SGarrett D'Amore (void) snprintf(mi->handle, sizeof (mi->handle), "%s", name);
1354682cb104SGarrett D'Amore mi->modify_counter = (int)auclnt_dev_get_serial(d);
135588447a05SGarrett D'Amore mi->card_number = auclnt_get_dev_index(d);
135688447a05SGarrett D'Amore mi->port_number = 0;
135788447a05SGarrett D'Amore return (0);
135888447a05SGarrett D'Amore }
135988447a05SGarrett D'Amore
136088447a05SGarrett D'Amore static int
sound_mixer_read_devmask(audio_client_t * c,int * devmask)136188447a05SGarrett D'Amore sound_mixer_read_devmask(audio_client_t *c, int *devmask)
136288447a05SGarrett D'Amore {
136388447a05SGarrett D'Amore _NOTE(ARGUNUSED(c));
136488447a05SGarrett D'Amore *devmask = SOUND_MASK_VOLUME | SOUND_MASK_PCM | SOUND_MASK_IGAIN;
136588447a05SGarrett D'Amore return (0);
136688447a05SGarrett D'Amore }
136788447a05SGarrett D'Amore
136888447a05SGarrett D'Amore static int
sound_mixer_read_recmask(audio_client_t * c,int * recmask)136988447a05SGarrett D'Amore sound_mixer_read_recmask(audio_client_t *c, int *recmask)
137088447a05SGarrett D'Amore {
137188447a05SGarrett D'Amore _NOTE(ARGUNUSED(c));
137288447a05SGarrett D'Amore *recmask = 0;
137388447a05SGarrett D'Amore return (0);
137488447a05SGarrett D'Amore }
137588447a05SGarrett D'Amore
137688447a05SGarrett D'Amore static int
sound_mixer_read_recsrc(audio_client_t * c,int * recsrc)137788447a05SGarrett D'Amore sound_mixer_read_recsrc(audio_client_t *c, int *recsrc)
137888447a05SGarrett D'Amore {
137988447a05SGarrett D'Amore _NOTE(ARGUNUSED(c));
138088447a05SGarrett D'Amore *recsrc = 0;
138188447a05SGarrett D'Amore return (0);
138288447a05SGarrett D'Amore }
138388447a05SGarrett D'Amore
138488447a05SGarrett D'Amore static int
sound_mixer_read_caps(audio_client_t * c,int * caps)138588447a05SGarrett D'Amore sound_mixer_read_caps(audio_client_t *c, int *caps)
138688447a05SGarrett D'Amore {
138788447a05SGarrett D'Amore _NOTE(ARGUNUSED(c));
138888447a05SGarrett D'Amore /* single recording source... sort of */
138988447a05SGarrett D'Amore *caps = SOUND_CAP_EXCL_INPUT;
139088447a05SGarrett D'Amore return (0);
139188447a05SGarrett D'Amore }
139288447a05SGarrett D'Amore
139388447a05SGarrett D'Amore static int
sndctl_mixerinfo(audio_client_t * c,oss_mixerinfo * mi)139488447a05SGarrett D'Amore sndctl_mixerinfo(audio_client_t *c, oss_mixerinfo *mi)
139588447a05SGarrett D'Amore {
139688447a05SGarrett D'Amore audio_dev_t *d;
139788447a05SGarrett D'Amore ossdev_t *odev;
139888447a05SGarrett D'Amore const char *name;
139988447a05SGarrett D'Amore int n;
140088447a05SGarrett D'Amore boolean_t release = B_FALSE;
140188447a05SGarrett D'Amore
140288447a05SGarrett D'Amore if ((n = mi->dev) == -1) {
140388447a05SGarrett D'Amore release = B_FALSE;
140488447a05SGarrett D'Amore d = auclnt_get_dev(c);
140588447a05SGarrett D'Amore n = auclnt_get_dev_index(d);
140688447a05SGarrett D'Amore } else {
140788447a05SGarrett D'Amore release = B_TRUE;
140888447a05SGarrett D'Amore n++;
140988447a05SGarrett D'Amore d = auclnt_hold_dev_by_index(n);
141088447a05SGarrett D'Amore }
141188447a05SGarrett D'Amore
141288447a05SGarrett D'Amore bzero(mi, sizeof (*mi));
141388447a05SGarrett D'Amore mi->dev = n - 1;
141488447a05SGarrett D'Amore
141588447a05SGarrett D'Amore if (d == NULL) {
141688447a05SGarrett D'Amore mi->card_number = n;
141788447a05SGarrett D'Amore mi->enabled = 0;
141888447a05SGarrett D'Amore mi->legacy_device = -1;
141988447a05SGarrett D'Amore (void) snprintf(mi->name, sizeof (mi->name), "<removed>");
142088447a05SGarrett D'Amore (void) snprintf(mi->id, sizeof (mi->id), "<removed>");
142188447a05SGarrett D'Amore return (0);
142288447a05SGarrett D'Amore }
142388447a05SGarrett D'Amore
142488447a05SGarrett D'Amore if ((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) {
142588447a05SGarrett D'Amore if (release)
142688447a05SGarrett D'Amore auclnt_release_dev(d);
142788447a05SGarrett D'Amore return (EINVAL);
142888447a05SGarrett D'Amore }
142988447a05SGarrett D'Amore
143088447a05SGarrett D'Amore name = auclnt_get_dev_name(d);
143188447a05SGarrett D'Amore (void) snprintf(mi->name, sizeof (mi->name), "%s", name);
143288447a05SGarrett D'Amore (void) snprintf(mi->id, sizeof (mi->id), "%s", name);
143388447a05SGarrett D'Amore (void) snprintf(mi->handle, sizeof (mi->handle), "%s", name);
1434682cb104SGarrett D'Amore mi->modify_counter = (int)auclnt_dev_get_serial(d);
143588447a05SGarrett D'Amore mi->card_number = auclnt_get_dev_index(d);
143688447a05SGarrett D'Amore mi->legacy_device = auclnt_get_dev_number(d);
143788447a05SGarrett D'Amore if (mi->legacy_device >= 0) {
143888447a05SGarrett D'Amore (void) snprintf(mi->devnode, sizeof (mi->devnode),
143988447a05SGarrett D'Amore "/dev/sound/%s:%dmixer",
144088447a05SGarrett D'Amore auclnt_get_dev_driver(d), auclnt_get_dev_instance(d));
144188447a05SGarrett D'Amore mi->enabled = 1;
144288447a05SGarrett D'Amore } else {
144388447a05SGarrett D'Amore /* special nodes use generic sndstat node */
144488447a05SGarrett D'Amore (void) snprintf(mi->devnode, sizeof (mi->devnode),
144588447a05SGarrett D'Amore "/dev/sndstat");
144688447a05SGarrett D'Amore mi->enabled = 0;
144788447a05SGarrett D'Amore }
144888447a05SGarrett D'Amore mi->nrext = odev->d_nctrl;
144988447a05SGarrett D'Amore
145088447a05SGarrett D'Amore if (release)
145188447a05SGarrett D'Amore auclnt_release_dev(d);
145288447a05SGarrett D'Amore
145388447a05SGarrett D'Amore return (0);
145488447a05SGarrett D'Amore }
145588447a05SGarrett D'Amore
145688447a05SGarrett D'Amore static int
sndctl_dsp_getblksize(audio_client_t * c,int * fragsz)145788447a05SGarrett D'Amore sndctl_dsp_getblksize(audio_client_t *c, int *fragsz)
145888447a05SGarrett D'Amore {
145988447a05SGarrett D'Amore int oflag = auclnt_get_oflag(c);
146088447a05SGarrett D'Amore
146188447a05SGarrett D'Amore if (oflag & FWRITE)
146288447a05SGarrett D'Amore *fragsz = auclnt_get_fragsz(auclnt_output_stream(c));
146388447a05SGarrett D'Amore else if (oflag & FREAD)
146488447a05SGarrett D'Amore *fragsz = auclnt_get_fragsz(auclnt_input_stream(c));
146588447a05SGarrett D'Amore
146688447a05SGarrett D'Amore return (0);
146788447a05SGarrett D'Amore }
146888447a05SGarrett D'Amore
146988447a05SGarrett D'Amore static int
sndctl_dsp_getospace(audio_client_t * c,audio_buf_info * bi)147088447a05SGarrett D'Amore sndctl_dsp_getospace(audio_client_t *c, audio_buf_info *bi)
147188447a05SGarrett D'Amore {
147288447a05SGarrett D'Amore audio_stream_t *sp;
147388447a05SGarrett D'Amore unsigned n;
147488447a05SGarrett D'Amore
147588447a05SGarrett D'Amore if ((auclnt_get_oflag(c) & FWRITE) == 0) {
147688447a05SGarrett D'Amore return (EACCES);
147788447a05SGarrett D'Amore }
147888447a05SGarrett D'Amore
147988447a05SGarrett D'Amore sp = auclnt_output_stream(c);
148088447a05SGarrett D'Amore n = auclnt_get_nframes(sp) - auclnt_get_count(sp);
148188447a05SGarrett D'Amore
148288447a05SGarrett D'Amore bi->fragsize = auclnt_get_fragsz(sp);
148388447a05SGarrett D'Amore bi->fragstotal = auclnt_get_nfrags(sp);
148488447a05SGarrett D'Amore bi->bytes = (n * auclnt_get_framesz(sp));
148588447a05SGarrett D'Amore bi->fragments = bi->bytes / bi->fragsize;
148688447a05SGarrett D'Amore
148788447a05SGarrett D'Amore return (0);
148888447a05SGarrett D'Amore }
148988447a05SGarrett D'Amore
149088447a05SGarrett D'Amore static int
sndctl_dsp_getispace(audio_client_t * c,audio_buf_info * bi)149188447a05SGarrett D'Amore sndctl_dsp_getispace(audio_client_t *c, audio_buf_info *bi)
149288447a05SGarrett D'Amore {
149388447a05SGarrett D'Amore audio_stream_t *sp;
149488447a05SGarrett D'Amore unsigned n;
149588447a05SGarrett D'Amore
149688447a05SGarrett D'Amore if ((auclnt_get_oflag(c) & FREAD) == 0) {
149788447a05SGarrett D'Amore return (EACCES);
149888447a05SGarrett D'Amore }
149988447a05SGarrett D'Amore
150088447a05SGarrett D'Amore sp = auclnt_input_stream(c);
150188447a05SGarrett D'Amore n = auclnt_get_count(sp);
150288447a05SGarrett D'Amore
150388447a05SGarrett D'Amore bi->fragsize = auclnt_get_fragsz(sp);
150488447a05SGarrett D'Amore bi->fragstotal = auclnt_get_nfrags(sp);
150588447a05SGarrett D'Amore bi->bytes = (n * auclnt_get_framesz(sp));
150688447a05SGarrett D'Amore bi->fragments = bi->bytes / bi->fragsize;
150788447a05SGarrett D'Amore
150888447a05SGarrett D'Amore return (0);
150988447a05SGarrett D'Amore }
151088447a05SGarrett D'Amore
151188447a05SGarrett D'Amore static int
sndctl_dsp_getodelay(audio_client_t * c,int * bytes)151288447a05SGarrett D'Amore sndctl_dsp_getodelay(audio_client_t *c, int *bytes)
151388447a05SGarrett D'Amore {
151488447a05SGarrett D'Amore unsigned framesz;
151588447a05SGarrett D'Amore unsigned slen, flen;
151688447a05SGarrett D'Amore
151788447a05SGarrett D'Amore if (auclnt_get_oflag(c) & FWRITE) {
151888447a05SGarrett D'Amore audio_stream_t *sp = auclnt_output_stream(c);
151988447a05SGarrett D'Amore framesz = auclnt_get_framesz(sp);
152088447a05SGarrett D'Amore auclnt_get_output_qlen(c, &slen, &flen);
152188447a05SGarrett D'Amore *bytes = (slen + flen) * framesz;
152288447a05SGarrett D'Amore } else {
152388447a05SGarrett D'Amore *bytes = 0;
152488447a05SGarrett D'Amore }
152588447a05SGarrett D'Amore return (0);
152688447a05SGarrett D'Amore }
152788447a05SGarrett D'Amore
152888447a05SGarrett D'Amore static int
sndctl_dsp_current_iptr(audio_client_t * c,oss_count_t * count)152988447a05SGarrett D'Amore sndctl_dsp_current_iptr(audio_client_t *c, oss_count_t *count)
153088447a05SGarrett D'Amore {
153188447a05SGarrett D'Amore if (auclnt_get_oflag(c) & FREAD) {
153288447a05SGarrett D'Amore count->samples = auclnt_get_samples(auclnt_input_stream(c));
153388447a05SGarrett D'Amore count->fifo_samples = 0; /* not quite accurate */
153488447a05SGarrett D'Amore } else {
153588447a05SGarrett D'Amore count->samples = 0;
153688447a05SGarrett D'Amore count->fifo_samples = 0;
153788447a05SGarrett D'Amore }
153888447a05SGarrett D'Amore return (0);
153988447a05SGarrett D'Amore }
154088447a05SGarrett D'Amore
154188447a05SGarrett D'Amore static int
sndctl_dsp_current_optr(audio_client_t * c,oss_count_t * count)154288447a05SGarrett D'Amore sndctl_dsp_current_optr(audio_client_t *c, oss_count_t *count)
154388447a05SGarrett D'Amore {
154488447a05SGarrett D'Amore unsigned samples, fifo;
154588447a05SGarrett D'Amore
154688447a05SGarrett D'Amore if (auclnt_get_oflag(c) & FWRITE) {
154788447a05SGarrett D'Amore auclnt_get_output_qlen(c, &samples, &fifo);
154888447a05SGarrett D'Amore count->samples = samples;
154988447a05SGarrett D'Amore count->fifo_samples = fifo;
155088447a05SGarrett D'Amore } else {
155188447a05SGarrett D'Amore count->samples = 0;
155288447a05SGarrett D'Amore count->fifo_samples = 0;
155388447a05SGarrett D'Amore }
155488447a05SGarrett D'Amore return (0);
155588447a05SGarrett D'Amore }
155688447a05SGarrett D'Amore
155788447a05SGarrett D'Amore static int
sndctl_dsp_getoptr(audio_client_t * c,count_info * ci)155888447a05SGarrett D'Amore sndctl_dsp_getoptr(audio_client_t *c, count_info *ci)
155988447a05SGarrett D'Amore {
156088447a05SGarrett D'Amore audio_stream_t *sp;
156188447a05SGarrett D'Amore unsigned framesz;
156288447a05SGarrett D'Amore unsigned fragsz;
156388447a05SGarrett D'Amore
156488447a05SGarrett D'Amore bzero(ci, sizeof (*ci));
156588447a05SGarrett D'Amore if ((auclnt_get_oflag(c) & FWRITE) == 0) {
156688447a05SGarrett D'Amore return (0);
156788447a05SGarrett D'Amore }
156888447a05SGarrett D'Amore sp = auclnt_output_stream(c);
156988447a05SGarrett D'Amore framesz = auclnt_get_framesz(sp);
157088447a05SGarrett D'Amore fragsz = auclnt_get_fragsz(sp);
157188447a05SGarrett D'Amore ci->blocks = auclnt_get_samples(sp) * framesz / fragsz;
157288447a05SGarrett D'Amore auclnt_set_samples(sp, 0);
157388447a05SGarrett D'Amore ci->bytes = auclnt_get_tail(sp) * framesz;
157488447a05SGarrett D'Amore ci->ptr = auclnt_get_tidx(sp) * framesz;
157588447a05SGarrett D'Amore return (0);
157688447a05SGarrett D'Amore }
157788447a05SGarrett D'Amore
157888447a05SGarrett D'Amore static int
sndctl_dsp_getiptr(audio_client_t * c,count_info * ci)157988447a05SGarrett D'Amore sndctl_dsp_getiptr(audio_client_t *c, count_info *ci)
158088447a05SGarrett D'Amore {
158188447a05SGarrett D'Amore audio_stream_t *sp;
158288447a05SGarrett D'Amore unsigned framesz;
158388447a05SGarrett D'Amore unsigned fragsz;
158488447a05SGarrett D'Amore
158588447a05SGarrett D'Amore bzero(ci, sizeof (*ci));
158688447a05SGarrett D'Amore if ((auclnt_get_oflag(c) & FREAD) == 0) {
158788447a05SGarrett D'Amore return (0);
158888447a05SGarrett D'Amore }
158988447a05SGarrett D'Amore sp = auclnt_input_stream(c);
159088447a05SGarrett D'Amore framesz = auclnt_get_framesz(sp);
159188447a05SGarrett D'Amore fragsz = auclnt_get_fragsz(sp);
159288447a05SGarrett D'Amore ci->blocks = auclnt_get_samples(sp) * framesz / fragsz;
159388447a05SGarrett D'Amore auclnt_set_samples(sp, 0);
159488447a05SGarrett D'Amore ci->bytes = auclnt_get_head(sp) * framesz;
159588447a05SGarrett D'Amore ci->ptr = auclnt_get_hidx(sp) * framesz;
159688447a05SGarrett D'Amore return (0);
159788447a05SGarrett D'Amore }
159888447a05SGarrett D'Amore
159988447a05SGarrett D'Amore static int
sndctl_dsp_geterror(audio_client_t * c,audio_errinfo * bi)160088447a05SGarrett D'Amore sndctl_dsp_geterror(audio_client_t *c, audio_errinfo *bi)
160188447a05SGarrett D'Amore {
160288447a05SGarrett D'Amore audio_stream_t *sp;
160388447a05SGarrett D'Amore unsigned fragsz;
160488447a05SGarrett D'Amore /*
160588447a05SGarrett D'Amore * Note: The use of this structure is unsafe... different
160688447a05SGarrett D'Amore * meanings for error codes are used by different implementations,
160788447a05SGarrett D'Amore * according to the spec. (Even different versions of the same
160888447a05SGarrett D'Amore * implementation could have different values.)
160988447a05SGarrett D'Amore *
161088447a05SGarrett D'Amore * Rather than try to come up with a reliable solution here, we
161188447a05SGarrett D'Amore * don't use it. If you want to report errors, or see the result
161288447a05SGarrett D'Amore * of errors, use syslog.
161388447a05SGarrett D'Amore */
161488447a05SGarrett D'Amore bzero(bi, sizeof (*bi));
161588447a05SGarrett D'Amore
161688447a05SGarrett D'Amore sp = auclnt_output_stream(c);
161788447a05SGarrett D'Amore fragsz = max(auclnt_get_fragsz(sp), 1);
161888447a05SGarrett D'Amore bi->play_underruns = (int)((auclnt_get_errors(sp) + (fragsz - 1)) /
161988447a05SGarrett D'Amore fragsz);
162088447a05SGarrett D'Amore auclnt_set_errors(sp, 0);
162188447a05SGarrett D'Amore
162288447a05SGarrett D'Amore sp = auclnt_input_stream(c);
162388447a05SGarrett D'Amore fragsz = max(auclnt_get_fragsz(sp), 1);
162488447a05SGarrett D'Amore bi->rec_overruns = (int)((auclnt_get_errors(sp) + (fragsz - 1)) /
162588447a05SGarrett D'Amore fragsz);
162688447a05SGarrett D'Amore auclnt_set_errors(sp, 0);
162788447a05SGarrett D'Amore
162888447a05SGarrett D'Amore return (0);
162988447a05SGarrett D'Amore }
163088447a05SGarrett D'Amore
163188447a05SGarrett D'Amore static int
sndctl_sun_send_number(audio_client_t * c,int * num,cred_t * cr)163288447a05SGarrett D'Amore sndctl_sun_send_number(audio_client_t *c, int *num, cred_t *cr)
163388447a05SGarrett D'Amore {
163488447a05SGarrett D'Amore audio_dev_t *dev;
163588447a05SGarrett D'Amore int rv;
163688447a05SGarrett D'Amore
163788447a05SGarrett D'Amore if ((rv = drv_priv(cr)) != 0) {
163888447a05SGarrett D'Amore return (rv);
163988447a05SGarrett D'Amore }
164088447a05SGarrett D'Amore
164188447a05SGarrett D'Amore dev = auclnt_get_dev(c);
164288447a05SGarrett D'Amore auclnt_set_dev_number(dev, *num);
164388447a05SGarrett D'Amore return (0);
164488447a05SGarrett D'Amore }
164588447a05SGarrett D'Amore
164688447a05SGarrett D'Amore static int
oss_getversion(int * versp)164788447a05SGarrett D'Amore oss_getversion(int *versp)
164888447a05SGarrett D'Amore {
164988447a05SGarrett D'Amore *versp = OSS_VERSION;
165088447a05SGarrett D'Amore return (0);
165188447a05SGarrett D'Amore }
165288447a05SGarrett D'Amore
165388447a05SGarrett D'Amore static int
oss_ioctl(audio_client_t * c,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)165488447a05SGarrett D'Amore oss_ioctl(audio_client_t *c, int cmd, intptr_t arg, int mode, cred_t *credp,
165588447a05SGarrett D'Amore int *rvalp)
165688447a05SGarrett D'Amore {
165788447a05SGarrett D'Amore int sz;
165888447a05SGarrett D'Amore void *data;
165988447a05SGarrett D'Amore int rv = 0;
166088447a05SGarrett D'Amore
166188447a05SGarrett D'Amore _NOTE(ARGUNUSED(credp));
166288447a05SGarrett D'Amore
166388447a05SGarrett D'Amore sz = OSSIOC_GETSZ(cmd);
166488447a05SGarrett D'Amore
166588447a05SGarrett D'Amore if ((cmd & (OSSIOC_IN | OSSIOC_OUT)) && sz) {
166688447a05SGarrett D'Amore if ((data = kmem_zalloc(sz, KM_NOSLEEP)) == NULL) {
166788447a05SGarrett D'Amore return (ENOMEM);
166888447a05SGarrett D'Amore }
166988447a05SGarrett D'Amore } else {
167088447a05SGarrett D'Amore sz = 0;
167188447a05SGarrett D'Amore }
167288447a05SGarrett D'Amore
167388447a05SGarrett D'Amore if (cmd & OSSIOC_IN) {
167488447a05SGarrett D'Amore if ((rv = ddi_copyin((void *)arg, data, sz, mode)) != 0) {
167588447a05SGarrett D'Amore goto done;
167688447a05SGarrett D'Amore }
167788447a05SGarrett D'Amore }
167888447a05SGarrett D'Amore
167988447a05SGarrett D'Amore switch (cmd) {
168088447a05SGarrett D'Amore /*
168188447a05SGarrett D'Amore * DSP specific ioctls
168288447a05SGarrett D'Amore */
168388447a05SGarrett D'Amore case SNDCTL_DSP_HALT:
168488447a05SGarrett D'Amore rv = sndctl_dsp_halt(c);
168588447a05SGarrett D'Amore break;
168688447a05SGarrett D'Amore
168788447a05SGarrett D'Amore case SNDCTL_DSP_SYNC:
168888447a05SGarrett D'Amore rv = sndctl_dsp_sync(c);
168988447a05SGarrett D'Amore break;
169088447a05SGarrett D'Amore
169188447a05SGarrett D'Amore case SNDCTL_DSP_SPEED:
169288447a05SGarrett D'Amore rv = sndctl_dsp_speed(c, (int *)data);
169388447a05SGarrett D'Amore break;
169488447a05SGarrett D'Amore case SNDCTL_DSP_SETFMT:
169588447a05SGarrett D'Amore rv = sndctl_dsp_setfmt(c, (int *)data);
169688447a05SGarrett D'Amore break;
169788447a05SGarrett D'Amore case SNDCTL_DSP_GETFMTS:
169888447a05SGarrett D'Amore rv = sndctl_dsp_getfmts(c, (int *)data);
169988447a05SGarrett D'Amore break;
170088447a05SGarrett D'Amore case SNDCTL_DSP_STEREO:
170188447a05SGarrett D'Amore rv = sndctl_dsp_stereo(c, (int *)data);
170288447a05SGarrett D'Amore break;
170388447a05SGarrett D'Amore case SNDCTL_DSP_CHANNELS:
170488447a05SGarrett D'Amore rv = sndctl_dsp_channels(c, (int *)data);
170588447a05SGarrett D'Amore break;
170688447a05SGarrett D'Amore case SNDCTL_DSP_POST:
170788447a05SGarrett D'Amore rv = sndctl_dsp_post(c);
170888447a05SGarrett D'Amore break;
170988447a05SGarrett D'Amore case SNDCTL_DSP_GETCAPS:
171088447a05SGarrett D'Amore rv = sndctl_dsp_getcaps(c, (int *)data);
171188447a05SGarrett D'Amore break;
171288447a05SGarrett D'Amore case SNDCTL_DSP_GETTRIGGER:
171388447a05SGarrett D'Amore rv = sndctl_dsp_gettrigger(c, (int *)data);
171488447a05SGarrett D'Amore break;
171588447a05SGarrett D'Amore case SNDCTL_DSP_SETTRIGGER:
171688447a05SGarrett D'Amore rv = sndctl_dsp_settrigger(c, (int *)data);
171788447a05SGarrett D'Amore break;
171888447a05SGarrett D'Amore case SNDCTL_DSP_GETPLAYVOL:
171988447a05SGarrett D'Amore case SOUND_MIXER_READ_VOLUME: /* legacy mixer on dsp */
172088447a05SGarrett D'Amore case SOUND_MIXER_READ_PCM: /* legacy mixer on dsp */
172188447a05SGarrett D'Amore case SOUND_MIXER_READ_OGAIN: /* legacy mixer on dsp */
172288447a05SGarrett D'Amore rv = sndctl_dsp_getplayvol(c, (int *)data);
172388447a05SGarrett D'Amore break;
172488447a05SGarrett D'Amore case SOUND_MIXER_WRITE_VOLUME: /* legacy mixer on dsp */
172588447a05SGarrett D'Amore case SOUND_MIXER_WRITE_PCM: /* legacy mixer on dsp */
172688447a05SGarrett D'Amore case SOUND_MIXER_WRITE_OGAIN: /* legacy mixer on dsp */
172788447a05SGarrett D'Amore rv = sound_mixer_write_ogain(c, (int *)data);
172888447a05SGarrett D'Amore break;
172988447a05SGarrett D'Amore case SNDCTL_DSP_SETPLAYVOL:
173088447a05SGarrett D'Amore rv = sndctl_dsp_setplayvol(c, (int *)data);
173188447a05SGarrett D'Amore break;
173288447a05SGarrett D'Amore case SNDCTL_DSP_READCTL:
173388447a05SGarrett D'Amore rv = sndctl_dsp_readctl(c, (oss_digital_control *)data);
173488447a05SGarrett D'Amore break;
173588447a05SGarrett D'Amore case SNDCTL_DSP_WRITECTL:
173688447a05SGarrett D'Amore rv = sndctl_dsp_writectl(c, (oss_digital_control *)data);
173788447a05SGarrett D'Amore break;
173888447a05SGarrett D'Amore case SNDCTL_DSP_COOKEDMODE:
173988447a05SGarrett D'Amore rv = sndctl_dsp_cookedmode(c, (int *)data);
174088447a05SGarrett D'Amore break;
174188447a05SGarrett D'Amore case SNDCTL_DSP_SILENCE:
174288447a05SGarrett D'Amore rv = sndctl_dsp_silence(c);
174388447a05SGarrett D'Amore break;
174488447a05SGarrett D'Amore case SNDCTL_DSP_SKIP:
174588447a05SGarrett D'Amore rv = sndctl_dsp_skip(c);
174688447a05SGarrett D'Amore break;
174788447a05SGarrett D'Amore case SNDCTL_DSP_HALT_INPUT:
174888447a05SGarrett D'Amore rv = sndctl_dsp_halt_input(c);
174988447a05SGarrett D'Amore break;
175088447a05SGarrett D'Amore case SNDCTL_DSP_HALT_OUTPUT:
175188447a05SGarrett D'Amore rv = sndctl_dsp_halt_output(c);
175288447a05SGarrett D'Amore break;
175388447a05SGarrett D'Amore case SNDCTL_DSP_GET_RECSRC_NAMES:
175488447a05SGarrett D'Amore rv = sndctl_dsp_get_recsrc_names(c, (oss_mixer_enuminfo *)data);
175588447a05SGarrett D'Amore break;
175688447a05SGarrett D'Amore case SNDCTL_DSP_SETFRAGMENT:
175788447a05SGarrett D'Amore rv = sndctl_dsp_setfragment(c, (int *)data);
175888447a05SGarrett D'Amore break;
175988447a05SGarrett D'Amore case SNDCTL_DSP_GET_RECSRC:
176088447a05SGarrett D'Amore rv = sndctl_dsp_get_recsrc(c, (int *)data);
176188447a05SGarrett D'Amore break;
176288447a05SGarrett D'Amore case SNDCTL_DSP_SET_RECSRC:
176388447a05SGarrett D'Amore rv = sndctl_dsp_set_recsrc(c, (int *)data);
176488447a05SGarrett D'Amore break;
176588447a05SGarrett D'Amore case SNDCTL_DSP_GET_PLAYTGT_NAMES:
176688447a05SGarrett D'Amore rv = sndctl_dsp_get_playtgt_names(c,
176788447a05SGarrett D'Amore (oss_mixer_enuminfo *)data);
176888447a05SGarrett D'Amore break;
176988447a05SGarrett D'Amore case SNDCTL_DSP_GET_PLAYTGT:
177088447a05SGarrett D'Amore rv = sndctl_dsp_get_playtgt(c, (int *)data);
177188447a05SGarrett D'Amore break;
177288447a05SGarrett D'Amore case SNDCTL_DSP_SET_PLAYTGT:
177388447a05SGarrett D'Amore rv = sndctl_dsp_set_playtgt(c, (int *)data);
177488447a05SGarrett D'Amore break;
177588447a05SGarrett D'Amore case SNDCTL_DSP_GETRECVOL:
177688447a05SGarrett D'Amore case SOUND_MIXER_READ_RECGAIN: /* legacy mixer on dsp */
177788447a05SGarrett D'Amore case SOUND_MIXER_READ_RECLEV: /* legacy mixer on dsp */
177888447a05SGarrett D'Amore case SOUND_MIXER_READ_IGAIN: /* legacy mixer on dsp */
177988447a05SGarrett D'Amore rv = sndctl_dsp_getrecvol(c, (int *)data);
178088447a05SGarrett D'Amore break;
178188447a05SGarrett D'Amore case SOUND_MIXER_WRITE_RECGAIN: /* legacy mixer on dsp */
178288447a05SGarrett D'Amore case SOUND_MIXER_WRITE_RECLEV: /* legacy mixer on dsp */
178388447a05SGarrett D'Amore case SOUND_MIXER_WRITE_IGAIN: /* legacy mixer on dsp */
178488447a05SGarrett D'Amore rv = sound_mixer_write_igain(c, (int *)data);
178588447a05SGarrett D'Amore break;
178688447a05SGarrett D'Amore case SNDCTL_DSP_SETRECVOL:
178788447a05SGarrett D'Amore rv = sndctl_dsp_setrecvol(c, (int *)data);
178888447a05SGarrett D'Amore break;
1789a702341cSGarrett D'Amore case SNDCTL_DSP_SUBDIVIDE: /* Ignored */
179088447a05SGarrett D'Amore case SNDCTL_DSP_SETDUPLEX: /* Ignored */
179188447a05SGarrett D'Amore case SNDCTL_DSP_LOW_WATER: /* Ignored */
179288447a05SGarrett D'Amore case SNDCTL_DSP_PROFILE: /* Ignored */
179388447a05SGarrett D'Amore rv = 0;
179488447a05SGarrett D'Amore break;
1795a702341cSGarrett D'Amore case SNDCTL_DSP_POLICY:
1796a702341cSGarrett D'Amore rv = sndctl_dsp_policy(c, (int *)data);
1797a702341cSGarrett D'Amore break;
179888447a05SGarrett D'Amore case SNDCTL_DSP_GETBLKSIZE:
179988447a05SGarrett D'Amore rv = sndctl_dsp_getblksize(c, (int *)data);
180088447a05SGarrett D'Amore break;
180188447a05SGarrett D'Amore case SNDCTL_DSP_GETOSPACE:
180288447a05SGarrett D'Amore rv = sndctl_dsp_getospace(c, (audio_buf_info *)data);
180388447a05SGarrett D'Amore break;
180488447a05SGarrett D'Amore case SNDCTL_DSP_GETISPACE:
180588447a05SGarrett D'Amore rv = sndctl_dsp_getispace(c, (audio_buf_info *)data);
180688447a05SGarrett D'Amore break;
180788447a05SGarrett D'Amore case SNDCTL_DSP_GETODELAY:
180888447a05SGarrett D'Amore rv = sndctl_dsp_getodelay(c, (int *)data);
180988447a05SGarrett D'Amore break;
181088447a05SGarrett D'Amore case SNDCTL_DSP_GETOPTR:
181188447a05SGarrett D'Amore rv = sndctl_dsp_getoptr(c, (count_info *)data);
181288447a05SGarrett D'Amore break;
181388447a05SGarrett D'Amore case SNDCTL_DSP_GETIPTR:
181488447a05SGarrett D'Amore rv = sndctl_dsp_getiptr(c, (count_info *)data);
181588447a05SGarrett D'Amore break;
181688447a05SGarrett D'Amore case SNDCTL_DSP_GETERROR:
181788447a05SGarrett D'Amore rv = sndctl_dsp_geterror(c, (audio_errinfo *)data);
181888447a05SGarrett D'Amore break;
181988447a05SGarrett D'Amore case SNDCTL_DSP_CURRENT_IPTR:
182088447a05SGarrett D'Amore rv = sndctl_dsp_current_iptr(c, (oss_count_t *)data);
182188447a05SGarrett D'Amore break;
182288447a05SGarrett D'Amore case SNDCTL_DSP_CURRENT_OPTR:
182388447a05SGarrett D'Amore rv = sndctl_dsp_current_optr(c, (oss_count_t *)data);
182488447a05SGarrett D'Amore break;
182588447a05SGarrett D'Amore
182688447a05SGarrett D'Amore /*
182788447a05SGarrett D'Amore * Shared ioctls with /dev/mixer.
182888447a05SGarrett D'Amore */
182988447a05SGarrett D'Amore case OSS_GETVERSION:
183088447a05SGarrett D'Amore rv = oss_getversion((int *)data);
183188447a05SGarrett D'Amore break;
183288447a05SGarrett D'Amore case SNDCTL_CARDINFO:
183388447a05SGarrett D'Amore rv = sndctl_cardinfo(c, (oss_card_info *)data);
183488447a05SGarrett D'Amore break;
183588447a05SGarrett D'Amore case SNDCTL_ENGINEINFO:
183688447a05SGarrett D'Amore case SNDCTL_AUDIOINFO:
183788447a05SGarrett D'Amore case SNDCTL_AUDIOINFO_EX:
183888447a05SGarrett D'Amore rv = sndctl_audioinfo(c, (oss_audioinfo *)data);
183988447a05SGarrett D'Amore break;
184088447a05SGarrett D'Amore case SNDCTL_SYSINFO:
184188447a05SGarrett D'Amore rv = sndctl_sysinfo((oss_sysinfo *)data);
184288447a05SGarrett D'Amore break;
184388447a05SGarrett D'Amore case SNDCTL_MIXERINFO:
184488447a05SGarrett D'Amore rv = sndctl_mixerinfo(c, (oss_mixerinfo *)data);
184588447a05SGarrett D'Amore break;
184688447a05SGarrett D'Amore case SOUND_MIXER_INFO:
184788447a05SGarrett D'Amore rv = sound_mixer_info(c, (mixer_info *)data);
184888447a05SGarrett D'Amore break;
184988447a05SGarrett D'Amore
185088447a05SGarrett D'Amore /*
185188447a05SGarrett D'Amore * These are mixer ioctls that are virtualized for the DSP
185288447a05SGarrett D'Amore * device. They are accessible via either /dev/mixer or
185388447a05SGarrett D'Amore * /dev/dsp.
185488447a05SGarrett D'Amore */
185588447a05SGarrett D'Amore case SOUND_MIXER_READ_RECSRC:
185688447a05SGarrett D'Amore case SOUND_MIXER_WRITE_RECSRC:
185788447a05SGarrett D'Amore rv = sound_mixer_read_recsrc(c, (int *)data);
185888447a05SGarrett D'Amore break;
185988447a05SGarrett D'Amore
186088447a05SGarrett D'Amore case SOUND_MIXER_READ_DEVMASK:
186188447a05SGarrett D'Amore case SOUND_MIXER_READ_STEREODEVS:
186288447a05SGarrett D'Amore rv = sound_mixer_read_devmask(c, (int *)data);
186388447a05SGarrett D'Amore break;
186488447a05SGarrett D'Amore
186588447a05SGarrett D'Amore case SOUND_MIXER_READ_RECMASK:
186688447a05SGarrett D'Amore rv = sound_mixer_read_recmask(c, (int *)data);
186788447a05SGarrett D'Amore break;
186888447a05SGarrett D'Amore
186988447a05SGarrett D'Amore case SOUND_MIXER_READ_CAPS:
187088447a05SGarrett D'Amore rv = sound_mixer_read_caps(c, (int *)data);
187188447a05SGarrett D'Amore break;
187288447a05SGarrett D'Amore
187388447a05SGarrett D'Amore /*
187488447a05SGarrett D'Amore * Ioctls we have chosen not to support for now. Some
187588447a05SGarrett D'Amore * of these are of legacy interest only.
187688447a05SGarrett D'Amore */
187788447a05SGarrett D'Amore case SNDCTL_SETSONG:
187888447a05SGarrett D'Amore case SNDCTL_GETSONG:
187988447a05SGarrett D'Amore case SNDCTL_DSP_SYNCGROUP:
188088447a05SGarrett D'Amore case SNDCTL_DSP_SYNCSTART:
188188447a05SGarrett D'Amore case SNDCTL_DSP_GET_CHNORDER:
188288447a05SGarrett D'Amore case SNDCTL_DSP_SET_CHNORDER:
188388447a05SGarrett D'Amore case SNDCTL_DSP_GETIPEAKS:
188488447a05SGarrett D'Amore case SNDCTL_DSP_GETOPEAKS:
188588447a05SGarrett D'Amore case SNDCTL_DSP_GETCHANNELMASK:
188688447a05SGarrett D'Amore case SNDCTL_DSP_BIND_CHANNEL:
188788447a05SGarrett D'Amore case SNDCTL_DSP_SETSYNCRO:
188826025630SGarrett D'Amore case SNDCTL_DSP_NONBLOCK:
188988447a05SGarrett D'Amore default:
189088447a05SGarrett D'Amore rv = EINVAL;
189188447a05SGarrett D'Amore break;
189288447a05SGarrett D'Amore }
189388447a05SGarrett D'Amore
189488447a05SGarrett D'Amore if ((rv == 0) && (cmd & OSSIOC_OUT)) {
189588447a05SGarrett D'Amore rv = ddi_copyout(data, (void *)arg, sz, mode);
189688447a05SGarrett D'Amore }
189788447a05SGarrett D'Amore if (rv == 0) {
189888447a05SGarrett D'Amore *rvalp = 0;
189988447a05SGarrett D'Amore }
190088447a05SGarrett D'Amore
190188447a05SGarrett D'Amore done:
190288447a05SGarrett D'Amore if (sz) {
190388447a05SGarrett D'Amore kmem_free(data, sz);
190488447a05SGarrett D'Amore }
190588447a05SGarrett D'Amore return (rv);
190688447a05SGarrett D'Amore }
190788447a05SGarrett D'Amore
190888447a05SGarrett D'Amore static void
oss_output(audio_client_t * c)190988447a05SGarrett D'Amore oss_output(audio_client_t *c)
191088447a05SGarrett D'Amore {
191188447a05SGarrett D'Amore auclnt_pollwakeup(c, POLLOUT);
191288447a05SGarrett D'Amore }
191388447a05SGarrett D'Amore
191488447a05SGarrett D'Amore static void
oss_input(audio_client_t * c)191588447a05SGarrett D'Amore oss_input(audio_client_t *c)
191688447a05SGarrett D'Amore {
191788447a05SGarrett D'Amore auclnt_pollwakeup(c, POLLIN | POLLRDNORM);
191888447a05SGarrett D'Amore }
191988447a05SGarrett D'Amore
192088447a05SGarrett D'Amore static int
ossmix_open(audio_client_t * c,int oflag)192188447a05SGarrett D'Amore ossmix_open(audio_client_t *c, int oflag)
192288447a05SGarrett D'Amore {
192388447a05SGarrett D'Amore int rv;
192488447a05SGarrett D'Amore ossclient_t *sc;
192588447a05SGarrett D'Amore ossdev_t *odev;
192688447a05SGarrett D'Amore
192788447a05SGarrett D'Amore _NOTE(ARGUNUSED(oflag));
192888447a05SGarrett D'Amore
1929*2c30fa45SGarrett D'Amore if ((rv = auclnt_open(c, 0)) != 0) {
193088447a05SGarrett D'Amore return (rv);
193188447a05SGarrett D'Amore }
193288447a05SGarrett D'Amore
193388447a05SGarrett D'Amore if ((sc = kmem_zalloc(sizeof (*sc), KM_NOSLEEP)) == NULL) {
193488447a05SGarrett D'Amore return (ENOMEM);
193588447a05SGarrett D'Amore }
193688447a05SGarrett D'Amore sc->o_ss_sz = 8192;
193788447a05SGarrett D'Amore if ((sc->o_ss_buf = kmem_zalloc(sc->o_ss_sz, KM_NOSLEEP)) == NULL) {
193888447a05SGarrett D'Amore kmem_free(sc, sizeof (*sc));
193988447a05SGarrett D'Amore return (ENOMEM);
194088447a05SGarrett D'Amore }
194188447a05SGarrett D'Amore auclnt_set_private(c, sc);
194288447a05SGarrett D'Amore
194388447a05SGarrett D'Amore odev = auclnt_get_minor_data(c, AUDIO_MINOR_DSP);
194488447a05SGarrett D'Amore
194588447a05SGarrett D'Amore /* set a couple of common fields */
194688447a05SGarrett D'Amore sc->o_client = c;
194788447a05SGarrett D'Amore sc->o_ossdev = odev;
194888447a05SGarrett D'Amore
194988447a05SGarrett D'Amore return (rv);
195088447a05SGarrett D'Amore }
195188447a05SGarrett D'Amore
195288447a05SGarrett D'Amore static void
ossmix_close(audio_client_t * c)195388447a05SGarrett D'Amore ossmix_close(audio_client_t *c)
195488447a05SGarrett D'Amore {
195588447a05SGarrett D'Amore ossclient_t *sc;
195688447a05SGarrett D'Amore
195788447a05SGarrett D'Amore sc = auclnt_get_private(c);
195888447a05SGarrett D'Amore
195988447a05SGarrett D'Amore kmem_free(sc->o_ss_buf, sc->o_ss_sz);
196088447a05SGarrett D'Amore kmem_free(sc, sizeof (*sc));
196188447a05SGarrett D'Amore
196288447a05SGarrett D'Amore auclnt_close(c);
196388447a05SGarrett D'Amore }
196488447a05SGarrett D'Amore
196588447a05SGarrett D'Amore static int
sndctl_mix_nrext(audio_client_t * c,int * ncp)196688447a05SGarrett D'Amore sndctl_mix_nrext(audio_client_t *c, int *ncp)
196788447a05SGarrett D'Amore {
196888447a05SGarrett D'Amore audio_dev_t *d;
196988447a05SGarrett D'Amore ossdev_t *odev;
197088447a05SGarrett D'Amore
197188447a05SGarrett D'Amore d = auclnt_get_dev(c);
197288447a05SGarrett D'Amore
197388447a05SGarrett D'Amore if ((*ncp != -1) && (*ncp != (auclnt_get_dev_index(d) - 1))) {
197488447a05SGarrett D'Amore return (ENXIO);
197588447a05SGarrett D'Amore }
197688447a05SGarrett D'Amore
197788447a05SGarrett D'Amore if ((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) {
197888447a05SGarrett D'Amore return (EINVAL);
197988447a05SGarrett D'Amore }
198088447a05SGarrett D'Amore
198188447a05SGarrett D'Amore *ncp = odev->d_nctrl;
198288447a05SGarrett D'Amore
198388447a05SGarrett D'Amore return (0);
198488447a05SGarrett D'Amore }
198588447a05SGarrett D'Amore
198688447a05SGarrett D'Amore static int
sndctl_mix_extinfo(audio_client_t * c,oss_mixext * pext)198788447a05SGarrett D'Amore sndctl_mix_extinfo(audio_client_t *c, oss_mixext *pext)
198888447a05SGarrett D'Amore {
198988447a05SGarrett D'Amore audio_dev_t *d;
199088447a05SGarrett D'Amore ossdev_t *odev;
199188447a05SGarrett D'Amore int rv = 0;
199288447a05SGarrett D'Amore int dev;
199388447a05SGarrett D'Amore
199488447a05SGarrett D'Amore d = auclnt_get_dev(c);
199588447a05SGarrett D'Amore
199688447a05SGarrett D'Amore if (((dev = pext->dev) != -1) && (dev != (auclnt_get_dev_index(d) - 1)))
199788447a05SGarrett D'Amore return (ENXIO);
199888447a05SGarrett D'Amore
199988447a05SGarrett D'Amore if (((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) ||
200088447a05SGarrett D'Amore (pext->ctrl >= odev->d_nctrl)) {
200188447a05SGarrett D'Amore return (EINVAL);
200288447a05SGarrett D'Amore }
200388447a05SGarrett D'Amore
200488447a05SGarrett D'Amore bcopy(&odev->d_exts[pext->ctrl], pext, sizeof (*pext));
200588447a05SGarrett D'Amore pext->enumbit = 0;
200688447a05SGarrett D'Amore pext->dev = dev;
200788447a05SGarrett D'Amore
200888447a05SGarrett D'Amore return (rv);
200988447a05SGarrett D'Amore }
201088447a05SGarrett D'Amore
201188447a05SGarrett D'Amore static int
sndctl_mix_enuminfo(audio_client_t * c,oss_mixer_enuminfo * ei)201288447a05SGarrett D'Amore sndctl_mix_enuminfo(audio_client_t *c, oss_mixer_enuminfo *ei)
201388447a05SGarrett D'Amore {
201488447a05SGarrett D'Amore audio_dev_t *d;
201588447a05SGarrett D'Amore audio_ctrl_desc_t desc;
201688447a05SGarrett D'Amore audio_ctrl_t *ctrl;
201788447a05SGarrett D'Amore ossdev_t *odev;
201888447a05SGarrett D'Amore uint64_t mask;
201988447a05SGarrett D'Amore int bit;
202088447a05SGarrett D'Amore ushort_t nxt;
202188447a05SGarrett D'Amore
202288447a05SGarrett D'Amore d = auclnt_get_dev(c);
202388447a05SGarrett D'Amore
202488447a05SGarrett D'Amore if ((ei->dev != -1) && (ei->dev != (auclnt_get_dev_index(d) - 1)))
202588447a05SGarrett D'Amore return (ENXIO);
202688447a05SGarrett D'Amore
202788447a05SGarrett D'Amore if (((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) ||
202888447a05SGarrett D'Amore (ei->ctrl >= odev->d_nctrl) ||
202988447a05SGarrett D'Amore (odev->d_exts[ei->ctrl].type != MIXT_ENUM) ||
203088447a05SGarrett D'Amore ((ctrl = odev->d_ctrls[ei->ctrl]) == NULL) ||
203188447a05SGarrett D'Amore (auclnt_control_describe(ctrl, &desc) != 0)) {
203288447a05SGarrett D'Amore return (EINVAL);
203388447a05SGarrett D'Amore }
203488447a05SGarrett D'Amore
203588447a05SGarrett D'Amore mask = desc.acd_maxvalue;
203688447a05SGarrett D'Amore bit = 0;
203788447a05SGarrett D'Amore nxt = 0;
203888447a05SGarrett D'Amore ei->nvalues = 0;
203988447a05SGarrett D'Amore bzero(ei->strings, sizeof (ei->strings));
204088447a05SGarrett D'Amore bzero(ei->strindex, sizeof (ei->strindex));
204188447a05SGarrett D'Amore
204288447a05SGarrett D'Amore while (mask) {
204388447a05SGarrett D'Amore const char *name = desc.acd_enum[bit];
204488447a05SGarrett D'Amore nxt = oss_set_enum(ei, nxt, name ? name : "");
204588447a05SGarrett D'Amore mask >>= 1;
204688447a05SGarrett D'Amore bit++;
204788447a05SGarrett D'Amore }
204888447a05SGarrett D'Amore
204988447a05SGarrett D'Amore return (0);
205088447a05SGarrett D'Amore }
205188447a05SGarrett D'Amore
205288447a05SGarrett D'Amore static int
sndctl_mix_read(audio_client_t * c,oss_mixer_value * vr)205388447a05SGarrett D'Amore sndctl_mix_read(audio_client_t *c, oss_mixer_value *vr)
205488447a05SGarrett D'Amore {
205588447a05SGarrett D'Amore int rv;
205688447a05SGarrett D'Amore uint64_t v;
205788447a05SGarrett D'Amore audio_dev_t *d;
205888447a05SGarrett D'Amore audio_ctrl_t *ctrl;
205988447a05SGarrett D'Amore ossdev_t *odev;
206088447a05SGarrett D'Amore
206188447a05SGarrett D'Amore d = auclnt_get_dev(c);
206288447a05SGarrett D'Amore
206388447a05SGarrett D'Amore if ((vr->dev != -1) && (vr->dev != (auclnt_get_dev_index(d) - 1)))
206488447a05SGarrett D'Amore return (ENXIO);
206588447a05SGarrett D'Amore
206688447a05SGarrett D'Amore if (((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) ||
206788447a05SGarrett D'Amore (vr->ctrl >= odev->d_nctrl) ||
206888447a05SGarrett D'Amore ((ctrl = odev->d_ctrls[vr->ctrl]) == NULL)) {
206988447a05SGarrett D'Amore return (EINVAL);
207088447a05SGarrett D'Amore }
207188447a05SGarrett D'Amore if ((rv = auclnt_control_read(ctrl, &v)) == 0) {
207288447a05SGarrett D'Amore switch (odev->d_exts[vr->ctrl].type) {
207388447a05SGarrett D'Amore case MIXT_ENUM:
207488447a05SGarrett D'Amore /* translate this from an enum style bit mask */
207588447a05SGarrett D'Amore vr->value = ddi_ffs((unsigned long)v) - 1;
207688447a05SGarrett D'Amore break;
207788447a05SGarrett D'Amore case MIXT_STEREOSLIDER:
207888447a05SGarrett D'Amore vr->value = (int)ddi_swap16(v & 0xffff);
207988447a05SGarrett D'Amore break;
208088447a05SGarrett D'Amore case MIXT_MONOSLIDER:
208188447a05SGarrett D'Amore vr->value = (int)(v | (v << 8));
208288447a05SGarrett D'Amore break;
208388447a05SGarrett D'Amore case MIXT_ONOFF:
208488447a05SGarrett D'Amore /* this could be simple, or could be part of a multi */
208588447a05SGarrett D'Amore if (odev->d_exts[vr->ctrl].enumbit >= 0) {
208688447a05SGarrett D'Amore uint64_t mask;
208788447a05SGarrett D'Amore mask = 1;
208888447a05SGarrett D'Amore mask <<= (odev->d_exts[vr->ctrl].enumbit);
208988447a05SGarrett D'Amore vr->value = (v & mask) ? 1 : 0;
209088447a05SGarrett D'Amore } else {
209188447a05SGarrett D'Amore vr->value = v ? 1 : 0;
209288447a05SGarrett D'Amore }
209388447a05SGarrett D'Amore break;
209488447a05SGarrett D'Amore
209588447a05SGarrett D'Amore default:
209688447a05SGarrett D'Amore vr->value = (int)v;
209788447a05SGarrett D'Amore break;
209888447a05SGarrett D'Amore }
209988447a05SGarrett D'Amore }
210088447a05SGarrett D'Amore
210188447a05SGarrett D'Amore return (rv);
210288447a05SGarrett D'Amore }
210388447a05SGarrett D'Amore
210488447a05SGarrett D'Amore static int
sndctl_mix_write(audio_client_t * c,oss_mixer_value * vr)210588447a05SGarrett D'Amore sndctl_mix_write(audio_client_t *c, oss_mixer_value *vr)
210688447a05SGarrett D'Amore {
210788447a05SGarrett D'Amore int rv;
210888447a05SGarrett D'Amore uint64_t v;
210988447a05SGarrett D'Amore audio_dev_t *d;
211088447a05SGarrett D'Amore audio_ctrl_t *ctrl;
211188447a05SGarrett D'Amore ossdev_t *odev;
211288447a05SGarrett D'Amore
211388447a05SGarrett D'Amore d = auclnt_get_dev(c);
211488447a05SGarrett D'Amore
211588447a05SGarrett D'Amore if ((vr->dev != -1) && (vr->dev != (auclnt_get_dev_index(d) - 1)))
211688447a05SGarrett D'Amore return (ENXIO);
211788447a05SGarrett D'Amore
211888447a05SGarrett D'Amore if (((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) ||
211988447a05SGarrett D'Amore (vr->ctrl >= odev->d_nctrl) ||
212088447a05SGarrett D'Amore ((ctrl = odev->d_ctrls[vr->ctrl]) == NULL)) {
212188447a05SGarrett D'Amore return (EINVAL);
212288447a05SGarrett D'Amore }
212388447a05SGarrett D'Amore
212488447a05SGarrett D'Amore switch (odev->d_exts[vr->ctrl].type) {
212588447a05SGarrett D'Amore case MIXT_ONOFF:
212688447a05SGarrett D'Amore /* this could be standalone, or it could be part of a multi */
212788447a05SGarrett D'Amore if (odev->d_exts[vr->ctrl].enumbit >= 0) {
212888447a05SGarrett D'Amore uint64_t mask;
212988447a05SGarrett D'Amore if ((rv = auclnt_control_read(ctrl, &v)) != 0) {
213088447a05SGarrett D'Amore return (EINVAL);
213188447a05SGarrett D'Amore }
213288447a05SGarrett D'Amore mask = 1;
213388447a05SGarrett D'Amore mask <<= (odev->d_exts[vr->ctrl].enumbit);
213488447a05SGarrett D'Amore if (vr->value) {
213588447a05SGarrett D'Amore v |= mask;
213688447a05SGarrett D'Amore } else {
213788447a05SGarrett D'Amore v &= ~mask;
213888447a05SGarrett D'Amore }
213988447a05SGarrett D'Amore } else {
214088447a05SGarrett D'Amore v = vr->value;
214188447a05SGarrett D'Amore }
214288447a05SGarrett D'Amore break;
214388447a05SGarrett D'Amore case MIXT_ENUM:
214488447a05SGarrett D'Amore /* translate this to an enum style bit mask */
214588447a05SGarrett D'Amore v = 1U << vr->value;
214688447a05SGarrett D'Amore break;
214788447a05SGarrett D'Amore case MIXT_MONOSLIDER:
214888447a05SGarrett D'Amore /* mask off high order bits */
214988447a05SGarrett D'Amore v = vr->value & 0xff;
215088447a05SGarrett D'Amore break;
215188447a05SGarrett D'Amore case MIXT_STEREOSLIDER:
215288447a05SGarrett D'Amore /* OSS uses reverse byte ordering */
215388447a05SGarrett D'Amore v = vr->value;
215488447a05SGarrett D'Amore v = ddi_swap16(vr->value & 0xffff);
215588447a05SGarrett D'Amore break;
215688447a05SGarrett D'Amore default:
215788447a05SGarrett D'Amore v = vr->value;
215888447a05SGarrett D'Amore }
215988447a05SGarrett D'Amore rv = auclnt_control_write(ctrl, v);
216088447a05SGarrett D'Amore
216188447a05SGarrett D'Amore return (rv);
216288447a05SGarrett D'Amore }
216388447a05SGarrett D'Amore
216488447a05SGarrett D'Amore static int
sndctl_mix_nrmix(audio_client_t * c,int * nmixp)216588447a05SGarrett D'Amore sndctl_mix_nrmix(audio_client_t *c, int *nmixp)
216688447a05SGarrett D'Amore {
216788447a05SGarrett D'Amore _NOTE(ARGUNUSED(c));
216888447a05SGarrett D'Amore *nmixp = oss_cnt_devs() - 1;
216988447a05SGarrett D'Amore return (0);
217088447a05SGarrett D'Amore }
217188447a05SGarrett D'Amore
217288447a05SGarrett D'Amore static int
ossmix_ioctl(audio_client_t * c,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)217388447a05SGarrett D'Amore ossmix_ioctl(audio_client_t *c, int cmd, intptr_t arg, int mode, cred_t *credp,
217488447a05SGarrett D'Amore int *rvalp)
217588447a05SGarrett D'Amore {
217688447a05SGarrett D'Amore int sz;
217788447a05SGarrett D'Amore void *data;
217888447a05SGarrett D'Amore int rv = 0;
217988447a05SGarrett D'Amore
218088447a05SGarrett D'Amore sz = OSSIOC_GETSZ(cmd);
218188447a05SGarrett D'Amore
218288447a05SGarrett D'Amore if ((cmd & (OSSIOC_IN | OSSIOC_OUT)) && sz) {
218388447a05SGarrett D'Amore if ((data = kmem_zalloc(sz, KM_NOSLEEP)) == NULL) {
218488447a05SGarrett D'Amore return (ENOMEM);
218588447a05SGarrett D'Amore }
218688447a05SGarrett D'Amore } else {
218788447a05SGarrett D'Amore sz = 0;
218888447a05SGarrett D'Amore }
218988447a05SGarrett D'Amore
219088447a05SGarrett D'Amore if (cmd & OSSIOC_IN) {
219188447a05SGarrett D'Amore if ((rv = ddi_copyin((void *)arg, data, sz, mode)) != 0) {
219288447a05SGarrett D'Amore goto done;
219388447a05SGarrett D'Amore }
219488447a05SGarrett D'Amore }
219588447a05SGarrett D'Amore
219688447a05SGarrett D'Amore switch (cmd) {
219788447a05SGarrett D'Amore /*
219888447a05SGarrett D'Amore * Mixer specific ioctls
219988447a05SGarrett D'Amore */
220088447a05SGarrett D'Amore case SNDCTL_MIX_NREXT:
220188447a05SGarrett D'Amore rv = sndctl_mix_nrext(c, (int *)data);
220288447a05SGarrett D'Amore break;
220388447a05SGarrett D'Amore case SNDCTL_MIX_EXTINFO:
220488447a05SGarrett D'Amore rv = sndctl_mix_extinfo(c, (oss_mixext *)data);
220588447a05SGarrett D'Amore break;
220688447a05SGarrett D'Amore case SNDCTL_MIX_ENUMINFO:
220788447a05SGarrett D'Amore rv = sndctl_mix_enuminfo(c, (oss_mixer_enuminfo *)data);
220888447a05SGarrett D'Amore break;
220988447a05SGarrett D'Amore case SNDCTL_MIX_READ:
221088447a05SGarrett D'Amore rv = sndctl_mix_read(c, (oss_mixer_value *)data);
221188447a05SGarrett D'Amore break;
221288447a05SGarrett D'Amore case SNDCTL_MIX_WRITE:
221388447a05SGarrett D'Amore rv = sndctl_mix_write(c, (oss_mixer_value *)data);
221488447a05SGarrett D'Amore break;
221588447a05SGarrett D'Amore case SNDCTL_MIX_NRMIX:
221688447a05SGarrett D'Amore rv = sndctl_mix_nrmix(c, (int *)data);
221788447a05SGarrett D'Amore break;
221888447a05SGarrett D'Amore
221988447a05SGarrett D'Amore /*
222088447a05SGarrett D'Amore * Legacy ioctls. These are treated as soft values only,
222188447a05SGarrett D'Amore * and do not affect global hardware state. For use by
222288447a05SGarrett D'Amore * legacy DSP applications.
222388447a05SGarrett D'Amore */
222488447a05SGarrett D'Amore case SOUND_MIXER_READ_VOLUME:
222588447a05SGarrett D'Amore case SOUND_MIXER_READ_PCM:
222688447a05SGarrett D'Amore case SOUND_MIXER_READ_OGAIN:
222788447a05SGarrett D'Amore rv = sndctl_dsp_getplayvol(c, (int *)data);
222888447a05SGarrett D'Amore break;
222988447a05SGarrett D'Amore
223088447a05SGarrett D'Amore case SOUND_MIXER_WRITE_VOLUME:
223188447a05SGarrett D'Amore case SOUND_MIXER_WRITE_PCM:
223288447a05SGarrett D'Amore case SOUND_MIXER_WRITE_OGAIN:
223388447a05SGarrett D'Amore rv = sound_mixer_write_ogain(c, (int *)data);
223488447a05SGarrett D'Amore break;
223588447a05SGarrett D'Amore
223688447a05SGarrett D'Amore case SOUND_MIXER_READ_RECGAIN:
223788447a05SGarrett D'Amore case SOUND_MIXER_READ_RECLEV:
223888447a05SGarrett D'Amore case SOUND_MIXER_READ_IGAIN:
223988447a05SGarrett D'Amore rv = sndctl_dsp_getrecvol(c, (int *)data);
224088447a05SGarrett D'Amore break;
224188447a05SGarrett D'Amore
224288447a05SGarrett D'Amore case SOUND_MIXER_WRITE_RECGAIN:
224388447a05SGarrett D'Amore case SOUND_MIXER_WRITE_RECLEV:
224488447a05SGarrett D'Amore case SOUND_MIXER_WRITE_IGAIN:
224588447a05SGarrett D'Amore rv = sound_mixer_write_igain(c, (int *)data);
224688447a05SGarrett D'Amore break;
224788447a05SGarrett D'Amore
224888447a05SGarrett D'Amore case SOUND_MIXER_READ_RECSRC:
224988447a05SGarrett D'Amore case SOUND_MIXER_WRITE_RECSRC:
225088447a05SGarrett D'Amore rv = sound_mixer_read_recsrc(c, (int *)data);
225188447a05SGarrett D'Amore break;
225288447a05SGarrett D'Amore
225388447a05SGarrett D'Amore case SOUND_MIXER_READ_DEVMASK:
225488447a05SGarrett D'Amore case SOUND_MIXER_READ_STEREODEVS:
225588447a05SGarrett D'Amore rv = sound_mixer_read_devmask(c, (int *)data);
225688447a05SGarrett D'Amore break;
225788447a05SGarrett D'Amore
225888447a05SGarrett D'Amore case SOUND_MIXER_READ_RECMASK:
225988447a05SGarrett D'Amore rv = sound_mixer_read_recmask(c, (int *)data);
226088447a05SGarrett D'Amore break;
226188447a05SGarrett D'Amore
22621069b515SGarrett D'Amore case SOUND_MIXER_READ_CAPS:
22631069b515SGarrett D'Amore rv = sound_mixer_read_caps(c, (int *)data);
22641069b515SGarrett D'Amore break;
22651069b515SGarrett D'Amore
226688447a05SGarrett D'Amore /*
226788447a05SGarrett D'Amore * Common ioctls shared with DSP
226888447a05SGarrett D'Amore */
226988447a05SGarrett D'Amore case OSS_GETVERSION:
227088447a05SGarrett D'Amore rv = oss_getversion((int *)data);
227188447a05SGarrett D'Amore break;
227288447a05SGarrett D'Amore
227388447a05SGarrett D'Amore case SNDCTL_CARDINFO:
227488447a05SGarrett D'Amore rv = sndctl_cardinfo(c, (oss_card_info *)data);
227588447a05SGarrett D'Amore break;
227688447a05SGarrett D'Amore
227788447a05SGarrett D'Amore case SNDCTL_ENGINEINFO:
227888447a05SGarrett D'Amore case SNDCTL_AUDIOINFO:
227988447a05SGarrett D'Amore case SNDCTL_AUDIOINFO_EX:
228088447a05SGarrett D'Amore rv = sndctl_audioinfo(c, (oss_audioinfo *)data);
228188447a05SGarrett D'Amore break;
228288447a05SGarrett D'Amore
228388447a05SGarrett D'Amore case SNDCTL_SYSINFO:
228488447a05SGarrett D'Amore rv = sndctl_sysinfo((oss_sysinfo *)data);
228588447a05SGarrett D'Amore break;
228688447a05SGarrett D'Amore
228788447a05SGarrett D'Amore case SNDCTL_MIXERINFO:
228888447a05SGarrett D'Amore rv = sndctl_mixerinfo(c, (oss_mixerinfo *)data);
228988447a05SGarrett D'Amore break;
229088447a05SGarrett D'Amore
229188447a05SGarrett D'Amore case SOUND_MIXER_INFO:
229288447a05SGarrett D'Amore rv = sound_mixer_info(c, (mixer_info *)data);
229388447a05SGarrett D'Amore break;
229488447a05SGarrett D'Amore
229588447a05SGarrett D'Amore case SNDCTL_MIX_DESCRIPTION: /* NOT SUPPORTED: tooltip */
229688447a05SGarrett D'Amore rv = EIO; /* OSS returns EIO for this one */
229788447a05SGarrett D'Amore break;
229888447a05SGarrett D'Amore
229988447a05SGarrett D'Amore /*
230088447a05SGarrett D'Amore * Special implementation-private ioctls.
230188447a05SGarrett D'Amore */
230288447a05SGarrett D'Amore case SNDCTL_SUN_SEND_NUMBER:
230388447a05SGarrett D'Amore rv = sndctl_sun_send_number(c, (int *)data, credp);
230488447a05SGarrett D'Amore break;
230588447a05SGarrett D'Amore
230688447a05SGarrett D'Amore /*
230788447a05SGarrett D'Amore * Legacy ioctls we don't support.
230888447a05SGarrett D'Amore */
230988447a05SGarrett D'Amore case SOUND_MIXER_WRITE_MONGAIN:
231088447a05SGarrett D'Amore case SOUND_MIXER_READ_MONGAIN:
231188447a05SGarrett D'Amore case SOUND_MIXER_READ_BASS:
231288447a05SGarrett D'Amore case SOUND_MIXER_READ_TREBLE:
231388447a05SGarrett D'Amore case SOUND_MIXER_READ_SPEAKER:
231488447a05SGarrett D'Amore case SOUND_MIXER_READ_LINE:
231588447a05SGarrett D'Amore case SOUND_MIXER_READ_MIC:
231688447a05SGarrett D'Amore case SOUND_MIXER_READ_CD:
231788447a05SGarrett D'Amore case SOUND_MIXER_READ_IMIX:
231888447a05SGarrett D'Amore case SOUND_MIXER_READ_ALTPCM:
231988447a05SGarrett D'Amore case SOUND_MIXER_READ_SYNTH:
232088447a05SGarrett D'Amore case SOUND_MIXER_READ_LINE1:
232188447a05SGarrett D'Amore case SOUND_MIXER_READ_LINE2:
232288447a05SGarrett D'Amore case SOUND_MIXER_READ_LINE3:
232388447a05SGarrett D'Amore case SOUND_MIXER_WRITE_BASS:
232488447a05SGarrett D'Amore case SOUND_MIXER_WRITE_TREBLE:
232588447a05SGarrett D'Amore case SOUND_MIXER_WRITE_SPEAKER:
232688447a05SGarrett D'Amore case SOUND_MIXER_WRITE_LINE:
232788447a05SGarrett D'Amore case SOUND_MIXER_WRITE_MIC:
232888447a05SGarrett D'Amore case SOUND_MIXER_WRITE_CD:
232988447a05SGarrett D'Amore case SOUND_MIXER_WRITE_IMIX:
233088447a05SGarrett D'Amore case SOUND_MIXER_WRITE_ALTPCM:
233188447a05SGarrett D'Amore case SOUND_MIXER_WRITE_SYNTH:
233288447a05SGarrett D'Amore case SOUND_MIXER_WRITE_LINE1:
233388447a05SGarrett D'Amore case SOUND_MIXER_WRITE_LINE2:
233488447a05SGarrett D'Amore case SOUND_MIXER_WRITE_LINE3:
233588447a05SGarrett D'Amore /*
233688447a05SGarrett D'Amore * Additional ioctls we *could* support, but don't.
233788447a05SGarrett D'Amore */
233888447a05SGarrett D'Amore case SNDCTL_SETSONG:
233988447a05SGarrett D'Amore case SNDCTL_SETLABEL:
234088447a05SGarrett D'Amore case SNDCTL_GETSONG:
234188447a05SGarrett D'Amore case SNDCTL_GETLABEL:
234288447a05SGarrett D'Amore case SNDCTL_MIDIINFO:
234388447a05SGarrett D'Amore case SNDCTL_SETNAME:
234488447a05SGarrett D'Amore default:
234588447a05SGarrett D'Amore rv = EINVAL;
234688447a05SGarrett D'Amore break;
234788447a05SGarrett D'Amore }
234888447a05SGarrett D'Amore
234988447a05SGarrett D'Amore if ((rv == 0) && (cmd & OSSIOC_OUT)) {
235088447a05SGarrett D'Amore rv = ddi_copyout(data, (void *)arg, sz, mode);
235188447a05SGarrett D'Amore }
235288447a05SGarrett D'Amore if (rv == 0) {
235388447a05SGarrett D'Amore *rvalp = 0;
235488447a05SGarrett D'Amore }
235588447a05SGarrett D'Amore
235688447a05SGarrett D'Amore done:
235788447a05SGarrett D'Amore if (sz) {
235888447a05SGarrett D'Amore kmem_free(data, sz);
235988447a05SGarrett D'Amore }
236088447a05SGarrett D'Amore return (rv);
236188447a05SGarrett D'Amore }
236288447a05SGarrett D'Amore
236388447a05SGarrett D'Amore static void *
oss_dev_init(audio_dev_t * dev)236488447a05SGarrett D'Amore oss_dev_init(audio_dev_t *dev)
236588447a05SGarrett D'Amore {
236688447a05SGarrett D'Amore ossdev_t *odev;
236788447a05SGarrett D'Amore
236888447a05SGarrett D'Amore odev = kmem_zalloc(sizeof (*odev), KM_SLEEP);
236988447a05SGarrett D'Amore odev->d_dev = dev;
237088447a05SGarrett D'Amore
237188447a05SGarrett D'Amore mutex_init(&odev->d_mx, NULL, MUTEX_DRIVER, NULL);
237288447a05SGarrett D'Amore cv_init(&odev->d_cv, NULL, CV_DRIVER, NULL);
237388447a05SGarrett D'Amore oss_alloc_controls(odev);
237488447a05SGarrett D'Amore
237588447a05SGarrett D'Amore return (odev);
237688447a05SGarrett D'Amore }
237788447a05SGarrett D'Amore
237888447a05SGarrett D'Amore static void
oss_dev_fini(void * arg)237988447a05SGarrett D'Amore oss_dev_fini(void *arg)
238088447a05SGarrett D'Amore {
238188447a05SGarrett D'Amore ossdev_t *odev = arg;
238288447a05SGarrett D'Amore
238388447a05SGarrett D'Amore if (odev != NULL) {
238488447a05SGarrett D'Amore oss_free_controls(odev);
238588447a05SGarrett D'Amore mutex_destroy(&odev->d_mx);
238688447a05SGarrett D'Amore cv_destroy(&odev->d_cv);
238788447a05SGarrett D'Amore kmem_free(odev, sizeof (*odev));
238888447a05SGarrett D'Amore }
238988447a05SGarrett D'Amore }
239088447a05SGarrett D'Amore
239188447a05SGarrett D'Amore static void
sndstat_printf(ossclient_t * oc,const char * fmt,...)239288447a05SGarrett D'Amore sndstat_printf(ossclient_t *oc, const char *fmt, ...)
239388447a05SGarrett D'Amore {
239488447a05SGarrett D'Amore va_list va;
239588447a05SGarrett D'Amore
239688447a05SGarrett D'Amore va_start(va, fmt);
239788447a05SGarrett D'Amore (void) vsnprintf(oc->o_ss_buf + oc->o_ss_len,
239888447a05SGarrett D'Amore oc->o_ss_sz - oc->o_ss_len, fmt, va);
239988447a05SGarrett D'Amore va_end(va);
240088447a05SGarrett D'Amore oc->o_ss_len = strlen(oc->o_ss_buf);
240188447a05SGarrett D'Amore }
240288447a05SGarrett D'Amore
240388447a05SGarrett D'Amore static int
sndstat_dev_walker(audio_dev_t * d,void * arg)240488447a05SGarrett D'Amore sndstat_dev_walker(audio_dev_t *d, void *arg)
240588447a05SGarrett D'Amore {
240688447a05SGarrett D'Amore ossclient_t *oc = arg;
240788447a05SGarrett D'Amore const char *capstr;
240888447a05SGarrett D'Amore unsigned cap;
240988447a05SGarrett D'Amore
241088447a05SGarrett D'Amore cap = auclnt_get_dev_capab(d);
241188447a05SGarrett D'Amore
241288447a05SGarrett D'Amore if (cap & AUDIO_CLIENT_CAP_DUPLEX) {
241388447a05SGarrett D'Amore capstr = "DUPLEX";
241488447a05SGarrett D'Amore } else if ((cap & AUDIO_CLIENT_CAP_PLAY) &&
241588447a05SGarrett D'Amore (cap & AUDIO_CLIENT_CAP_RECORD)) {
241688447a05SGarrett D'Amore capstr = "INPUT,OUTPUT";
241788447a05SGarrett D'Amore } else if (cap & AUDIO_CLIENT_CAP_PLAY) {
241888447a05SGarrett D'Amore capstr = "OUTPUT";
241988447a05SGarrett D'Amore } else if (cap & AUDIO_CLIENT_CAP_RECORD) {
242088447a05SGarrett D'Amore capstr = "INPUT";
242188447a05SGarrett D'Amore } else {
242288447a05SGarrett D'Amore capstr = NULL;
242388447a05SGarrett D'Amore }
242488447a05SGarrett D'Amore
242588447a05SGarrett D'Amore if (capstr == NULL)
242688447a05SGarrett D'Amore return (AUDIO_WALK_CONTINUE);
242788447a05SGarrett D'Amore
242888447a05SGarrett D'Amore sndstat_printf(oc, "%d: %s %s, %s (%s)\n",
242988447a05SGarrett D'Amore auclnt_get_dev_number(d), auclnt_get_dev_name(d),
243088447a05SGarrett D'Amore auclnt_get_dev_description(d), auclnt_get_dev_version(d), capstr);
243188447a05SGarrett D'Amore
243288447a05SGarrett D'Amore return (AUDIO_WALK_CONTINUE);
243388447a05SGarrett D'Amore }
243488447a05SGarrett D'Amore
243588447a05SGarrett D'Amore static int
sndstat_mixer_walker(audio_dev_t * d,void * arg)243688447a05SGarrett D'Amore sndstat_mixer_walker(audio_dev_t *d, void *arg)
243788447a05SGarrett D'Amore {
243888447a05SGarrett D'Amore ossclient_t *oc = arg;
243988447a05SGarrett D'Amore unsigned cap;
244088447a05SGarrett D'Amore void *iter;
244188447a05SGarrett D'Amore const char *info;
244288447a05SGarrett D'Amore
244388447a05SGarrett D'Amore cap = auclnt_get_dev_capab(d);
244488447a05SGarrett D'Amore
244588447a05SGarrett D'Amore if ((cap & (AUDIO_CLIENT_CAP_PLAY|AUDIO_CLIENT_CAP_RECORD)) == 0)
244688447a05SGarrett D'Amore return (AUDIO_WALK_CONTINUE);
244788447a05SGarrett D'Amore
244888447a05SGarrett D'Amore sndstat_printf(oc, "%d: %s %s, %s\n",
244988447a05SGarrett D'Amore auclnt_get_dev_number(d), auclnt_get_dev_name(d),
245088447a05SGarrett D'Amore auclnt_get_dev_description(d), auclnt_get_dev_version(d));
245188447a05SGarrett D'Amore iter = NULL;
245288447a05SGarrett D'Amore while ((info = auclnt_get_dev_hw_info(d, &iter)) != NULL) {
245388447a05SGarrett D'Amore sndstat_printf(oc, "\t%s\n", info);
245488447a05SGarrett D'Amore }
245588447a05SGarrett D'Amore return (AUDIO_WALK_CONTINUE);
245688447a05SGarrett D'Amore }
245788447a05SGarrett D'Amore
245888447a05SGarrett D'Amore static int
ossmix_write(audio_client_t * c,struct uio * uio,cred_t * cr)245988447a05SGarrett D'Amore ossmix_write(audio_client_t *c, struct uio *uio, cred_t *cr)
246088447a05SGarrett D'Amore {
246188447a05SGarrett D'Amore /* write on sndstat is a no-op */
246288447a05SGarrett D'Amore _NOTE(ARGUNUSED(c));
246388447a05SGarrett D'Amore _NOTE(ARGUNUSED(uio));
246488447a05SGarrett D'Amore _NOTE(ARGUNUSED(cr));
246588447a05SGarrett D'Amore
246688447a05SGarrett D'Amore return (0);
246788447a05SGarrett D'Amore }
246888447a05SGarrett D'Amore
246988447a05SGarrett D'Amore static int
ossmix_read(audio_client_t * c,struct uio * uio,cred_t * cr)247088447a05SGarrett D'Amore ossmix_read(audio_client_t *c, struct uio *uio, cred_t *cr)
247188447a05SGarrett D'Amore {
247288447a05SGarrett D'Amore ossclient_t *oc;
247388447a05SGarrett D'Amore unsigned n;
247488447a05SGarrett D'Amore int rv;
247588447a05SGarrett D'Amore
247688447a05SGarrett D'Amore _NOTE(ARGUNUSED(cr));
247788447a05SGarrett D'Amore
247888447a05SGarrett D'Amore if (uio->uio_resid == 0) {
247988447a05SGarrett D'Amore return (0);
248088447a05SGarrett D'Amore }
248188447a05SGarrett D'Amore
248288447a05SGarrett D'Amore oc = auclnt_get_private(c);
248388447a05SGarrett D'Amore
248488447a05SGarrett D'Amore mutex_enter(&oc->o_ss_lock);
248588447a05SGarrett D'Amore
248688447a05SGarrett D'Amore if (oc->o_ss_off == 0) {
248788447a05SGarrett D'Amore
248888447a05SGarrett D'Amore sndstat_printf(oc, "SunOS Audio Framework\n");
248988447a05SGarrett D'Amore
249088447a05SGarrett D'Amore sndstat_printf(oc, "\nAudio Devices:\n");
249188447a05SGarrett D'Amore auclnt_walk_devs_by_number(sndstat_dev_walker, oc);
249288447a05SGarrett D'Amore
249388447a05SGarrett D'Amore sndstat_printf(oc, "\nMixers:\n");
249488447a05SGarrett D'Amore auclnt_walk_devs_by_number(sndstat_mixer_walker, oc);
249588447a05SGarrett D'Amore }
249688447a05SGarrett D'Amore
249788447a05SGarrett D'Amore /*
249888447a05SGarrett D'Amore * For simplicity's sake, we implement a non-seekable device. We could
249988447a05SGarrett D'Amore * support seekability, but offsets would be rather meaningless between
250088447a05SGarrett D'Amore * changes.
250188447a05SGarrett D'Amore */
250288447a05SGarrett D'Amore n = min(uio->uio_resid, (oc->o_ss_len - oc->o_ss_off));
250388447a05SGarrett D'Amore
250488447a05SGarrett D'Amore rv = uiomove(oc->o_ss_buf + oc->o_ss_off, n, UIO_READ, uio);
250588447a05SGarrett D'Amore if (rv != 0) {
250688447a05SGarrett D'Amore n = 0;
250788447a05SGarrett D'Amore }
250888447a05SGarrett D'Amore oc->o_ss_off += n;
250988447a05SGarrett D'Amore
251088447a05SGarrett D'Amore if (n == 0) {
251188447a05SGarrett D'Amore /*
251288447a05SGarrett D'Amore * end-of-file reached... clear the sndstat buffer so that
251388447a05SGarrett D'Amore * subsequent reads will get the latest data.
251488447a05SGarrett D'Amore */
251588447a05SGarrett D'Amore oc->o_ss_off = oc->o_ss_len = 0;
251688447a05SGarrett D'Amore }
251788447a05SGarrett D'Amore mutex_exit(&oc->o_ss_lock);
251888447a05SGarrett D'Amore return (rv);
251988447a05SGarrett D'Amore }
252088447a05SGarrett D'Amore
252188447a05SGarrett D'Amore int
oss_read(audio_client_t * c,struct uio * uio,cred_t * cr)252288447a05SGarrett D'Amore oss_read(audio_client_t *c, struct uio *uio, cred_t *cr)
252388447a05SGarrett D'Amore {
252488447a05SGarrett D'Amore _NOTE(ARGUNUSED(cr));
252588447a05SGarrett D'Amore
252688447a05SGarrett D'Amore auclnt_clear_paused(auclnt_input_stream(c));
252788447a05SGarrett D'Amore
252888447a05SGarrett D'Amore return (auclnt_read(c, uio));
252988447a05SGarrett D'Amore }
253088447a05SGarrett D'Amore
253188447a05SGarrett D'Amore int
oss_write(audio_client_t * c,struct uio * uio,cred_t * cr)253288447a05SGarrett D'Amore oss_write(audio_client_t *c, struct uio *uio, cred_t *cr)
253388447a05SGarrett D'Amore {
253488447a05SGarrett D'Amore _NOTE(ARGUNUSED(cr));
253588447a05SGarrett D'Amore
253688447a05SGarrett D'Amore auclnt_clear_paused(auclnt_output_stream(c));
253788447a05SGarrett D'Amore
253888447a05SGarrett D'Amore return (auclnt_write(c, uio));
253988447a05SGarrett D'Amore }
254088447a05SGarrett D'Amore
254188447a05SGarrett D'Amore int
oss_chpoll(audio_client_t * c,short events,int anyyet,short * reventsp,struct pollhead ** phpp)254288447a05SGarrett D'Amore oss_chpoll(audio_client_t *c, short events, int anyyet, short *reventsp,
254388447a05SGarrett D'Amore struct pollhead **phpp)
254488447a05SGarrett D'Amore {
254588447a05SGarrett D'Amore return (auclnt_chpoll(c, events, anyyet, reventsp, phpp));
254688447a05SGarrett D'Amore }
254788447a05SGarrett D'Amore
254888447a05SGarrett D'Amore static struct audio_client_ops oss_ops = {
254988447a05SGarrett D'Amore "sound,dsp",
255088447a05SGarrett D'Amore oss_dev_init,
255188447a05SGarrett D'Amore oss_dev_fini,
255288447a05SGarrett D'Amore oss_open,
255388447a05SGarrett D'Amore oss_close,
255488447a05SGarrett D'Amore oss_read,
255588447a05SGarrett D'Amore oss_write,
255688447a05SGarrett D'Amore oss_ioctl,
255788447a05SGarrett D'Amore oss_chpoll,
255888447a05SGarrett D'Amore NULL, /* mmap */
255988447a05SGarrett D'Amore oss_input,
256088447a05SGarrett D'Amore oss_output,
256188447a05SGarrett D'Amore NULL, /* drain */
256288447a05SGarrett D'Amore };
256388447a05SGarrett D'Amore
256488447a05SGarrett D'Amore static struct audio_client_ops ossmix_ops = {
256588447a05SGarrett D'Amore "sound,mixer",
256688447a05SGarrett D'Amore NULL,
256788447a05SGarrett D'Amore NULL,
256888447a05SGarrett D'Amore ossmix_open,
256988447a05SGarrett D'Amore ossmix_close,
257088447a05SGarrett D'Amore ossmix_read,
257188447a05SGarrett D'Amore ossmix_write,
257288447a05SGarrett D'Amore ossmix_ioctl,
257388447a05SGarrett D'Amore NULL, /* chpoll */
257488447a05SGarrett D'Amore NULL, /* mmap */
257588447a05SGarrett D'Amore NULL, /* input */
257688447a05SGarrett D'Amore NULL, /* output */
257788447a05SGarrett D'Amore NULL, /* drain */
2578a19bb1faSGarrett D'Amore NULL, /* wput */
2579a19bb1faSGarrett D'Amore NULL, /* wsrv */
258088447a05SGarrett D'Amore };
258188447a05SGarrett D'Amore
258288447a05SGarrett D'Amore /* nearly the same as ossxmix; different minor name helps devfsadm */
258388447a05SGarrett D'Amore static struct audio_client_ops sndstat_ops = {
258488447a05SGarrett D'Amore "sound,sndstat",
258588447a05SGarrett D'Amore NULL, /* dev_init */
258688447a05SGarrett D'Amore NULL, /* dev_fini */
258788447a05SGarrett D'Amore ossmix_open,
258888447a05SGarrett D'Amore ossmix_close,
258988447a05SGarrett D'Amore ossmix_read,
259088447a05SGarrett D'Amore ossmix_write,
259188447a05SGarrett D'Amore ossmix_ioctl,
259288447a05SGarrett D'Amore NULL, /* chpoll */
259388447a05SGarrett D'Amore NULL, /* mmap */
259488447a05SGarrett D'Amore NULL, /* input */
259588447a05SGarrett D'Amore NULL, /* output */
259688447a05SGarrett D'Amore NULL, /* drain */
2597a19bb1faSGarrett D'Amore NULL, /* wput */
2598a19bb1faSGarrett D'Amore NULL, /* wsrv */
259988447a05SGarrett D'Amore };
260088447a05SGarrett D'Amore
260188447a05SGarrett D'Amore void
auimpl_oss_init(void)260288447a05SGarrett D'Amore auimpl_oss_init(void)
260388447a05SGarrett D'Amore {
260488447a05SGarrett D'Amore auclnt_register_ops(AUDIO_MINOR_DSP, &oss_ops);
260588447a05SGarrett D'Amore auclnt_register_ops(AUDIO_MINOR_MIXER, &ossmix_ops);
260688447a05SGarrett D'Amore auclnt_register_ops(AUDIO_MINOR_SNDSTAT, &sndstat_ops);
260788447a05SGarrett D'Amore }
2608