[BACK]Return to ossaudio.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / lib / libossaudio

Annotation of src/lib/libossaudio/ossaudio.c, Revision 1.41

1.41    ! nia         1: /*     $NetBSD: ossaudio.c,v 1.40 2020/04/15 15:25:33 nia Exp $        */
1.1       augustss    2:
1.7       augustss    3: /*-
1.1       augustss    4:  * Copyright (c) 1997 The NetBSD Foundation, Inc.
                      5:  * All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  *
                     16:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     17:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     18:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     19:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     20:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     21:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     22:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     23:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     24:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     25:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     26:  * POSSIBILITY OF SUCH DAMAGE.
                     27:  */
1.18      lukem      28:
                     29: #include <sys/cdefs.h>
1.41    ! nia        30: __RCSID("$NetBSD: ossaudio.c,v 1.40 2020/04/15 15:25:33 nia Exp $");
1.1       augustss   31:
                     32: /*
                     33:  * This is an OSS (Linux) sound API emulator.
                     34:  * It provides the essentials of the API.
                     35:  */
                     36:
                     37: /* XXX This file is essentially the same as sys/compat/ossaudio.c.
1.3       augustss   38:  * With some preprocessor magic it could be the same file.
1.1       augustss   39:  */
                     40:
                     41: #include <string.h>
                     42: #include <sys/types.h>
                     43: #include <sys/ioctl.h>
                     44: #include <sys/audioio.h>
                     45: #include <sys/stat.h>
                     46: #include <errno.h>
1.29      nat        47: #include <fcntl.h>
                     48: #include <stdio.h>
                     49: #include <unistd.h>
1.27      christos   50: #include <stdarg.h>
1.1       augustss   51:
                     52: #include "soundcard.h"
                     53: #undef ioctl
                     54:
                     55: #define GET_DEV(com) ((com) & 0xff)
                     56:
1.12      tron       57: #define TO_OSSVOL(x)   (((x) * 100 + 127) / 255)
                     58: #define FROM_OSSVOL(x) ((((x) > 100 ? 100 : (x)) * 255 + 50) / 100)
1.1       augustss   59:
1.38      isaki      60: #define GETPRINFO(info, name)  \
                     61:        (((info)->mode == AUMODE_RECORD) \
                     62:            ? (info)->record.name : (info)->play.name)
                     63:
1.1       augustss   64: static struct audiodevinfo *getdevinfo(int);
                     65:
1.41    ! nia        66: static void setchannels(int, int, int);
1.1       augustss   67: static void setblocksize(int, struct audio_info *);
                     68:
                     69: static int audio_ioctl(int, unsigned long, void *);
                     70: static int mixer_ioctl(int, unsigned long, void *);
1.27      christos   71: static int opaque_to_enum(struct audiodevinfo *, audio_mixer_name_t *, int);
                     72: static int enum_to_ord(struct audiodevinfo *, int);
                     73: static int enum_to_mask(struct audiodevinfo *, int);
1.1       augustss   74:
                     75: #define INTARG (*(int*)argp)
                     76:
                     77: int
