[BACK]Return to pad.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / dev / pad

Annotation of src/sys/dev/pad/pad.c, Revision 1.23

1.23    ! nat         1: /* $NetBSD: pad.c,v 1.22 2014/11/18 01:53:17 jmcneill Exp $ */
1.1       jmcneill    2:
                      3: /*-
                      4:  * Copyright (c) 2007 Jared D. McNeill <jmcneill@invisible.ca>
                      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:  */
                     28:
                     29: #include <sys/cdefs.h>
1.23    ! nat        30: __KERNEL_RCSID(0, "$NetBSD: pad.c,v 1.22 2014/11/18 01:53:17 jmcneill Exp $");
1.1       jmcneill   31:
                     32: #include <sys/types.h>
                     33: #include <sys/param.h>
                     34: #include <sys/conf.h>
                     35: #include <sys/buf.h>
                     36: #include <sys/kmem.h>
                     37: #include <sys/kernel.h>
                     38: #include <sys/device.h>
                     39: #include <sys/proc.h>
                     40: #include <sys/condvar.h>
                     41: #include <sys/select.h>
                     42: #include <sys/audioio.h>
1.5       dyoung     43: #include <sys/vnode.h>
1.13      ahoka      44: #include <sys/module.h>
1.17      jmcneill   45: #include <sys/atomic.h>
1.1       jmcneill   46:
                     47: #include <dev/audio_if.h>
                     48: #include <dev/audiovar.h>
                     49: #include <dev/auconv.h>
1.22      jmcneill   50: #include <dev/auvolconv.h>
1.1       jmcneill   51:
1.2       jmcneill   52: #include <dev/pad/padvar.h>
                     53:
1.1       jmcneill   54: #define PADUNIT(x)     minor(x)
                     55:
                     56: extern struct cfdriver pad_cd;
                     57:
                     58: typedef struct pad_block {
                     59:        uint8_t         *pb_ptr;
                     60:        int             pb_len;
                     61: } pad_block_t;
                     62:
1.2       jmcneill   63: enum {
                     64:        PAD_OUTPUT_CLASS,
                     65:        PAD_INPUT_CLASS,
                     66:        PAD_OUTPUT_MASTER_VOLUME,
                     67:        PAD_INPUT_DAC_VOLUME,
                     68:        PAD_ENUM_LAST,
                     69: };
1.1       jmcneill   70:
1.10      christos   71: static int     pad_match(device_t, cfdata_t, void *);
1.5       dyoung     72: static void    pad_attach(device_t, device_t, void *);
                     73: static int     pad_detach(device_t, int);
                     74: static void    pad_childdet(device_t, device_t);
1.1       jmcneill   75:
                     76: static int     pad_query_encoding(void *, struct audio_encoding *);
                     77: static int     pad_set_params(void *, int, int,
                     78:                                audio_params_t *, audio_params_t *,
                     79:                                stream_filter_list_t *, stream_filter_list_t *);
                     80: static int     pad_start_output(void *, void *, int,
                     81:                                    void (*)(void *), void *);
                     82: static int     pad_start_input(void *, void *, int,
                     83:                                   void (*)(void *), void *);
                     84: static int     pad_halt_output(void *);
                     85: static int     pad_halt_input(void *);
                     86: static int     pad_getdev(void *, struct audio_device *);
                     87: static int     pad_set_port(void *, mixer_ctrl_t *);
                     88: static int     pad_get_port(void *, mixer_ctrl_t *);
                     89: static int     pad_query_devinfo(void *, mixer_devinfo_t *);
                     90: static int     pad_get_props(void *);
                     91: static int     pad_round_blocksize(void *, int, int, const audio_params_t *);
1.17      jmcneill   92: static void    pad_get_locks(void *, kmutex_t **, kmutex_t **);
1.1       jmcneill   93:
1.22      jmcneill   94: static stream_filter_t *pad_swvol_filter_le(struct audio_softc *,
                     95:     const audio_params_t *, const audio_params_t *);
                     96: static stream_filter_t *pad_swvol_filter_be(struct audio_softc *,
                     97:     const audio_params_t *, const audio_params_t *);
                     98: static void    pad_swvol_dtor(stream_filter_t *);
                     99:
