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 /*
2288447a05SGarrett D'Amore * Copyright (C) 4Front Technologies 1996-2008.
2388447a05SGarrett D'Amore *
2468c47f65SGarrett D'Amore * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
2588447a05SGarrett D'Amore * Use is subject to license terms.
2688447a05SGarrett D'Amore */
2788447a05SGarrett D'Amore
2888447a05SGarrett D'Amore #include <sys/types.h>
2988447a05SGarrett D'Amore #include <sys/sysmacros.h>
3088447a05SGarrett D'Amore #include <sys/stropts.h>
3188447a05SGarrett D'Amore #include <sys/strsun.h>
3288447a05SGarrett D'Amore #include <sys/list.h>
3388447a05SGarrett D'Amore #include <sys/mkdev.h>
3488447a05SGarrett D'Amore #include <sys/conf.h>
3588447a05SGarrett D'Amore #include <sys/note.h>
36682cb104SGarrett D'Amore #include <sys/atomic.h>
3788447a05SGarrett D'Amore #include <sys/ddi.h>
3888447a05SGarrett D'Amore #include <sys/sunddi.h>
3988447a05SGarrett D'Amore
4088447a05SGarrett D'Amore #include "audio_impl.h"
4188447a05SGarrett D'Amore
4288447a05SGarrett D'Amore /*
4388447a05SGarrett D'Amore * Audio DDI glue implementation.
4488447a05SGarrett D'Amore */
4588447a05SGarrett D'Amore
4688447a05SGarrett D'Amore /*
4788447a05SGarrett D'Amore * The audio module is itself a pseudo driver, as it contains the
4888447a05SGarrett D'Amore * logic to support un-associated nodes. (Think generic /dev/mixer
4988447a05SGarrett D'Amore * and /dev/sndstat used by OSS.)
5088447a05SGarrett D'Amore */
5188447a05SGarrett D'Amore static int
audio_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)5288447a05SGarrett D'Amore audio_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
5388447a05SGarrett D'Amore {
5488447a05SGarrett D'Amore audio_dev_t *adev;
5588447a05SGarrett D'Amore
5688447a05SGarrett D'Amore /* pseudo devices don't need S/R support */
5788447a05SGarrett D'Amore if ((cmd != DDI_ATTACH) || (dip == NULL)) {
5888447a05SGarrett D'Amore return (DDI_FAILURE);
5988447a05SGarrett D'Amore }
6088447a05SGarrett D'Amore
6188447a05SGarrett D'Amore if (ddi_get_instance(dip) != 0) {
6288447a05SGarrett D'Amore return (DDI_FAILURE);
6388447a05SGarrett D'Amore }
6488447a05SGarrett D'Amore
6588447a05SGarrett D'Amore /* this can't fail */
6688447a05SGarrett D'Amore adev = audio_dev_alloc(dip, 0);
6788447a05SGarrett D'Amore adev->d_flags = DEV_SNDSTAT_CAP;
6888447a05SGarrett D'Amore audio_dev_set_description(adev, "Audio Common Code");
6988447a05SGarrett D'Amore audio_dev_set_version(adev, "pseudo");
7088447a05SGarrett D'Amore ddi_set_driver_private(dip, adev);
7188447a05SGarrett D'Amore
7288447a05SGarrett D'Amore /* look up our properties! */
7388447a05SGarrett D'Amore
7417f65767SToomas Soome if (audio_dev_register(adev) != DDI_SUCCESS) {
7588447a05SGarrett D'Amore audio_dev_free(adev);
7688447a05SGarrett D'Amore return (DDI_FAILURE);
7788447a05SGarrett D'Amore }
7888447a05SGarrett D'Amore
7988447a05SGarrett D'Amore ddi_report_dev(dip);
8088447a05SGarrett D'Amore
8188447a05SGarrett D'Amore return (DDI_SUCCESS);
8288447a05SGarrett D'Amore }
8388447a05SGarrett D'Amore
8488447a05SGarrett D'Amore static int
audio_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)8588447a05SGarrett D'Amore audio_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
8688447a05SGarrett D'Amore {
8788447a05SGarrett D'Amore audio_dev_t *adev;
8888447a05SGarrett D'Amore
8988447a05SGarrett D'Amore /* pseudo devices don't need S/R support */
9088447a05SGarrett D'Amore if (cmd != DDI_DETACH) {
9188447a05SGarrett D'Amore return (DDI_FAILURE);
9288447a05SGarrett D'Amore }
9388447a05SGarrett D'Amore
9488447a05SGarrett D'Amore if (dip == NULL) {
9588447a05SGarrett D'Amore return (DDI_FAILURE);
9688447a05SGarrett D'Amore }
9788447a05SGarrett D'Amore
9888447a05SGarrett D'Amore if ((adev = ddi_get_driver_private(dip)) == NULL) {
9988447a05SGarrett D'Amore return (DDI_FAILURE);
10088447a05SGarrett D'Amore }
10188447a05SGarrett D'Amore
10288447a05SGarrett D'Amore if (audio_dev_unregister(adev) != DDI_SUCCESS) {
10388447a05SGarrett D'Amore return (DDI_FAILURE);
10488447a05SGarrett D'Amore }
10588447a05SGarrett D'Amore
10688447a05SGarrett D'Amore audio_dev_free(adev);
10788447a05SGarrett D'Amore
10888447a05SGarrett D'Amore return (DDI_SUCCESS);
10988447a05SGarrett D'Amore }
11088447a05SGarrett D'Amore
11188447a05SGarrett D'Amore static int
audio_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** resp)11288447a05SGarrett D'Amore audio_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resp)
11388447a05SGarrett D'Amore {
11488447a05SGarrett D'Amore dip = NULL;
11588447a05SGarrett D'Amore
11688447a05SGarrett D'Amore if (getminor((dev_t)arg) & AUDIO_MN_CLONE_MASK) {
11788447a05SGarrett D'Amore audio_client_t *c;
11888447a05SGarrett D'Amore c = auclnt_hold_by_devt((dev_t)arg);
11988447a05SGarrett D'Amore if (c != NULL) {
12088447a05SGarrett D'Amore dip = c->c_dev->d_dip;
12188447a05SGarrett D'Amore auclnt_release(c);
12288447a05SGarrett D'Amore }
12388447a05SGarrett D'Amore } else {
12488447a05SGarrett D'Amore audio_dev_t *adev;
12588447a05SGarrett D'Amore if ((adev = auimpl_dev_hold_by_devt((dev_t)arg)) != NULL) {
12688447a05SGarrett D'Amore dip = adev->d_dip;
12788447a05SGarrett D'Amore auimpl_dev_release(adev);
12888447a05SGarrett D'Amore }
12988447a05SGarrett D'Amore }
13088447a05SGarrett D'Amore
13188447a05SGarrett D'Amore if (dip == NULL) {
13288447a05SGarrett D'Amore return (DDI_FAILURE);
13388447a05SGarrett D'Amore }
13488447a05SGarrett D'Amore
13588447a05SGarrett D'Amore switch (cmd) {
13688447a05SGarrett D'Amore case DDI_INFO_DEVT2DEVINFO:
13788447a05SGarrett D'Amore *resp = dip;
13888447a05SGarrett D'Amore break;
13988447a05SGarrett D'Amore case DDI_INFO_DEVT2INSTANCE:
14088447a05SGarrett D'Amore *resp = (void *)(uintptr_t)ddi_get_instance(dip);
14188447a05SGarrett D'Amore break;
14288447a05SGarrett D'Amore default:
14388447a05SGarrett D'Amore *resp = NULL;
14488447a05SGarrett D'Amore return (DDI_FAILURE);
14588447a05SGarrett D'Amore }
14688447a05SGarrett D'Amore return (DDI_SUCCESS);
14788447a05SGarrett D'Amore }
14888447a05SGarrett D'Amore
14988447a05SGarrett D'Amore static int
audio_open(dev_t * devp,int oflag,int otyp,cred_t * credp)15088447a05SGarrett D'Amore audio_open(dev_t *devp, int oflag, int otyp, cred_t *credp)
15188447a05SGarrett D'Amore {
15288447a05SGarrett D'Amore int rv;
15388447a05SGarrett D'Amore audio_client_t *c;
15488447a05SGarrett D'Amore
15588447a05SGarrett D'Amore if (otyp == OTYP_BLK) {
15688447a05SGarrett D'Amore return (ENXIO);
15788447a05SGarrett D'Amore }
15888447a05SGarrett D'Amore
15988447a05SGarrett D'Amore if ((c = auimpl_client_create(*devp)) == NULL) {
16088447a05SGarrett D'Amore audio_dev_warn(NULL, "client create failed");
16188447a05SGarrett D'Amore return (ENXIO);
16288447a05SGarrett D'Amore }
16388447a05SGarrett D'Amore
16488447a05SGarrett D'Amore c->c_omode = oflag;
16588447a05SGarrett D'Amore c->c_pid = ddi_get_pid();
16688447a05SGarrett D'Amore c->c_cred = credp;
16788447a05SGarrett D'Amore
16888447a05SGarrett D'Amore /*
16988447a05SGarrett D'Amore * Call client/personality specific open handler. Note that
17088447a05SGarrett D'Amore * we "insist" that there is an open. The personality layer
17188447a05SGarrett D'Amore * will initialize/allocate any engines required.
17288447a05SGarrett D'Amore *
17388447a05SGarrett D'Amore * Hmm... do we need to pass in the cred?
17488447a05SGarrett D'Amore */
17588447a05SGarrett D'Amore if ((rv = c->c_open(c, oflag)) != 0) {
17688447a05SGarrett D'Amore audio_dev_warn(c->c_dev, "open failed (rv %d)", rv);
17788447a05SGarrett D'Amore auimpl_client_destroy(c);
17888447a05SGarrett D'Amore return (rv);
17988447a05SGarrett D'Amore }
18088447a05SGarrett D'Amore
18188447a05SGarrett D'Amore /* we do device cloning! */
18288447a05SGarrett D'Amore *devp = makedevice(c->c_major, c->c_minor);
18388447a05SGarrett D'Amore
18453a539a7SGarrett D'Amore /* now we can receive upcalls */
18553a539a7SGarrett D'Amore auimpl_client_activate(c);
18688447a05SGarrett D'Amore
187682cb104SGarrett D'Amore atomic_inc_uint(&c->c_dev->d_serial);
18888447a05SGarrett D'Amore
18988447a05SGarrett D'Amore return (0);
19088447a05SGarrett D'Amore }
19188447a05SGarrett D'Amore
192a19bb1faSGarrett D'Amore static int
audio_stropen(queue_t * rq,dev_t * devp,int oflag,int sflag,cred_t * credp)193a19bb1faSGarrett D'Amore audio_stropen(queue_t *rq, dev_t *devp, int oflag, int sflag, cred_t *credp)
194a19bb1faSGarrett D'Amore {
195a19bb1faSGarrett D'Amore int rv;
196a19bb1faSGarrett D'Amore audio_client_t *c;
197a19bb1faSGarrett D'Amore
198a19bb1faSGarrett D'Amore if (sflag != 0) {
199a19bb1faSGarrett D'Amore /* no direct clone or module opens */
200a19bb1faSGarrett D'Amore return (ENXIO);
201a19bb1faSGarrett D'Amore }
202a19bb1faSGarrett D'Amore
203a19bb1faSGarrett D'Amore /*
204a19bb1faSGarrett D'Amore * Make sure its a STREAMS personality - only legacy Sun API uses
205a19bb1faSGarrett D'Amore * STREAMS.
206a19bb1faSGarrett D'Amore */
207a19bb1faSGarrett D'Amore switch (AUDIO_MN_TYPE_MASK & getminor(*devp)) {
208a19bb1faSGarrett D'Amore case AUDIO_MINOR_DEVAUDIO:
209a19bb1faSGarrett D'Amore case AUDIO_MINOR_DEVAUDIOCTL:
210a19bb1faSGarrett D'Amore break;
211a19bb1faSGarrett D'Amore default:
212a19bb1faSGarrett D'Amore return (ENOSTR);
213a19bb1faSGarrett D'Amore }
214a19bb1faSGarrett D'Amore
215a19bb1faSGarrett D'Amore if ((c = auimpl_client_create(*devp)) == NULL) {
216a19bb1faSGarrett D'Amore audio_dev_warn(NULL, "client create failed");
217a19bb1faSGarrett D'Amore return (ENXIO);
218a19bb1faSGarrett D'Amore }
219a19bb1faSGarrett D'Amore
220a19bb1faSGarrett D'Amore rq->q_ptr = WR(rq)->q_ptr = c;
221a19bb1faSGarrett D'Amore c->c_omode = oflag;
222a19bb1faSGarrett D'Amore c->c_pid = ddi_get_pid();
223a19bb1faSGarrett D'Amore c->c_cred = credp;
224a19bb1faSGarrett D'Amore c->c_rq = rq;
225a19bb1faSGarrett D'Amore c->c_wq = WR(rq);
226a19bb1faSGarrett D'Amore
227a19bb1faSGarrett D'Amore /*
228a19bb1faSGarrett D'Amore * Call client/personality specific open handler. Note that
229a19bb1faSGarrett D'Amore * we "insist" that there is an open. The personality layer
230a19bb1faSGarrett D'Amore * will initialize/allocate any engines required.
231a19bb1faSGarrett D'Amore *
232a19bb1faSGarrett D'Amore * Hmm... do we need to pass in the cred?
233a19bb1faSGarrett D'Amore */
234a19bb1faSGarrett D'Amore if ((rv = c->c_open(c, oflag)) != 0) {
235a19bb1faSGarrett D'Amore audio_dev_warn(c->c_dev, "open failed (rv %d)", rv);
236a19bb1faSGarrett D'Amore auimpl_client_destroy(c);
237a19bb1faSGarrett D'Amore return (rv);
238a19bb1faSGarrett D'Amore }
239a19bb1faSGarrett D'Amore
240a19bb1faSGarrett D'Amore /* we do device cloning! */
241a19bb1faSGarrett D'Amore *devp = makedevice(c->c_major, c->c_minor);
242a19bb1faSGarrett D'Amore
24353a539a7SGarrett D'Amore qprocson(rq);
244a19bb1faSGarrett D'Amore
24553a539a7SGarrett D'Amore /* now we can receive upcalls */
24653a539a7SGarrett D'Amore auimpl_client_activate(c);
247a19bb1faSGarrett D'Amore
248682cb104SGarrett D'Amore atomic_inc_uint(&c->c_dev->d_serial);
249a19bb1faSGarrett D'Amore
250a19bb1faSGarrett D'Amore return (0);
251a19bb1faSGarrett D'Amore }
252a19bb1faSGarrett D'Amore
253a19bb1faSGarrett D'Amore static int
audio_strclose(queue_t * rq,int flag,cred_t * credp)254a19bb1faSGarrett D'Amore audio_strclose(queue_t *rq, int flag, cred_t *credp)
255a19bb1faSGarrett D'Amore {
256a19bb1faSGarrett D'Amore audio_client_t *c;
257a19bb1faSGarrett D'Amore audio_dev_t *d;
258a19bb1faSGarrett D'Amore int rv;
259a19bb1faSGarrett D'Amore
260a19bb1faSGarrett D'Amore _NOTE(ARGUNUSED(flag));
261a19bb1faSGarrett D'Amore _NOTE(ARGUNUSED(credp));
262a19bb1faSGarrett D'Amore
263a19bb1faSGarrett D'Amore if ((c = rq->q_ptr) == NULL) {
264a19bb1faSGarrett D'Amore return (ENXIO);
265a19bb1faSGarrett D'Amore }
266a19bb1faSGarrett D'Amore if (ddi_can_receive_sig() || (ddi_get_pid() == 0)) {
267a19bb1faSGarrett D'Amore rv = auclnt_drain(c);
268a19bb1faSGarrett D'Amore }
269a19bb1faSGarrett D'Amore
27053a539a7SGarrett D'Amore /* make sure we won't get any upcalls */
27153a539a7SGarrett D'Amore auimpl_client_deactivate(c);
272a19bb1faSGarrett D'Amore
273a19bb1faSGarrett D'Amore /*
274a19bb1faSGarrett D'Amore * Pick up any data sitting around in input buffers. This
275a19bb1faSGarrett D'Amore * avoids leaving record data stuck in queues.
276a19bb1faSGarrett D'Amore */
277a19bb1faSGarrett D'Amore if (c->c_istream.s_engine != NULL)
27868c47f65SGarrett D'Amore auimpl_input_callback(c->c_istream.s_engine);
279a19bb1faSGarrett D'Amore
280a19bb1faSGarrett D'Amore /* get a local hold on the device */
281a19bb1faSGarrett D'Amore d = c->c_dev;
282a19bb1faSGarrett D'Amore auimpl_dev_hold(c->c_dev);
283a19bb1faSGarrett D'Amore
284a19bb1faSGarrett D'Amore /* Turn off queue processing... */
285a19bb1faSGarrett D'Amore qprocsoff(rq);
286a19bb1faSGarrett D'Amore
287a19bb1faSGarrett D'Amore /* Call personality specific close handler */
288a19bb1faSGarrett D'Amore c->c_close(c);
289a19bb1faSGarrett D'Amore
290a19bb1faSGarrett D'Amore auimpl_client_destroy(c);
291a19bb1faSGarrett D'Amore
292a19bb1faSGarrett D'Amore /* notify peers that a change has occurred */
293682cb104SGarrett D'Amore atomic_inc_uint(&d->d_serial);
294a19bb1faSGarrett D'Amore
295a19bb1faSGarrett D'Amore /* now we can drop the release we had on the device */
296a19bb1faSGarrett D'Amore auimpl_dev_release(d);
297a19bb1faSGarrett D'Amore
298a19bb1faSGarrett D'Amore return (rv);
299a19bb1faSGarrett D'Amore }
300a19bb1faSGarrett D'Amore
30188447a05SGarrett D'Amore static int
audio_close(dev_t dev,int flag,int otyp,cred_t * credp)30288447a05SGarrett D'Amore audio_close(dev_t dev, int flag, int otyp, cred_t *credp)
30388447a05SGarrett D'Amore {
30488447a05SGarrett D'Amore audio_client_t *c;
30588447a05SGarrett D'Amore audio_dev_t *d;
30688447a05SGarrett D'Amore
30788447a05SGarrett D'Amore _NOTE(ARGUNUSED(flag));
30888447a05SGarrett D'Amore _NOTE(ARGUNUSED(credp));
30988447a05SGarrett D'Amore _NOTE(ARGUNUSED(otyp));
31088447a05SGarrett D'Amore
31188447a05SGarrett D'Amore if ((c = auclnt_hold_by_devt(dev)) == NULL) {
312a19bb1faSGarrett D'Amore audio_dev_warn(NULL, "close on bogus devt %x,%x",
31388447a05SGarrett D'Amore getmajor(dev), getminor(dev));
31488447a05SGarrett D'Amore return (ENXIO);
31588447a05SGarrett D'Amore }
31688447a05SGarrett D'Amore
31753a539a7SGarrett D'Amore /* we don't want any upcalls anymore */
31853a539a7SGarrett D'Amore auimpl_client_deactivate(c);
31988447a05SGarrett D'Amore
32088447a05SGarrett D'Amore /*
32188447a05SGarrett D'Amore * Pick up any data sitting around in input buffers. This
32288447a05SGarrett D'Amore * avoids leaving record data stuck in queues.
32388447a05SGarrett D'Amore */
32488447a05SGarrett D'Amore if (c->c_istream.s_engine != NULL)
32568c47f65SGarrett D'Amore auimpl_input_callback(c->c_istream.s_engine);
32688447a05SGarrett D'Amore
32788447a05SGarrett D'Amore /* get a local hold on the device */
32888447a05SGarrett D'Amore d = c->c_dev;
32988447a05SGarrett D'Amore auimpl_dev_hold(c->c_dev);
33088447a05SGarrett D'Amore
33188447a05SGarrett D'Amore /*
33288447a05SGarrett D'Amore * NB: This must be done before c->c_close, since it calls
33388447a05SGarrett D'Amore * auclnt_close which will block waiting for the refence count
33488447a05SGarrett D'Amore * to drop to zero.
33588447a05SGarrett D'Amore */
33688447a05SGarrett D'Amore auclnt_release(c);
33788447a05SGarrett D'Amore
33888447a05SGarrett D'Amore /* Call personality specific close handler */
33988447a05SGarrett D'Amore c->c_close(c);
34088447a05SGarrett D'Amore
34188447a05SGarrett D'Amore auimpl_client_destroy(c);
34288447a05SGarrett D'Amore
34388447a05SGarrett D'Amore /* notify peers that a change has occurred */
344682cb104SGarrett D'Amore atomic_inc_uint(&d->d_serial);
34588447a05SGarrett D'Amore
34688447a05SGarrett D'Amore /* now we can drop the release we had on the device */
34788447a05SGarrett D'Amore auimpl_dev_release(d);
34888447a05SGarrett D'Amore
34988447a05SGarrett D'Amore return (0);
35088447a05SGarrett D'Amore }
35188447a05SGarrett D'Amore
35288447a05SGarrett D'Amore static int
audio_write(dev_t dev,struct uio * uio,cred_t * credp)35388447a05SGarrett D'Amore audio_write(dev_t dev, struct uio *uio, cred_t *credp)
35488447a05SGarrett D'Amore {
35588447a05SGarrett D'Amore audio_client_t *c;
35688447a05SGarrett D'Amore int rv;
35788447a05SGarrett D'Amore
35888447a05SGarrett D'Amore if ((c = auclnt_hold_by_devt(dev)) == NULL) {
35988447a05SGarrett D'Amore return (ENXIO);
36088447a05SGarrett D'Amore }
36168c47f65SGarrett D'Amore if ((rv = auclnt_serialize(c)) == 0) {
36268c47f65SGarrett D'Amore rv = (c->c_write == NULL) ? ENXIO : c->c_write(c, uio, credp);
36368c47f65SGarrett D'Amore auclnt_unserialize(c);
36468c47f65SGarrett D'Amore }
36588447a05SGarrett D'Amore auclnt_release(c);
36688447a05SGarrett D'Amore
36788447a05SGarrett D'Amore return (rv);
36888447a05SGarrett D'Amore }
36988447a05SGarrett D'Amore
37088447a05SGarrett D'Amore static int
audio_read(dev_t dev,struct uio * uio,cred_t * credp)37188447a05SGarrett D'Amore audio_read(dev_t dev, struct uio *uio, cred_t *credp)
37288447a05SGarrett D'Amore {
37388447a05SGarrett D'Amore audio_client_t *c;
37488447a05SGarrett D'Amore int rv;
37588447a05SGarrett D'Amore
37688447a05SGarrett D'Amore if ((c = auclnt_hold_by_devt(dev)) == NULL) {
37788447a05SGarrett D'Amore return (ENXIO);
37888447a05SGarrett D'Amore }
37968c47f65SGarrett D'Amore if ((rv = auclnt_serialize(c)) == 0) {
38068c47f65SGarrett D'Amore rv = (c->c_read == NULL) ? ENXIO : c->c_read(c, uio, credp);
38168c47f65SGarrett D'Amore auclnt_unserialize(c);
38268c47f65SGarrett D'Amore }
38388447a05SGarrett D'Amore auclnt_release(c);
38488447a05SGarrett D'Amore
38588447a05SGarrett D'Amore return (rv);
38688447a05SGarrett D'Amore }
38788447a05SGarrett D'Amore
38888447a05SGarrett D'Amore static int
audio_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)38988447a05SGarrett D'Amore audio_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
39088447a05SGarrett D'Amore int *rvalp)
39188447a05SGarrett D'Amore {
39288447a05SGarrett D'Amore audio_client_t *c;
39388447a05SGarrett D'Amore int rv;
39488447a05SGarrett D'Amore
39588447a05SGarrett D'Amore if ((c = auclnt_hold_by_devt(dev)) == NULL) {
39688447a05SGarrett D'Amore return (ENXIO);
39788447a05SGarrett D'Amore }
39888447a05SGarrett D'Amore rv = (c->c_ioctl == NULL) ? ENXIO : c->c_ioctl(c, cmd, arg, mode,
39988447a05SGarrett D'Amore credp, rvalp);
40088447a05SGarrett D'Amore auclnt_release(c);
40188447a05SGarrett D'Amore
40288447a05SGarrett D'Amore return (rv);
40388447a05SGarrett D'Amore }
40488447a05SGarrett D'Amore
40588447a05SGarrett D'Amore static int
audio_chpoll(dev_t dev,short events,int anyyet,short * reventsp,struct pollhead ** phpp)40688447a05SGarrett D'Amore audio_chpoll(dev_t dev, short events, int anyyet, short *reventsp,
40788447a05SGarrett D'Amore struct pollhead **phpp)
40888447a05SGarrett D'Amore {
40988447a05SGarrett D'Amore audio_client_t *c;
41088447a05SGarrett D'Amore int rv;
41188447a05SGarrett D'Amore
41288447a05SGarrett D'Amore if ((c = auclnt_hold_by_devt(dev)) == NULL) {
41388447a05SGarrett D'Amore return (ENXIO);
41488447a05SGarrett D'Amore }
41588447a05SGarrett D'Amore rv = (c->c_chpoll == NULL) ?
41688447a05SGarrett D'Amore ENXIO :
41788447a05SGarrett D'Amore c->c_chpoll(c, events, anyyet, reventsp, phpp);
41888447a05SGarrett D'Amore auclnt_release(c);
41988447a05SGarrett D'Amore
42088447a05SGarrett D'Amore return (rv);
42188447a05SGarrett D'Amore }
42288447a05SGarrett D'Amore
423a19bb1faSGarrett D'Amore static int
audio_wput(queue_t * wq,mblk_t * mp)424a19bb1faSGarrett D'Amore audio_wput(queue_t *wq, mblk_t *mp)
425a19bb1faSGarrett D'Amore {
426a19bb1faSGarrett D'Amore audio_client_t *c;
427a19bb1faSGarrett D'Amore
428a19bb1faSGarrett D'Amore c = wq->q_ptr;
429a19bb1faSGarrett D'Amore if (c->c_wput) {
430a19bb1faSGarrett D'Amore c->c_wput(c, mp);
431a19bb1faSGarrett D'Amore } else {
432a19bb1faSGarrett D'Amore freemsg(mp);
433a19bb1faSGarrett D'Amore }
434a19bb1faSGarrett D'Amore return (0);
435a19bb1faSGarrett D'Amore }
436a19bb1faSGarrett D'Amore
437a19bb1faSGarrett D'Amore static int
audio_wsrv(queue_t * wq)438a19bb1faSGarrett D'Amore audio_wsrv(queue_t *wq)
439a19bb1faSGarrett D'Amore {
440a19bb1faSGarrett D'Amore audio_client_t *c;
441a19bb1faSGarrett D'Amore
442a19bb1faSGarrett D'Amore c = wq->q_ptr;
443a19bb1faSGarrett D'Amore if (c->c_wsrv) {
444a19bb1faSGarrett D'Amore c->c_wsrv(c);
445a19bb1faSGarrett D'Amore } else {
446a19bb1faSGarrett D'Amore flushq(wq, FLUSHALL);
447a19bb1faSGarrett D'Amore }
448a19bb1faSGarrett D'Amore return (0);
449a19bb1faSGarrett D'Amore }
45088447a05SGarrett D'Amore
451682cb104SGarrett D'Amore static int
audio_rsrv(queue_t * rq)452682cb104SGarrett D'Amore audio_rsrv(queue_t *rq)
453682cb104SGarrett D'Amore {
454682cb104SGarrett D'Amore audio_client_t *c;
455682cb104SGarrett D'Amore
456682cb104SGarrett D'Amore c = rq->q_ptr;
457682cb104SGarrett D'Amore if (c->c_rsrv) {
458682cb104SGarrett D'Amore c->c_rsrv(c);
459682cb104SGarrett D'Amore } else {
460682cb104SGarrett D'Amore flushq(rq, FLUSHALL);
461682cb104SGarrett D'Amore }
462682cb104SGarrett D'Amore return (0);
463682cb104SGarrett D'Amore }
464682cb104SGarrett D'Amore
465682cb104SGarrett D'Amore
46688447a05SGarrett D'Amore static struct dev_ops audio_dev_ops = {
46788447a05SGarrett D'Amore DEVO_REV, /* rev */
46888447a05SGarrett D'Amore 0, /* refcnt */
469a19bb1faSGarrett D'Amore NULL, /* getinfo */
47088447a05SGarrett D'Amore nulldev, /* identify */
47188447a05SGarrett D'Amore nulldev, /* probe */
47288447a05SGarrett D'Amore audio_attach, /* attach */
47388447a05SGarrett D'Amore audio_detach, /* detach */
47488447a05SGarrett D'Amore nodev, /* reset */
475a19bb1faSGarrett D'Amore NULL, /* cb_ops */
47688447a05SGarrett D'Amore NULL, /* bus_ops */
47788447a05SGarrett D'Amore NULL, /* power */
47888447a05SGarrett D'Amore };
47988447a05SGarrett D'Amore
48088447a05SGarrett D'Amore static struct modldrv modldrv = {
48188447a05SGarrett D'Amore &mod_driverops,
48288447a05SGarrett D'Amore "Audio Framework",
48388447a05SGarrett D'Amore &audio_dev_ops,
48488447a05SGarrett D'Amore };
48588447a05SGarrett D'Amore
48688447a05SGarrett D'Amore static struct modlinkage modlinkage = {
48788447a05SGarrett D'Amore MODREV_1, /* MODREV_1 indicated by manual */
48888447a05SGarrett D'Amore &modldrv,
48988447a05SGarrett D'Amore NULL
49088447a05SGarrett D'Amore };
49188447a05SGarrett D'Amore
49288447a05SGarrett D'Amore struct audio_ops_helper {
493a19bb1faSGarrett D'Amore struct cb_ops cbops; /* NB: must be first */
494a19bb1faSGarrett D'Amore struct streamtab strtab;
495a19bb1faSGarrett D'Amore struct qinit rqinit;
496a19bb1faSGarrett D'Amore struct qinit wqinit;
497a19bb1faSGarrett D'Amore struct module_info minfo;
498a19bb1faSGarrett D'Amore char name[MODMAXNAMELEN+1];
49988447a05SGarrett D'Amore };
50088447a05SGarrett D'Amore
50188447a05SGarrett D'Amore void
audio_init_ops(struct dev_ops * devops,const char * name)50288447a05SGarrett D'Amore audio_init_ops(struct dev_ops *devops, const char *name)
50388447a05SGarrett D'Amore {
50488447a05SGarrett D'Amore struct audio_ops_helper *helper;
50588447a05SGarrett D'Amore
50688447a05SGarrett D'Amore helper = kmem_zalloc(sizeof (*helper), KM_SLEEP);
50788447a05SGarrett D'Amore
508a19bb1faSGarrett D'Amore (void) strlcpy(helper->name, name, sizeof (helper->name));
509a19bb1faSGarrett D'Amore
510*bbf21555SRichard Lowe helper->minfo.mi_idnum = 0; /* only for strlog(8) */
511a19bb1faSGarrett D'Amore helper->minfo.mi_idname = helper->name;
512a19bb1faSGarrett D'Amore helper->minfo.mi_minpsz = 0;
513682cb104SGarrett D'Amore helper->minfo.mi_maxpsz = 8192;
514a19bb1faSGarrett D'Amore helper->minfo.mi_hiwat = 65536;
515a19bb1faSGarrett D'Amore helper->minfo.mi_lowat = 32768;
516a19bb1faSGarrett D'Amore
517a19bb1faSGarrett D'Amore helper->wqinit.qi_putp = audio_wput;
518a19bb1faSGarrett D'Amore helper->wqinit.qi_srvp = audio_wsrv;
519a19bb1faSGarrett D'Amore helper->wqinit.qi_qopen = NULL;
520a19bb1faSGarrett D'Amore helper->wqinit.qi_qclose = NULL;
521a19bb1faSGarrett D'Amore helper->wqinit.qi_qadmin = NULL;
522a19bb1faSGarrett D'Amore helper->wqinit.qi_minfo = &helper->minfo;
523a19bb1faSGarrett D'Amore helper->wqinit.qi_mstat = NULL;
524a19bb1faSGarrett D'Amore
525682cb104SGarrett D'Amore helper->rqinit.qi_putp = putq;
526682cb104SGarrett D'Amore helper->rqinit.qi_srvp = audio_rsrv;
527a19bb1faSGarrett D'Amore helper->rqinit.qi_qopen = audio_stropen;
528a19bb1faSGarrett D'Amore helper->rqinit.qi_qclose = audio_strclose;
529a19bb1faSGarrett D'Amore helper->rqinit.qi_qadmin = NULL;
530a19bb1faSGarrett D'Amore helper->rqinit.qi_minfo = &helper->minfo;
531a19bb1faSGarrett D'Amore helper->rqinit.qi_mstat = NULL;
532a19bb1faSGarrett D'Amore
533a19bb1faSGarrett D'Amore helper->strtab.st_rdinit = &helper->rqinit;
534a19bb1faSGarrett D'Amore helper->strtab.st_wrinit = &helper->wqinit;
535a19bb1faSGarrett D'Amore helper->strtab.st_muxrinit = NULL;
536a19bb1faSGarrett D'Amore helper->strtab.st_muxwinit = NULL;
537a19bb1faSGarrett D'Amore
53888447a05SGarrett D'Amore helper->cbops.cb_open = audio_open;
53988447a05SGarrett D'Amore helper->cbops.cb_close = audio_close;
54088447a05SGarrett D'Amore helper->cbops.cb_strategy = nodev;
54188447a05SGarrett D'Amore helper->cbops.cb_print = nodev;
54288447a05SGarrett D'Amore helper->cbops.cb_dump = nodev;
54388447a05SGarrett D'Amore helper->cbops.cb_read = audio_read;
54488447a05SGarrett D'Amore helper->cbops.cb_write = audio_write;
54588447a05SGarrett D'Amore helper->cbops.cb_ioctl = audio_ioctl;
54688447a05SGarrett D'Amore helper->cbops.cb_devmap = nodev;
54788447a05SGarrett D'Amore helper->cbops.cb_mmap = nodev;
54888447a05SGarrett D'Amore helper->cbops.cb_segmap = nodev;
54988447a05SGarrett D'Amore helper->cbops.cb_chpoll = audio_chpoll;
55088447a05SGarrett D'Amore helper->cbops.cb_prop_op = ddi_prop_op;
551a19bb1faSGarrett D'Amore helper->cbops.cb_str = &helper->strtab;
55288447a05SGarrett D'Amore helper->cbops.cb_flag = D_MP | D_64BIT;
55388447a05SGarrett D'Amore helper->cbops.cb_rev = CB_REV;
55488447a05SGarrett D'Amore helper->cbops.cb_aread = nodev;
55588447a05SGarrett D'Amore helper->cbops.cb_awrite = nodev;
55688447a05SGarrett D'Amore
55788447a05SGarrett D'Amore devops->devo_cb_ops = &helper->cbops;
55888447a05SGarrett D'Amore devops->devo_getinfo = audio_getinfo;
55988447a05SGarrett D'Amore }
56088447a05SGarrett D'Amore
56188447a05SGarrett D'Amore void
audio_fini_ops(struct dev_ops * devops)56288447a05SGarrett D'Amore audio_fini_ops(struct dev_ops *devops)
56388447a05SGarrett D'Amore {
56488447a05SGarrett D'Amore kmem_free(devops->devo_cb_ops, sizeof (struct audio_ops_helper));
56588447a05SGarrett D'Amore devops->devo_cb_ops = NULL;
56688447a05SGarrett D'Amore devops->devo_getinfo = NULL;
56788447a05SGarrett D'Amore }
56888447a05SGarrett D'Amore
56988447a05SGarrett D'Amore void
auimpl_dev_vwarn(audio_dev_t * dev,const char * fmt,va_list va)57088447a05SGarrett D'Amore auimpl_dev_vwarn(audio_dev_t *dev, const char *fmt, va_list va)
57188447a05SGarrett D'Amore {
57288447a05SGarrett D'Amore char buf[256];
57388447a05SGarrett D'Amore
57488447a05SGarrett D'Amore if (dev != NULL) {
57588447a05SGarrett D'Amore (void) snprintf(buf, sizeof (buf), "%s#%d: %s",
57688447a05SGarrett D'Amore ddi_driver_name(dev->d_dip), ddi_get_instance(dev->d_dip),
57788447a05SGarrett D'Amore fmt);
57888447a05SGarrett D'Amore } else {
57988447a05SGarrett D'Amore (void) snprintf(buf, sizeof (buf), "audio: %s", fmt);
58088447a05SGarrett D'Amore }
58188447a05SGarrett D'Amore
58288447a05SGarrett D'Amore vcmn_err(CE_WARN, buf, va);
58388447a05SGarrett D'Amore }
58488447a05SGarrett D'Amore
58588447a05SGarrett D'Amore
58688447a05SGarrett D'Amore void
audio_dev_warn(audio_dev_t * dev,const char * fmt,...)58788447a05SGarrett D'Amore audio_dev_warn(audio_dev_t *dev, const char *fmt, ...)
58888447a05SGarrett D'Amore {
58988447a05SGarrett D'Amore va_list va;
59088447a05SGarrett D'Amore
59188447a05SGarrett D'Amore va_start(va, fmt);
59288447a05SGarrett D'Amore auimpl_dev_vwarn(dev, fmt, va);
59388447a05SGarrett D'Amore va_end(va);
59488447a05SGarrett D'Amore }
59588447a05SGarrett D'Amore
59688447a05SGarrett D'Amore /*
59788447a05SGarrett D'Amore * _init, _info, and _fini DDI glue.
59888447a05SGarrett D'Amore */
59988447a05SGarrett D'Amore int
_init(void)60088447a05SGarrett D'Amore _init(void)
60188447a05SGarrett D'Amore {
60288447a05SGarrett D'Amore int rv;
60388447a05SGarrett D'Amore
60488447a05SGarrett D'Amore auimpl_client_init();
60588447a05SGarrett D'Amore auimpl_dev_init();
60688447a05SGarrett D'Amore auimpl_sun_init();
60788447a05SGarrett D'Amore auimpl_oss_init();
60888447a05SGarrett D'Amore
609a19bb1faSGarrett D'Amore audio_init_ops(&audio_dev_ops, "audio");
610a19bb1faSGarrett D'Amore
61188447a05SGarrett D'Amore if ((rv = mod_install(&modlinkage)) != 0) {
612a19bb1faSGarrett D'Amore audio_fini_ops(&audio_dev_ops);
61388447a05SGarrett D'Amore auimpl_dev_fini();
61488447a05SGarrett D'Amore auimpl_client_fini();
61588447a05SGarrett D'Amore }
61688447a05SGarrett D'Amore return (rv);
61788447a05SGarrett D'Amore }
61888447a05SGarrett D'Amore
61988447a05SGarrett D'Amore int
_info(struct modinfo * modinfop)62088447a05SGarrett D'Amore _info(struct modinfo *modinfop)
62188447a05SGarrett D'Amore {
62288447a05SGarrett D'Amore return (mod_info(&modlinkage, modinfop));
62388447a05SGarrett D'Amore }
62488447a05SGarrett D'Amore
62588447a05SGarrett D'Amore int
_fini(void)62688447a05SGarrett D'Amore _fini(void)
62788447a05SGarrett D'Amore {
62888447a05SGarrett D'Amore int rv;
62988447a05SGarrett D'Amore
63088447a05SGarrett D'Amore if ((rv = mod_remove(&modlinkage)) != 0)
63188447a05SGarrett D'Amore return (rv);
63288447a05SGarrett D'Amore
63388447a05SGarrett D'Amore auimpl_dev_fini();
63488447a05SGarrett D'Amore auimpl_client_fini();
63588447a05SGarrett D'Amore
63688447a05SGarrett D'Amore return (rv);
63788447a05SGarrett D'Amore }
638