1.27      christos   78: _oss_ioctl(int fd, unsigned long com, ...)
1.1       augustss   79: {
1.27      christos   80:        va_list ap;
                     81:        void *argp;
                     82:
                     83:        va_start(ap, com);
                     84:        argp = va_arg(ap, void *);
                     85:        va_end(ap);
                     86:
1.1       augustss   87:        if (IOCGROUP(com) == 'P')
                     88:                return audio_ioctl(fd, com, argp);
                     89:        else if (IOCGROUP(com) == 'M')
                     90:                return mixer_ioctl(fd, com, argp);
                     91:        else
                     92:                return ioctl(fd, com, argp);
                     93: }
                     94:
                     95: static int
                     96: audio_ioctl(int fd, unsigned long com, void *argp)
                     97: {
1.8       simonb     98:
1.39      nia        99:        struct audio_info tmpinfo, hwfmt;
1.1       augustss  100:        struct audio_offset tmpoffs;
                    101:        struct audio_buf_info bufinfo;
                    102:        struct count_info cntinfo;
                    103:        struct audio_encoding tmpenc;
1.29      nat       104:        struct oss_sysinfo tmpsysinfo;
                    105:        struct oss_audioinfo *tmpaudioinfo;
                    106:        audio_device_t tmpaudiodev;
                    107:        struct stat tmpstat;
                    108:        dev_t devno;
                    109:        char version[32] = "4.01";
                    110:        char license[16] = "NetBSD";
1.1       augustss  111:        u_int u;
1.38      isaki     112:        u_int encoding;
                    113:        u_int precision;
1.1       augustss  114:        int idat, idata;
                    115:        int retval;
1.29      nat       116:        int i;
1.1       augustss  117:
1.20      lukem     118:        idat = 0;
                    119:
1.1       augustss  120:        switch (com) {
                    121:        case SNDCTL_DSP_RESET:
                    122:                retval = ioctl(fd, AUDIO_FLUSH, 0);
                    123:                if (retval < 0)
                    124:                        return retval;
                    125:                break;
                    126:        case SNDCTL_DSP_SYNC:
                    127:                retval = ioctl(fd, AUDIO_DRAIN, 0);
                    128:                if (retval < 0)
                    129:                        return retval;
1.16      mycroft   130:                break;
                    131:        case SNDCTL_DSP_POST:
                    132:                /* This call is merely advisory, and may be a nop. */
1.1       augustss  133:                break;
                    134:        case SNDCTL_DSP_SPEED:
                    135:                AUDIO_INITINFO(&tmpinfo);
                    136:                tmpinfo.play.sample_rate =
                    137:                tmpinfo.record.sample_rate = INTARG;
1.39      nia       138:                /*
                    139:                 * The default NetBSD behavior if an unsupported sample rate
                    140:                 * is set is to return an error code and keep the rate at the
                    141:                 * default of 8000 Hz.
                    142:                 *
                    143:                 * However, OSS specifies that a sample rate supported by the
                    144:                 * hardware is returned if the exact rate could not be set.
                    145:                 *
                    146:                 * So, if the chosen sample rate is invalid, set and return
                    147:                 * the current hardware rate.
                    148:                 */
                    149:                if (ioctl(fd, AUDIO_SETINFO, &tmpinfo) < 0) {
                    150:                        /* Don't care that SETINFO failed the first time... */
                    151:                        errno = 0;
                    152:                        retval = ioctl(fd, AUDIO_GETFORMAT, &hwfmt);
                    153:                        if (retval < 0)
                    154:                                return retval;
                    155:                        retval = ioctl(fd, AUDIO_GETINFO, &tmpinfo);
                    156:                        if (retval < 0)
                    157:                                return retval;
                    158:                        tmpinfo.play.sample_rate =
                    159:                        tmpinfo.record.sample_rate =
                    160:                            (tmpinfo.mode == AUMODE_RECORD) ?
                    161:                            hwfmt.record.sample_rate :
                    162:                            hwfmt.play.sample_rate;
                    163:                        retval = ioctl(fd, AUDIO_SETINFO, &tmpinfo);
                    164:                        if (retval < 0)
                    165:                                return retval;
                    166:                }
1.10      augustss  167:                /* FALLTHRU */
1.1       augustss  168:        case SOUND_PCM_READ_RATE:
1.21      joerg     169:                retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
1.1       augustss  170:                if (retval < 0)
                    171:                        return retval;
1.38      isaki     172:                INTARG = GETPRINFO(&tmpinfo, sample_rate);
1.1       augustss  173:                break;
                    174:        case SNDCTL_DSP_STEREO:
                    175:                AUDIO_INITINFO(&tmpinfo);
                    176:                tmpinfo.play.channels =
                    177:                tmpinfo.record.channels = INTARG ? 2 : 1;
                    178:                (void) ioctl(fd, AUDIO_SETINFO, &tmpinfo);
1.21      joerg     179:                retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
1.1       augustss  180:                if (retval < 0)
                    181:                        return retval;
1.38      isaki     182:                INTARG = GETPRINFO(&tmpinfo, channels) - 1;
1.1       augustss  183:                break;
                    184:        case SNDCTL_DSP_GETBLKSIZE:
1.21      joerg     185:                retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
1.1       augustss  186:                if (retval < 0)
                    187:                        return retval;
                    188:                setblocksize(fd, &tmpinfo);
                    189:                INTARG = tmpinfo.blocksize;
                    190:                break;
                    191:        case SNDCTL_DSP_SETFMT:
1.4       augustss  192:                AUDIO_INITINFO(&tmpinfo);
1.1       augustss  193:                switch (INTARG) {
                    194:                case AFMT_MU_LAW:
                    195:                        tmpinfo.play.precision =
                    196:                        tmpinfo.record.precision = 8;
                    197:                        tmpinfo.play.encoding =
                    198:                        tmpinfo.record.encoding = AUDIO_ENCODING_ULAW;
                    199:                        break;
                    200:                case AFMT_A_LAW:
                    201:                        tmpinfo.play.precision =
                    202:                        tmpinfo.record.precision = 8;
                    203:                        tmpinfo.play.encoding =
                    204:                        tmpinfo.record.encoding = AUDIO_ENCODING_ALAW;
                    205:                        break;
                    206:                case AFMT_U8:
                    207:                        tmpinfo.play.precision =
                    208:                        tmpinfo.record.precision = 8;
                    209:                        tmpinfo.play.encoding =
                    210:                        tmpinfo.record.encoding = AUDIO_ENCODING_ULINEAR;
                    211:                        break;
                    212:                case AFMT_S8:
                    213:                        tmpinfo.play.precision =
                    214:                        tmpinfo.record.precision = 8;
                    215:                        tmpinfo.play.encoding =
                    216:                        tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR;
                    217:                        break;
                    218:                case AFMT_S16_LE:
                    219:                        tmpinfo.play.precision =
                    220:                        tmpinfo.record.precision = 16;
                    221:                        tmpinfo.play.encoding =
                    222:                        tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR_LE;
                    223:                        break;
                    224:                case AFMT_S16_BE:
                    225:                        tmpinfo.play.precision =
                    226:                        tmpinfo.record.precision = 16;
                    227:                        tmpinfo.play.encoding =
                    228:                        tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR_BE;
                    229:                        break;
                    230:                case AFMT_U16_LE:
                    231:                        tmpinfo.play.precision =
                    232:                        tmpinfo.record.precision = 16;
                    233:                        tmpinfo.play.encoding =
                    234:                        tmpinfo.record.encoding = AUDIO_ENCODING_ULINEAR_LE;
                    235:                        break;
                    236:                case AFMT_U16_BE:
                    237:                        tmpinfo.play.precision =
                    238:                        tmpinfo.record.precision = 16;
                    239:                        tmpinfo.play.encoding =
                    240:                        tmpinfo.record.encoding = AUDIO_ENCODING_ULINEAR_BE;
                    241:                        break;
1.40      nia       242:                /*
                    243:                 * XXX: When the kernel supports 24-bit LPCM by default,
                    244:                 * the 24-bit formats should be handled properly instead
                    245:                 * of falling back to 32 bits.
                    246:                 */
1.30      nat       247:                case AFMT_S24_LE:
                    248:                case AFMT_S32_LE:
                    249:                        tmpinfo.play.precision =
                    250:                        tmpinfo.record.precision = 32;
                    251:                        tmpinfo.play.encoding =
                    252:                        tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR_LE;
                    253:                        break;
1.40      nia       254:                case AFMT_S24_BE:
1.30      nat       255:                case AFMT_S32_BE:
                    256:                        tmpinfo.play.precision =
                    257:                        tmpinfo.record.precision = 32;
                    258:                        tmpinfo.play.encoding =
                    259:                        tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR_BE;
                    260:                        break;
1.25      jmcneill  261:                case AFMT_AC3:
                    262:                        tmpinfo.play.precision =
                    263:                        tmpinfo.record.precision = 16;
                    264:                        tmpinfo.play.encoding =
                    265:                        tmpinfo.record.encoding = AUDIO_ENCODING_AC3;
                    266:                        break;
1.1       augustss  267:                default:
1.40      nia       268:                        /*
                    269:                         * OSSv4 specifies that if an invalid format is chosen
                    270:                         * by an application then a sensible format supported
                    271:                         * by the hardware is returned.
                    272:                         *
                    273:                         * In this case, we pick the current hardware format.
                    274:                         */
                    275:                        retval = ioctl(fd, AUDIO_GETFORMAT, &hwfmt);
                    276:                        if (retval < 0)
                    277:                                return retval;
                    278:                        retval = ioctl(fd, AUDIO_GETINFO, &tmpinfo);
                    279:                        if (retval < 0)
                    280:                                return retval;
                    281:                        tmpinfo.play.encoding =
                    282:                        tmpinfo.record.encoding =
                    283:                            (tmpinfo.mode == AUMODE_RECORD) ?
                    284:                            hwfmt.record.encoding : hwfmt.play.encoding;
                    285:                        tmpinfo.play.precision =
                    286:                        tmpinfo.record.precision =
                    287:                            (tmpinfo.mode == AUMODE_RECORD) ?
                    288:                            hwfmt.record.precision : hwfmt.play.precision ;
                    289:                        break;
1.1       augustss  290:                }
1.40      nia       291:                /*
                    292:                 * In the post-kernel-mixer world, assume that any error means
                    293:                 * it's fatal rather than an unsupported format being selected.
                    294:                 */
                    295:                retval = ioctl(fd, AUDIO_SETINFO, &tmpinfo);
                    296:                if (retval < 0)
                    297:                        return retval;
1.10      augustss  298:                /* FALLTHRU */
1.1       augustss  299:        case SOUND_PCM_READ_BITS:
1.21      joerg     300:                retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
1.1       augustss  301:                if (retval < 0)
                    302:                        return retval;
1.38      isaki     303:                encoding = GETPRINFO(&tmpinfo, encoding);
                    304:                precision = GETPRINFO(&tmpinfo, precision);
                    305:                switch (encoding) {
1.1       augustss  306:                case AUDIO_ENCODING_ULAW:
                    307:                        idat = AFMT_MU_LAW;
                    308:                        break;
                    309:                case AUDIO_ENCODING_ALAW:
                    310:                        idat = AFMT_A_LAW;
                    311:                        break;
                    312:                case AUDIO_ENCODING_SLINEAR_LE:
1.38      isaki     313:                        if (precision == 32)
1.30      nat       314:                                idat = AFMT_S32_LE;
1.38      isaki     315:                        else if (precision == 24)
1.30      nat       316:                                idat = AFMT_S24_LE;
1.38      isaki     317:                        else if (precision == 16)
1.1       augustss  318:                                idat = AFMT_S16_LE;
                    319:                        else
                    320:                                idat = AFMT_S8;
                    321:                        break;
                    322:                case AUDIO_ENCODING_SLINEAR_BE:
1.38      isaki     323:                        if (precision == 32)
1.30      nat       324:                                idat = AFMT_S32_BE;
1.38      isaki     325:                        else if (precision == 24)
1.30      nat       326:                                idat = AFMT_S24_BE;
1.38      isaki     327:                        else if (precision == 16)
1.1       augustss  328:                                idat = AFMT_S16_BE;
                    329:                        else
                    330:                                idat = AFMT_S8;
                    331:                        break;
                    332:                case AUDIO_ENCODING_ULINEAR_LE:
1.38      isaki     333:                        if (precision == 16)
1.1       augustss  334:                                idat = AFMT_U16_LE;
                    335:                        else
                    336:                                idat = AFMT_U8;
                    337:                        break;
                    338:                case AUDIO_ENCODING_ULINEAR_BE:
1.38      isaki     339:                        if (precision == 16)
1.1       augustss  340:                                idat = AFMT_U16_BE;
                    341:                        else
                    342:                                idat = AFMT_U8;
                    343:                        break;
                    344:                case AUDIO_ENCODING_ADPCM:
                    345:                        idat = AFMT_IMA_ADPCM;
                    346:                        break;
1.25      jmcneill  347:                case AUDIO_ENCODING_AC3:
                    348:                        idat = AFMT_AC3;
                    349:                        break;
1.1       augustss  350:                }
                    351:                INTARG = idat;
                    352:                break;
                    353:        case SNDCTL_DSP_CHANNELS:
1.41    ! nia       354:                retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
        !           355:                if (retval < 0)
        !           356:                        return retval;
        !           357:                setchannels(fd, tmpinfo.mode, INTARG);
1.10      augustss  358:                /* FALLTHRU */
1.1       augustss  359:        case SOUND_PCM_READ_CHANNELS:
1.21      joerg     360:                retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
1.1       augustss  361:                if (retval < 0)
                    362:                        return retval;
1.38      isaki     363:                INTARG = GETPRINFO(&tmpinfo, channels);
1.1       augustss  364:                break;
                    365:        case SOUND_PCM_WRITE_FILTER:
                    366:        case SOUND_PCM_READ_FILTER:
                    367:                errno = EINVAL;
                    368:                return -1; /* XXX unimplemented */
                    369:        case SNDCTL_DSP_SUBDIVIDE:
1.21      joerg     370:                retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
1.1       augustss  371:                if (retval < 0)
                    372:                        return retval;
                    373:                setblocksize(fd, &tmpinfo);
                    374:                idat = INTARG;
                    375:                if (idat == 0)
1.2       augustss  376:                        idat = tmpinfo.play.buffer_size / tmpinfo.blocksize;
                    377:                idat = (tmpinfo.play.buffer_size / idat) & -4;
1.1       augustss  378:                AUDIO_INITINFO(&tmpinfo);
                    379:                tmpinfo.blocksize = idat;
                    380:                retval = ioctl(fd, AUDIO_SETINFO, &tmpinfo);
                    381:                if (retval < 0)
                    382:                        return retval;
1.2       augustss  383:                INTARG = tmpinfo.play.buffer_size / tmpinfo.blocksize;
1.1       augustss  384:                break;
                    385:        case SNDCTL_DSP_SETFRAGMENT:
                    386:                AUDIO_INITINFO(&tmpinfo);
                    387:                idat = INTARG;
                    388:                if ((idat & 0xffff) < 4 || (idat & 0xffff) > 17)
                    389:                        return EINVAL;
                    390:                tmpinfo.blocksize = 1 << (idat & 0xffff);
1.11      augustss  391:                tmpinfo.hiwat = ((unsigned)idat >> 16) & 0x7fff;
1.1       augustss  392:                if (tmpinfo.hiwat == 0) /* 0 means set to max */
                    393:                        tmpinfo.hiwat = 65536;
                    394:                (void) ioctl(fd, AUDIO_SETINFO, &tmpinfo);
1.21      joerg     395:                retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
1.1       augustss  396:                if (retval < 0)
                    397:                        return retval;
                    398:                u = tmpinfo.blocksize;
1.6       augustss  399:                for(idat = 0; u > 1; idat++, u >>= 1)
1.1       augustss  400:                        ;
1.5       augustss  401:                idat |= (tmpinfo.hiwat & 0x7fff) << 16;
1.1       augustss  402:                INTARG = idat;
                    403:                break;
                    404:        case SNDCTL_DSP_GETFMTS:
1.8       simonb    405:                for(idat = 0, tmpenc.index = 0;
                    406:                    ioctl(fd, AUDIO_GETENC, &tmpenc) == 0;
1.1       augustss  407:                    tmpenc.index++) {
                    408:                        switch(tmpenc.encoding) {
                    409:                        case AUDIO_ENCODING_ULAW:
                    410:                                idat |= AFMT_MU_LAW;
                    411:                                break;
                    412:                        case AUDIO_ENCODING_ALAW:
                    413:                                idat |= AFMT_A_LAW;
                    414:                                break;
                    415:                        case AUDIO_ENCODING_SLINEAR:
                    416:                                idat |= AFMT_S8;
                    417:                                break;
                    418:                        case AUDIO_ENCODING_SLINEAR_LE:
1.29      nat       419:                                if (tmpenc.precision == 32)
                    420:                                        idat |= AFMT_S32_LE;
                    421:                                else if (tmpenc.precision == 24)
                    422:                                        idat |= AFMT_S24_LE;
                    423:                                else if (tmpenc.precision == 16)
1.1       augustss  424:                                        idat |= AFMT_S16_LE;
                    425:                                else
                    426:                                        idat |= AFMT_S8;
                    427:                                break;
                    428:                        case AUDIO_ENCODING_SLINEAR_BE:
1.29      nat       429:                                if (tmpenc.precision == 32)
                    430:                                        idat |= AFMT_S32_BE;
                    431:                                else if (tmpenc.precision == 24)
                    432:                                        idat |= AFMT_S24_BE;
                    433:                                else if (tmpenc.precision == 16)
1.1       augustss  434:                                        idat |= AFMT_S16_BE;
                    435:                                else
                    436:                                        idat |= AFMT_S8;
                    437:                                break;
                    438:                        case AUDIO_ENCODING_ULINEAR:
                    439:                                idat |= AFMT_U8;
                    440:                                break;
                    441:                        case AUDIO_ENCODING_ULINEAR_LE:
                    442:                                if (tmpenc.precision == 16)
                    443:                                        idat |= AFMT_U16_LE;
                    444:                                else
                    445:                                        idat |= AFMT_U8;
                    446:                                break;
                    447:                        case AUDIO_ENCODING_ULINEAR_BE:
                    448:                                if (tmpenc.precision == 16)
                    449:                                        idat |= AFMT_U16_BE;
                    450:                                else
                    451:                                        idat |= AFMT_U8;
                    452:                                break;
                    453:                        case AUDIO_ENCODING_ADPCM:
                    454:                                idat |= AFMT_IMA_ADPCM;
                    455:                                break;
1.25      jmcneill  456:                        case AUDIO_ENCODING_AC3:
                    457:                                idat |= AFMT_AC3;
                    458:                                break;
1.1       augustss  459:                        default:
                    460:                                break;
                    461:                        }
                    462:                }
                    463:                INTARG = idat;
                    464:                break;
                    465:        case SNDCTL_DSP_GETOSPACE:
1.21      joerg     466:                retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
1.14      augustss  467:                if (retval < 0)
                    468:                        return retval;
                    469:                setblocksize(fd, &tmpinfo);
                    470:                bufinfo.fragsize = tmpinfo.blocksize;
1.35      isaki     471:                bufinfo.fragments = tmpinfo.hiwat - (tmpinfo.play.seek
                    472:                    + tmpinfo.blocksize - 1) / tmpinfo.blocksize;
1.14      augustss  473:                bufinfo.fragstotal = tmpinfo.hiwat;
1.35      isaki     474:                bufinfo.bytes = tmpinfo.hiwat * tmpinfo.blocksize
                    475:                    - tmpinfo.play.seek;
1.14      augustss  476:                *(struct audio_buf_info *)argp = bufinfo;
                    477:                break;
1.1       augustss  478:        case SNDCTL_DSP_GETISPACE:
1.21      joerg     479:                retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
1.1       augustss  480:                if (retval < 0)
                    481:                        return retval;
                    482:                setblocksize(fd, &tmpinfo);
                    483:                bufinfo.fragsize = tmpinfo.blocksize;
1.33      nat       484:                bufinfo.fragments = tmpinfo.record.seek / tmpinfo.blocksize;
1.36      isaki     485:                bufinfo.fragstotal =
                    486:                    tmpinfo.record.buffer_size / tmpinfo.blocksize;
                    487:                bufinfo.bytes = tmpinfo.record.seek;
1.1       augustss  488:                *(struct audio_buf_info *)argp = bufinfo;
                    489:                break;
                    490:        case SNDCTL_DSP_NONBLOCK:
                    491:                idat = 1;
                    492:                retval = ioctl(fd, FIONBIO, &idat);
                    493:                if (retval < 0)
                    494:                        return retval;
                    495:                break;
                    496:        case SNDCTL_DSP_GETCAPS:
1.10      augustss  497:                retval = ioctl(fd, AUDIO_GETPROPS, &idata);
1.1       augustss  498:                if (retval < 0)
                    499:                        return retval;
                    500:                idat = DSP_CAP_TRIGGER; /* pretend we have trigger */
                    501:                if (idata & AUDIO_PROP_FULLDUPLEX)
                    502:                        idat |= DSP_CAP_DUPLEX;
                    503:                if (idata & AUDIO_PROP_MMAP)
                    504:                        idat |= DSP_CAP_MMAP;
                    505:                INTARG = idat;
                    506:                break;
                    507: #if 0
                    508:        case SNDCTL_DSP_GETTRIGGER:
1.21      joerg     509:                retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
1.1       augustss  510:                if (retval < 0)
                    511:                        return retval;
                    512:                idat = (tmpinfo.play.pause ? 0 : PCM_ENABLE_OUTPUT) |
                    513:                       (tmpinfo.record.pause ? 0 : PCM_ENABLE_INPUT);
                    514:                retval = copyout(&idat, SCARG(uap, data), sizeof idat);
                    515:                if (retval < 0)
                    516:                        return retval;
                    517:                break;
                    518:        case SNDCTL_DSP_SETTRIGGER:
                    519:                AUDIO_INITINFO(&tmpinfo);
                    520:                retval = copyin(SCARG(uap, data), &idat, sizeof idat);
                    521:                if (retval < 0)
                    522:                        return retval;
                    523:                tmpinfo.play.pause = (idat & PCM_ENABLE_OUTPUT) == 0;
                    524:                tmpinfo.record.pause = (idat & PCM_ENABLE_INPUT) == 0;
1.10      augustss  525:                (void) ioctl(fd, AUDIO_SETINFO, &tmpinfo);
1.1       augustss  526:                retval = copyout(&idat, SCARG(uap, data), sizeof idat);
                    527:                if (retval < 0)
                    528:                        return retval;
                    529:                break;
                    530: #else
                    531:        case SNDCTL_DSP_GETTRIGGER:
                    532:        case SNDCTL_DSP_SETTRIGGER:
                    533:                /* XXX Do nothing for now. */
                    534:                INTARG = PCM_ENABLE_OUTPUT;
                    535:                break;
                    536: #endif
                    537:        case SNDCTL_DSP_GETIPTR:
                    538:                retval = ioctl(fd, AUDIO_GETIOFFS, &tmpoffs);
                    539:                if (retval < 0)
                    540:                        return retval;
                    541:                cntinfo.bytes = tmpoffs.samples;
                    542:                cntinfo.blocks = tmpoffs.deltablks;
                    543:                cntinfo.ptr = tmpoffs.offset;
                    544:                *(struct count_info *)argp = cntinfo;
                    545:                break;
                    546:        case SNDCTL_DSP_GETOPTR:
                    547:                retval = ioctl(fd, AUDIO_GETOOFFS, &tmpoffs);
                    548:                if (retval < 0)
                    549:                        return retval;
                    550:                cntinfo.bytes = tmpoffs.samples;
                    551:                cntinfo.blocks = tmpoffs.deltablks;
                    552:                cntinfo.ptr = tmpoffs.offset;
                    553:                *(struct count_info *)argp = cntinfo;
                    554:                break;
1.29      nat       555:        case SNDCTL_SYSINFO:
1.32      maya      556:                strlcpy(tmpsysinfo.product, "OSS/NetBSD",
                    557:                    sizeof tmpsysinfo.product);
1.31      maya      558:                strlcpy(tmpsysinfo.version, version, sizeof tmpsysinfo.version);
                    559:                strlcpy(tmpsysinfo.license, license, sizeof tmpsysinfo.license);
1.29      nat       560:                tmpsysinfo.versionnum = SOUND_VERSION;
                    561:                memset(tmpsysinfo.options, 0, 8);
                    562:                tmpsysinfo.numaudios = OSS_MAX_AUDIO_DEVS;
                    563:                tmpsysinfo.numaudioengines = 1;
1.34      mrg       564:                memset(tmpsysinfo.openedaudio, 0, sizeof(tmpsysinfo.openedaudio));
1.29      nat       565:                tmpsysinfo.numsynths = 1;
                    566:                tmpsysinfo.nummidis = -1;
                    567:                tmpsysinfo.numtimers = -1;
                    568:                tmpsysinfo.nummixers = 1;
                    569:                tmpsysinfo.numcards = 1;
1.34      mrg       570:                memset(tmpsysinfo.openedmidi, 0, sizeof(tmpsysinfo.openedmidi));
1.29      nat       571:                *(struct oss_sysinfo *)argp = tmpsysinfo;
                    572:                break;
                    573:        case SNDCTL_ENGINEINFO:
                    574:        case SNDCTL_AUDIOINFO:
                    575:                devno = 0;
                    576:                tmpaudioinfo = (struct oss_audioinfo*)argp;
                    577:                if (tmpaudioinfo == NULL)
                    578:                        return EINVAL;
                    579:                if (tmpaudioinfo->dev < 0) {
                    580:                        fstat(fd, &tmpstat);
                    581:                        if ((tmpstat.st_rdev & 0xff00) == 0x2a00)
                    582:                                devno = tmpstat.st_rdev & 0xff;
                    583:                        if (devno >= 0x80)
                    584:                                tmpaudioinfo->dev = devno & 0x7f;
                    585:                }
                    586:                if (tmpaudioinfo->dev < 0)
                    587:                        tmpaudioinfo->dev = 0;
                    588:
                    589:                snprintf(tmpaudioinfo->devnode, OSS_DEVNODE_SIZE,
                    590:                    "/dev/audio%d", tmpaudioinfo->dev);
                    591:
                    592:                retval = ioctl(fd, AUDIO_GETDEV, &tmpaudiodev);
                    593:                if (retval < 0)
                    594:                        return retval;
                    595:                retval = ioctl(fd, AUDIO_GETINFO, &tmpinfo);
                    596:                if (retval < 0)
                    597:                        return retval;
                    598:                retval = ioctl(fd, AUDIO_GETPROPS, &idata);
                    599:                if (retval < 0)
                    600:                        return retval;
                    601:                idat = DSP_CAP_TRIGGER; /* pretend we have trigger */
                    602:                if (idata & AUDIO_PROP_FULLDUPLEX)
                    603:                        idat |= DSP_CAP_DUPLEX;
                    604:                if (idata & AUDIO_PROP_MMAP)
                    605:                        idat |= DSP_CAP_MMAP;
                    606:                idat = PCM_CAP_INPUT | PCM_CAP_OUTPUT;
1.31      maya      607:                strlcpy(tmpaudioinfo->name, tmpaudiodev.name,
                    608:                    sizeof tmpaudioinfo->name);
1.29      nat       609:                tmpaudioinfo->busy = tmpinfo.play.open;
                    610:                tmpaudioinfo->pid = -1;
                    611:                tmpaudioinfo->caps = idat;
                    612:                ioctl(fd, SNDCTL_DSP_GETFMTS, &tmpaudioinfo->iformats);
                    613:                tmpaudioinfo->oformats = tmpaudioinfo->iformats;
                    614:                tmpaudioinfo->magic = -1;
                    615:                memset(tmpaudioinfo->cmd, 0, 64);
                    616:                tmpaudioinfo->card_number = -1;
                    617:                memset(tmpaudioinfo->song_name, 0, 64);
                    618:                memset(tmpaudioinfo->label, 0, 16);
                    619:                tmpaudioinfo->port_number = tmpinfo.play.port;
                    620:                tmpaudioinfo->mixer_dev = tmpaudioinfo->dev;
                    621:                tmpaudioinfo->legacy_device = -1;
                    622:                tmpaudioinfo->enabled = 1;
                    623:                tmpaudioinfo->flags = -1;
                    624:                tmpaudioinfo->min_rate = tmpinfo.play.sample_rate;
                    625:                tmpaudioinfo->max_rate = tmpinfo.play.sample_rate;
                    626:                tmpaudioinfo->nrates = 2;
                    627:                for (i = 0; i < tmpaudioinfo->nrates; i++)
                    628:                        tmpaudioinfo->rates[i] = tmpinfo.play.sample_rate;
                    629:                tmpaudioinfo->min_channels = tmpinfo.play.channels;
                    630:                tmpaudioinfo->max_channels = tmpinfo.play.channels;
                    631:                tmpaudioinfo->binding = -1;
                    632:                tmpaudioinfo->rate_source = -1;
                    633:                memset(tmpaudioinfo->handle, 0, 16);
                    634:                tmpaudioinfo->next_play_engine = 0;
                    635:                tmpaudioinfo->next_rec_engine = 0;
                    636:                argp = tmpaudioinfo;
                    637:                break;
                    638:        case SNDCTL_DSP_GETPLAYVOL:
                    639:                retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
                    640:                if (retval < 0)
                    641:                        return retval;
                    642:                *(uint *)argp = tmpinfo.play.gain;
                    643:                break;
                    644:        case SNDCTL_DSP_SETPLAYVOL:
                    645:                retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
                    646:                if (retval < 0)
                    647:                        return retval;
                    648:                if (*(uint *)argp > 255)
                    649:                        tmpinfo.play.gain = 255;
                    650:                else
                    651:                        tmpinfo.play.gain = *(uint *)argp;
                    652:                retval = ioctl(fd, AUDIO_SETINFO, &tmpinfo);
                    653:                if (retval < 0)
                    654:                        return retval;
                    655:                break;
                    656:        case SNDCTL_DSP_GETRECVOL:
                    657:                retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
                    658:                if (retval < 0)
                    659:                        return retval;
                    660:                *(uint *)argp = tmpinfo.record.gain;
                    661:                break;
                    662:        case SNDCTL_DSP_SETRECVOL:
                    663:                retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
                    664:                if (retval < 0)
                    665:                        return retval;
                    666:                if (*(uint *)argp > 255)
                    667:                        tmpinfo.record.gain = 255;
                    668:                else
                    669:                        tmpinfo.record.gain = *(uint *)argp;
                    670:                retval = ioctl(fd, AUDIO_SETINFO, &tmpinfo);
                    671:                if (retval < 0)
                    672:                        return retval;
                    673:                break;
                    674:        case SNDCTL_DSP_SKIP:
                    675:        case SNDCTL_DSP_SILENCE:
                    676:                return EINVAL;
1.17      jdolecek  677:        case SNDCTL_DSP_SETDUPLEX:
                    678:                idat = 1;
                    679:                retval = ioctl(fd, AUDIO_SETFD, &idat);
                    680:                if (retval < 0)
                    681:                        return retval;
                    682:                break;
1.22      mlelstv   683:        case SNDCTL_DSP_GETODELAY:
                    684:                retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
                    685:                if (retval < 0)
                    686:                        return retval;
                    687:                idat = tmpinfo.play.seek + tmpinfo.blocksize / 2;
                    688:                INTARG = idat;
                    689:                break;
                    690:        case SNDCTL_DSP_PROFILE:
                    691:                /* This gives just a hint to the driver,
                    692:                 * implementing it as a NOP is ok
                    693:                 */
                    694:                break;
1.1       augustss  695:        case SNDCTL_DSP_MAPINBUF:
                    696:        case SNDCTL_DSP_MAPOUTBUF:
                    697:        case SNDCTL_DSP_SETSYNCRO:
                    698:                errno = EINVAL;
                    699:                return -1; /* XXX unimplemented */
                    700:        default:
                    701:                errno = EINVAL;
                    702:                return -1;
                    703:        }
                    704:
                    705:        return 0;
                    706: }
                    707:
                    708:
1.11      augustss  709: /* If the NetBSD mixer device should have more than NETBSD_MAXDEVS devices
1.1       augustss  710:  * some will not be available to Linux */
1.11      augustss  711: #define NETBSD_MAXDEVS 64
1.1       augustss  712: struct audiodevinfo {
                    713:        int done;
                    714:        dev_t dev;
1.8       simonb    715:        int16_t devmap[SOUND_MIXER_NRDEVICES],
1.1       augustss  716:                rdevmap[NETBSD_MAXDEVS];
1.11      augustss  717:        char names[NETBSD_MAXDEVS][MAX_AUDIO_DEV_LEN];
                    718:        int enum2opaque[NETBSD_MAXDEVS];
1.1       augustss  719:         u_long devmask, recmask, stereomask;
1.20      lukem     720:        u_long caps;
                    721:        int source;
1.1       augustss  722: };
                    723:
1.11      augustss  724: static int
                    725: opaque_to_enum(struct audiodevinfo *di, audio_mixer_name_t *label, int opq)
                    726: {
                    727:        int i, o;
                    728:
                    729:        for (i = 0; i < NETBSD_MAXDEVS; i++) {
                    730:                o = di->enum2opaque[i];
                    731:                if (o == opq)
                    732:                        break;
                    733:                if (o == -1 && label != NULL &&
                    734:                    !strncmp(di->names[i], label->name, sizeof di->names[i])) {
                    735:                        di->enum2opaque[i] = opq;
                    736:                        break;
                    737:                }
                    738:        }
                    739:        if (i >= NETBSD_MAXDEVS)
                    740:                i = -1;
                    741:        /*printf("opq_to_enum %s %d -> %d\n", label->name, opq, i);*/
                    742:        return (i);
                    743: }
                    744:
                    745: static int
                    746: enum_to_ord(struct audiodevinfo *di, int enm)
                    747: {
                    748:        if (enm >= NETBSD_MAXDEVS)
                    749:                return (-1);
                    750:
                    751:        /*printf("enum_to_ord %d -> %d\n", enm, di->enum2opaque[enm]);*/
                    752:        return (di->enum2opaque[enm]);
                    753: }
                    754:
                    755: static int
                    756: enum_to_mask(struct audiodevinfo *di, int enm)
                    757: {
                    758:        int m;
                    759:        if (enm >= NETBSD_MAXDEVS)
                    760:                return (0);
                    761:
                    762:        m = di->enum2opaque[enm];
                    763:        if (m == -1)
                    764:                m = 0;
                    765:        /*printf("enum_to_mask %d -> %d\n", enm, di->enum2opaque[enm]);*/
                    766:        return (m);
                    767: }
                    768:
1.8       simonb    769: /*
1.1       augustss  770:  * Collect the audio device information to allow faster
                    771:  * emulation of the Linux mixer ioctls.  Cache the information
                    772:  * to eliminate the overhead of repeating all the ioctls needed
                    773:  * to collect the information.
                    774:  */
                    775: static struct audiodevinfo *
                    776: getdevinfo(int fd)
                    777: {
                    778:        mixer_devinfo_t mi;
1.11      augustss  779:        int i, j, e;
1.1       augustss  780:        static struct {
1.28      christos  781:                const char *name;
1.1       augustss  782:                int code;
                    783:        } *dp, devs[] = {
                    784:                { AudioNmicrophone,     SOUND_MIXER_MIC },
                    785:                { AudioNline,           SOUND_MIXER_LINE },
                    786:                { AudioNcd,             SOUND_MIXER_CD },
                    787:                { AudioNdac,            SOUND_MIXER_PCM },
1.15      kim       788:                { AudioNaux,            SOUND_MIXER_LINE1 },
1.1       augustss  789:                { AudioNrecord,         SOUND_MIXER_IMIX },
                    790:                { AudioNmaster,         SOUND_MIXER_VOLUME },
                    791:                { AudioNtreble,         SOUND_MIXER_TREBLE },
                    792:                { AudioNbass,           SOUND_MIXER_BASS },
                    793:                { AudioNspeaker,        SOUND_MIXER_SPEAKER },
                    794: /*             { AudioNheadphone,      ?? },*/
                    795:                { AudioNoutput,         SOUND_MIXER_OGAIN },
                    796:                { AudioNinput,          SOUND_MIXER_IGAIN },
                    797: /*             { AudioNmaster,         SOUND_MIXER_SPEAKER },*/
                    798: /*             { AudioNstereo,         ?? },*/
                    799: /*             { AudioNmono,           ?? },*/
                    800:                { AudioNfmsynth,        SOUND_MIXER_SYNTH },
                    801: /*             { AudioNwave,           SOUND_MIXER_PCM },*/
                    802:                { AudioNmidi,           SOUND_MIXER_SYNTH },
                    803: /*             { AudioNmixerout,       ?? },*/
                    804:                { 0, -1 }
                    805:        };
1.28      christos  806:        static struct audiodevinfo devcache = { .done = 0 };
1.1       augustss  807:        struct audiodevinfo *di = &devcache;
                    808:        struct stat sb;
1.27      christos  809:        size_t mlen, dlen;
1.1       augustss  810:
                    811:        /* Figure out what device it is so we can check if the
                    812:         * cached data is valid.
                    813:         */
                    814:        if (fstat(fd, &sb) < 0)
                    815:                return 0;
                    816:        if (di->done && di->dev == sb.st_dev)
                    817:                return di;
                    818:
                    819:        di->done = 1;
                    820:        di->dev = sb.st_dev;
                    821:        di->devmask = 0;
                    822:        di->recmask = 0;
                    823:        di->stereomask = 0;
1.11      augustss  824:        di->source = ~0;
1.1       augustss  825:        di->caps = 0;
                    826:        for(i = 0; i < SOUND_MIXER_NRDEVICES; i++)
                    827:                di->devmap[i] = -1;
1.11      augustss  828:        for(i = 0; i < NETBSD_MAXDEVS; i++) {
1.1       augustss  829:                di->rdevmap[i] = -1;
1.11      augustss  830:                di->names[i][0] = '\0';
                    831:                di->enum2opaque[i] = -1;
                    832:        }
1.1       augustss  833:        for(i = 0; i < NETBSD_MAXDEVS; i++) {
                    834:                mi.index = i;
                    835:                if (ioctl(fd, AUDIO_MIXER_DEVINFO, &mi) < 0)
                    836:                        break;
                    837:                switch(mi.type) {
                    838:                case AUDIO_MIXER_VALUE:
1.19      kent      839:                        for(dp = devs; dp->name; dp++) {
                    840:                                if (strcmp(dp->name, mi.label.name) == 0)
1.1       augustss  841:                                        break;
1.19      kent      842:                                dlen = strlen(dp->name);
                    843:                                mlen = strlen(mi.label.name);
                    844:                                if (dlen < mlen
                    845:                                    && mi.label.name[mlen-dlen-1] == '.'
1.27      christos  846:                                    && strcmp(dp->name,
                    847:                                    mi.label.name + mlen - dlen) == 0)
1.19      kent      848:                                        break;
                    849:                        }
1.1       augustss  850:                        if (dp->code >= 0) {
                    851:                                di->devmap[dp->code] = i;
                    852:                                di->rdevmap[i] = dp->code;
                    853:                                di->devmask |= 1 << dp->code;
                    854:                                if (mi.un.v.num_channels == 2)
                    855:                                        di->stereomask |= 1 << dp->code;
1.31      maya      856:                                strlcpy(di->names[i], mi.label.name,
1.11      augustss  857:                                        sizeof di->names[i]);
1.1       augustss  858:                        }
                    859:                        break;
1.11      augustss  860:                }
                    861:        }
                    862:        for(i = 0; i < NETBSD_MAXDEVS; i++) {
                    863:                mi.index = i;
                    864:                if (ioctl(fd, AUDIO_MIXER_DEVINFO, &mi) < 0)
                    865:                        break;
                    866:                if (strcmp(mi.label.name, AudioNsource) != 0)
                    867:                        continue;
                    868:                di->source = i;
                    869:                switch(mi.type) {
1.1       augustss  870:                case AUDIO_MIXER_ENUM:
1.11      augustss  871:                        for(j = 0; j < mi.un.e.num_mem; j++) {
                    872:                                e = opaque_to_enum(di,
                    873:                                                   &mi.un.e.member[j].label,
                    874:                                                   mi.un.e.member[j].ord);
                    875:                                if (e >= 0)
                    876:                                        di->recmask |= 1 << di->rdevmap[e];
1.1       augustss  877:                        }
1.11      augustss  878:                        di->caps = SOUND_CAP_EXCL_INPUT;
1.1       augustss  879:                        break;
                    880:                case AUDIO_MIXER_SET:
1.11      augustss  881:                        for(j = 0; j < mi.un.s.num_mem; j++) {
                    882:                                e = opaque_to_enum(di,
                    883:                                                   &mi.un.s.member[j].label,
                    884:                                                   mi.un.s.member[j].mask);
                    885:                                if (e >= 0)
                    886:                                        di->recmask |= 1 << di->rdevmap[e];
1.1       augustss  887:                        }
                    888:                        break;
                    889:                }
                    890:        }
                    891:        return di;
                    892: }
                    893:
                    894: int
                    895: mixer_ioctl(int fd, unsigned long com, void *argp)
