19484Sgarrett.damore@Sun.COM /*
29484Sgarrett.damore@Sun.COM * CDDL HEADER START
39484Sgarrett.damore@Sun.COM *
49484Sgarrett.damore@Sun.COM * The contents of this file are subject to the terms of the
59484Sgarrett.damore@Sun.COM * Common Development and Distribution License (the "License").
69484Sgarrett.damore@Sun.COM * You may not use this file except in compliance with the License.
79484Sgarrett.damore@Sun.COM *
89484Sgarrett.damore@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99484Sgarrett.damore@Sun.COM * or http://www.opensolaris.org/os/licensing.
109484Sgarrett.damore@Sun.COM * See the License for the specific language governing permissions
119484Sgarrett.damore@Sun.COM * and limitations under the License.
129484Sgarrett.damore@Sun.COM *
139484Sgarrett.damore@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
149484Sgarrett.damore@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159484Sgarrett.damore@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
169484Sgarrett.damore@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
179484Sgarrett.damore@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
189484Sgarrett.damore@Sun.COM *
199484Sgarrett.damore@Sun.COM * CDDL HEADER END
209484Sgarrett.damore@Sun.COM */
219484Sgarrett.damore@Sun.COM /*
22*12165Sgdamore@opensolaris.org * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
239484Sgarrett.damore@Sun.COM */
249484Sgarrett.damore@Sun.COM
259484Sgarrett.damore@Sun.COM /*
269484Sgarrett.damore@Sun.COM * Sun audio(7I) and mixer(7I) personality.
279484Sgarrett.damore@Sun.COM *
289484Sgarrett.damore@Sun.COM * There are some "undocumented" details of how legacy Sun audio
299484Sgarrett.damore@Sun.COM * interfaces work. The following "rules" were derived from reading the
309484Sgarrett.damore@Sun.COM * legacy Sun mixer code, and to the best of our knowledge are not
319484Sgarrett.damore@Sun.COM * documented elsewhere.
329484Sgarrett.damore@Sun.COM *
339484Sgarrett.damore@Sun.COM * - We create a "fake" audio device, which behaves like a classic
349484Sgarrett.damore@Sun.COM * exclusive audio device, for each PID, as determined during open(2).
359484Sgarrett.damore@Sun.COM *
369484Sgarrett.damore@Sun.COM * - Different processes don't interfere with each other. Even though
379484Sgarrett.damore@Sun.COM * they are running concurrently, they each think they have exclusive
389484Sgarrett.damore@Sun.COM * control over the audio device.
399484Sgarrett.damore@Sun.COM *
409484Sgarrett.damore@Sun.COM * - Read and write directions operate independent of each other. That
419484Sgarrett.damore@Sun.COM * is, a device open for reading won't intefere with a future open for
429484Sgarrett.damore@Sun.COM * writing, and vice versa. This is true even within the same process.
439484Sgarrett.damore@Sun.COM *
449484Sgarrett.damore@Sun.COM * - Because the virtualization is by PID, strange behavior may occur
459484Sgarrett.damore@Sun.COM * if a process tries to open an audio device at the same time it
469484Sgarrett.damore@Sun.COM * has already received a file descriptor from another process (such
479484Sgarrett.damore@Sun.COM * through inheritence via fork()).
489484Sgarrett.damore@Sun.COM *
499484Sgarrett.damore@Sun.COM * - The "fake" audio device has no control over physical settings.
509484Sgarrett.damore@Sun.COM * It sees only the software attenuation-based volumes for play and
519484Sgarrett.damore@Sun.COM * record, and has no support for alternate input or output ports or
529484Sgarrett.damore@Sun.COM * access to the monitoring features of the hardware.
539484Sgarrett.damore@Sun.COM *
549484Sgarrett.damore@Sun.COM * - Explicit notificaton signals (SIGPOLL) are only ever sent up the
559484Sgarrett.damore@Sun.COM * audioctl node -- never up a regular audio node. (The stream head
569484Sgarrett.damore@Sun.COM * may still issue SIGPOLL based on readability/writability of
579484Sgarrett.damore@Sun.COM * course.)
589484Sgarrett.damore@Sun.COM *
599484Sgarrett.damore@Sun.COM * - Corollary: processes that want asynch. notifications will open
609484Sgarrett.damore@Sun.COM * /dev/audioctl as well as /dev/audio.
619484Sgarrett.damore@Sun.COM *
629484Sgarrett.damore@Sun.COM * - We don't support the MIXER mode at all.
639484Sgarrett.damore@Sun.COM *
649484Sgarrett.damore@Sun.COM * - By corollary, a process is only allowed to open /dev/audio once
659484Sgarrett.damore@Sun.COM * (in each direction.)
669484Sgarrett.damore@Sun.COM *
679484Sgarrett.damore@Sun.COM * - Attempts to open /dev/audio in duplex mode (O_RDWR) fail (EBUSY)
689484Sgarrett.damore@Sun.COM * if the device cannot support duplex operation.
699484Sgarrett.damore@Sun.COM *
709484Sgarrett.damore@Sun.COM * - Attempts to open a device with FREAD set fail if the device is not
719484Sgarrett.damore@Sun.COM * capable of recording. (Likewise for FWRITE and playback.)
729484Sgarrett.damore@Sun.COM *
739484Sgarrett.damore@Sun.COM * - No data transfer is permitted for audioctl nodes. (No actual
749484Sgarrett.damore@Sun.COM * record or play.)
759484Sgarrett.damore@Sun.COM *
769484Sgarrett.damore@Sun.COM * - Sun audio does not support any formats other than linear and
779484Sgarrett.damore@Sun.COM * ULAW/ALAW. I.e. it will never support AC3 or other "opaque"
789484Sgarrett.damore@Sun.COM * streams which require special handling.
799484Sgarrett.damore@Sun.COM *
809484Sgarrett.damore@Sun.COM * - Sun audio only supports stereo or monophonic data streams.
819484Sgarrett.damore@Sun.COM */
829484Sgarrett.damore@Sun.COM
839484Sgarrett.damore@Sun.COM #include <sys/types.h>
849484Sgarrett.damore@Sun.COM #include <sys/open.h>
859484Sgarrett.damore@Sun.COM #include <sys/errno.h>
869484Sgarrett.damore@Sun.COM #include <sys/audio.h>
879484Sgarrett.damore@Sun.COM #include <sys/mixer.h>
889484Sgarrett.damore@Sun.COM #include <sys/file.h>
899484Sgarrett.damore@Sun.COM #include <sys/stropts.h>
909484Sgarrett.damore@Sun.COM #include <sys/strsun.h>
919484Sgarrett.damore@Sun.COM #include <sys/sysmacros.h>
929484Sgarrett.damore@Sun.COM #include <sys/list.h>
939484Sgarrett.damore@Sun.COM #include <sys/note.h>
949484Sgarrett.damore@Sun.COM #include <sys/stat.h>
959484Sgarrett.damore@Sun.COM #include <sys/ddi.h>
969484Sgarrett.damore@Sun.COM #include <sys/sunddi.h>
979484Sgarrett.damore@Sun.COM #include "audio_client.h"
989484Sgarrett.damore@Sun.COM
9910157Sgdamore@opensolaris.org typedef struct daclient daclient_t;
10010157Sgdamore@opensolaris.org typedef struct dadev dadev_t;
10110157Sgdamore@opensolaris.org typedef struct daproc daproc_t;
1029484Sgarrett.damore@Sun.COM
1039484Sgarrett.damore@Sun.COM /* common structure shared between both audioctl and audio nodes */
10410157Sgdamore@opensolaris.org struct daclient {
10510157Sgdamore@opensolaris.org daproc_t *dc_proc;
10610157Sgdamore@opensolaris.org dadev_t *dc_dev;
10710157Sgdamore@opensolaris.org audio_client_t *dc_client;
10810157Sgdamore@opensolaris.org queue_t *dc_wq;
10910157Sgdamore@opensolaris.org unsigned dc_eof;
11010157Sgdamore@opensolaris.org list_t dc_eofcnt;
11110157Sgdamore@opensolaris.org kmutex_t dc_lock;
11210157Sgdamore@opensolaris.org mblk_t *dc_draining;
1139484Sgarrett.damore@Sun.COM };
1149484Sgarrett.damore@Sun.COM
1159484Sgarrett.damore@Sun.COM struct eofcnt {
1169484Sgarrett.damore@Sun.COM list_node_t linkage;
1179484Sgarrett.damore@Sun.COM uint64_t tail;
1189484Sgarrett.damore@Sun.COM };
1199484Sgarrett.damore@Sun.COM
12010157Sgdamore@opensolaris.org struct dadev {
1219484Sgarrett.damore@Sun.COM audio_dev_t *d_dev;
1229484Sgarrett.damore@Sun.COM
1239484Sgarrett.damore@Sun.COM list_t d_procs;
1249484Sgarrett.damore@Sun.COM kmutex_t d_mx;
1259484Sgarrett.damore@Sun.COM kcondvar_t d_cv;
1269484Sgarrett.damore@Sun.COM };
1279484Sgarrett.damore@Sun.COM
12810157Sgdamore@opensolaris.org struct daproc {
1299484Sgarrett.damore@Sun.COM pid_t p_id;
1309484Sgarrett.damore@Sun.COM struct audio_info p_info;
1319484Sgarrett.damore@Sun.COM int p_refcnt;
1329484Sgarrett.damore@Sun.COM int p_oflag;
1339484Sgarrett.damore@Sun.COM list_node_t p_linkage;
13410157Sgdamore@opensolaris.org dadev_t *p_dev;
13510157Sgdamore@opensolaris.org audio_client_t *p_writer;
13610157Sgdamore@opensolaris.org audio_client_t *p_reader;
1379484Sgarrett.damore@Sun.COM };
1389484Sgarrett.damore@Sun.COM
13910157Sgdamore@opensolaris.org int devaudio_proc_hold(audio_client_t *, int);
14010157Sgdamore@opensolaris.org void devaudio_proc_release(audio_client_t *);
14110157Sgdamore@opensolaris.org static void devaudio_proc_update(daproc_t *);
1429484Sgarrett.damore@Sun.COM
1439484Sgarrett.damore@Sun.COM
1449484Sgarrett.damore@Sun.COM static int
devaudio_compose_format(audio_prinfo_t * prinfo)14510157Sgdamore@opensolaris.org devaudio_compose_format(audio_prinfo_t *prinfo)
1469484Sgarrett.damore@Sun.COM {
1479484Sgarrett.damore@Sun.COM switch (prinfo->precision) {
1489484Sgarrett.damore@Sun.COM case 8:
1499484Sgarrett.damore@Sun.COM switch (prinfo->encoding) {
1509484Sgarrett.damore@Sun.COM case AUDIO_ENCODING_ULAW:
1519484Sgarrett.damore@Sun.COM return (AUDIO_FORMAT_ULAW);
1529484Sgarrett.damore@Sun.COM case AUDIO_ENCODING_ALAW:
1539484Sgarrett.damore@Sun.COM return (AUDIO_FORMAT_ALAW);
1549484Sgarrett.damore@Sun.COM case AUDIO_ENCODING_LINEAR8:
1559484Sgarrett.damore@Sun.COM return (AUDIO_FORMAT_U8);
1569484Sgarrett.damore@Sun.COM case AUDIO_ENCODING_LINEAR:
1579484Sgarrett.damore@Sun.COM return (AUDIO_FORMAT_S8);
1589484Sgarrett.damore@Sun.COM }
1599484Sgarrett.damore@Sun.COM break;
1609484Sgarrett.damore@Sun.COM case 16:
1619484Sgarrett.damore@Sun.COM if (prinfo->encoding == AUDIO_ENCODING_LINEAR)
1629484Sgarrett.damore@Sun.COM return (AUDIO_FORMAT_S16_NE);
1639484Sgarrett.damore@Sun.COM break;
1649484Sgarrett.damore@Sun.COM case 32:
1659484Sgarrett.damore@Sun.COM if (prinfo->encoding == AUDIO_ENCODING_LINEAR)
1669484Sgarrett.damore@Sun.COM return (AUDIO_FORMAT_S32_NE);
1679484Sgarrett.damore@Sun.COM break;
1689484Sgarrett.damore@Sun.COM }
1699484Sgarrett.damore@Sun.COM return (AUDIO_FORMAT_NONE);
1709484Sgarrett.damore@Sun.COM
1719484Sgarrett.damore@Sun.COM }
1729484Sgarrett.damore@Sun.COM
1739484Sgarrett.damore@Sun.COM static void
devaudio_decompose_format(audio_prinfo_t * prinfo,int afmt)17410157Sgdamore@opensolaris.org devaudio_decompose_format(audio_prinfo_t *prinfo, int afmt)
1759484Sgarrett.damore@Sun.COM {
1769484Sgarrett.damore@Sun.COM int e, p;
1779484Sgarrett.damore@Sun.COM
1789484Sgarrett.damore@Sun.COM /*
1799484Sgarrett.damore@Sun.COM * N.B.: Even though some of the formats below can't be set by
1809484Sgarrett.damore@Sun.COM * this personality, reporting them (using the closest match)
1819484Sgarrett.damore@Sun.COM * allows this personality to roughly approximate settings for
1829484Sgarrett.damore@Sun.COM * other streams. It would be incredibly poor form for any
1839484Sgarrett.damore@Sun.COM * personality to modify the format settings for a different
1849484Sgarrett.damore@Sun.COM * personality, so we don't worry about that case.
1859484Sgarrett.damore@Sun.COM */
1869484Sgarrett.damore@Sun.COM
1879484Sgarrett.damore@Sun.COM switch (afmt) {
1889484Sgarrett.damore@Sun.COM case AUDIO_FORMAT_ULAW:
1899484Sgarrett.damore@Sun.COM e = AUDIO_ENCODING_ULAW;
1909484Sgarrett.damore@Sun.COM p = 8;
1919484Sgarrett.damore@Sun.COM break;
1929484Sgarrett.damore@Sun.COM
1939484Sgarrett.damore@Sun.COM case AUDIO_FORMAT_ALAW:
1949484Sgarrett.damore@Sun.COM e = AUDIO_ENCODING_ALAW;
1959484Sgarrett.damore@Sun.COM p = 8;
1969484Sgarrett.damore@Sun.COM break;
1979484Sgarrett.damore@Sun.COM
1989484Sgarrett.damore@Sun.COM case AUDIO_FORMAT_U8:
1999484Sgarrett.damore@Sun.COM e = AUDIO_ENCODING_LINEAR8;
2009484Sgarrett.damore@Sun.COM p = 8;
2019484Sgarrett.damore@Sun.COM break;
2029484Sgarrett.damore@Sun.COM
2039484Sgarrett.damore@Sun.COM case AUDIO_FORMAT_S8:
2049484Sgarrett.damore@Sun.COM e = AUDIO_ENCODING_LINEAR;
2059484Sgarrett.damore@Sun.COM p = 8;
2069484Sgarrett.damore@Sun.COM break;
2079484Sgarrett.damore@Sun.COM
2089484Sgarrett.damore@Sun.COM case AUDIO_FORMAT_S16_NE:
2099484Sgarrett.damore@Sun.COM case AUDIO_FORMAT_S16_OE:
2109484Sgarrett.damore@Sun.COM case AUDIO_FORMAT_U16_NE:
2119484Sgarrett.damore@Sun.COM case AUDIO_FORMAT_U16_OE:
2129484Sgarrett.damore@Sun.COM e = AUDIO_ENCODING_LINEAR;
2139484Sgarrett.damore@Sun.COM p = 16;
2149484Sgarrett.damore@Sun.COM break;
2159484Sgarrett.damore@Sun.COM
2169484Sgarrett.damore@Sun.COM case AUDIO_FORMAT_S24_NE:
2179484Sgarrett.damore@Sun.COM case AUDIO_FORMAT_S24_OE:
2189484Sgarrett.damore@Sun.COM case AUDIO_FORMAT_S24_PACKED:
2199484Sgarrett.damore@Sun.COM e = AUDIO_ENCODING_LINEAR;
2209484Sgarrett.damore@Sun.COM p = 24;
2219484Sgarrett.damore@Sun.COM break;
2229484Sgarrett.damore@Sun.COM
2239484Sgarrett.damore@Sun.COM case AUDIO_FORMAT_S32_NE:
2249484Sgarrett.damore@Sun.COM case AUDIO_FORMAT_S32_OE:
2259484Sgarrett.damore@Sun.COM e = AUDIO_ENCODING_LINEAR;
2269484Sgarrett.damore@Sun.COM p = 32;
2279484Sgarrett.damore@Sun.COM break;
2289484Sgarrett.damore@Sun.COM
2299484Sgarrett.damore@Sun.COM default:
2309484Sgarrett.damore@Sun.COM /* all other formats (e.g. AC3) are uninterpreted */
2319484Sgarrett.damore@Sun.COM e = AUDIO_ENCODING_NONE;
2329484Sgarrett.damore@Sun.COM p = 32;
2339484Sgarrett.damore@Sun.COM break;
2349484Sgarrett.damore@Sun.COM }
2359484Sgarrett.damore@Sun.COM
2369484Sgarrett.damore@Sun.COM prinfo->encoding = e;
2379484Sgarrett.damore@Sun.COM prinfo->precision = p;
2389484Sgarrett.damore@Sun.COM }
2399484Sgarrett.damore@Sun.COM
24010157Sgdamore@opensolaris.org static daproc_t *
devaudio_proc_alloc(audio_client_t * c)24110157Sgdamore@opensolaris.org devaudio_proc_alloc(audio_client_t *c)
2429484Sgarrett.damore@Sun.COM {
2439484Sgarrett.damore@Sun.COM audio_info_t *info;
2449484Sgarrett.damore@Sun.COM audio_prinfo_t *prinfo;
2459484Sgarrett.damore@Sun.COM uint32_t caps;
24610157Sgdamore@opensolaris.org daproc_t *proc;
2479484Sgarrett.damore@Sun.COM
2489484Sgarrett.damore@Sun.COM if ((proc = kmem_zalloc(sizeof (*proc), KM_NOSLEEP)) == NULL) {
2499484Sgarrett.damore@Sun.COM return (NULL);
2509484Sgarrett.damore@Sun.COM }
2519484Sgarrett.damore@Sun.COM info = &proc->p_info;
2529484Sgarrett.damore@Sun.COM
2539484Sgarrett.damore@Sun.COM /*
2549484Sgarrett.damore@Sun.COM * audio(7I) says: Upon the initial open() of the audio
2559484Sgarrett.damore@Sun.COM * device, the driver resets the data format of the device to
2569484Sgarrett.damore@Sun.COM * the default state of 8-bit, 8Khz, mono u-Law data.
2579484Sgarrett.damore@Sun.COM */
2589484Sgarrett.damore@Sun.COM prinfo = &info->play;
2599484Sgarrett.damore@Sun.COM prinfo->channels = 1;
2609484Sgarrett.damore@Sun.COM prinfo->sample_rate = 8000;
2619484Sgarrett.damore@Sun.COM prinfo->encoding = AUDIO_ENCODING_ULAW;
2629484Sgarrett.damore@Sun.COM prinfo->precision = 8;
2639484Sgarrett.damore@Sun.COM prinfo->gain = AUDIO_MAX_GAIN;
2649484Sgarrett.damore@Sun.COM prinfo->balance = AUDIO_MID_BALANCE;
2659484Sgarrett.damore@Sun.COM prinfo->buffer_size = 8192;
2669484Sgarrett.damore@Sun.COM prinfo->pause = B_FALSE;
2679484Sgarrett.damore@Sun.COM prinfo->waiting = B_FALSE;
2689484Sgarrett.damore@Sun.COM prinfo->open = B_FALSE;
2699484Sgarrett.damore@Sun.COM prinfo->active = B_FALSE;
2709484Sgarrett.damore@Sun.COM prinfo->samples = 0;
2719484Sgarrett.damore@Sun.COM prinfo->eof = 0;
2729484Sgarrett.damore@Sun.COM prinfo->error = 0;
2739484Sgarrett.damore@Sun.COM prinfo->minordev = 0;
2749484Sgarrett.damore@Sun.COM prinfo->port = AUDIO_SPEAKER;
2759484Sgarrett.damore@Sun.COM prinfo->avail_ports = AUDIO_SPEAKER;
2769484Sgarrett.damore@Sun.COM prinfo->mod_ports = AUDIO_NONE;
2779484Sgarrett.damore@Sun.COM prinfo->_xxx = 0;
2789484Sgarrett.damore@Sun.COM
2799484Sgarrett.damore@Sun.COM prinfo = &info->record;
2809484Sgarrett.damore@Sun.COM prinfo->channels = 1;
2819484Sgarrett.damore@Sun.COM prinfo->sample_rate = 8000;
2829484Sgarrett.damore@Sun.COM prinfo->encoding = AUDIO_ENCODING_ULAW;
2839484Sgarrett.damore@Sun.COM prinfo->precision = 8;
2849484Sgarrett.damore@Sun.COM prinfo->gain = AUDIO_MAX_GAIN;
2859484Sgarrett.damore@Sun.COM prinfo->balance = AUDIO_MID_BALANCE;
2869484Sgarrett.damore@Sun.COM prinfo->buffer_size = 8192;
2879484Sgarrett.damore@Sun.COM prinfo->waiting = B_FALSE;
2889484Sgarrett.damore@Sun.COM prinfo->open = B_FALSE;
2899484Sgarrett.damore@Sun.COM prinfo->active = B_FALSE;
2909484Sgarrett.damore@Sun.COM prinfo->samples = 0;
2919484Sgarrett.damore@Sun.COM prinfo->eof = 0;
2929484Sgarrett.damore@Sun.COM prinfo->error = 0;
2939484Sgarrett.damore@Sun.COM prinfo->minordev = 0;
2949484Sgarrett.damore@Sun.COM prinfo->port = AUDIO_MICROPHONE;
2959484Sgarrett.damore@Sun.COM prinfo->avail_ports = AUDIO_MICROPHONE;
2969484Sgarrett.damore@Sun.COM prinfo->mod_ports = AUDIO_MICROPHONE;
2979484Sgarrett.damore@Sun.COM
2989484Sgarrett.damore@Sun.COM info->output_muted = B_FALSE;
2999484Sgarrett.damore@Sun.COM /* pretend we don't have a software mixer - we don't support the API */
3009484Sgarrett.damore@Sun.COM info->hw_features = 0;
3019484Sgarrett.damore@Sun.COM info->sw_features = 0;
3029484Sgarrett.damore@Sun.COM info->sw_features_enabled = 0;
3039484Sgarrett.damore@Sun.COM
3049484Sgarrett.damore@Sun.COM caps = auclnt_get_dev_capab(auclnt_get_dev(c));
3059484Sgarrett.damore@Sun.COM if (caps & AUDIO_CLIENT_CAP_PLAY)
3069484Sgarrett.damore@Sun.COM info->hw_features |= AUDIO_HWFEATURE_PLAY;
3079484Sgarrett.damore@Sun.COM if (caps & AUDIO_CLIENT_CAP_RECORD)
3089484Sgarrett.damore@Sun.COM info->hw_features |= AUDIO_HWFEATURE_RECORD;
3099484Sgarrett.damore@Sun.COM if (caps & AUDIO_CLIENT_CAP_DUPLEX)
3109484Sgarrett.damore@Sun.COM info->hw_features |= AUDIO_HWFEATURE_DUPLEX;
3119484Sgarrett.damore@Sun.COM
3129484Sgarrett.damore@Sun.COM return (proc);
3139484Sgarrett.damore@Sun.COM }
3149484Sgarrett.damore@Sun.COM
3159484Sgarrett.damore@Sun.COM static void
devaudio_proc_free(daproc_t * proc)31610157Sgdamore@opensolaris.org devaudio_proc_free(daproc_t *proc)
3179484Sgarrett.damore@Sun.COM {
3189484Sgarrett.damore@Sun.COM kmem_free(proc, sizeof (*proc));
3199484Sgarrett.damore@Sun.COM }
3209484Sgarrett.damore@Sun.COM
3219484Sgarrett.damore@Sun.COM int
devaudio_proc_hold(audio_client_t * c,int oflag)32210157Sgdamore@opensolaris.org devaudio_proc_hold(audio_client_t *c, int oflag)
3239484Sgarrett.damore@Sun.COM {
3249484Sgarrett.damore@Sun.COM pid_t pid;
32510157Sgdamore@opensolaris.org daproc_t *proc;
32610157Sgdamore@opensolaris.org dadev_t *dev;
32710157Sgdamore@opensolaris.org daclient_t *dc;
3289484Sgarrett.damore@Sun.COM list_t *l;
3299484Sgarrett.damore@Sun.COM audio_dev_t *adev;
3309484Sgarrett.damore@Sun.COM int rv;
3319484Sgarrett.damore@Sun.COM
3329484Sgarrett.damore@Sun.COM adev = auclnt_get_dev(c);
3339484Sgarrett.damore@Sun.COM
33410157Sgdamore@opensolaris.org /* first allocate and initialize the daclient private data */
33510157Sgdamore@opensolaris.org if ((dc = kmem_zalloc(sizeof (*dc), KM_NOSLEEP)) == NULL) {
3369484Sgarrett.damore@Sun.COM return (ENOMEM);
3379484Sgarrett.damore@Sun.COM }
3389484Sgarrett.damore@Sun.COM
33910157Sgdamore@opensolaris.org mutex_init(&dc->dc_lock, NULL, MUTEX_DRIVER, NULL);
34010157Sgdamore@opensolaris.org list_create(&dc->dc_eofcnt, sizeof (struct eofcnt),
3419484Sgarrett.damore@Sun.COM offsetof(struct eofcnt, linkage));
34210157Sgdamore@opensolaris.org auclnt_set_private(c, dc);
3439484Sgarrett.damore@Sun.COM
34410157Sgdamore@opensolaris.org dev = auclnt_get_dev_minor_data(adev, AUDIO_MINOR_DEVAUDIO);
34510157Sgdamore@opensolaris.org l = &dev->d_procs;
3469484Sgarrett.damore@Sun.COM pid = auclnt_get_pid(c);
3479484Sgarrett.damore@Sun.COM
3489484Sgarrett.damore@Sun.COM /* set a couple of common fields */
34910157Sgdamore@opensolaris.org dc->dc_client = c;
35010157Sgdamore@opensolaris.org dc->dc_dev = dev;
3519484Sgarrett.damore@Sun.COM
35210157Sgdamore@opensolaris.org mutex_enter(&dev->d_mx);
3539484Sgarrett.damore@Sun.COM for (proc = list_head(l); proc != NULL; proc = list_next(l, proc)) {
3549484Sgarrett.damore@Sun.COM if (proc->p_id == pid) {
3559484Sgarrett.damore@Sun.COM proc->p_refcnt++;
3569484Sgarrett.damore@Sun.COM break;
3579484Sgarrett.damore@Sun.COM }
3589484Sgarrett.damore@Sun.COM }
3599484Sgarrett.damore@Sun.COM if (proc == NULL) {
36010157Sgdamore@opensolaris.org if ((proc = devaudio_proc_alloc(c)) == NULL) {
3619484Sgarrett.damore@Sun.COM rv = ENOMEM;
3629484Sgarrett.damore@Sun.COM goto failed;
3639484Sgarrett.damore@Sun.COM }
3649484Sgarrett.damore@Sun.COM proc->p_refcnt = 1;
3659484Sgarrett.damore@Sun.COM proc->p_id = pid;
36610157Sgdamore@opensolaris.org proc->p_dev = dev;
3679484Sgarrett.damore@Sun.COM list_insert_tail(l, proc);
3689484Sgarrett.damore@Sun.COM }
3699484Sgarrett.damore@Sun.COM
3709484Sgarrett.damore@Sun.COM while (proc->p_oflag & oflag) {
3719484Sgarrett.damore@Sun.COM
3729484Sgarrett.damore@Sun.COM if (oflag & (FNDELAY|FNONBLOCK)) {
3739484Sgarrett.damore@Sun.COM rv = EBUSY;
3749484Sgarrett.damore@Sun.COM goto failed;
3759484Sgarrett.damore@Sun.COM }
3769484Sgarrett.damore@Sun.COM if (oflag & FWRITE)
3779484Sgarrett.damore@Sun.COM proc->p_info.play.waiting++;
3789484Sgarrett.damore@Sun.COM if (oflag & FREAD)
3799484Sgarrett.damore@Sun.COM proc->p_info.record.waiting++;
38010157Sgdamore@opensolaris.org if (cv_wait_sig(&dev->d_cv, &dev->d_mx) == 0) {
3819484Sgarrett.damore@Sun.COM /* interrupted! */
3829484Sgarrett.damore@Sun.COM if (oflag & FWRITE)
3839484Sgarrett.damore@Sun.COM proc->p_info.play.waiting--;
3849484Sgarrett.damore@Sun.COM if (oflag & FREAD)
3859484Sgarrett.damore@Sun.COM proc->p_info.record.waiting--;
3869484Sgarrett.damore@Sun.COM rv = EINTR;
3879484Sgarrett.damore@Sun.COM goto failed;
3889484Sgarrett.damore@Sun.COM }
3899484Sgarrett.damore@Sun.COM if (oflag & FWRITE)
3909484Sgarrett.damore@Sun.COM proc->p_info.play.waiting--;
3919484Sgarrett.damore@Sun.COM if (oflag & FREAD)
3929484Sgarrett.damore@Sun.COM proc->p_info.record.waiting--;
3939484Sgarrett.damore@Sun.COM }
3949484Sgarrett.damore@Sun.COM
3959484Sgarrett.damore@Sun.COM if (oflag & FWRITE) {
3969484Sgarrett.damore@Sun.COM audio_prinfo_t *play = &proc->p_info.play;
3979484Sgarrett.damore@Sun.COM audio_stream_t *sp = auclnt_output_stream(c);
3989484Sgarrett.damore@Sun.COM
3999484Sgarrett.damore@Sun.COM if (((rv = auclnt_set_rate(sp, 8000)) != 0) ||
4009484Sgarrett.damore@Sun.COM ((rv = auclnt_set_format(sp, AUDIO_FORMAT_ULAW)) != 0) ||
4019484Sgarrett.damore@Sun.COM ((rv = auclnt_set_channels(sp, 1)) != 0)) {
4029484Sgarrett.damore@Sun.COM goto failed;
4039484Sgarrett.damore@Sun.COM }
4049484Sgarrett.damore@Sun.COM
4059484Sgarrett.damore@Sun.COM auclnt_set_samples(sp, 0);
4069484Sgarrett.damore@Sun.COM auclnt_set_errors(sp, 0);
4079484Sgarrett.damore@Sun.COM play->eof = 0;
4089484Sgarrett.damore@Sun.COM play->buffer_size = 8192;
4099484Sgarrett.damore@Sun.COM
4109484Sgarrett.damore@Sun.COM auclnt_set_gain(sp, ((play->gain * 100) / AUDIO_MAX_GAIN));
4119484Sgarrett.damore@Sun.COM auclnt_set_muted(sp, proc->p_info.output_muted);
4129484Sgarrett.damore@Sun.COM play->open = B_TRUE;
41310157Sgdamore@opensolaris.org proc->p_writer = c;
4149484Sgarrett.damore@Sun.COM proc->p_oflag |= FWRITE;
4159484Sgarrett.damore@Sun.COM }
4169484Sgarrett.damore@Sun.COM
4179484Sgarrett.damore@Sun.COM if (oflag & FREAD) {
4189484Sgarrett.damore@Sun.COM audio_prinfo_t *rec = &proc->p_info.record;
4199484Sgarrett.damore@Sun.COM audio_stream_t *sp = auclnt_input_stream(c);
4209484Sgarrett.damore@Sun.COM
4219484Sgarrett.damore@Sun.COM if (((rv = auclnt_set_rate(sp, 8000)) != 0) ||
4229484Sgarrett.damore@Sun.COM ((rv = auclnt_set_format(sp, AUDIO_FORMAT_ULAW)) != 0) ||
4239484Sgarrett.damore@Sun.COM ((rv = auclnt_set_channels(sp, 1)) != 0)) {
4249484Sgarrett.damore@Sun.COM goto failed;
4259484Sgarrett.damore@Sun.COM }
4269484Sgarrett.damore@Sun.COM
4279484Sgarrett.damore@Sun.COM auclnt_set_samples(sp, 0);
4289484Sgarrett.damore@Sun.COM auclnt_set_errors(sp, 0);
4299484Sgarrett.damore@Sun.COM rec->eof = 0;
4309484Sgarrett.damore@Sun.COM rec->buffer_size = 8192;
4319484Sgarrett.damore@Sun.COM
4329484Sgarrett.damore@Sun.COM auclnt_set_gain(sp, ((rec->gain * 100) / AUDIO_MAX_GAIN));
4339484Sgarrett.damore@Sun.COM rec->open = B_TRUE;
43410157Sgdamore@opensolaris.org proc->p_reader = c;
4359484Sgarrett.damore@Sun.COM proc->p_oflag |= FREAD;
4369484Sgarrett.damore@Sun.COM }
4379484Sgarrett.damore@Sun.COM
43810157Sgdamore@opensolaris.org
43910157Sgdamore@opensolaris.org dc->dc_wq = auclnt_get_wq(c);
44010157Sgdamore@opensolaris.org
44110016Sgdamore@opensolaris.org /* we update the s_proc last to avoid a race */
44210157Sgdamore@opensolaris.org dc->dc_proc = proc;
44310016Sgdamore@opensolaris.org
44410157Sgdamore@opensolaris.org devaudio_proc_update(proc);
4459484Sgarrett.damore@Sun.COM
44610157Sgdamore@opensolaris.org mutex_exit(&dev->d_mx);
4479484Sgarrett.damore@Sun.COM
4489484Sgarrett.damore@Sun.COM return (0);
4499484Sgarrett.damore@Sun.COM
4509484Sgarrett.damore@Sun.COM failed:
45110157Sgdamore@opensolaris.org mutex_exit(&dev->d_mx);
45210157Sgdamore@opensolaris.org devaudio_proc_release(c);
4539484Sgarrett.damore@Sun.COM return (rv);
4549484Sgarrett.damore@Sun.COM
4559484Sgarrett.damore@Sun.COM }
4569484Sgarrett.damore@Sun.COM
4579484Sgarrett.damore@Sun.COM static void
devaudio_clear_eof(audio_client_t * c)45810157Sgdamore@opensolaris.org devaudio_clear_eof(audio_client_t *c)
4599484Sgarrett.damore@Sun.COM {
46010157Sgdamore@opensolaris.org struct eofcnt *eof;
46110157Sgdamore@opensolaris.org daclient_t *dc;
46210157Sgdamore@opensolaris.org
46310157Sgdamore@opensolaris.org dc = auclnt_get_private(c);
46410157Sgdamore@opensolaris.org mutex_enter(&dc->dc_lock);
46510157Sgdamore@opensolaris.org while ((eof = list_remove_head(&dc->dc_eofcnt)) != NULL) {
4669484Sgarrett.damore@Sun.COM kmem_free(eof, sizeof (*eof));
4679484Sgarrett.damore@Sun.COM }
46810157Sgdamore@opensolaris.org mutex_exit(&dc->dc_lock);
4699484Sgarrett.damore@Sun.COM }
4709484Sgarrett.damore@Sun.COM
4719484Sgarrett.damore@Sun.COM void
devaudio_proc_release(audio_client_t * c)47210157Sgdamore@opensolaris.org devaudio_proc_release(audio_client_t *c)
4739484Sgarrett.damore@Sun.COM {
47410157Sgdamore@opensolaris.org daproc_t *proc;
47510157Sgdamore@opensolaris.org dadev_t *dev;
4769484Sgarrett.damore@Sun.COM mblk_t *mp;
47710157Sgdamore@opensolaris.org daclient_t *dc;
4789484Sgarrett.damore@Sun.COM
47910157Sgdamore@opensolaris.org dc = auclnt_get_private(c);
48010157Sgdamore@opensolaris.org proc = dc->dc_proc;
48110157Sgdamore@opensolaris.org dev = dc->dc_dev;
48210157Sgdamore@opensolaris.org dc->dc_proc = NULL;
4839484Sgarrett.damore@Sun.COM
48410157Sgdamore@opensolaris.org mutex_enter(&dev->d_mx);
4859484Sgarrett.damore@Sun.COM
4869484Sgarrett.damore@Sun.COM if (proc != NULL) {
4879484Sgarrett.damore@Sun.COM proc->p_refcnt--;
4889484Sgarrett.damore@Sun.COM ASSERT(proc->p_refcnt >= 0);
4899484Sgarrett.damore@Sun.COM
49010157Sgdamore@opensolaris.org if (c == proc->p_writer) {
4919484Sgarrett.damore@Sun.COM proc->p_oflag &= ~FWRITE;
4929484Sgarrett.damore@Sun.COM proc->p_writer = NULL;
4939484Sgarrett.damore@Sun.COM }
49410157Sgdamore@opensolaris.org if (c == proc->p_reader) {
4959484Sgarrett.damore@Sun.COM proc->p_oflag &= ~FREAD;
4969484Sgarrett.damore@Sun.COM proc->p_reader = NULL;
4979484Sgarrett.damore@Sun.COM }
49810157Sgdamore@opensolaris.org cv_broadcast(&dev->d_cv);
4999484Sgarrett.damore@Sun.COM
5009484Sgarrett.damore@Sun.COM if (proc->p_refcnt == 0) {
50110157Sgdamore@opensolaris.org list_remove(&dev->d_procs, proc);
50210157Sgdamore@opensolaris.org devaudio_proc_free(proc);
5039484Sgarrett.damore@Sun.COM }
50410157Sgdamore@opensolaris.org dc->dc_proc = NULL;
5059484Sgarrett.damore@Sun.COM }
5069484Sgarrett.damore@Sun.COM
50710157Sgdamore@opensolaris.org mutex_exit(&dev->d_mx);
5089484Sgarrett.damore@Sun.COM
50910157Sgdamore@opensolaris.org devaudio_clear_eof(c);
5109484Sgarrett.damore@Sun.COM
51110157Sgdamore@opensolaris.org while ((mp = dc->dc_draining) != NULL) {
51210157Sgdamore@opensolaris.org dc->dc_draining = mp->b_next;
5139484Sgarrett.damore@Sun.COM mp->b_next = NULL;
5149484Sgarrett.damore@Sun.COM freemsg(mp);
5159484Sgarrett.damore@Sun.COM }
5169484Sgarrett.damore@Sun.COM
51710157Sgdamore@opensolaris.org mutex_destroy(&dc->dc_lock);
51810157Sgdamore@opensolaris.org list_destroy(&dc->dc_eofcnt);
51910157Sgdamore@opensolaris.org kmem_free(dc, sizeof (*dc));
5209484Sgarrett.damore@Sun.COM }
5219484Sgarrett.damore@Sun.COM
5229484Sgarrett.damore@Sun.COM static void
devaudio_input(audio_client_t * c)52310157Sgdamore@opensolaris.org devaudio_input(audio_client_t *c)
5249484Sgarrett.damore@Sun.COM {
5259484Sgarrett.damore@Sun.COM audio_stream_t *sp = auclnt_input_stream(c);
52610157Sgdamore@opensolaris.org daclient_t *dc = auclnt_get_private(c);
5279484Sgarrett.damore@Sun.COM unsigned framesz = auclnt_get_framesz(sp);
52810157Sgdamore@opensolaris.org queue_t *rq = auclnt_get_rq(c);
5299484Sgarrett.damore@Sun.COM mblk_t *mp;
53010157Sgdamore@opensolaris.org unsigned nbytes = dc->dc_proc->p_info.record.buffer_size;
5319484Sgarrett.damore@Sun.COM unsigned count = nbytes / framesz;
5329484Sgarrett.damore@Sun.COM
5339484Sgarrett.damore@Sun.COM /*
5349484Sgarrett.damore@Sun.COM * Potentially send a message upstream with the record data.
5359484Sgarrett.damore@Sun.COM * We collect this up in chunks of the buffer size requested
5369484Sgarrett.damore@Sun.COM * by the client.
5379484Sgarrett.damore@Sun.COM */
5389484Sgarrett.damore@Sun.COM
5399484Sgarrett.damore@Sun.COM while (auclnt_get_count(sp) >= count) {
5409484Sgarrett.damore@Sun.COM
54110632Sgdamore@opensolaris.org if ((!canput(rq)) ||
5429484Sgarrett.damore@Sun.COM ((mp = allocb(nbytes, BPRI_MED)) == NULL)) {
5439484Sgarrett.damore@Sun.COM /*
5449484Sgarrett.damore@Sun.COM * This will apply back pressure to the
5459484Sgarrett.damore@Sun.COM * buffer. We haven't yet lost any data, we
5469484Sgarrett.damore@Sun.COM * just can't send it up. The point at which
5479484Sgarrett.damore@Sun.COM * we have an unrecoverable overrun is in the
5489484Sgarrett.damore@Sun.COM * buffer, not in the streams queue. So, no
5499484Sgarrett.damore@Sun.COM * need to do anything right now.
5509484Sgarrett.damore@Sun.COM *
5519484Sgarrett.damore@Sun.COM * Note that since recording is enabled, we
5529484Sgarrett.damore@Sun.COM * expect that the callback routine will be
5539484Sgarrett.damore@Sun.COM * called repeatedly & regularly, so we don't
5549484Sgarrett.damore@Sun.COM * have to worry about leaving data orphaned
5559484Sgarrett.damore@Sun.COM * in the queue.
5569484Sgarrett.damore@Sun.COM */
5579484Sgarrett.damore@Sun.COM break;
5589484Sgarrett.damore@Sun.COM }
5599484Sgarrett.damore@Sun.COM
5609484Sgarrett.damore@Sun.COM (void) auclnt_consume_data(sp, (caddr_t)mp->b_wptr, count);
5619484Sgarrett.damore@Sun.COM mp->b_wptr += nbytes;
56210632Sgdamore@opensolaris.org (void) putq(rq, mp);
5639484Sgarrett.damore@Sun.COM }
5649484Sgarrett.damore@Sun.COM }
5659484Sgarrett.damore@Sun.COM
5669484Sgarrett.damore@Sun.COM static void
devaudio_proc_update(daproc_t * proc)56710157Sgdamore@opensolaris.org devaudio_proc_update(daproc_t *proc)
5689484Sgarrett.damore@Sun.COM {
5699484Sgarrett.damore@Sun.COM audio_info_t *info;
5709484Sgarrett.damore@Sun.COM audio_stream_t *sp;
57110157Sgdamore@opensolaris.org audio_client_t *c;
5729484Sgarrett.damore@Sun.COM
5739484Sgarrett.damore@Sun.COM info = &proc->p_info;
5749484Sgarrett.damore@Sun.COM
57510157Sgdamore@opensolaris.org ASSERT(mutex_owned(&proc->p_dev->d_mx));
5769484Sgarrett.damore@Sun.COM
57710157Sgdamore@opensolaris.org if ((c = proc->p_writer) != NULL) {
57810157Sgdamore@opensolaris.org sp = auclnt_output_stream(c);
5799484Sgarrett.damore@Sun.COM
5809484Sgarrett.damore@Sun.COM info->play.sample_rate = auclnt_get_rate(sp);
5819484Sgarrett.damore@Sun.COM info->play.channels = auclnt_get_channels(sp);
58210157Sgdamore@opensolaris.org devaudio_decompose_format(&info->play, auclnt_get_format(sp));
5839484Sgarrett.damore@Sun.COM
5849484Sgarrett.damore@Sun.COM info->play.gain =
5859484Sgarrett.damore@Sun.COM (auclnt_get_gain(sp) * AUDIO_MAX_GAIN) / 100;
5869484Sgarrett.damore@Sun.COM info->play.pause = auclnt_is_paused(sp);
58710172Sgdamore@opensolaris.org info->play.active = auclnt_is_running(sp);
5889484Sgarrett.damore@Sun.COM info->play.samples = auclnt_get_samples(sp);
5899484Sgarrett.damore@Sun.COM info->play.error = auclnt_get_errors(sp) ? B_TRUE : B_FALSE;
5909484Sgarrett.damore@Sun.COM info->output_muted = auclnt_get_muted(sp);
59110172Sgdamore@opensolaris.org } else {
59210172Sgdamore@opensolaris.org info->play.encoding = AUDIO_ENCODING_NONE;
59310172Sgdamore@opensolaris.org info->play.precision = 0;
59410172Sgdamore@opensolaris.org info->play.sample_rate = 0;
59510172Sgdamore@opensolaris.org info->play.pause = B_FALSE;
59610172Sgdamore@opensolaris.org info->play.active = B_FALSE;
59710172Sgdamore@opensolaris.org info->play.error = B_FALSE;
59810172Sgdamore@opensolaris.org info->play.samples = 0;
5999484Sgarrett.damore@Sun.COM }
6009484Sgarrett.damore@Sun.COM
60110157Sgdamore@opensolaris.org if ((c = proc->p_reader) != NULL) {
60210157Sgdamore@opensolaris.org sp = auclnt_input_stream(c);
6039484Sgarrett.damore@Sun.COM
6049484Sgarrett.damore@Sun.COM info->record.sample_rate = auclnt_get_rate(sp);
6059484Sgarrett.damore@Sun.COM info->record.channels = auclnt_get_channels(sp);
60610157Sgdamore@opensolaris.org devaudio_decompose_format(&info->record, auclnt_get_format(sp));
6079484Sgarrett.damore@Sun.COM
6089484Sgarrett.damore@Sun.COM info->record.gain =
6099484Sgarrett.damore@Sun.COM (auclnt_get_gain(sp) * AUDIO_MAX_GAIN) / 100;
6109484Sgarrett.damore@Sun.COM info->record.pause = auclnt_is_paused(sp);
61110172Sgdamore@opensolaris.org info->record.active = auclnt_is_running(sp);
6129484Sgarrett.damore@Sun.COM info->record.samples = auclnt_get_samples(sp);
6139484Sgarrett.damore@Sun.COM info->record.error = auclnt_get_errors(sp) ? B_TRUE : B_FALSE;
61410172Sgdamore@opensolaris.org } else {
61510172Sgdamore@opensolaris.org info->record.encoding = AUDIO_ENCODING_NONE;
61610172Sgdamore@opensolaris.org info->record.precision = 0;
61710172Sgdamore@opensolaris.org info->record.sample_rate = 0;
61810172Sgdamore@opensolaris.org info->record.pause = B_FALSE;
61910172Sgdamore@opensolaris.org info->record.active = B_FALSE;
62010172Sgdamore@opensolaris.org info->record.error = B_FALSE;
62110172Sgdamore@opensolaris.org info->record.samples = 0;
6229484Sgarrett.damore@Sun.COM }
6239484Sgarrett.damore@Sun.COM }
6249484Sgarrett.damore@Sun.COM
6259484Sgarrett.damore@Sun.COM static void
devaudio_ioc_getinfo(queue_t * wq,audio_client_t * c,mblk_t * mp)62610157Sgdamore@opensolaris.org devaudio_ioc_getinfo(queue_t *wq, audio_client_t *c, mblk_t *mp)
6279484Sgarrett.damore@Sun.COM {
62810157Sgdamore@opensolaris.org daclient_t *dc = auclnt_get_private(c);
62910157Sgdamore@opensolaris.org daproc_t *proc = dc->dc_proc;
63010157Sgdamore@opensolaris.org mblk_t *bcont;
6319484Sgarrett.damore@Sun.COM
63210157Sgdamore@opensolaris.org if ((bcont = allocb(sizeof (audio_info_t), BPRI_MED)) == NULL) {
63310157Sgdamore@opensolaris.org miocnak(wq, mp, 0, ENOMEM);
63410157Sgdamore@opensolaris.org return;
6359484Sgarrett.damore@Sun.COM }
6369484Sgarrett.damore@Sun.COM
63710157Sgdamore@opensolaris.org mutex_enter(&dc->dc_dev->d_mx);
63810157Sgdamore@opensolaris.org devaudio_proc_update(proc);
63910157Sgdamore@opensolaris.org bcopy(&proc->p_info, bcont->b_wptr, sizeof (audio_info_t));
64010157Sgdamore@opensolaris.org mutex_exit(&dc->dc_dev->d_mx);
64110157Sgdamore@opensolaris.org
64210157Sgdamore@opensolaris.org bcont->b_wptr += sizeof (audio_info_t);
64310157Sgdamore@opensolaris.org
64410157Sgdamore@opensolaris.org mcopyout(mp, NULL, sizeof (audio_info_t), NULL, bcont);
64510157Sgdamore@opensolaris.org qreply(wq, mp);
6469484Sgarrett.damore@Sun.COM }
6479484Sgarrett.damore@Sun.COM
6489484Sgarrett.damore@Sun.COM #define CHANGED(new, old, field) \
6499484Sgarrett.damore@Sun.COM ((new->field != ((uint32_t)~0)) && (new->field != old->field))
6509484Sgarrett.damore@Sun.COM #define CHANGED8(new, old, field) \
6519484Sgarrett.damore@Sun.COM ((new->field != ((uint8_t)~0)) && (new->field != old->field))
6529484Sgarrett.damore@Sun.COM
65310157Sgdamore@opensolaris.org static void
devaudio_ioc_setinfo(queue_t * wq,audio_client_t * c,mblk_t * mp)65410157Sgdamore@opensolaris.org devaudio_ioc_setinfo(queue_t *wq, audio_client_t *c, mblk_t *mp)
6559484Sgarrett.damore@Sun.COM {
65610157Sgdamore@opensolaris.org daclient_t *dc;
65710157Sgdamore@opensolaris.org daproc_t *proc;
65810157Sgdamore@opensolaris.org audio_info_t *oinfo;
65910157Sgdamore@opensolaris.org audio_info_t *ninfo;
6609484Sgarrett.damore@Sun.COM audio_prinfo_t *npr;
6619484Sgarrett.damore@Sun.COM audio_prinfo_t *opr;
6629484Sgarrett.damore@Sun.COM
6639484Sgarrett.damore@Sun.COM int pfmt = AUDIO_FORMAT_NONE;
6649484Sgarrett.damore@Sun.COM int rfmt = AUDIO_FORMAT_NONE;
6659484Sgarrett.damore@Sun.COM
6669484Sgarrett.damore@Sun.COM boolean_t reader;
6679484Sgarrett.damore@Sun.COM boolean_t writer;
6689484Sgarrett.damore@Sun.COM boolean_t isctl;
6699484Sgarrett.damore@Sun.COM audio_stream_t *sp;
6709484Sgarrett.damore@Sun.COM int rv;
67110157Sgdamore@opensolaris.org caddr_t uaddr;
67210157Sgdamore@opensolaris.org mblk_t *bcont;
6739484Sgarrett.damore@Sun.COM
67410157Sgdamore@opensolaris.org struct copyresp *csp;
67510157Sgdamore@opensolaris.org
67610157Sgdamore@opensolaris.org if (DB_TYPE(mp) == M_IOCTL) {
67710157Sgdamore@opensolaris.org /* the special value "1" indicates that this is a copyin */
67810157Sgdamore@opensolaris.org uaddr = *(caddr_t *)(void *)mp->b_cont->b_rptr;
67910157Sgdamore@opensolaris.org
68010157Sgdamore@opensolaris.org mcopyin(mp, uaddr, sizeof (audio_info_t), NULL);
68110157Sgdamore@opensolaris.org qreply(wq, mp);
68210157Sgdamore@opensolaris.org return;
68310157Sgdamore@opensolaris.org }
68410157Sgdamore@opensolaris.org
68510157Sgdamore@opensolaris.org ASSERT(DB_TYPE(mp) == M_IOCDATA);
68610157Sgdamore@opensolaris.org if (((bcont = mp->b_cont) == NULL) ||
68710157Sgdamore@opensolaris.org (MBLKL(mp->b_cont) != sizeof (audio_info_t))) {
68810157Sgdamore@opensolaris.org miocnak(wq, mp, 0, EINVAL);
68910157Sgdamore@opensolaris.org return;
69010157Sgdamore@opensolaris.org }
69110157Sgdamore@opensolaris.org
69210157Sgdamore@opensolaris.org mp->b_cont = NULL;
69310157Sgdamore@opensolaris.org csp = (void *)mp->b_rptr;
69410157Sgdamore@opensolaris.org uaddr = (void *)csp->cp_private;
69510157Sgdamore@opensolaris.org dc = auclnt_get_private(c);
69610157Sgdamore@opensolaris.org ninfo = (void *)bcont->b_rptr;
69710157Sgdamore@opensolaris.org
69810157Sgdamore@opensolaris.org mutex_enter(&dc->dc_dev->d_mx);
69910157Sgdamore@opensolaris.org
70010157Sgdamore@opensolaris.org proc = dc->dc_proc;
70110157Sgdamore@opensolaris.org oinfo = &proc->p_info;
70210157Sgdamore@opensolaris.org
70310157Sgdamore@opensolaris.org if (auclnt_get_minor_type(c) == AUDIO_MINOR_DEVAUDIOCTL) {
7049484Sgarrett.damore@Sun.COM /* control node can do both read and write fields */
7059484Sgarrett.damore@Sun.COM isctl = B_TRUE;
7069484Sgarrett.damore@Sun.COM reader = B_TRUE;
7079484Sgarrett.damore@Sun.COM writer = B_TRUE;
7089484Sgarrett.damore@Sun.COM } else {
7099484Sgarrett.damore@Sun.COM isctl = B_FALSE;
71010157Sgdamore@opensolaris.org writer = (c == proc->p_writer);
71110157Sgdamore@opensolaris.org reader = (c == proc->p_reader);
7129484Sgarrett.damore@Sun.COM }
7139484Sgarrett.damore@Sun.COM
7149484Sgarrett.damore@Sun.COM /*
7159484Sgarrett.damore@Sun.COM * Start by validating settings.
7169484Sgarrett.damore@Sun.COM */
7179484Sgarrett.damore@Sun.COM npr = &ninfo->play;
7189484Sgarrett.damore@Sun.COM opr = &oinfo->play;
7199484Sgarrett.damore@Sun.COM
7209484Sgarrett.damore@Sun.COM if (writer && CHANGED(npr, opr, sample_rate)) {
7219484Sgarrett.damore@Sun.COM if ((isctl) ||
7229484Sgarrett.damore@Sun.COM (npr->sample_rate < 5500) || (npr->sample_rate > 48000)) {
72310157Sgdamore@opensolaris.org rv = EINVAL;
72410157Sgdamore@opensolaris.org goto err;
7259484Sgarrett.damore@Sun.COM }
7269484Sgarrett.damore@Sun.COM }
7279484Sgarrett.damore@Sun.COM if (writer && CHANGED(npr, opr, channels)) {
7289484Sgarrett.damore@Sun.COM if ((isctl) || (npr->channels < 1) || (npr->channels > 2)) {
72910157Sgdamore@opensolaris.org rv = EINVAL;
73010157Sgdamore@opensolaris.org goto err;
7319484Sgarrett.damore@Sun.COM }
7329484Sgarrett.damore@Sun.COM }
7339484Sgarrett.damore@Sun.COM if (writer &&
7349484Sgarrett.damore@Sun.COM (CHANGED(npr, opr, encoding) || CHANGED(npr, opr, precision))) {
7359484Sgarrett.damore@Sun.COM if (npr->encoding == (uint32_t)~0)
7369484Sgarrett.damore@Sun.COM npr->encoding = opr->encoding;
7379484Sgarrett.damore@Sun.COM if (npr->precision == (uint32_t)~0)
7389484Sgarrett.damore@Sun.COM npr->precision = opr->precision;
73910157Sgdamore@opensolaris.org pfmt = devaudio_compose_format(npr);
7409484Sgarrett.damore@Sun.COM if ((isctl) || (pfmt == AUDIO_FORMAT_NONE)) {
74110157Sgdamore@opensolaris.org rv = EINVAL;
74210157Sgdamore@opensolaris.org goto err;
7439484Sgarrett.damore@Sun.COM }
7449484Sgarrett.damore@Sun.COM }
7459484Sgarrett.damore@Sun.COM
7469484Sgarrett.damore@Sun.COM /* play fields that anyone can modify */
7479484Sgarrett.damore@Sun.COM if (CHANGED(npr, opr, gain)) {
7489484Sgarrett.damore@Sun.COM if (npr->gain > AUDIO_MAX_GAIN) {
74910157Sgdamore@opensolaris.org rv = EINVAL;
75010157Sgdamore@opensolaris.org goto err;
7519484Sgarrett.damore@Sun.COM }
7529484Sgarrett.damore@Sun.COM }
7539484Sgarrett.damore@Sun.COM
7549484Sgarrett.damore@Sun.COM
7559484Sgarrett.damore@Sun.COM npr = &ninfo->record;
7569484Sgarrett.damore@Sun.COM opr = &oinfo->record;
7579484Sgarrett.damore@Sun.COM
7589484Sgarrett.damore@Sun.COM if (reader && CHANGED(npr, opr, sample_rate)) {
7599484Sgarrett.damore@Sun.COM if ((isctl) ||
76010157Sgdamore@opensolaris.org (npr->sample_rate < 5500) || (npr->sample_rate > 48000)) {
76110157Sgdamore@opensolaris.org rv = EINVAL;
76210157Sgdamore@opensolaris.org goto err;
7639484Sgarrett.damore@Sun.COM }
7649484Sgarrett.damore@Sun.COM }
7659484Sgarrett.damore@Sun.COM if (reader && CHANGED(npr, opr, channels)) {
7669484Sgarrett.damore@Sun.COM if ((isctl) || (npr->channels < 1) || (npr->channels > 2)) {
76710157Sgdamore@opensolaris.org rv = EINVAL;
76810157Sgdamore@opensolaris.org goto err;
7699484Sgarrett.damore@Sun.COM }
7709484Sgarrett.damore@Sun.COM }
7719484Sgarrett.damore@Sun.COM if (reader &&
7729484Sgarrett.damore@Sun.COM (CHANGED(npr, opr, encoding) || CHANGED(npr, opr, precision))) {
7739484Sgarrett.damore@Sun.COM if (npr->encoding == (uint32_t)~0)
7749484Sgarrett.damore@Sun.COM npr->encoding = opr->encoding;
7759484Sgarrett.damore@Sun.COM if (npr->precision == (uint32_t)~0)
7769484Sgarrett.damore@Sun.COM npr->precision = opr->precision;
77710157Sgdamore@opensolaris.org rfmt = devaudio_compose_format(npr);
7789484Sgarrett.damore@Sun.COM if ((isctl) || (rfmt == AUDIO_FORMAT_NONE)) {
77910157Sgdamore@opensolaris.org rv = EINVAL;
78010157Sgdamore@opensolaris.org goto err;
7819484Sgarrett.damore@Sun.COM }
7829484Sgarrett.damore@Sun.COM }
7839484Sgarrett.damore@Sun.COM if (reader && CHANGED(npr, opr, buffer_size)) {
7849484Sgarrett.damore@Sun.COM if (isctl) {
78510157Sgdamore@opensolaris.org rv = EINVAL;
78610157Sgdamore@opensolaris.org goto err;
7879484Sgarrett.damore@Sun.COM }
7889484Sgarrett.damore@Sun.COM /* make sure we can support 16-bit stereo samples */
7899484Sgarrett.damore@Sun.COM if ((npr->buffer_size % 4) != 0) {
7909484Sgarrett.damore@Sun.COM npr->buffer_size = (npr->buffer_size + 3) & ~3;
7919484Sgarrett.damore@Sun.COM }
7929484Sgarrett.damore@Sun.COM /* limit the maximum buffer size somewhat */
7939484Sgarrett.damore@Sun.COM if (npr->buffer_size > 16384) {
7949484Sgarrett.damore@Sun.COM npr->buffer_size = 16384;
7959484Sgarrett.damore@Sun.COM }
7969484Sgarrett.damore@Sun.COM }
7979484Sgarrett.damore@Sun.COM
7989484Sgarrett.damore@Sun.COM /* record fields that anyone can modify */
7999484Sgarrett.damore@Sun.COM if (CHANGED(npr, opr, gain)) {
8009484Sgarrett.damore@Sun.COM if (npr->gain > AUDIO_MAX_GAIN) {
80110157Sgdamore@opensolaris.org rv = EINVAL;
80210157Sgdamore@opensolaris.org goto err;
8039484Sgarrett.damore@Sun.COM }
8049484Sgarrett.damore@Sun.COM }
8059484Sgarrett.damore@Sun.COM
8069484Sgarrett.damore@Sun.COM /*
8079484Sgarrett.damore@Sun.COM * Now apply the changes.
8089484Sgarrett.damore@Sun.COM */
8099484Sgarrett.damore@Sun.COM if (proc->p_writer != NULL) {
81010157Sgdamore@opensolaris.org sp = auclnt_output_stream(proc->p_writer);
8119484Sgarrett.damore@Sun.COM npr = &ninfo->play;
8129484Sgarrett.damore@Sun.COM opr = &oinfo->play;
8139484Sgarrett.damore@Sun.COM
8149484Sgarrett.damore@Sun.COM if (CHANGED(npr, opr, sample_rate)) {
81510157Sgdamore@opensolaris.org if ((rv = auclnt_set_rate(sp, npr->sample_rate)) != 0)
81610157Sgdamore@opensolaris.org goto err;
8179484Sgarrett.damore@Sun.COM }
8189484Sgarrett.damore@Sun.COM if (CHANGED(npr, opr, channels)) {
81910157Sgdamore@opensolaris.org if ((rv = auclnt_set_channels(sp, npr->channels)) != 0)
82010157Sgdamore@opensolaris.org goto err;
8219484Sgarrett.damore@Sun.COM }
8229484Sgarrett.damore@Sun.COM if (pfmt != AUDIO_FORMAT_NONE) {
82310157Sgdamore@opensolaris.org if ((rv = auclnt_set_format(sp, pfmt)) != 0)
82410157Sgdamore@opensolaris.org goto err;
8259484Sgarrett.damore@Sun.COM }
8269484Sgarrett.damore@Sun.COM if (CHANGED(npr, opr, samples)) {
8279484Sgarrett.damore@Sun.COM auclnt_set_samples(sp, npr->samples);
8289484Sgarrett.damore@Sun.COM }
8299484Sgarrett.damore@Sun.COM if (CHANGED(npr, opr, eof)) {
8309484Sgarrett.damore@Sun.COM /*
8319484Sgarrett.damore@Sun.COM * This ugly special case code is required to
8329484Sgarrett.damore@Sun.COM * prevent problems with realaudio.
8339484Sgarrett.damore@Sun.COM */
8349484Sgarrett.damore@Sun.COM if (npr->eof == 0) {
83510157Sgdamore@opensolaris.org devaudio_clear_eof(proc->p_writer);
8369484Sgarrett.damore@Sun.COM }
8379484Sgarrett.damore@Sun.COM opr->eof = npr->eof;
8389484Sgarrett.damore@Sun.COM }
8399484Sgarrett.damore@Sun.COM if (CHANGED8(npr, opr, pause)) {
8409484Sgarrett.damore@Sun.COM if (npr->pause) {
8419484Sgarrett.damore@Sun.COM auclnt_set_paused(sp);
8429484Sgarrett.damore@Sun.COM } else {
8439484Sgarrett.damore@Sun.COM auclnt_clear_paused(sp);
84410157Sgdamore@opensolaris.org
8459484Sgarrett.damore@Sun.COM /* qenable to start up the playback */
84610157Sgdamore@opensolaris.org qenable(auclnt_get_wq(proc->p_writer));
8479484Sgarrett.damore@Sun.COM }
8489484Sgarrett.damore@Sun.COM }
8499484Sgarrett.damore@Sun.COM if (CHANGED8(npr, opr, waiting) && (npr->waiting)) {
8509484Sgarrett.damore@Sun.COM opr->waiting = npr->waiting;
8519484Sgarrett.damore@Sun.COM }
8529484Sgarrett.damore@Sun.COM if (CHANGED8(npr, opr, error)) {
8539484Sgarrett.damore@Sun.COM auclnt_set_errors(sp, npr->error);
8549484Sgarrett.damore@Sun.COM }
8559484Sgarrett.damore@Sun.COM if (CHANGED(npr, opr, gain)) {
8569484Sgarrett.damore@Sun.COM auclnt_set_gain(sp, (npr->gain * 100) / AUDIO_MAX_GAIN);
8579484Sgarrett.damore@Sun.COM }
8589484Sgarrett.damore@Sun.COM if (CHANGED8(ninfo, oinfo, output_muted)) {
8599484Sgarrett.damore@Sun.COM auclnt_set_muted(sp, ninfo->output_muted);
8609484Sgarrett.damore@Sun.COM }
8619484Sgarrett.damore@Sun.COM if (CHANGED(npr, opr, buffer_size)) {
8629484Sgarrett.damore@Sun.COM /*
8639484Sgarrett.damore@Sun.COM * No checks on the buffer size are performed
8649484Sgarrett.damore@Sun.COM * for play side. The value of the buffer size
8659484Sgarrett.damore@Sun.COM * is meaningless for play side anyway.
8669484Sgarrett.damore@Sun.COM */
8679484Sgarrett.damore@Sun.COM opr->buffer_size = npr->buffer_size;
8689484Sgarrett.damore@Sun.COM }
8699484Sgarrett.damore@Sun.COM } else {
87010172Sgdamore@opensolaris.org /* these values are preserved even if /dev/audio not open */
8719484Sgarrett.damore@Sun.COM if (CHANGED(npr, opr, gain)) {
8729484Sgarrett.damore@Sun.COM opr->gain = npr->gain;
8739484Sgarrett.damore@Sun.COM }
8749484Sgarrett.damore@Sun.COM if (CHANGED8(ninfo, oinfo, output_muted)) {
8759484Sgarrett.damore@Sun.COM oinfo->output_muted = ninfo->output_muted;
8769484Sgarrett.damore@Sun.COM }
8779484Sgarrett.damore@Sun.COM }
8789484Sgarrett.damore@Sun.COM
8799484Sgarrett.damore@Sun.COM if (proc->p_reader != NULL) {
88010157Sgdamore@opensolaris.org sp = auclnt_input_stream(proc->p_reader);
8819484Sgarrett.damore@Sun.COM npr = &ninfo->record;
8829484Sgarrett.damore@Sun.COM opr = &oinfo->record;
8839484Sgarrett.damore@Sun.COM
8849484Sgarrett.damore@Sun.COM if (CHANGED(npr, opr, sample_rate)) {
88510157Sgdamore@opensolaris.org if ((rv = auclnt_set_rate(sp, npr->sample_rate)) != 0)
88610157Sgdamore@opensolaris.org goto err;
8879484Sgarrett.damore@Sun.COM }
8889484Sgarrett.damore@Sun.COM if (CHANGED(npr, opr, channels)) {
88910157Sgdamore@opensolaris.org if ((rv = auclnt_set_channels(sp, npr->channels)) != 0)
89010157Sgdamore@opensolaris.org goto err;
8919484Sgarrett.damore@Sun.COM }
8929484Sgarrett.damore@Sun.COM if (rfmt != AUDIO_FORMAT_NONE) {
89310157Sgdamore@opensolaris.org if ((rv = auclnt_set_format(sp, rfmt)) != 0)
89410157Sgdamore@opensolaris.org goto err;
8959484Sgarrett.damore@Sun.COM }
8969484Sgarrett.damore@Sun.COM if (CHANGED(npr, opr, samples)) {
8979484Sgarrett.damore@Sun.COM auclnt_set_samples(sp, npr->samples);
8989484Sgarrett.damore@Sun.COM }
8999484Sgarrett.damore@Sun.COM if (CHANGED(npr, opr, eof)) {
9009484Sgarrett.damore@Sun.COM opr->eof = npr->eof;
9019484Sgarrett.damore@Sun.COM }
9029484Sgarrett.damore@Sun.COM if (CHANGED8(npr, opr, pause)) {
9039484Sgarrett.damore@Sun.COM if (npr->pause) {
9049484Sgarrett.damore@Sun.COM auclnt_set_paused(sp);
9059484Sgarrett.damore@Sun.COM } else {
9069484Sgarrett.damore@Sun.COM auclnt_clear_paused(sp);
9079484Sgarrett.damore@Sun.COM auclnt_start(sp);
9089484Sgarrett.damore@Sun.COM }
9099484Sgarrett.damore@Sun.COM }
9109484Sgarrett.damore@Sun.COM if (CHANGED8(npr, opr, waiting) && (npr->waiting)) {
9119484Sgarrett.damore@Sun.COM opr->waiting = npr->waiting;
9129484Sgarrett.damore@Sun.COM }
9139484Sgarrett.damore@Sun.COM if (CHANGED8(npr, opr, error)) {
9149484Sgarrett.damore@Sun.COM auclnt_set_errors(sp, npr->error);
9159484Sgarrett.damore@Sun.COM }
9169484Sgarrett.damore@Sun.COM if (CHANGED(npr, opr, buffer_size)) {
9179484Sgarrett.damore@Sun.COM opr->buffer_size = npr->buffer_size;
9189484Sgarrett.damore@Sun.COM }
9199484Sgarrett.damore@Sun.COM if (CHANGED(npr, opr, gain)) {
9209484Sgarrett.damore@Sun.COM auclnt_set_gain(sp, (npr->gain * 100) / AUDIO_MAX_GAIN);
9219484Sgarrett.damore@Sun.COM }
9229484Sgarrett.damore@Sun.COM } else {
9239484Sgarrett.damore@Sun.COM /* these values are preserved even if /dev/audio not open */
9249484Sgarrett.damore@Sun.COM if (CHANGED(npr, opr, gain)) {
9259484Sgarrett.damore@Sun.COM opr->gain = npr->gain;
9269484Sgarrett.damore@Sun.COM }
9279484Sgarrett.damore@Sun.COM }
9289484Sgarrett.damore@Sun.COM
92910157Sgdamore@opensolaris.org devaudio_proc_update(dc->dc_proc);
93010157Sgdamore@opensolaris.org bcopy(&dc->dc_proc->p_info, ninfo, sizeof (*ninfo));
93110172Sgdamore@opensolaris.org
93210157Sgdamore@opensolaris.org mutex_exit(&dc->dc_dev->d_mx);
93310157Sgdamore@opensolaris.org mcopyout(mp, NULL, sizeof (audio_info_t), uaddr, bcont);
93410157Sgdamore@opensolaris.org qreply(wq, mp);
93510157Sgdamore@opensolaris.org return;
93610157Sgdamore@opensolaris.org
93710157Sgdamore@opensolaris.org err:
93810157Sgdamore@opensolaris.org mutex_exit(&dc->dc_dev->d_mx);
93910157Sgdamore@opensolaris.org miocnak(wq, mp, 0, rv);
94010157Sgdamore@opensolaris.org }
94110157Sgdamore@opensolaris.org
94210157Sgdamore@opensolaris.org static void
devaudio_ioc_getdev(queue_t * wq,audio_client_t * c,mblk_t * mp)94310157Sgdamore@opensolaris.org devaudio_ioc_getdev(queue_t *wq, audio_client_t *c, mblk_t *mp)
94410157Sgdamore@opensolaris.org {
94510157Sgdamore@opensolaris.org audio_dev_t *d = auclnt_get_dev(c);
94610157Sgdamore@opensolaris.org mblk_t *bcont;
94710157Sgdamore@opensolaris.org audio_device_t *a;
94810157Sgdamore@opensolaris.org
94910157Sgdamore@opensolaris.org if ((bcont = allocb(sizeof (*a), BPRI_MED)) == NULL) {
95010157Sgdamore@opensolaris.org miocnak(wq, mp, 0, ENOMEM);
95110157Sgdamore@opensolaris.org return;
95210157Sgdamore@opensolaris.org }
95310157Sgdamore@opensolaris.org
95410157Sgdamore@opensolaris.org a = (void *)bcont->b_wptr;
95510157Sgdamore@opensolaris.org (void) snprintf(a->name, sizeof (a->name),
95610157Sgdamore@opensolaris.org "SUNW,%s", auclnt_get_dev_name(d));
95710157Sgdamore@opensolaris.org (void) strlcpy(a->config,
95810157Sgdamore@opensolaris.org auclnt_get_dev_description(d), sizeof (a->config));
95910157Sgdamore@opensolaris.org (void) strlcpy(a->version,
96010157Sgdamore@opensolaris.org auclnt_get_dev_version(d), sizeof (a->version));
96110157Sgdamore@opensolaris.org bcont->b_wptr += sizeof (*a);
96210157Sgdamore@opensolaris.org
96310157Sgdamore@opensolaris.org mcopyout(mp, NULL, sizeof (*a), NULL, bcont);
96410157Sgdamore@opensolaris.org qreply(wq, mp);
96510157Sgdamore@opensolaris.org }
96610157Sgdamore@opensolaris.org
96710157Sgdamore@opensolaris.org static int
devaudio_sigpoll(audio_client_t * c,void * arg)96810157Sgdamore@opensolaris.org devaudio_sigpoll(audio_client_t *c, void *arg)
96910157Sgdamore@opensolaris.org {
97010632Sgdamore@opensolaris.org pid_t pid = (pid_t)(uintptr_t)arg;
97110157Sgdamore@opensolaris.org
97210157Sgdamore@opensolaris.org if (auclnt_get_minor_type(c) == AUDIO_MINOR_DEVAUDIOCTL) {
97310157Sgdamore@opensolaris.org /* we only need to notify peers in our own process */
97410632Sgdamore@opensolaris.org if (auclnt_get_pid(c) == pid) {
97510632Sgdamore@opensolaris.org (void) putctl1(auclnt_get_rq(c), M_PCSIG, SIGPOLL);
97610157Sgdamore@opensolaris.org }
97710157Sgdamore@opensolaris.org }
97810157Sgdamore@opensolaris.org return (AUDIO_WALK_CONTINUE);
97910157Sgdamore@opensolaris.org }
98010157Sgdamore@opensolaris.org
98110157Sgdamore@opensolaris.org static void
devaudio_drain(audio_client_t * c)98210157Sgdamore@opensolaris.org devaudio_drain(audio_client_t *c)
98310157Sgdamore@opensolaris.org {
98410157Sgdamore@opensolaris.org daclient_t *dc = auclnt_get_private(c);
98510157Sgdamore@opensolaris.org mblk_t *mplist, *mp;
98610157Sgdamore@opensolaris.org
98710157Sgdamore@opensolaris.org mutex_enter(&dc->dc_lock);
98810157Sgdamore@opensolaris.org mplist = dc->dc_draining;
98910157Sgdamore@opensolaris.org dc->dc_draining = NULL;
99010157Sgdamore@opensolaris.org mutex_exit(&dc->dc_lock);
99110157Sgdamore@opensolaris.org
99210157Sgdamore@opensolaris.org while ((mp = mplist) != NULL) {
99310157Sgdamore@opensolaris.org mplist = mp->b_next;
99410157Sgdamore@opensolaris.org mp->b_next = NULL;
99510632Sgdamore@opensolaris.org mioc2ack(mp, NULL, 0, 0);
99610632Sgdamore@opensolaris.org (void) putq(auclnt_get_rq(c), mp);
99710157Sgdamore@opensolaris.org }
99810157Sgdamore@opensolaris.org }
99910157Sgdamore@opensolaris.org
100010157Sgdamore@opensolaris.org static void
devaudio_output(audio_client_t * c)100110157Sgdamore@opensolaris.org devaudio_output(audio_client_t *c)
100210157Sgdamore@opensolaris.org {
100310157Sgdamore@opensolaris.org daclient_t *dc = auclnt_get_private(c);
100410157Sgdamore@opensolaris.org daproc_t *proc = dc->dc_proc;
100510157Sgdamore@opensolaris.org uint64_t tail;
100610157Sgdamore@opensolaris.org struct eofcnt *eof;
100710157Sgdamore@opensolaris.org int eofs = 0;
100810157Sgdamore@opensolaris.org
100910157Sgdamore@opensolaris.org tail = auclnt_get_tail(auclnt_output_stream(c));
101010157Sgdamore@opensolaris.org
101110157Sgdamore@opensolaris.org /* get more data! (do this early) */
101210157Sgdamore@opensolaris.org qenable(auclnt_get_wq(c));
101310157Sgdamore@opensolaris.org
101410157Sgdamore@opensolaris.org mutex_enter(&dc->dc_lock);
101510157Sgdamore@opensolaris.org while (((eof = list_head(&dc->dc_eofcnt)) != NULL) &&
101610644SGarrett.Damore@Sun.COM (eof->tail <= tail)) {
101710157Sgdamore@opensolaris.org list_remove(&dc->dc_eofcnt, eof);
101810157Sgdamore@opensolaris.org kmem_free(eof, sizeof (*eof));
101910157Sgdamore@opensolaris.org eofs++;
102010157Sgdamore@opensolaris.org }
102110157Sgdamore@opensolaris.org proc->p_info.play.eof += eofs;
102210157Sgdamore@opensolaris.org mutex_exit(&dc->dc_lock);
102310157Sgdamore@opensolaris.org
102410157Sgdamore@opensolaris.org if (eofs) {
102510157Sgdamore@opensolaris.org auclnt_dev_walk_clients(auclnt_get_dev(c),
102610632Sgdamore@opensolaris.org devaudio_sigpoll, (void *)(uintptr_t)auclnt_get_pid(c));
102710157Sgdamore@opensolaris.org }
102810157Sgdamore@opensolaris.org }
102910157Sgdamore@opensolaris.org
103010157Sgdamore@opensolaris.org static void *
devaudio_init(audio_dev_t * adev)103110157Sgdamore@opensolaris.org devaudio_init(audio_dev_t *adev)
103210157Sgdamore@opensolaris.org {
103310157Sgdamore@opensolaris.org dadev_t *dev;
103410157Sgdamore@opensolaris.org unsigned cap;
103510157Sgdamore@opensolaris.org
103610157Sgdamore@opensolaris.org cap = auclnt_get_dev_capab(adev);
103710157Sgdamore@opensolaris.org /* if not a play or record device, don't bother initializing it */
103810157Sgdamore@opensolaris.org if ((cap & (AUDIO_CLIENT_CAP_PLAY | AUDIO_CLIENT_CAP_RECORD)) == 0) {
103910157Sgdamore@opensolaris.org return (NULL);
104010157Sgdamore@opensolaris.org }
104110157Sgdamore@opensolaris.org
104210157Sgdamore@opensolaris.org dev = kmem_zalloc(sizeof (*dev), KM_SLEEP);
104310157Sgdamore@opensolaris.org dev->d_dev = adev;
104410157Sgdamore@opensolaris.org mutex_init(&dev->d_mx, NULL, MUTEX_DRIVER, NULL);
104510157Sgdamore@opensolaris.org cv_init(&dev->d_cv, NULL, CV_DRIVER, NULL);
104610157Sgdamore@opensolaris.org list_create(&dev->d_procs, sizeof (struct daproc),
104710157Sgdamore@opensolaris.org offsetof(struct daproc, p_linkage));
104810157Sgdamore@opensolaris.org
104910157Sgdamore@opensolaris.org return (dev);
105010157Sgdamore@opensolaris.org }
105110157Sgdamore@opensolaris.org
105210157Sgdamore@opensolaris.org static void
devaudio_fini(void * arg)105310157Sgdamore@opensolaris.org devaudio_fini(void *arg)
105410157Sgdamore@opensolaris.org {
105510157Sgdamore@opensolaris.org dadev_t *dev = arg;
105610157Sgdamore@opensolaris.org
105710157Sgdamore@opensolaris.org if (dev != NULL) {
105810157Sgdamore@opensolaris.org
105910157Sgdamore@opensolaris.org mutex_destroy(&dev->d_mx);
106010157Sgdamore@opensolaris.org cv_destroy(&dev->d_cv);
106110157Sgdamore@opensolaris.org list_destroy(&dev->d_procs);
106210157Sgdamore@opensolaris.org kmem_free(dev, sizeof (*dev));
106310157Sgdamore@opensolaris.org }
106410157Sgdamore@opensolaris.org }
106510157Sgdamore@opensolaris.org
106610157Sgdamore@opensolaris.org static int
devaudio_open(audio_client_t * c,int oflag)106710157Sgdamore@opensolaris.org devaudio_open(audio_client_t *c, int oflag)
106810157Sgdamore@opensolaris.org {
106910157Sgdamore@opensolaris.org int rv;
107010157Sgdamore@opensolaris.org
1071*12165Sgdamore@opensolaris.org if ((rv = auclnt_open(c, oflag)) != 0) {
107210157Sgdamore@opensolaris.org return (rv);
107310157Sgdamore@opensolaris.org }
107410157Sgdamore@opensolaris.org
107510157Sgdamore@opensolaris.org if ((rv = devaudio_proc_hold(c, oflag)) != 0) {
107610157Sgdamore@opensolaris.org auclnt_close(c);
107710157Sgdamore@opensolaris.org return (rv);
107810157Sgdamore@opensolaris.org }
107910157Sgdamore@opensolaris.org
108010157Sgdamore@opensolaris.org /* start up the input */
108110157Sgdamore@opensolaris.org if (oflag & FREAD) {
108210157Sgdamore@opensolaris.org auclnt_start(auclnt_input_stream(c));
108310157Sgdamore@opensolaris.org }
108410157Sgdamore@opensolaris.org
108510157Sgdamore@opensolaris.org return (0);
108610157Sgdamore@opensolaris.org }
108710157Sgdamore@opensolaris.org
108810157Sgdamore@opensolaris.org static int
devaudioctl_open(audio_client_t * c,int oflag)108910157Sgdamore@opensolaris.org devaudioctl_open(audio_client_t *c, int oflag)
109010157Sgdamore@opensolaris.org {
109110157Sgdamore@opensolaris.org int rv;
109210157Sgdamore@opensolaris.org
109310157Sgdamore@opensolaris.org _NOTE(ARGUNUSED(oflag));
109410157Sgdamore@opensolaris.org
109510157Sgdamore@opensolaris.org oflag &= ~(FWRITE | FREAD);
109610157Sgdamore@opensolaris.org
1097*12165Sgdamore@opensolaris.org if ((rv = auclnt_open(c, 0)) != 0) {
109810157Sgdamore@opensolaris.org return (rv);
109910157Sgdamore@opensolaris.org }
110010157Sgdamore@opensolaris.org
110110157Sgdamore@opensolaris.org if ((rv = devaudio_proc_hold(c, oflag)) != 0) {
110210157Sgdamore@opensolaris.org auclnt_close(c);
110310157Sgdamore@opensolaris.org return (rv);
110410157Sgdamore@opensolaris.org }
110510157Sgdamore@opensolaris.org
11069484Sgarrett.damore@Sun.COM return (0);
11079484Sgarrett.damore@Sun.COM }
11089484Sgarrett.damore@Sun.COM
11099484Sgarrett.damore@Sun.COM static void
devaudio_close(audio_client_t * c)111010157Sgdamore@opensolaris.org devaudio_close(audio_client_t *c)
11119484Sgarrett.damore@Sun.COM {
111210157Sgdamore@opensolaris.org auclnt_stop(auclnt_output_stream(c));
111310157Sgdamore@opensolaris.org auclnt_stop(auclnt_input_stream(c));
11149484Sgarrett.damore@Sun.COM
111510157Sgdamore@opensolaris.org auclnt_close(c);
111610157Sgdamore@opensolaris.org devaudio_proc_release(c);
111710157Sgdamore@opensolaris.org }
11189484Sgarrett.damore@Sun.COM
111910157Sgdamore@opensolaris.org static void
devaudioctl_close(audio_client_t * c)112010157Sgdamore@opensolaris.org devaudioctl_close(audio_client_t *c)
112110157Sgdamore@opensolaris.org {
112210157Sgdamore@opensolaris.org auclnt_close(c);
112310157Sgdamore@opensolaris.org devaudio_proc_release(c);
11249484Sgarrett.damore@Sun.COM }
11259484Sgarrett.damore@Sun.COM
11269484Sgarrett.damore@Sun.COM static void
devaudio_miocdata(audio_client_t * c,mblk_t * mp)112710157Sgdamore@opensolaris.org devaudio_miocdata(audio_client_t *c, mblk_t *mp)
11289484Sgarrett.damore@Sun.COM {
112910157Sgdamore@opensolaris.org struct copyresp *csp;
113010157Sgdamore@opensolaris.org queue_t *wq;
113110157Sgdamore@opensolaris.org
113210157Sgdamore@opensolaris.org csp = (void *)mp->b_rptr;
113310157Sgdamore@opensolaris.org wq = auclnt_get_wq(c);
11349484Sgarrett.damore@Sun.COM
113510157Sgdamore@opensolaris.org /*
113610157Sgdamore@opensolaris.org * If a transfer error occurred, the framework already
113710157Sgdamore@opensolaris.org * MIOCNAK'd it.
113810157Sgdamore@opensolaris.org */
113910157Sgdamore@opensolaris.org if (csp->cp_rval != 0) {
114010157Sgdamore@opensolaris.org freemsg(mp);
114110157Sgdamore@opensolaris.org return;
114210157Sgdamore@opensolaris.org }
11439484Sgarrett.damore@Sun.COM
114410157Sgdamore@opensolaris.org /*
114510157Sgdamore@opensolaris.org * If no state, then this is a response to M_COPYOUT, and we
114610157Sgdamore@opensolaris.org * are done. (Audio ioctls just copyout a single structure at
114710157Sgdamore@opensolaris.org * completion of work.)
114810157Sgdamore@opensolaris.org */
114910157Sgdamore@opensolaris.org if (csp->cp_private == NULL) {
115010157Sgdamore@opensolaris.org miocack(wq, mp, 0, 0);
115110157Sgdamore@opensolaris.org return;
115210157Sgdamore@opensolaris.org }
115310157Sgdamore@opensolaris.org
115410157Sgdamore@opensolaris.org /* now, call the handler ioctl */
115510157Sgdamore@opensolaris.org switch (csp->cp_cmd) {
115610157Sgdamore@opensolaris.org case AUDIO_SETINFO:
115710157Sgdamore@opensolaris.org devaudio_ioc_setinfo(wq, c, mp);
11589484Sgarrett.damore@Sun.COM break;
115910157Sgdamore@opensolaris.org default:
116010157Sgdamore@opensolaris.org miocnak(wq, mp, 0, EINVAL);
11619484Sgarrett.damore@Sun.COM break;
11629484Sgarrett.damore@Sun.COM }
11639484Sgarrett.damore@Sun.COM }
11649484Sgarrett.damore@Sun.COM
11659484Sgarrett.damore@Sun.COM static void
devaudio_mioctl(audio_client_t * c,mblk_t * mp)116610157Sgdamore@opensolaris.org devaudio_mioctl(audio_client_t *c, mblk_t *mp)
11679484Sgarrett.damore@Sun.COM {
116810157Sgdamore@opensolaris.org struct iocblk *iocp = (void *)mp->b_rptr;
116910157Sgdamore@opensolaris.org queue_t *wq = auclnt_get_wq(c);
117010157Sgdamore@opensolaris.org
117110157Sgdamore@opensolaris.org /* BSD legacy here: we only support transparent ioctls */
117210157Sgdamore@opensolaris.org if (iocp->ioc_count != TRANSPARENT) {
117310157Sgdamore@opensolaris.org miocnak(wq, mp, 0, EINVAL);
117410157Sgdamore@opensolaris.org return;
117510157Sgdamore@opensolaris.org }
117610157Sgdamore@opensolaris.org
117710157Sgdamore@opensolaris.org switch (iocp->ioc_cmd) {
11789484Sgarrett.damore@Sun.COM case AUDIO_GETINFO:
117910157Sgdamore@opensolaris.org devaudio_ioc_getinfo(wq, c, mp);
11809484Sgarrett.damore@Sun.COM break;
11819484Sgarrett.damore@Sun.COM
11829484Sgarrett.damore@Sun.COM case AUDIO_SETINFO:
118310157Sgdamore@opensolaris.org devaudio_ioc_setinfo(wq, c, mp);
11849484Sgarrett.damore@Sun.COM break;
11859484Sgarrett.damore@Sun.COM
11869484Sgarrett.damore@Sun.COM case AUDIO_GETDEV:
118710157Sgdamore@opensolaris.org devaudio_ioc_getdev(wq, c, mp);
11889484Sgarrett.damore@Sun.COM break;
11899484Sgarrett.damore@Sun.COM
11909484Sgarrett.damore@Sun.COM case AUDIO_DIAG_LOOPBACK:
11919484Sgarrett.damore@Sun.COM /* we don't support this one */
119210157Sgdamore@opensolaris.org miocnak(wq, mp, 0, ENOTTY);
11939484Sgarrett.damore@Sun.COM break;
11949484Sgarrett.damore@Sun.COM
11959484Sgarrett.damore@Sun.COM case AUDIO_MIXERCTL_GET_MODE:
11969484Sgarrett.damore@Sun.COM case AUDIO_MIXERCTL_SET_MODE:
11979484Sgarrett.damore@Sun.COM case AUDIO_MIXERCTL_GET_CHINFO:
11989484Sgarrett.damore@Sun.COM case AUDIO_MIXERCTL_SET_CHINFO:
11999484Sgarrett.damore@Sun.COM case AUDIO_MIXERCTL_GETINFO:
12009484Sgarrett.damore@Sun.COM case AUDIO_MIXERCTL_SETINFO:
12019484Sgarrett.damore@Sun.COM case AUDIO_GET_NUM_CHS:
12029484Sgarrett.damore@Sun.COM case AUDIO_GET_CH_NUMBER:
12039484Sgarrett.damore@Sun.COM case AUDIO_GET_CH_TYPE:
12049484Sgarrett.damore@Sun.COM case AUDIO_MIXER_SINGLE_OPEN:
12059484Sgarrett.damore@Sun.COM case AUDIO_MIXER_MULTIPLE_OPEN:
12069484Sgarrett.damore@Sun.COM case AUDIO_MIXER_GET_SAMPLE_RATES:
12079484Sgarrett.damore@Sun.COM default:
120810157Sgdamore@opensolaris.org miocnak(wq, mp, 0, EINVAL);
12099484Sgarrett.damore@Sun.COM break;
12109484Sgarrett.damore@Sun.COM }
12119484Sgarrett.damore@Sun.COM }
12129484Sgarrett.damore@Sun.COM
12139484Sgarrett.damore@Sun.COM static void
devaudioctl_wput(audio_client_t * c,mblk_t * mp)121410157Sgdamore@opensolaris.org devaudioctl_wput(audio_client_t *c, mblk_t *mp)
12159484Sgarrett.damore@Sun.COM {
121610157Sgdamore@opensolaris.org queue_t *wq = auclnt_get_wq(c);
12179484Sgarrett.damore@Sun.COM
12189484Sgarrett.damore@Sun.COM switch (DB_TYPE(mp)) {
12199484Sgarrett.damore@Sun.COM case M_IOCTL:
12209484Sgarrett.damore@Sun.COM /* Drain ioctl needs to be handled on the service queue */
122110157Sgdamore@opensolaris.org devaudio_mioctl(c, mp);
122210157Sgdamore@opensolaris.org break;
122310157Sgdamore@opensolaris.org
122410157Sgdamore@opensolaris.org case M_IOCDATA:
122510157Sgdamore@opensolaris.org devaudio_miocdata(c, mp);
122610157Sgdamore@opensolaris.org break;
122710157Sgdamore@opensolaris.org
122810157Sgdamore@opensolaris.org case M_FLUSH:
122910157Sgdamore@opensolaris.org /*
123010157Sgdamore@opensolaris.org * We don't flush the engine. The reason is that
123110157Sgdamore@opensolaris.org * other streams might be using the engine. This is
123210157Sgdamore@opensolaris.org * fundamentally no different from the case where the
123310157Sgdamore@opensolaris.org * engine hardware has data buffered in an
123410157Sgdamore@opensolaris.org * inaccessible FIFO.
123510157Sgdamore@opensolaris.org *
123610157Sgdamore@opensolaris.org * Clients that want to ensure no more data is coming
123710157Sgdamore@opensolaris.org * should stop the stream before flushing.
123810157Sgdamore@opensolaris.org */
123910157Sgdamore@opensolaris.org if (*mp->b_rptr & FLUSHW) {
124010157Sgdamore@opensolaris.org *mp->b_rptr &= ~FLUSHW;
124110157Sgdamore@opensolaris.org }
124210157Sgdamore@opensolaris.org if (*mp->b_rptr & FLUSHR) {
124310157Sgdamore@opensolaris.org qreply(wq, mp);
12449484Sgarrett.damore@Sun.COM } else {
124510157Sgdamore@opensolaris.org freemsg(mp);
124610157Sgdamore@opensolaris.org }
124710157Sgdamore@opensolaris.org break;
124810157Sgdamore@opensolaris.org
124910157Sgdamore@opensolaris.org case M_DATA:
125010157Sgdamore@opensolaris.org /*
125110157Sgdamore@opensolaris.org * No audio data on control nodes!
125210157Sgdamore@opensolaris.org */
125310157Sgdamore@opensolaris.org freemsg(mp);
125410157Sgdamore@opensolaris.org
125510157Sgdamore@opensolaris.org default:
125610157Sgdamore@opensolaris.org freemsg(mp);
125710157Sgdamore@opensolaris.org break;
125810157Sgdamore@opensolaris.org }
125910157Sgdamore@opensolaris.org }
126010157Sgdamore@opensolaris.org
126110157Sgdamore@opensolaris.org static void
devaudio_wput(audio_client_t * c,mblk_t * mp)126210157Sgdamore@opensolaris.org devaudio_wput(audio_client_t *c, mblk_t *mp)
126310157Sgdamore@opensolaris.org {
126410157Sgdamore@opensolaris.org queue_t *wq = auclnt_get_wq(c);
126510157Sgdamore@opensolaris.org
126610157Sgdamore@opensolaris.org switch (DB_TYPE(mp)) {
126710157Sgdamore@opensolaris.org case M_IOCTL:
126810157Sgdamore@opensolaris.org /* Drain ioctl needs to be handled on the service queue */
126910157Sgdamore@opensolaris.org if (*(int *)(void *)mp->b_rptr == AUDIO_DRAIN) {
127010157Sgdamore@opensolaris.org (void) putq(wq, mp);
127110157Sgdamore@opensolaris.org } else {
127210157Sgdamore@opensolaris.org devaudio_mioctl(c, mp);
12739484Sgarrett.damore@Sun.COM }
12749484Sgarrett.damore@Sun.COM break;
12759484Sgarrett.damore@Sun.COM
12769484Sgarrett.damore@Sun.COM case M_IOCDATA:
127710157Sgdamore@opensolaris.org devaudio_miocdata(c, mp);
12789484Sgarrett.damore@Sun.COM break;
12799484Sgarrett.damore@Sun.COM
12809484Sgarrett.damore@Sun.COM case M_FLUSH:
12819484Sgarrett.damore@Sun.COM /*
12829484Sgarrett.damore@Sun.COM * We don't flush the engine. The reason is that
12839484Sgarrett.damore@Sun.COM * other streams might be using the engine. This is
12849484Sgarrett.damore@Sun.COM * fundamentally no different from the case where the
12859484Sgarrett.damore@Sun.COM * engine hardware has data buffered in an
12869484Sgarrett.damore@Sun.COM * inaccessible FIFO.
12879484Sgarrett.damore@Sun.COM *
12889484Sgarrett.damore@Sun.COM * Clients that want to ensure no more data is coming
12899484Sgarrett.damore@Sun.COM * should stop the stream before flushing.
12909484Sgarrett.damore@Sun.COM */
12919484Sgarrett.damore@Sun.COM if (*mp->b_rptr & FLUSHW) {
12929484Sgarrett.damore@Sun.COM flushq(wq, FLUSHALL);
129310157Sgdamore@opensolaris.org auclnt_flush(auclnt_output_stream(c));
12949484Sgarrett.damore@Sun.COM *mp->b_rptr &= ~FLUSHW;
12959484Sgarrett.damore@Sun.COM }
12969484Sgarrett.damore@Sun.COM if (*mp->b_rptr & FLUSHR) {
12979484Sgarrett.damore@Sun.COM flushq(RD(wq), FLUSHALL);
129810157Sgdamore@opensolaris.org auclnt_flush(auclnt_input_stream(c));
12999484Sgarrett.damore@Sun.COM qreply(wq, mp);
13009484Sgarrett.damore@Sun.COM } else {
13019484Sgarrett.damore@Sun.COM freemsg(mp);
13029484Sgarrett.damore@Sun.COM }
13039484Sgarrett.damore@Sun.COM break;
13049484Sgarrett.damore@Sun.COM
13059484Sgarrett.damore@Sun.COM case M_DATA:
13069484Sgarrett.damore@Sun.COM /*
130710157Sgdamore@opensolaris.org * Defer processing to the queue. This keeps the data
130810157Sgdamore@opensolaris.org * ordered, and allows the wsrv routine to gather
130910157Sgdamore@opensolaris.org * multiple mblks at once.
13109484Sgarrett.damore@Sun.COM */
131110157Sgdamore@opensolaris.org if (mp->b_cont != NULL) {
13129484Sgarrett.damore@Sun.COM
131310157Sgdamore@opensolaris.org /*
131410157Sgdamore@opensolaris.org * If we need to pullup, do it here to
131510157Sgdamore@opensolaris.org * simplify the rest of the processing later.
131610157Sgdamore@opensolaris.org * This should rarely (if ever) be necessary.
131710157Sgdamore@opensolaris.org */
131810157Sgdamore@opensolaris.org mblk_t *nmp;
13199484Sgarrett.damore@Sun.COM
132010157Sgdamore@opensolaris.org if ((nmp = msgpullup(mp, -1)) == NULL) {
132110157Sgdamore@opensolaris.org freemsg(mp);
13229484Sgarrett.damore@Sun.COM } else {
132310157Sgdamore@opensolaris.org freemsg(mp);
132410157Sgdamore@opensolaris.org (void) putq(wq, nmp);
13259484Sgarrett.damore@Sun.COM }
132610157Sgdamore@opensolaris.org } else {
132710157Sgdamore@opensolaris.org (void) putq(wq, mp);
13289484Sgarrett.damore@Sun.COM }
13299484Sgarrett.damore@Sun.COM break;
13309484Sgarrett.damore@Sun.COM
13319484Sgarrett.damore@Sun.COM default:
13329484Sgarrett.damore@Sun.COM freemsg(mp);
13339484Sgarrett.damore@Sun.COM break;
13349484Sgarrett.damore@Sun.COM }
13359484Sgarrett.damore@Sun.COM }
13369484Sgarrett.damore@Sun.COM
133710157Sgdamore@opensolaris.org static void
devaudio_rsrv(audio_client_t * c)133810632Sgdamore@opensolaris.org devaudio_rsrv(audio_client_t *c)
133910632Sgdamore@opensolaris.org {
134010632Sgdamore@opensolaris.org queue_t *rq = auclnt_get_rq(c);
134110632Sgdamore@opensolaris.org mblk_t *mp;
134210632Sgdamore@opensolaris.org
134310632Sgdamore@opensolaris.org while ((mp = getq(rq)) != NULL) {
134410632Sgdamore@opensolaris.org
134510632Sgdamore@opensolaris.org if ((queclass(mp) != QPCTL) && (!canputnext(rq))) {
134610644SGarrett.Damore@Sun.COM /*
134710644SGarrett.Damore@Sun.COM * Put it back in the queue so we can apply
134810644SGarrett.Damore@Sun.COM * backpressure properly.
134910644SGarrett.Damore@Sun.COM */
135010644SGarrett.Damore@Sun.COM (void) putbq(rq, mp);
135110632Sgdamore@opensolaris.org return;
135210632Sgdamore@opensolaris.org }
135310632Sgdamore@opensolaris.org putnext(rq, mp);
135410632Sgdamore@opensolaris.org }
135510632Sgdamore@opensolaris.org }
135610632Sgdamore@opensolaris.org
135710632Sgdamore@opensolaris.org static void
devaudio_wsrv(audio_client_t * c)135810157Sgdamore@opensolaris.org devaudio_wsrv(audio_client_t *c)
13599484Sgarrett.damore@Sun.COM {
136010157Sgdamore@opensolaris.org queue_t *wq = auclnt_get_wq(c);
136110157Sgdamore@opensolaris.org daclient_t *dc = auclnt_get_private(c);
13629484Sgarrett.damore@Sun.COM audio_stream_t *sp;
13639484Sgarrett.damore@Sun.COM mblk_t *mp;
13649484Sgarrett.damore@Sun.COM unsigned framesz;
13659484Sgarrett.damore@Sun.COM
13669484Sgarrett.damore@Sun.COM sp = auclnt_output_stream(c);
13679484Sgarrett.damore@Sun.COM
13689484Sgarrett.damore@Sun.COM framesz = auclnt_get_framesz(sp);
13699484Sgarrett.damore@Sun.COM
13709484Sgarrett.damore@Sun.COM while ((mp = getq(wq)) != NULL) {
13719484Sgarrett.damore@Sun.COM
13729484Sgarrett.damore@Sun.COM unsigned count;
13739484Sgarrett.damore@Sun.COM
13749484Sgarrett.damore@Sun.COM /* got a message */
13759484Sgarrett.damore@Sun.COM
13769484Sgarrett.damore@Sun.COM /* if its a drain ioctl, we need to process it here */
13779484Sgarrett.damore@Sun.COM if (DB_TYPE(mp) == M_IOCTL) {
13789484Sgarrett.damore@Sun.COM ASSERT((*(int *)(void *)mp->b_rptr) == AUDIO_DRAIN);
137910157Sgdamore@opensolaris.org mutex_enter(&dc->dc_lock);
138010157Sgdamore@opensolaris.org mp->b_next = dc->dc_draining;
138110157Sgdamore@opensolaris.org dc->dc_draining = mp;
138210157Sgdamore@opensolaris.org mutex_exit(&dc->dc_lock);
13839484Sgarrett.damore@Sun.COM
13849484Sgarrett.damore@Sun.COM if (auclnt_start_drain(c) != 0) {
138510157Sgdamore@opensolaris.org devaudio_drain(c);
13869484Sgarrett.damore@Sun.COM }
13879484Sgarrett.damore@Sun.COM continue;
13889484Sgarrett.damore@Sun.COM }
13899484Sgarrett.damore@Sun.COM
13909484Sgarrett.damore@Sun.COM ASSERT(DB_TYPE(mp) == M_DATA);
13919484Sgarrett.damore@Sun.COM
13929484Sgarrett.damore@Sun.COM /*
13939484Sgarrett.damore@Sun.COM * Empty mblk require special handling, since they
13949484Sgarrett.damore@Sun.COM * indicate EOF. We treat them separate from the main
13959484Sgarrett.damore@Sun.COM * processing loop.
13969484Sgarrett.damore@Sun.COM */
13979484Sgarrett.damore@Sun.COM if (MBLKL(mp) == 0) {
13989484Sgarrett.damore@Sun.COM struct eofcnt *eof;
13999484Sgarrett.damore@Sun.COM
14009484Sgarrett.damore@Sun.COM eof = kmem_zalloc(sizeof (*eof), KM_NOSLEEP);
14019484Sgarrett.damore@Sun.COM if (eof != NULL) {
14029484Sgarrett.damore@Sun.COM eof->tail = auclnt_get_head(sp);
140310157Sgdamore@opensolaris.org mutex_enter(&dc->dc_lock);
140410157Sgdamore@opensolaris.org list_insert_tail(&dc->dc_eofcnt, eof);
140510157Sgdamore@opensolaris.org mutex_exit(&dc->dc_lock);
14069484Sgarrett.damore@Sun.COM }
14079484Sgarrett.damore@Sun.COM freemsg(mp);
14089484Sgarrett.damore@Sun.COM continue;
14099484Sgarrett.damore@Sun.COM }
14109484Sgarrett.damore@Sun.COM
14119484Sgarrett.damore@Sun.COM count = auclnt_produce_data(sp, (caddr_t)mp->b_rptr,
14129484Sgarrett.damore@Sun.COM MBLKL(mp) / framesz);
14139484Sgarrett.damore@Sun.COM
14149484Sgarrett.damore@Sun.COM mp->b_rptr += count * framesz;
14159484Sgarrett.damore@Sun.COM
14169484Sgarrett.damore@Sun.COM if (MBLKL(mp) >= framesz) {
14179484Sgarrett.damore@Sun.COM (void) putbq(wq, mp);
14189484Sgarrett.damore@Sun.COM break;
14199484Sgarrett.damore@Sun.COM } else {
14209484Sgarrett.damore@Sun.COM freemsg(mp);
14219484Sgarrett.damore@Sun.COM }
14229484Sgarrett.damore@Sun.COM }
14239484Sgarrett.damore@Sun.COM
14249484Sgarrett.damore@Sun.COM /* if the stream isn't running yet, start it up */
14259484Sgarrett.damore@Sun.COM if (!auclnt_is_paused(sp))
14269484Sgarrett.damore@Sun.COM auclnt_start(sp);
14279484Sgarrett.damore@Sun.COM }
14289484Sgarrett.damore@Sun.COM
142910157Sgdamore@opensolaris.org static struct audio_client_ops devaudio_ops = {
143010157Sgdamore@opensolaris.org "sound,audio",
143110157Sgdamore@opensolaris.org devaudio_init,
143210157Sgdamore@opensolaris.org devaudio_fini,
143310157Sgdamore@opensolaris.org devaudio_open,
143410157Sgdamore@opensolaris.org devaudio_close,
143510157Sgdamore@opensolaris.org NULL, /* read */
143610157Sgdamore@opensolaris.org NULL, /* write */
143710157Sgdamore@opensolaris.org NULL, /* ioctl */
143810157Sgdamore@opensolaris.org NULL, /* chpoll */
143910157Sgdamore@opensolaris.org NULL, /* mmap */
144010157Sgdamore@opensolaris.org devaudio_input,
144110157Sgdamore@opensolaris.org devaudio_output,
144210157Sgdamore@opensolaris.org devaudio_drain,
144310157Sgdamore@opensolaris.org devaudio_wput,
144410632Sgdamore@opensolaris.org devaudio_wsrv,
144510632Sgdamore@opensolaris.org devaudio_rsrv
14469484Sgarrett.damore@Sun.COM };
14479484Sgarrett.damore@Sun.COM
144810157Sgdamore@opensolaris.org static struct audio_client_ops devaudioctl_ops = {
144910157Sgdamore@opensolaris.org "sound,audioctl",
145010157Sgdamore@opensolaris.org NULL, /* dev_init */
145110157Sgdamore@opensolaris.org NULL, /* dev_fini */
145210157Sgdamore@opensolaris.org devaudioctl_open,
145310157Sgdamore@opensolaris.org devaudioctl_close,
145410157Sgdamore@opensolaris.org NULL, /* read */
145510157Sgdamore@opensolaris.org NULL, /* write */
145610157Sgdamore@opensolaris.org NULL, /* ioctl */
145710157Sgdamore@opensolaris.org NULL, /* chpoll */
145810157Sgdamore@opensolaris.org NULL, /* mmap */
145910157Sgdamore@opensolaris.org NULL, /* output */
146010157Sgdamore@opensolaris.org NULL, /* input */
146110157Sgdamore@opensolaris.org NULL, /* drain */
146210157Sgdamore@opensolaris.org devaudioctl_wput,
14639484Sgarrett.damore@Sun.COM NULL,
146410644SGarrett.Damore@Sun.COM devaudio_rsrv
14659484Sgarrett.damore@Sun.COM };
14669484Sgarrett.damore@Sun.COM
146710157Sgdamore@opensolaris.org void
auimpl_sun_init(void)146810157Sgdamore@opensolaris.org auimpl_sun_init(void)
14699484Sgarrett.damore@Sun.COM {
147010157Sgdamore@opensolaris.org auclnt_register_ops(AUDIO_MINOR_DEVAUDIO, &devaudio_ops);
147110157Sgdamore@opensolaris.org auclnt_register_ops(AUDIO_MINOR_DEVAUDIOCTL, &devaudioctl_ops);
14729484Sgarrett.damore@Sun.COM }
1473