1.1       jmcneill  100: static const struct audio_hw_if pad_hw_if = {
                    101:        .query_encoding = pad_query_encoding,
                    102:        .set_params = pad_set_params,
                    103:        .start_output = pad_start_output,
                    104:        .start_input = pad_start_input,
                    105:        .halt_output = pad_halt_output,
                    106:        .halt_input = pad_halt_input,
                    107:        .getdev = pad_getdev,
                    108:        .set_port = pad_set_port,
                    109:        .get_port = pad_get_port,
                    110:        .query_devinfo = pad_query_devinfo,
                    111:        .get_props = pad_get_props,
                    112:        .round_blocksize = pad_round_blocksize,
1.17      jmcneill  113:        .get_locks = pad_get_locks,
1.1       jmcneill  114: };
                    115:
                    116: #define PAD_NFORMATS   1
                    117: static const struct audio_format pad_formats[PAD_NFORMATS] = {
                    118:        { NULL, AUMODE_PLAY|AUMODE_RECORD, AUDIO_ENCODING_SLINEAR_LE, 16, 16,
                    119:          2, AUFMT_STEREO, 1, { 44100 } },
                    120: };
                    121:
                    122: extern void    padattach(int);
                    123:
                    124: static int             pad_add_block(pad_softc_t *, uint8_t *, int);
                    125: static int             pad_get_block(pad_softc_t *, pad_block_t *, int);
                    126:
                    127: dev_type_open(pad_open);
                    128: dev_type_close(pad_close);
                    129: dev_type_read(pad_read);
                    130:
                    131: const struct cdevsw pad_cdevsw = {
                    132:        .d_open = pad_open,
                    133:        .d_close = pad_close,
                    134:        .d_read = pad_read,
                    135:        .d_write = nowrite,
                    136:        .d_ioctl = noioctl,
                    137:        .d_stop = nostop,
                    138:        .d_tty = notty,
                    139:        .d_poll = nopoll,
                    140:        .d_mmap = nommap,
                    141:        .d_kqfilter = nokqfilter,
1.21      dholland  142:        .d_discard = nodiscard,
1.17      jmcneill  143:        .d_flag = D_OTHER | D_MPSAFE,
1.1       jmcneill  144: };
                    145:
1.10      christos  146: CFATTACH_DECL2_NEW(pad, sizeof(pad_softc_t), pad_match, pad_attach, pad_detach,
1.5       dyoung    147:     NULL, NULL, pad_childdet);
1.1       jmcneill  148:
                    149: void
                    150: padattach(int n)
                    151: {
                    152:        int i, err;
1.10      christos  153:        cfdata_t cf;
1.1       jmcneill  154:
1.11      ad        155:        aprint_debug("pad: requested %d units\n", n);
1.1       jmcneill  156:
                    157:        err = config_cfattach_attach(pad_cd.cd_name, &pad_ca);
                    158:        if (err) {
                    159:                aprint_error("%s: couldn't register cfattach: %d\n",
                    160:                    pad_cd.cd_name, err);
                    161:                config_cfdriver_detach(&pad_cd);
                    162:                return;
                    163:        }
                    164:
                    165:        for (i = 0; i < n; i++) {
1.17      jmcneill  166:                cf = kmem_alloc(sizeof(struct cfdata), KM_SLEEP);
1.1       jmcneill  167:                if (cf == NULL) {
                    168:                        aprint_error("%s: couldn't allocate cfdata\n",
                    169:                            pad_cd.cd_name);
                    170:                        continue;
                    171:                }
                    172:                cf->cf_name = pad_cd.cd_name;
                    173:                cf->cf_atname = pad_cd.cd_name;
                    174:                cf->cf_unit = i;
                    175:                cf->cf_fstate = FSTATE_STAR;
                    176:
                    177:                (void)config_attach_pseudo(cf);
                    178:        }
                    179:
                    180:        return;
                    181: }
                    182:
                    183: static int
                    184: pad_add_block(pad_softc_t *sc, uint8_t *blk, int blksize)
                    185: {
                    186:        int l;
                    187:
1.16      jmcneill  188:        if (sc->sc_open == 0)
                    189:                return EIO;
                    190:
1.17      jmcneill  191:        KASSERT(mutex_owned(&sc->sc_lock));
                    192:
1.1       jmcneill  193:        if (sc->sc_buflen + blksize > PAD_BUFSIZE)
                    194:                return ENOBUFS;
                    195:
                    196:        if (sc->sc_wpos + blksize <= PAD_BUFSIZE)
                    197:                memcpy(sc->sc_audiobuf + sc->sc_wpos, blk, blksize);
                    198:        else {
                    199:                l = PAD_BUFSIZE - sc->sc_wpos;
                    200:                memcpy(sc->sc_audiobuf + sc->sc_wpos, blk, l);
                    201:                memcpy(sc->sc_audiobuf, blk + l, blksize - l);
                    202:        }
                    203:
                    204:        sc->sc_wpos += blksize;
                    205:        if (sc->sc_wpos > PAD_BUFSIZE)
                    206:                sc->sc_wpos -= PAD_BUFSIZE;
                    207:
                    208:        sc->sc_buflen += blksize;
                    209:
                    210:        return 0;
                    211: }
                    212:
                    213: static int
                    214: pad_get_block(pad_softc_t *sc, pad_block_t *pb, int blksize)
                    215: {
                    216:        int l;
                    217:
1.17      jmcneill  218:        KASSERT(mutex_owned(&sc->sc_lock));
1.1       jmcneill  219:        KASSERT(pb != NULL);
                    220:
                    221:        if (sc->sc_buflen < blksize)
                    222:                return ERESTART;
                    223:
                    224:        pb->pb_ptr = (sc->sc_audiobuf + sc->sc_rpos);
                    225:        if (sc->sc_rpos + blksize < PAD_BUFSIZE) {
                    226:                pb->pb_len = blksize;
                    227:                sc->sc_rpos += blksize;
                    228:        } else {
                    229:                l = PAD_BUFSIZE - sc->sc_rpos;
                    230:                pb->pb_len = l;
                    231:                sc->sc_rpos = 0;
                    232:        }
                    233:        sc->sc_buflen -= pb->pb_len;
                    234:
                    235:        return 0;
                    236: }
                    237:
                    238: static int