1.8       simonb    896: {
1.1       augustss  897:        struct audiodevinfo *di;
1.10      augustss  898:        struct mixer_info *omi;
                    899:        struct audio_device adev;
1.1       augustss  900:        mixer_ctrl_t mc;
1.27      christos  901:        u_long idat, n;
1.1       augustss  902:        int i;
                    903:        int retval;
1.27      christos  904:        int l, r, error, e;
1.1       augustss  905:
1.20      lukem     906:        idat = 0;
1.1       augustss  907:        di = getdevinfo(fd);
                    908:        if (di == 0)
                    909:                return -1;
                    910:
                    911:        switch (com) {
1.11      augustss  912:         case OSS_GETVERSION:
                    913:                 idat = SOUND_VERSION;
                    914:                 break;
1.10      augustss  915:        case SOUND_MIXER_INFO:
                    916:        case SOUND_OLD_MIXER_INFO:
                    917:                error = ioctl(fd, AUDIO_GETDEV, &adev);
                    918:                if (error)
                    919:                        return (error);
                    920:                omi = argp;
                    921:                if (com == SOUND_MIXER_INFO)
                    922:                        omi->modify_counter = 1;
1.31      maya      923:                strlcpy(omi->id, adev.name, sizeof omi->id);
                    924:                strlcpy(omi->name, adev.name, sizeof omi->name);
1.10      augustss  925:                return 0;
1.1       augustss  926:        case SOUND_MIXER_READ_RECSRC:
                    927:                if (di->source == -1)
                    928:                        return EINVAL;
                    929:                mc.dev = di->source;
                    930:                if (di->caps & SOUND_CAP_EXCL_INPUT) {
                    931:                        mc.type = AUDIO_MIXER_ENUM;
                    932:                        retval = ioctl(fd, AUDIO_MIXER_READ, &mc);
                    933:                        if (retval < 0)
                    934:                                return retval;
1.11      augustss  935:                        e = opaque_to_enum(di, NULL, mc.un.ord);
                    936:                        if (e >= 0)
                    937:                                idat = 1 << di->rdevmap[e];
1.1       augustss  938:                } else {
                    939:                        mc.type = AUDIO_MIXER_SET;
                    940:                        retval = ioctl(fd, AUDIO_MIXER_READ, &mc);
                    941:                        if (retval < 0)
                    942:                                return retval;
1.11      augustss  943:                        e = opaque_to_enum(di, NULL, mc.un.mask);
                    944:                        if (e >= 0)
                    945:                                idat = 1 << di->rdevmap[e];
1.1       augustss  946:                }
                    947:                break;
                    948:        case SOUND_MIXER_READ_DEVMASK:
                    949:                idat = di->devmask;
                    950:                break;
                    951:        case SOUND_MIXER_READ_RECMASK:
                    952:                idat = di->recmask;
                    953:                break;
                    954:        case SOUND_MIXER_READ_STEREODEVS:
                    955:                idat = di->stereomask;
                    956:                break;
                    957:        case SOUND_MIXER_READ_CAPS:
                    958:                idat = di->caps;
                    959:                break;
                    960:        case SOUND_MIXER_WRITE_RECSRC:
                    961:        case SOUND_MIXER_WRITE_R_RECSRC:
                    962:                if (di->source == -1)
                    963:                        return EINVAL;
                    964:                mc.dev = di->source;
                    965:                idat = INTARG;
                    966:                if (di->caps & SOUND_CAP_EXCL_INPUT) {
                    967:                        mc.type = AUDIO_MIXER_ENUM;
                    968:                        for(i = 0; i < SOUND_MIXER_NRDEVICES; i++)
                    969:                                if (idat & (1 << i))
                    970:                                        break;
                    971:                        if (i >= SOUND_MIXER_NRDEVICES ||
                    972:                            di->devmap[i] == -1)
                    973:                                return EINVAL;
1.11      augustss  974:                        mc.un.ord = enum_to_ord(di, di->devmap[i]);
1.1       augustss  975:                } else {
                    976:                        mc.type = AUDIO_MIXER_SET;
                    977:                        mc.un.mask = 0;
                    978:                        for(i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
                    979:                                if (idat & (1 << i)) {
                    980:                                        if (di->devmap[i] == -1)
                    981:                                                return EINVAL;
1.27      christos  982:                                        mc.un.mask |=
                    983:                                            enum_to_mask(di, di->devmap[i]);
1.1       augustss  984:                                }
                    985:                        }
                    986:                }
                    987:                return ioctl(fd, AUDIO_MIXER_WRITE, &mc);
                    988:        default:
                    989:                if (MIXER_READ(SOUND_MIXER_FIRST) <= com &&
                    990:                    com < MIXER_READ(SOUND_MIXER_NRDEVICES)) {
                    991:                        n = GET_DEV(com);
                    992:                        if (di->devmap[n] == -1)
                    993:                                return EINVAL;
                    994:                        mc.dev = di->devmap[n];
                    995:                        mc.type = AUDIO_MIXER_VALUE;
                    996:                    doread:
1.27      christos  997:                        mc.un.value.num_channels =
                    998:                            di->stereomask & (1 << (u_int)n) ? 2 : 1;
1.1       augustss  999:                        retval = ioctl(fd, AUDIO_MIXER_READ, &mc);
                   1000:                        if (retval < 0)
                   1001:                                return retval;
                   1002:                        if (mc.type != AUDIO_MIXER_VALUE)
                   1003:                                return EINVAL;
                   1004:                        if (mc.un.value.num_channels != 2) {
1.27      christos 1005:                                l = r =
                   1006:                                    mc.un.value.level[AUDIO_MIXER_LEVEL_MONO];
1.1       augustss 1007:                        } else {
                   1008:                                l = mc.un.value.level[AUDIO_MIXER_LEVEL_LEFT];
                   1009:                                r = mc.un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
                   1010:                        }
                   1011:                        idat = TO_OSSVOL(l) | (TO_OSSVOL(r) << 8);
                   1012:                        break;
                   1013:                } else if ((MIXER_WRITE_R(SOUND_MIXER_FIRST) <= com &&
                   1014:                           com < MIXER_WRITE_R(SOUND_MIXER_NRDEVICES)) ||
                   1015:                           (MIXER_WRITE(SOUND_MIXER_FIRST) <= com &&
                   1016:                           com < MIXER_WRITE(SOUND_MIXER_NRDEVICES))) {
                   1017:                        n = GET_DEV(com);
                   1018:                        if (di->devmap[n] == -1)
                   1019:                                return EINVAL;
                   1020:                        idat = INTARG;
1.27      christos 1021:                        l = FROM_OSSVOL((u_int)idat & 0xff);
1.26      christos 1022:                        r = FROM_OSSVOL(((u_int)idat >> 8) & 0xff);
1.1       augustss 1023:                        mc.dev = di->devmap[n];
                   1024:                        mc.type = AUDIO_MIXER_VALUE;
1.27      christos 1025:                        if (di->stereomask & (1 << (u_int)n)) {
1.1       augustss 1026:                                mc.un.value.num_channels = 2;
                   1027:                                mc.un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
                   1028:                                mc.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
                   1029:                        } else {
                   1030:                                mc.un.value.num_channels = 1;
1.27      christos 1031:                                mc.un.value.level[AUDIO_MIXER_LEVEL_MONO] =
                   1032:                                    (l + r) / 2;
1.1       augustss 1033:                        }
                   1034:                        retval = ioctl(fd, AUDIO_MIXER_WRITE, &mc);
                   1035:                        if (retval < 0)
                   1036:                                return retval;
                   1037:                        if (MIXER_WRITE(SOUND_MIXER_FIRST) <= com &&
                   1038:                           com < MIXER_WRITE(SOUND_MIXER_NRDEVICES))
                   1039:                                return 0;
                   1040:                        goto doread;
                   1041:                } else {
                   1042:                        errno = EINVAL;
                   1043:                        return -1;
                   1044:                }
                   1045:        }
1.27      christos 1046:        INTARG = (int)idat;
1.1       augustss 1047:        return 0;
                   1048: }
                   1049:
                   1050: /*
1.41    ! nia      1051:  * When AUDIO_SETINFO fails to set a channel count, the application's chosen
        !          1052:  * number is out of range of what the kernel allows.
        !          1053:  *
        !          1054:  * When this happens, we use the current hardware settings. This is just in
        !          1055:  * case an application is abusing SNDCTL_DSP_CHANNELS - OSSv4 always sets and
        !          1056:  * returns a reasonable value, even if it wasn't what the user requested.
        !          1057:  *
        !          1058:  * XXX: If a device is opened for both playback and recording, and supports
        !          1059:  * fewer channels for recording than playback, applications that do both will
        !          1060:  * behave very strangely. OSS doesn't allow for reporting separate channel
        !          1061:  * counts for recording and playback. This could be worked around by always
        !          1062:  * mixing recorded data up to the same number of channels as is being used
        !          1063:  * for playback.
        !          1064:  */
        !          1065: static void
        !          1066: setchannels(int fd, int mode, int nchannels)
        !          1067: {
        !          1068:        struct audio_info tmpinfo, hwfmt;
        !          1069:
        !          1070:        if (ioctl(fd, AUDIO_GETFORMAT, &hwfmt) < 0) {
        !          1071:                errno = 0;
        !          1072:                hwfmt.record.channels = hwfmt.play.channels = 2;
        !          1073:        }
        !          1074:
        !          1075:        if (mode & AUMODE_PLAY) {
        !          1076:                AUDIO_INITINFO(&tmpinfo);
        !          1077:                tmpinfo.play.channels = nchannels;
        !          1078:                if (ioctl(fd, AUDIO_SETINFO, &tmpinfo) < 0) {
        !          1079:                        errno = 0;
        !          1080:                        AUDIO_INITINFO(&tmpinfo);
        !          1081:                        tmpinfo.play.channels = hwfmt.play.channels;
        !          1082:                        (void)ioctl(fd, AUDIO_SETINFO, &tmpinfo);
        !          1083:                }
        !          1084:        }
        !          1085:
        !          1086:        if (mode & AUMODE_RECORD) {
        !          1087:                AUDIO_INITINFO(&tmpinfo);
        !          1088:                tmpinfo.record.channels = nchannels;
        !          1089:                if (ioctl(fd, AUDIO_SETINFO, &tmpinfo) < 0) {
        !          1090:                        errno = 0;
        !          1091:                        AUDIO_INITINFO(&tmpinfo);
        !          1092:                        tmpinfo.record.channels = hwfmt.record.channels;
        !          1093:                        (void)ioctl(fd, AUDIO_SETINFO, &tmpinfo);
        !          1094:                }
        !          1095:        }
        !          1096: }
        !          1097:
        !          1098: /*
1.1       augustss 1099:  * Check that the blocksize is a power of 2 as OSS wants.
                   1100:  * If not, set it to be.
                   1101:  */
1.8       simonb   1102: static void
1.1       augustss 1103: setblocksize(int fd, struct audio_info *info)
                   1104: {
                   1105:        struct audio_info set;
1.28      christos 1106:        size_t s;
1.1       augustss 1107:
                   1108:        if (info->blocksize & (info->blocksize-1)) {
                   1109:                for(s = 32; s < info->blocksize; s <<= 1)
                   1110:                        ;
                   1111:                AUDIO_INITINFO(&set);
                   1112:                set.blocksize = s;
                   1113:                ioctl(fd, AUDIO_SETINFO, &set);
1.21      joerg    1114:                ioctl(fd, AUDIO_GETBUFINFO, info);
1.1       augustss 1115:        }
                   1116: }

CVSweb <webmaster@jp.NetBSD.org>