1.10      christos  239: pad_match(device_t parent, cfdata_t data, void *opaque)
1.1       jmcneill  240: {
1.17      jmcneill  241:
1.1       jmcneill  242:        return 1;
                    243: }
                    244:
                    245: static void
1.5       dyoung    246: pad_childdet(device_t self, device_t child)
1.1       jmcneill  247: {
1.5       dyoung    248:        pad_softc_t *sc = device_private(self);
                    249:
                    250:        sc->sc_audiodev = NULL;
                    251: }
1.1       jmcneill  252:
1.5       dyoung    253: static void
                    254: pad_attach(device_t parent, device_t self, void *opaque)
                    255: {
                    256:        pad_softc_t *sc = device_private(self);
1.1       jmcneill  257:
                    258:        aprint_normal_dev(self, "outputs: 44100Hz, 16-bit, stereo\n");
                    259:
1.10      christos  260:        sc->sc_dev = self;
1.1       jmcneill  261:        sc->sc_open = 0;
                    262:        if (auconv_create_encodings(pad_formats, PAD_NFORMATS,
                    263:            &sc->sc_encodings) != 0) {
                    264:                aprint_error_dev(self, "couldn't create encodings\n");
                    265:                return;
                    266:        }
                    267:
                    268:        cv_init(&sc->sc_condvar, device_xname(self));
1.17      jmcneill  269:        mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
                    270:        mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_NONE);
1.1       jmcneill  271:
1.2       jmcneill  272:        sc->sc_swvol = 255;
1.1       jmcneill  273:        sc->sc_buflen = 0;
                    274:        sc->sc_rpos = sc->sc_wpos = 0;
1.10      christos  275:        sc->sc_audiodev = (void *)audio_attach_mi(&pad_hw_if, sc, sc->sc_dev);
1.1       jmcneill  276:
1.4       jmcneill  277:        if (!pmf_device_register(self, NULL, NULL))
                    278:                aprint_error_dev(self, "couldn't establish power handler\n");
                    279:
1.1       jmcneill  280:        return;
                    281: }
                    282:
1.5       dyoung    283: static int
                    284: pad_detach(device_t self, int flags)
                    285: {
                    286:        pad_softc_t *sc = device_private(self);
                    287:        int cmaj, mn, rc;
                    288:
                    289:        cmaj = cdevsw_lookup_major(&pad_cdevsw);
                    290:        mn = device_unit(self);
                    291:        vdevgone(cmaj, mn, mn, VCHR);
                    292:
                    293:        if ((rc = config_detach_children(self, flags)) != 0)
                    294:                return rc;
                    295:
                    296:        pmf_device_deregister(self);
                    297:
1.17      jmcneill  298:        mutex_destroy(&sc->sc_lock);
                    299:        mutex_destroy(&sc->sc_intr_lock);
1.5       dyoung    300:        cv_destroy(&sc->sc_condvar);
                    301:
                    302:        auconv_delete_encodings(sc->sc_encodings);
                    303:
                    304:        return 0;
                    305: }
                    306:
1.1       jmcneill  307: int
                    308: pad_open(dev_t dev, int flags, int fmt, struct lwp *l)
                    309: {
                    310:        pad_softc_t *sc;
                    311:
1.8       tsutsui   312:        sc = device_lookup_private(&pad_cd, PADUNIT(dev));
1.1       jmcneill  313:        if (sc == NULL)
1.12      dyoung    314:                return ENXIO;
1.1       jmcneill  315:
1.17      jmcneill  316:        if (atomic_swap_uint(&sc->sc_open, 1) != 0) {
1.1       jmcneill  317:                return EBUSY;
                    318:        }
                    319:
                    320:        return 0;
                    321: }
                    322:
                    323: int
                    324: pad_close(dev_t dev, int flags, int fmt, struct lwp *l)
                    325: {
                    326:        pad_softc_t *sc;
                    327:
1.8       tsutsui   328:        sc = device_lookup_private(&pad_cd, PADUNIT(dev));
1.1       jmcneill  329:        if (sc == NULL)
1.12      dyoung    330:                return ENXIO;
1.1       jmcneill  331:
                    332:        KASSERT(sc->sc_open > 0);
1.17      jmcneill  333:        sc->sc_open = 0;
1.1       jmcneill  334:
                    335:        return 0;
                    336: }
                    337:
                    338: int
                    339: pad_read(dev_t dev, struct uio *uio, int flags)
                    340: {
                    341:        pad_softc_t *sc;
                    342:        pad_block_t pb;
                    343:        void (*intr)(void *);
                    344:        void *intrarg;
                    345:        int err;
                    346:
1.8       tsutsui   347:        sc = device_lookup_private(&pad_cd, PADUNIT(dev));
1.1       jmcneill  348:        if (sc == NULL)
1.12      dyoung    349:                return ENXIO;
1.1       jmcneill  350:
                    351:        err = 0;
                    352:
1.17      jmcneill  353:        mutex_enter(&sc->sc_lock);
1.1       jmcneill  354:        intr = sc->sc_intr;
                    355:        intrarg = sc->sc_intrarg;
                    356:
1.23    ! nat       357:        kpreempt_disable();
1.1       jmcneill  358:        while (uio->uio_resid > 0 && !err) {
                    359:                err = pad_get_block(sc, &pb, min(uio->uio_resid, PAD_BLKSIZE));
1.17      jmcneill  360:                if (!err) {
                    361:                        mutex_exit(&sc->sc_lock);
1.1       jmcneill  362:                        err = uiomove(pb.pb_ptr, pb.pb_len, uio);
1.17      jmcneill  363:                        mutex_enter(&sc->sc_lock);
                    364:                        continue;
                    365:                }
1.1       jmcneill  366:
1.17      jmcneill  367:                if (intr) {
                    368:                        mutex_enter(&sc->sc_intr_lock);
                    369:                        (*intr)(intrarg);
                    370:                        mutex_exit(&sc->sc_intr_lock);
1.1       jmcneill  371:                        intr = sc->sc_intr;
                    372:                        intrarg = sc->sc_intrarg;
                    373:                        err = 0;
1.17      jmcneill  374:                        continue;
                    375:                }
                    376:                err = cv_wait_sig(&sc->sc_condvar, &sc->sc_lock);
                    377:                if (err != 0) {
                    378:                        mutex_exit(&sc->sc_lock);
1.23    ! nat       379:                        kpreempt_enable();
1.17      jmcneill  380:                        return err;
1.1       jmcneill  381:                }
1.17      jmcneill  382:                intr = sc->sc_intr;
                    383:                intrarg = sc->sc_intrarg;
1.1       jmcneill  384:        }
                    385:
1.17      jmcneill  386:        if (intr) {
                    387:                mutex_enter(&sc->sc_intr_lock);
1.1       jmcneill  388:                (*intr)(intrarg);
1.17      jmcneill  389:                mutex_exit(&sc->sc_intr_lock);
                    390:        }
                    391:        mutex_exit(&sc->sc_lock);
1.23    ! nat       392:        kpreempt_enable();
1.1       jmcneill  393:
                    394:        return err;
                    395: }
                    396:
                    397: static int
                    398: pad_query_encoding(void *opaque, struct audio_encoding *ae)
                    399: {
                    400:        pad_softc_t *sc;
                    401:
                    402:        sc = (pad_softc_t *)opaque;
                    403:
1.17      jmcneill  404:        KASSERT(mutex_owned(&sc->sc_lock));
                    405:
1.1       jmcneill  406:        return auconv_query_encoding(sc->sc_encodings, ae);
                    407: }
                    408:
                    409: static int
                    410: pad_set_params(void *opaque, int setmode, int usemode,
                    411:     audio_params_t *play, audio_params_t *rec,
                    412:     stream_filter_list_t *pfil, stream_filter_list_t *rfil)
                    413: {
1.20      christos  414:        pad_softc_t *sc __diagused;
1.1       jmcneill  415:
                    416:        sc = (pad_softc_t *)opaque;
                    417:
1.17      jmcneill  418:        KASSERT(mutex_owned(&sc->sc_lock));
                    419:
1.1       jmcneill  420:        if (auconv_set_converter(pad_formats, PAD_NFORMATS, AUMODE_PLAY,
                    421:            play, true, pfil) < 0)
                    422:                return EINVAL;
                    423:        if (auconv_set_converter(pad_formats, PAD_NFORMATS, AUMODE_RECORD,
                    424:            rec, true, rfil) < 0)
                    425:                return EINVAL;
                    426:
1.2       jmcneill  427:        if (pfil->req_size > 0)
                    428:                play = &pfil->filters[0].param;
                    429:        switch (play->encoding) {
                    430:        case AUDIO_ENCODING_SLINEAR_LE:
                    431:                if (play->precision == 16 && play->validbits == 16)
1.22      jmcneill  432:                        pfil->prepend(pfil, pad_swvol_filter_le, play);
1.2       jmcneill  433:                break;
                    434:        case AUDIO_ENCODING_SLINEAR_BE:
                    435:                if (play->precision == 16 && play->validbits == 16)
1.22      jmcneill  436:                        pfil->prepend(pfil, pad_swvol_filter_be, play);
1.2       jmcneill  437:                break;
                    438:        default:
                    439:                break;
                    440:        }
                    441:
1.1       jmcneill  442:        return 0;
                    443: }
                    444:
                    445: static int
                    446: pad_start_output(void *opaque, void *block, int blksize,
                    447:     void (*intr)(void *), void *intrarg)
                    448: {
                    449:        pad_softc_t *sc;
                    450:        int err;
                    451:
                    452:        sc = (pad_softc_t *)opaque;
                    453:
1.17      jmcneill  454:        KASSERT(mutex_owned(&sc->sc_lock));
1.1       jmcneill  455:
                    456:        sc->sc_intr = intr;
                    457:        sc->sc_intrarg = intrarg;
                    458:        sc->sc_blksize = blksize;
                    459:
                    460:        err = pad_add_block(sc, block, blksize);
                    461:
1.17      jmcneill  462:        cv_broadcast(&sc->sc_condvar);
1.1       jmcneill  463:
                    464:        return err;
                    465: }
                    466:
                    467: static int
                    468: pad_start_input(void *opaque, void *block, int blksize,
                    469:     void (*intr)(void *), void *intrarg)
                    470: {
1.20      christos  471:        pad_softc_t *sc __diagused;
1.17      jmcneill  472:
                    473:        sc = (pad_softc_t *)opaque;
                    474:
                    475:        KASSERT(mutex_owned(&sc->sc_lock));
                    476:
                    477:        return EOPNOTSUPP;
1.1       jmcneill  478: }
                    479:
                    480: static int
                    481: pad_halt_output(void *opaque)
                    482: {
                    483:        pad_softc_t *sc;
                    484:
                    485:        sc = (pad_softc_t *)opaque;
1.17      jmcneill  486:
                    487:        KASSERT(mutex_owned(&sc->sc_lock));
                    488:
1.1       jmcneill  489:        sc->sc_intr = NULL;
                    490:        sc->sc_intrarg = NULL;
                    491:        sc->sc_buflen = 0;
                    492:        sc->sc_rpos = sc->sc_wpos = 0;
                    493:
                    494:        return 0;
                    495: }
                    496:
                    497: static int
                    498: pad_halt_input(void *opaque)
                    499: {
1.20      christos  500:        pad_softc_t *sc __diagused;
1.17      jmcneill  501:
                    502:        sc = (pad_softc_t *)opaque;
                    503:
                    504:        KASSERT(mutex_owned(&sc->sc_lock));
                    505:
1.1       jmcneill  506:        return 0;
                    507: }
                    508:
                    509: static int
                    510: pad_getdev(void *opaque, struct audio_device *ret)
                    511: {
1.16      jmcneill  512:        strlcpy(ret->name, "Virtual Audio", sizeof(ret->name));
                    513:        strlcpy(ret->version, osrelease, sizeof(ret->version));
                    514:        strlcpy(ret->config, "pad", sizeof(ret->config));
1.1       jmcneill  515:
                    516:        return 0;
                    517: }
                    518:
                    519: static int
                    520: pad_set_port(void *opaque, mixer_ctrl_t *mc)
                    521: {
1.2       jmcneill  522:        pad_softc_t *sc;
                    523:
                    524:        sc = (pad_softc_t *)opaque;
                    525:
1.17      jmcneill  526:        KASSERT(mutex_owned(&sc->sc_lock));
                    527:
1.2       jmcneill  528:        switch (mc->dev) {
                    529:        case PAD_OUTPUT_MASTER_VOLUME:
                    530:        case PAD_INPUT_DAC_VOLUME:
                    531:                sc->sc_swvol = mc->un.value.level[AUDIO_MIXER_LEVEL_MONO];
                    532:                return 0;
                    533:        }
                    534:
1.1       jmcneill  535:        return ENXIO;
                    536: }
                    537:
                    538: static int
                    539: pad_get_port(void *opaque, mixer_ctrl_t *mc)
                    540: {
1.2       jmcneill  541:        pad_softc_t *sc;
                    542:
                    543:        sc = (pad_softc_t *)opaque;
                    544:
1.17      jmcneill  545:        KASSERT(mutex_owned(&sc->sc_lock));
                    546:
1.2       jmcneill  547:        switch (mc->dev) {
                    548:        case PAD_OUTPUT_MASTER_VOLUME:
                    549:        case PAD_INPUT_DAC_VOLUME:
                    550:                mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_swvol;
                    551:                return 0;
                    552:        }
                    553:
1.1       jmcneill  554:        return ENXIO;
                    555: }
                    556:
                    557: static int
                    558: pad_query_devinfo(void *opaque, mixer_devinfo_t *di)
                    559: {
1.20      christos  560:        pad_softc_t *sc __diagused;
1.2       jmcneill  561:
                    562:        sc = (pad_softc_t *)opaque;
                    563:
1.17      jmcneill  564:        KASSERT(mutex_owned(&sc->sc_lock));
                    565:
1.2       jmcneill  566:        switch (di->index) {
                    567:        case PAD_OUTPUT_CLASS:
                    568:                di->mixer_class = PAD_OUTPUT_CLASS;
                    569:                strcpy(di->label.name, AudioCoutputs);
                    570:                di->type = AUDIO_MIXER_CLASS;
                    571:                di->next = di->prev = AUDIO_MIXER_LAST;
                    572:                return 0;
                    573:        case PAD_INPUT_CLASS:
                    574:                di->mixer_class = PAD_INPUT_CLASS;
                    575:                strcpy(di->label.name, AudioCinputs);
                    576:                di->type = AUDIO_MIXER_CLASS;
                    577:                di->next = di->prev = AUDIO_MIXER_LAST;
                    578:                return 0;
                    579:        case PAD_OUTPUT_MASTER_VOLUME:
                    580:                di->mixer_class = PAD_OUTPUT_CLASS;
                    581:                strcpy(di->label.name, AudioNmaster);
                    582:                di->type = AUDIO_MIXER_VALUE;
                    583:                di->next = di->prev = AUDIO_MIXER_LAST;
                    584:                di->un.v.num_channels = 1;
                    585:                strcpy(di->un.v.units.name, AudioNvolume);
                    586:                return 0;
                    587:        case PAD_INPUT_DAC_VOLUME:
                    588:                di->mixer_class = PAD_INPUT_CLASS;
                    589:                strcpy(di->label.name, AudioNdac);
                    590:                di->type = AUDIO_MIXER_VALUE;
                    591:                di->next = di->prev = AUDIO_MIXER_LAST;
                    592:                di->un.v.num_channels = 1;
                    593:                strcpy(di->un.v.units.name, AudioNvolume);
                    594:                return 0;
                    595:        }
                    596:
1.1       jmcneill  597:        return ENXIO;
                    598: }
                    599:
                    600: static int
                    601: pad_get_props(void *opaque)
                    602: {
1.20      christos  603:        pad_softc_t *sc __diagused;
1.17      jmcneill  604:
                    605:        sc = (pad_softc_t *)opaque;
                    606:
                    607:        KASSERT(mutex_owned(&sc->sc_lock));
                    608:
1.1       jmcneill  609:        return 0;
                    610: }
                    611:
                    612: static int
                    613: pad_round_blocksize(void *opaque, int blksize, int mode,
                    614:     const audio_params_t *p)
                    615: {
1.20      christos  616:        pad_softc_t *sc __diagused;
1.17      jmcneill  617:
                    618:        sc = (pad_softc_t *)opaque;
                    619:        KASSERT(mutex_owned(&sc->sc_lock));
                    620:
1.1       jmcneill  621:        return PAD_BLKSIZE;
                    622: }
1.13      ahoka     623:
1.17      jmcneill  624: static void
                    625: pad_get_locks(void *opaque, kmutex_t **intr, kmutex_t **thread)
                    626: {
                    627:        pad_softc_t *sc;
                    628:
                    629:        sc = (pad_softc_t *)opaque;
                    630:
                    631:        *intr = &sc->sc_intr_lock;
                    632:        *thread = &sc->sc_lock;
                    633: }
                    634:
1.22      jmcneill  635: static stream_filter_t *
                    636: pad_swvol_filter_le(struct audio_softc *asc,
                    637:     const audio_params_t *from, const audio_params_t *to)
                    638: {
                    639:        auvolconv_filter_t *this;
                    640:        device_t dev = audio_get_device(asc);
                    641:        struct pad_softc *sc = device_private(dev);
                    642:
                    643:        this = kmem_alloc(sizeof(auvolconv_filter_t), KM_SLEEP);
                    644:        this->base.base.fetch_to = auvolconv_slinear16_le_fetch_to;
                    645:        this->base.dtor = pad_swvol_dtor;
                    646:        this->base.set_fetcher = stream_filter_set_fetcher;
                    647:        this->base.set_inputbuffer = stream_filter_set_inputbuffer;
                    648:        this->vol = &sc->sc_swvol;
                    649:
                    650:        return (stream_filter_t *)this;
                    651: }
                    652:
                    653: static stream_filter_t *
                    654: pad_swvol_filter_be(struct audio_softc *asc,
                    655:     const audio_params_t *from, const audio_params_t *to)
                    656: {
                    657:        auvolconv_filter_t *this;
                    658:        device_t dev = audio_get_device(asc);
                    659:        struct pad_softc *sc = device_private(dev);
                    660:
                    661:        this = kmem_alloc(sizeof(auvolconv_filter_t), KM_SLEEP);
                    662:        this->base.base.fetch_to = auvolconv_slinear16_be_fetch_to;
                    663:        this->base.dtor = pad_swvol_dtor;
                    664:        this->base.set_fetcher = stream_filter_set_fetcher;
                    665:        this->base.set_inputbuffer = stream_filter_set_inputbuffer;
                    666:        this->vol = &sc->sc_swvol;
                    667:
                    668:        return (stream_filter_t *)this;
                    669: }
                    670:
                    671: static void
                    672: pad_swvol_dtor(stream_filter_t *this)
                    673: {
                    674:        if (this)
                    675:                kmem_free(this, sizeof(auvolconv_filter_t));
                    676: }
                    677:
1.13      ahoka     678: #ifdef _MODULE
                    679:
                    680: MODULE(MODULE_CLASS_DRIVER, pad, NULL);
                    681:
                    682: static const struct cfiattrdata audiobuscf_iattrdata = {
                    683:        "audiobus", 0, { { NULL, NULL, 0 }, }
                    684: };
                    685: static const struct cfiattrdata * const pad_attrs[] = {
                    686:        &audiobuscf_iattrdata, NULL
                    687: };
                    688:
                    689: CFDRIVER_DECL(pad, DV_DULL, pad_attrs);
                    690: extern struct cfattach pad_ca;
                    691: static int padloc[] = { -1, -1 };
                    692:
                    693: static struct cfdata pad_cfdata[] = {
                    694:        {
                    695:                .cf_name = "pad",
                    696:                .cf_atname = "pad",
                    697:                .cf_unit = 0,
                    698:                .cf_fstate = FSTATE_STAR,
                    699:                .cf_loc = padloc,
                    700:                .cf_flags = 0,
                    701:                .cf_pspec = NULL,
                    702:        },
1.14      pooka     703:        { NULL, NULL, 0, 0, NULL, 0, NULL }
1.13      ahoka     704: };
                    705:
                    706: static int
                    707: pad_modcmd(modcmd_t cmd, void *arg)
                    708: {
                    709:        devmajor_t cmajor = NODEVMAJOR, bmajor = NODEVMAJOR;
1.19      agc       710:        int error;
1.13      ahoka     711:
                    712:        switch (cmd) {
                    713:        case MODULE_CMD_INIT:
                    714:                error = config_cfdriver_attach(&pad_cd);
                    715:                if (error) {
                    716:                        return error;
                    717:                }
                    718:
                    719:                error = config_cfattach_attach(pad_cd.cd_name, &pad_ca);
                    720:                if (error) {
                    721:                        config_cfdriver_detach(&pad_cd);
                    722:                        aprint_error("%s: unable to register cfattach\n",
                    723:                                pad_cd.cd_name);
                    724:
                    725:                        return error;
                    726:                }
                    727:
                    728:                error = config_cfdata_attach(pad_cfdata, 1);
                    729:                if (error) {
                    730:                        config_cfattach_detach(pad_cd.cd_name, &pad_ca);
                    731:                        config_cfdriver_detach(&pad_cd);
                    732:                        aprint_error("%s: unable to register cfdata\n",
                    733:                                pad_cd.cd_name);
                    734:
                    735:                        return error;
                    736:                }
                    737:
                    738:                error = devsw_attach(pad_cd.cd_name, NULL, &bmajor, &pad_cdevsw, &cmajor);
                    739:                if (error) {
                    740:                        error = config_cfdata_detach(pad_cfdata);
                    741:                        if (error) {
                    742:                                return error;
                    743:                        }
                    744:                        config_cfattach_detach(pad_cd.cd_name, &pad_ca);
                    745:                        config_cfdriver_detach(&pad_cd);
                    746:                        aprint_error("%s: unable to register devsw\n",
                    747:                                pad_cd.cd_name);
                    748:
                    749:                        return error;
                    750:                }
                    751:
                    752:                (void)config_attach_pseudo(pad_cfdata);
                    753:
                    754:                return 0;
                    755:        case MODULE_CMD_FINI:
                    756:                error = config_cfdata_detach(pad_cfdata);
                    757:                if (error) {
                    758:                        return error;
                    759:                }
                    760:
                    761:                config_cfattach_detach(pad_cd.cd_name, &pad_ca);
                    762:                config_cfdriver_detach(&pad_cd);
                    763:                devsw_detach(NULL, &pad_cdevsw);
                    764:
                    765:                return 0;
                    766:        default:
                    767:                return ENOTTY;
                    768:        }
                    769: }
                    770:
                    771: #endif

CVSweb <webmaster@jp.NetBSD.org>