[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.72

1.72    ! riastrad    1: /* $NetBSD: pad.c,v 1.71 2021/06/14 10:14:58 riastradh 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.72    ! riastrad   30: __KERNEL_RCSID(0, "$NetBSD: pad.c,v 1.71 2021/06/14 10:14:58 riastradh Exp $");
1.1       jmcneill   31:
1.70      riastrad   32: #include <sys/param.h>
1.1       jmcneill   33: #include <sys/types.h>
1.70      riastrad   34:
                     35: #include <sys/audioio.h>
                     36: #include <sys/buf.h>
                     37: #include <sys/condvar.h>
1.1       jmcneill   38: #include <sys/conf.h>
1.70      riastrad   39: #include <sys/device.h>
1.57      nakayama   40: #include <sys/file.h>
                     41: #include <sys/filedesc.h>
                     42: #include <sys/kauth.h>
1.70      riastrad   43: #include <sys/kernel.h>
1.1       jmcneill   44: #include <sys/kmem.h>
1.70      riastrad   45: #include <sys/module.h>
1.63      isaki      46: #include <sys/poll.h>
1.1       jmcneill   47: #include <sys/proc.h>
                     48: #include <sys/select.h>
1.57      nakayama   49: #include <sys/stat.h>
1.70      riastrad   50: #include <sys/vnode.h>
1.1       jmcneill   51:
1.59      isaki      52: #include <dev/audio/audio_if.h>
                     53: #include <dev/audio/audiovar.h>
1.1       jmcneill   54:
1.2       jmcneill   55: #include <dev/pad/padvar.h>
                     56:
1.71      riastrad   57: #include "ioconf.h"
                     58:
1.59      isaki      59: /* #define PAD_DEBUG */
                     60: #ifdef PAD_DEBUG
                     61: #define DPRINTF(fmt...)        printf(fmt)
                     62: #else
                     63: #define DPRINTF(fmt...) /**/
                     64: #endif
                     65:
1.57      nakayama   66: #define PADFREQ                44100
                     67: #define PADCHAN                2
                     68: #define PADPREC                16
                     69:
1.1       jmcneill   70: typedef struct pad_block {
                     71:        uint8_t         *pb_ptr;
                     72:        int             pb_len;
                     73: } pad_block_t;
                     74:
1.2       jmcneill   75: enum {
                     76:        PAD_OUTPUT_CLASS,
                     77:        PAD_INPUT_CLASS,
                     78:        PAD_OUTPUT_MASTER_VOLUME,
                     79:        PAD_INPUT_DAC_VOLUME,
                     80:        PAD_ENUM_LAST,
                     81: };
1.1       jmcneill   82:
1.10      christos   83: static int     pad_match(device_t, cfdata_t, void *);
1.5       dyoung     84: static void    pad_attach(device_t, device_t, void *);
                     85: static int     pad_detach(device_t, int);
                     86: static void    pad_childdet(device_t, device_t);
1.1       jmcneill   87:
1.59      isaki      88: static int     pad_query_format(void *, audio_format_query_t *);
                     89: static int     pad_set_format(void *, int,
                     90:                    const audio_params_t *, const audio_params_t *,
                     91:                    audio_filter_reg_t *, audio_filter_reg_t *);
1.1       jmcneill   92: static int     pad_start_output(void *, void *, int,
1.62      isaki      93:                    void (*)(void *), void *);
1.1       jmcneill   94: static int     pad_halt_output(void *);
                     95: static int     pad_getdev(void *, struct audio_device *);
                     96: static int     pad_set_port(void *, mixer_ctrl_t *);
                     97: static int     pad_get_port(void *, mixer_ctrl_t *);
                     98: static int     pad_query_devinfo(void *, mixer_devinfo_t *);
                     99: static int     pad_get_props(void *);
1.17      jmcneill  100: static void    pad_get_locks(void *, kmutex_t **, kmutex_t **);
1.1       jmcneill  101:
1.59      isaki     102: static void    pad_done_output(void *);
                    103: static void    pad_swvol_codec(audio_filter_arg_t *);
1.22      jmcneill  104:
1.71      riastrad  105: static void    pad_close(struct pad_softc *);
1.62      isaki     106: static int     pad_read(struct pad_softc *, off_t *, struct uio *,
                    107:                    kauth_cred_t, int);
                    108:
                    109: static int     fops_pad_close(struct file *);
                    110: static int     fops_pad_read(struct file *, off_t *, struct uio *,
                    111:                    kauth_cred_t, int);
                    112: static int     fops_pad_write(struct file *, off_t *, struct uio *,
                    113:                    kauth_cred_t, int);
                    114: static int     fops_pad_ioctl(struct file *, u_long, void *);
                    115: static int     fops_pad_kqfilter(struct file *, struct knote *);
                    116: static int     fops_pad_poll(struct file *, int);
                    117: static int     fops_pad_stat(struct file *, struct stat *);
                    118: static int     fops_pad_mmap(struct file *, off_t *, size_t, int, int *, int *,
                    119:                    struct uvm_object **, int *);
1.32      pgoyette  120:
1.1       jmcneill  121: static const struct audio_hw_if pad_hw_if = {
1.62      isaki     122:        .query_format   = pad_query_format,
                    123:        .set_format     = pad_set_format,
                    124:        .start_output   = pad_start_output,
                    125:        .halt_output    = pad_halt_output,
                    126:        .getdev         = pad_getdev,
                    127:        .set_port       = pad_set_port,
                    128:        .get_port       = pad_get_port,
                    129:        .query_devinfo  = pad_query_devinfo,
                    130:        .get_props      = pad_get_props,
                    131:        .get_locks      = pad_get_locks,
1.1       jmcneill  132: };
                    133:
                    134: #define PAD_NFORMATS   1
                    135: static const struct audio_format pad_formats[PAD_NFORMATS] = {
1.59      isaki     136:        {
                    137:                .mode           = AUMODE_PLAY,
1.60      isaki     138:                .encoding       = AUDIO_ENCODING_SLINEAR_LE,
1.59      isaki     139:                .validbits      = PADPREC,
                    140:                .precision      = PADPREC,
                    141:                .channels       = PADCHAN,
                    142:                .channel_mask   = AUFMT_STEREO,
                    143:                .frequency_type = 1,
                    144:                .frequency      = { PADFREQ },
                    145:        },
1.1       jmcneill  146: };
                    147:
                    148: extern void    padattach(int);
                    149:
1.62      isaki     150: static int     pad_add_block(struct pad_softc *, uint8_t *, int);
                    151: static int     pad_get_block(struct pad_softc *, pad_block_t *, int);
1.1       jmcneill  152:
1.71      riastrad  153: static dev_type_open(pad_open);
1.1       jmcneill  154:
                    155: const struct cdevsw pad_cdevsw = {
1.71      riastrad  156:        .d_open         = pad_open,
                    157:        .d_close        = noclose,
                    158:        .d_read         = noread,
1.62      isaki     159:        .d_write        = nowrite,
                    160:        .d_ioctl        = noioctl,
                    161:        .d_stop         = nostop,
                    162:        .d_tty          = notty,
                    163:        .d_poll         = nopoll,
                    164:        .d_mmap         = nommap,
                    165:        .d_kqfilter     = nokqfilter,
                    166:        .d_discard      = nodiscard,
                    167:        .d_flag         = D_OTHER | D_MPSAFE,
1.1       jmcneill  168: };
                    169:
1.57      nakayama  170: const struct fileops pad_fileops = {
1.62      isaki     171:        .fo_name        = "pad",
                    172:        .fo_read        = fops_pad_read,
                    173:        .fo_write       = fops_pad_write,
                    174:        .fo_ioctl       = fops_pad_ioctl,
                    175:        .fo_fcntl       = fnullop_fcntl,
                    176:        .fo_stat        = fops_pad_stat,
                    177:        .fo_poll        = fops_pad_poll,
                    178:        .fo_close       = fops_pad_close,
                    179:        .fo_mmap        = fops_pad_mmap,
                    180:        .fo_kqfilter    = fops_pad_kqfilter,
                    181:        .fo_restart     = fnullop_restart
1.57      nakayama  182: };
                    183:
1.62      isaki     184: CFATTACH_DECL2_NEW(pad, sizeof(struct pad_softc),
                    185:     pad_match, pad_attach, pad_detach,
1.5       dyoung    186:     NULL, NULL, pad_childdet);
1.1       jmcneill  187:
                    188: void
                    189: padattach(int n)
                    190: {
1.57      nakayama  191:        int error;
1.1       jmcneill  192:
1.57      nakayama  193:        error = config_cfattach_attach(pad_cd.cd_name, &pad_ca);
                    194:        if (error) {
1.1       jmcneill  195:                aprint_error("%s: couldn't register cfattach: %d\n",
1.57      nakayama  196:                    pad_cd.cd_name, error);
1.1       jmcneill  197:                config_cfdriver_detach(&pad_cd);
                    198:                return;
                    199:        }
                    200: }
                    201:
                    202: static int
1.62      isaki     203: pad_match(device_t parent, cfdata_t data, void *opaque)
                    204: {
                    205:
                    206:        return 1;
                    207: }
                    208:
                    209: static void
                    210: pad_attach(device_t parent, device_t self, void *opaque)
                    211: {
1.68      riastrad  212:        struct pad_softc *sc = device_private(self);
1.62      isaki     213:
1.71      riastrad  214:        KASSERT(KERNEL_LOCKED_P());
                    215:
1.62      isaki     216:        aprint_normal_dev(self, "outputs: 44100Hz, 16-bit, stereo\n");
1.68      riastrad  217:
                    218:        sc->sc_dev = self;
                    219:
                    220:        cv_init(&sc->sc_condvar, device_xname(sc->sc_dev));
                    221:        mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
1.69      riastrad  222:        mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SOFTCLOCK);
                    223:        callout_init(&sc->sc_pcallout, CALLOUT_MPSAFE);
                    224:        callout_setfunc(&sc->sc_pcallout, pad_done_output, sc);
1.68      riastrad  225:
                    226:        sc->sc_swvol = 255;
                    227:        sc->sc_buflen = 0;
                    228:        sc->sc_rpos = sc->sc_wpos = 0;
                    229:        sc->sc_audiodev = audio_attach_mi(&pad_hw_if, sc, sc->sc_dev);
                    230:
                    231:        if (!pmf_device_register(sc->sc_dev, NULL, NULL))
                    232:                aprint_error_dev(sc->sc_dev,
                    233:                    "couldn't establish power handler\n");
1.71      riastrad  234:
                    235:        sc->sc_open = 1;
1.62      isaki     236: }
                    237:
                    238: static int
                    239: pad_detach(device_t self, int flags)
                    240: {
1.68      riastrad  241:        struct pad_softc *sc = device_private(self);
1.62      isaki     242:        int cmaj, mn;
1.68      riastrad  243:        int error;
                    244:
1.71      riastrad  245:        KASSERT(KERNEL_LOCKED_P());
                    246:
                    247:        /* Prevent detach without going through close -- e.g., drvctl.  */
                    248:        if (sc->sc_open)
                    249:                return EBUSY;
                    250:
1.68      riastrad  251:        error = config_detach_children(self, flags);
                    252:        if (error)
                    253:                return error;
1.62      isaki     254:
                    255:        cmaj = cdevsw_lookup_major(&pad_cdevsw);
                    256:        mn = device_unit(sc->sc_dev);
1.68      riastrad  257:        vdevgone(cmaj, mn, mn, VCHR);
                    258:
                    259:        pmf_device_deregister(sc->sc_dev);
                    260:
1.72    ! riastrad  261:        callout_destroy(&sc->sc_pcallout);
1.68      riastrad  262:        mutex_destroy(&sc->sc_lock);
                    263:        mutex_destroy(&sc->sc_intr_lock);
                    264:        cv_destroy(&sc->sc_condvar);
1.62      isaki     265:
                    266:        return 0;
                    267: }
                    268:
                    269: static void
                    270: pad_childdet(device_t self, device_t child)
                    271: {
                    272:        struct pad_softc *sc = device_private(self);
                    273:
1.68      riastrad  274:        if (child == sc->sc_audiodev)
                    275:                sc->sc_audiodev = NULL;
1.62      isaki     276: }
                    277:
                    278: static int
                    279: pad_add_block(struct pad_softc *sc, uint8_t *blk, int blksize)
1.1       jmcneill  280: {
                    281:        int l;
                    282:
                    283:        if (sc->sc_buflen + blksize > PAD_BUFSIZE)
                    284:                return ENOBUFS;
                    285:
                    286:        if (sc->sc_wpos + blksize <= PAD_BUFSIZE)
                    287:                memcpy(sc->sc_audiobuf + sc->sc_wpos, blk, blksize);
                    288:        else {
                    289:                l = PAD_BUFSIZE - sc->sc_wpos;
                    290:                memcpy(sc->sc_audiobuf + sc->sc_wpos, blk, l);
                    291:                memcpy(sc->sc_audiobuf, blk + l, blksize - l);
                    292:        }
                    293:
                    294:        sc->sc_wpos += blksize;
1.59      isaki     295:        if (sc->sc_wpos >= PAD_BUFSIZE)
1.1       jmcneill  296:                sc->sc_wpos -= PAD_BUFSIZE;
                    297:
                    298:        sc->sc_buflen += blksize;
                    299:
                    300:        return 0;
                    301: }
                    302:
                    303: static int
1.62      isaki     304: pad_get_block(struct pad_softc *sc, pad_block_t *pb, int blksize)
1.1       jmcneill  305: {
                    306:        int l;
                    307:
                    308:        KASSERT(pb != NULL);
                    309:
                    310:        pb->pb_ptr = (sc->sc_audiobuf + sc->sc_rpos);
                    311:        if (sc->sc_rpos + blksize < PAD_BUFSIZE) {
                    312:                pb->pb_len = blksize;
                    313:                sc->sc_rpos += blksize;
                    314:        } else {
                    315:                l = PAD_BUFSIZE - sc->sc_rpos;
                    316:                pb->pb_len = l;
                    317:                sc->sc_rpos = 0;
                    318:        }
                    319:        sc->sc_buflen -= pb->pb_len;
                    320:
                    321:        return 0;
                    322: }
                    323:
1.71      riastrad  324: static int
                    325: pad_open(dev_t dev, int flags, int fmt, struct lwp *l)
1.57      nakayama  326: {
1.71      riastrad  327:        struct file *fp = NULL;
                    328:        device_t self;
                    329:        struct pad_softc *sc = NULL;
                    330:        cfdata_t cf = NULL;
                    331:        int error, fd;
                    332:
                    333:        error = fd_allocfile(&fp, &fd);
                    334:        if (error)
                    335:                goto out;
1.57      nakayama  336:
1.71      riastrad  337:        cf = kmem_alloc(sizeof(*cf), KM_SLEEP);
1.57      nakayama  338:        cf->cf_name = pad_cd.cd_name;
                    339:        cf->cf_atname = pad_cd.cd_name;
1.71      riastrad  340:        cf->cf_unit = 0;
1.57      nakayama  341:        cf->cf_fstate = FSTATE_STAR;
                    342:
1.71      riastrad  343:        self = config_attach_pseudo(cf);
                    344:        if (self == NULL) {
                    345:                error = ENXIO;
                    346:                goto out;
                    347:        }
                    348:        sc = device_private(self);
                    349:        KASSERT(sc->sc_dev == self);
                    350:        cf = NULL;
                    351:
                    352:        error = fd_clone(fp, fd, flags, &pad_fileops, sc);
                    353:        KASSERT(error == EMOVEFD);
                    354:        fp = NULL;
                    355:        sc = NULL;
                    356:
                    357: out:   if (sc)
                    358:                pad_close(sc);
                    359:        if (cf)
                    360:                kmem_free(cf, sizeof(*cf));
                    361:        if (fp)
                    362:                fd_abort(curproc, fp, fd);
1.57      nakayama  363:        return error;
1.1       jmcneill  364: }
                    365:
1.71      riastrad  366: static void
1.57      nakayama  367: pad_close(struct pad_softc *sc)
1.41      nat       368: {
1.71      riastrad  369:        device_t self = sc->sc_dev;
                    370:        cfdata_t cf = device_cfdata(self);
1.50      nat       371:
1.71      riastrad  372:        KERNEL_LOCK(1, NULL);
                    373:        KASSERT(sc->sc_open);
                    374:        sc->sc_open = 0;
                    375:        (void)config_detach(self, DETACH_FORCE);
                    376:        KERNEL_UNLOCK_ONE(NULL);
1.41      nat       377:
1.71      riastrad  378:        kmem_free(cf, sizeof(*cf));
1.57      nakayama  379: }
                    380:
                    381: static int
                    382: fops_pad_close(struct file *fp)
                    383: {
1.68      riastrad  384:        struct pad_softc *sc = fp->f_pad;
1.57      nakayama  385:
1.68      riastrad  386:        pad_close(sc);
                    387:
                    388:        return 0;
1.57      nakayama  389: }
1.1       jmcneill  390:
1.57      nakayama  391: static int
1.62      isaki     392: fops_pad_poll(struct file *fp, int events)
1.57      nakayama  393: {
1.62      isaki     394:
1.63      isaki     395:        return POLLERR;
1.57      nakayama  396: }
                    397:
                    398: static int
1.62      isaki     399: fops_pad_kqfilter(struct file *fp, struct knote *kn)
1.57      nakayama  400: {
1.68      riastrad  401:        struct pad_softc *sc = fp->f_pad;
1.57      nakayama  402:        dev_t dev;
                    403:
1.62      isaki     404:        dev = makedev(cdevsw_lookup_major(&pad_cdevsw),
                    405:            device_unit(sc->sc_dev));
1.57      nakayama  406:
                    407:        return seltrue_kqfilter(dev, kn);
                    408: }
                    409:
                    410: static int
1.62      isaki     411: fops_pad_ioctl(struct file *fp, u_long cmd, void *data)
1.57      nakayama  412: {
1.62      isaki     413:
1.57      nakayama  414:        return ENODEV;
                    415: }
1.1       jmcneill  416:
1.57      nakayama  417: static int
1.62      isaki     418: fops_pad_stat(struct file *fp, struct stat *st)
1.57      nakayama  419: {
1.68      riastrad  420:        struct pad_softc *sc = fp->f_pad;
1.57      nakayama  421:
                    422:        memset(st, 0, sizeof(*st));
                    423:
1.62      isaki     424:        st->st_dev = makedev(cdevsw_lookup_major(&pad_cdevsw),
                    425:            device_unit(sc->sc_dev));
1.57      nakayama  426:
                    427:        st->st_uid = kauth_cred_geteuid(fp->f_cred);
                    428:        st->st_gid = kauth_cred_getegid(fp->f_cred);
                    429:        st->st_mode = S_IFCHR;
                    430:
1.54      nakayama  431:        return 0;
1.41      nat       432: }
1.39      nat       433:
1.57      nakayama  434: static int
1.62      isaki     435: fops_pad_mmap(struct file *fp, off_t *offp, size_t len, int prot, int *flagsp,
                    436:     int *advicep, struct uvm_object **uobjp, int *maxprotp)
1.57      nakayama  437: {
1.62      isaki     438:
1.57      nakayama  439:        return 1;
                    440: }
                    441:
                    442: static int
                    443: fops_pad_read(struct file *fp, off_t *offp, struct uio *uio, kauth_cred_t cred,
1.62      isaki     444:     int ioflag)
1.57      nakayama  445: {
1.68      riastrad  446:        struct pad_softc *sc = fp->f_pad;
1.39      nat       447:
1.57      nakayama  448:        return pad_read(sc, offp, uio, cred, ioflag);
1.1       jmcneill  449: }
                    450:
1.57      nakayama  451: static int
                    452: pad_read(struct pad_softc *sc, off_t *offp, struct uio *uio, kauth_cred_t cred,
1.62      isaki     453:     int ioflag)
1.1       jmcneill  454: {
                    455:        pad_block_t pb;
1.59      isaki     456:        int len;
                    457:        int err;
1.1       jmcneill  458:
                    459:        err = 0;
1.59      isaki     460:        DPRINTF("%s: resid=%zu\n", __func__, uio->uio_resid);
1.27      nat       461:        while (uio->uio_resid > 0 && !err) {
1.69      riastrad  462:                mutex_enter(&sc->sc_intr_lock);
1.59      isaki     463:                if (sc->sc_buflen == 0) {
                    464:                        DPRINTF("%s: wait\n", __func__);
1.69      riastrad  465:                        err = cv_wait_sig(&sc->sc_condvar, &sc->sc_intr_lock);
1.59      isaki     466:                        DPRINTF("%s: wake up %d\n", __func__, err);
1.69      riastrad  467:                        mutex_exit(&sc->sc_intr_lock);
1.59      isaki     468:                        if (err) {
                    469:                                if (err == ERESTART)
                    470:                                        err = EINTR;
                    471:                                break;
1.35      nat       472:                        }
1.59      isaki     473:                        if (sc->sc_buflen == 0)
                    474:                                break;
1.17      jmcneill  475:                        continue;
                    476:                }
1.1       jmcneill  477:
1.59      isaki     478:                len = uimin(uio->uio_resid, sc->sc_buflen);
                    479:                err = pad_get_block(sc, &pb, len);
1.69      riastrad  480:                mutex_exit(&sc->sc_intr_lock);
1.59      isaki     481:                if (err)
1.24      nat       482:                        break;
1.59      isaki     483:                DPRINTF("%s: move %d\n", __func__, pb.pb_len);
                    484:                uiomove(pb.pb_ptr, pb.pb_len, uio);
1.1       jmcneill  485:        }
                    486:
                    487:        return err;
                    488: }
                    489:
                    490: static int
1.62      isaki     491: fops_pad_write(struct file *fp, off_t *offp, struct uio *uio, kauth_cred_t cred,
                    492:     int ioflag)
1.57      nakayama  493: {
1.62      isaki     494:
1.57      nakayama  495:        return EOPNOTSUPP;
                    496: }
                    497:
                    498: static int
1.59      isaki     499: pad_query_format(void *opaque, audio_format_query_t *afp)
1.26      nat       500: {
                    501:
1.59      isaki     502:        return audio_query_format(pad_formats, PAD_NFORMATS, afp);
1.26      nat       503: }
                    504:
                    505: static int
1.59      isaki     506: pad_set_format(void *opaque, int setmode,
                    507:     const audio_params_t *play, const audio_params_t *rec,
                    508:     audio_filter_reg_t *pfil, audio_filter_reg_t *rfil)
1.1       jmcneill  509: {
1.69      riastrad  510:        struct pad_softc *sc = opaque;
1.1       jmcneill  511:
1.17      jmcneill  512:        KASSERT(mutex_owned(&sc->sc_lock));
                    513:
1.59      isaki     514:        /* XXX playback only */
                    515:        pfil->codec = pad_swvol_codec;
                    516:        pfil->context = sc;
1.2       jmcneill  517:
1.1       jmcneill  518:        return 0;
                    519: }
                    520:
                    521: static int
                    522: pad_start_output(void *opaque, void *block, int blksize,
                    523:     void (*intr)(void *), void *intrarg)
                    524: {
1.69      riastrad  525:        struct pad_softc *sc = opaque;
1.1       jmcneill  526:        int err;
1.59      isaki     527:        int ms;
1.1       jmcneill  528:
1.59      isaki     529:        KASSERT(mutex_owned(&sc->sc_intr_lock));
1.1       jmcneill  530:
                    531:        sc->sc_intr = intr;
                    532:        sc->sc_intrarg = intrarg;
                    533:        sc->sc_blksize = blksize;
                    534:
1.59      isaki     535:        DPRINTF("%s: blksize=%d\n", __func__, blksize);
1.1       jmcneill  536:        err = pad_add_block(sc, block, blksize);
1.59      isaki     537:        cv_broadcast(&sc->sc_condvar);
1.1       jmcneill  538:
1.59      isaki     539:        ms = blksize * 1000 / PADCHAN / (PADPREC / NBBY) / PADFREQ;
                    540:        DPRINTF("%s: callout ms=%d\n", __func__, ms);
1.69      riastrad  541:        callout_schedule(&sc->sc_pcallout, mstohz(ms));
1.1       jmcneill  542:
1.66      nia       543:        return err;
1.1       jmcneill  544: }
                    545:
                    546: static int
                    547: pad_halt_output(void *opaque)
                    548: {
1.69      riastrad  549:        struct pad_softc *sc = opaque;
1.17      jmcneill  550:
1.59      isaki     551:        DPRINTF("%s\n", __func__);
                    552:        KASSERT(mutex_owned(&sc->sc_intr_lock));
1.17      jmcneill  553:
1.69      riastrad  554:        callout_halt(&sc->sc_pcallout, &sc->sc_intr_lock);
                    555:
1.1       jmcneill  556:        sc->sc_intr = NULL;
                    557:        sc->sc_intrarg = NULL;
                    558:        sc->sc_buflen = 0;
                    559:        sc->sc_rpos = sc->sc_wpos = 0;
1.69      riastrad  560:        cv_broadcast(&sc->sc_condvar);
1.1       jmcneill  561:
                    562:        return 0;
                    563: }
                    564:
1.59      isaki     565: static void
                    566: pad_done_output(void *arg)
                    567: {
1.69      riastrad  568:        struct pad_softc *sc = arg;
1.59      isaki     569:
                    570:        DPRINTF("%s\n", __func__);
                    571:
                    572:        mutex_enter(&sc->sc_intr_lock);
                    573:        (*sc->sc_intr)(sc->sc_intrarg);
                    574:        mutex_exit(&sc->sc_intr_lock);
                    575: }
                    576:
1.1       jmcneill  577: static int
                    578: pad_getdev(void *opaque, struct audio_device *ret)
                    579: {
1.62      isaki     580:
1.16      jmcneill  581:        strlcpy(ret->name, "Virtual Audio", sizeof(ret->name));
                    582:        strlcpy(ret->version, osrelease, sizeof(ret->version));
                    583:        strlcpy(ret->config, "pad", sizeof(ret->config));
1.1       jmcneill  584:
                    585:        return 0;
                    586: }
                    587:
                    588: static int
                    589: pad_set_port(void *opaque, mixer_ctrl_t *mc)
                    590: {
1.69      riastrad  591:        struct pad_softc *sc = opaque;
1.2       jmcneill  592:
1.17      jmcneill  593:        KASSERT(mutex_owned(&sc->sc_lock));
                    594:
1.2       jmcneill  595:        switch (mc->dev) {
                    596:        case PAD_OUTPUT_MASTER_VOLUME:
                    597:        case PAD_INPUT_DAC_VOLUME:
1.58      nakayama  598:                if (mc->un.value.num_channels != 1)
                    599:                        return EINVAL;
1.2       jmcneill  600:                sc->sc_swvol = mc->un.value.level[AUDIO_MIXER_LEVEL_MONO];
                    601:                return 0;
                    602:        }
                    603:
1.1       jmcneill  604:        return ENXIO;
                    605: }
                    606:
                    607: static int
                    608: pad_get_port(void *opaque, mixer_ctrl_t *mc)
                    609: {
1.69      riastrad  610:        struct pad_softc *sc = opaque;
1.2       jmcneill  611:
1.17      jmcneill  612:        KASSERT(mutex_owned(&sc->sc_lock));
                    613:
1.2       jmcneill  614:        switch (mc->dev) {
                    615:        case PAD_OUTPUT_MASTER_VOLUME:
                    616:        case PAD_INPUT_DAC_VOLUME:
1.58      nakayama  617:                if (mc->un.value.num_channels != 1)
                    618:                        return EINVAL;
1.2       jmcneill  619:                mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_swvol;
                    620:                return 0;
                    621:        }
                    622:
1.1       jmcneill  623:        return ENXIO;
                    624: }
                    625:
                    626: static int
                    627: pad_query_devinfo(void *opaque, mixer_devinfo_t *di)
                    628: {
1.69      riastrad  629:        struct pad_softc *sc __diagused = opaque;
1.2       jmcneill  630:
1.17      jmcneill  631:        KASSERT(mutex_owned(&sc->sc_lock));
                    632:
1.2       jmcneill  633:        switch (di->index) {
                    634:        case PAD_OUTPUT_CLASS:
                    635:                di->mixer_class = PAD_OUTPUT_CLASS;
                    636:                strcpy(di->label.name, AudioCoutputs);
                    637:                di->type = AUDIO_MIXER_CLASS;
                    638:                di->next = di->prev = AUDIO_MIXER_LAST;
                    639:                return 0;
                    640:        case PAD_INPUT_CLASS:
                    641:                di->mixer_class = PAD_INPUT_CLASS;
                    642:                strcpy(di->label.name, AudioCinputs);
                    643:                di->type = AUDIO_MIXER_CLASS;
                    644:                di->next = di->prev = AUDIO_MIXER_LAST;
                    645:                return 0;
                    646:        case PAD_OUTPUT_MASTER_VOLUME:
                    647:                di->mixer_class = PAD_OUTPUT_CLASS;
                    648:                strcpy(di->label.name, AudioNmaster);
                    649:                di->type = AUDIO_MIXER_VALUE;
                    650:                di->next = di->prev = AUDIO_MIXER_LAST;
                    651:                di->un.v.num_channels = 1;
                    652:                strcpy(di->un.v.units.name, AudioNvolume);
                    653:                return 0;
                    654:        case PAD_INPUT_DAC_VOLUME:
                    655:                di->mixer_class = PAD_INPUT_CLASS;
                    656:                strcpy(di->label.name, AudioNdac);
                    657:                di->type = AUDIO_MIXER_VALUE;
                    658:                di->next = di->prev = AUDIO_MIXER_LAST;
                    659:                di->un.v.num_channels = 1;
                    660:                strcpy(di->un.v.units.name, AudioNvolume);
                    661:                return 0;
                    662:        }
                    663:
1.1       jmcneill  664:        return ENXIO;
                    665: }
                    666:
                    667: static int
                    668: pad_get_props(void *opaque)
                    669: {
1.17      jmcneill  670:
1.59      isaki     671:        return AUDIO_PROP_PLAYBACK;
1.1       jmcneill  672: }
1.13      ahoka     673:
1.17      jmcneill  674: static void
                    675: pad_get_locks(void *opaque, kmutex_t **intr, kmutex_t **thread)
                    676: {
1.69      riastrad  677:        struct pad_softc *sc = opaque;
1.17      jmcneill  678:
                    679:        *intr = &sc->sc_intr_lock;
                    680:        *thread = &sc->sc_lock;
                    681: }
                    682:
1.22      jmcneill  683: static void
1.59      isaki     684: pad_swvol_codec(audio_filter_arg_t *arg)
1.22      jmcneill  685: {
1.59      isaki     686:        struct pad_softc *sc = arg->context;
                    687:        const aint_t *src;
                    688:        aint_t *dst;
                    689:        u_int sample_count;
                    690:        u_int i;
                    691:
                    692:        src = arg->src;
                    693:        dst = arg->dst;
                    694:        sample_count = arg->count * arg->srcfmt->channels;
                    695:        for (i = 0; i < sample_count; i++) {
                    696:                aint2_t v = (aint2_t)(*src++);
                    697:                v = v * sc->sc_swvol / 255;
                    698:                *dst++ = (aint_t)v;
                    699:        }
1.22      jmcneill  700: }
                    701:
1.44      pgoyette  702: MODULE(MODULE_CLASS_DRIVER, pad, "audio");
                    703:
1.13      ahoka     704: #ifdef _MODULE
                    705:
1.57      nakayama  706: #include "ioconf.c"
                    707:
                    708: devmajor_t cmajor = NODEVMAJOR, bmajor = NODEVMAJOR;
                    709:
                    710: /*
                    711:  * We need our own version of cfattach since config(1)'s ioconf does not
                    712:  * generate what we need
                    713:  */
                    714:
                    715: static struct cfattach *pad_cfattachinit[] = { &pad_ca, NULL };
1.13      ahoka     716:
1.57      nakayama  717: static struct cfattachinit pad_cfattach[] = {
                    718:        { "pad", pad_cfattachinit },
                    719:        { NULL, NULL }
1.45      pgoyette  720: };
1.47      pgoyette  721: #endif
1.45      pgoyette  722:
1.13      ahoka     723: static int
                    724: pad_modcmd(modcmd_t cmd, void *arg)
                    725: {
1.44      pgoyette  726:        int error = 0;
1.13      ahoka     727:
                    728:        switch (cmd) {
                    729:        case MODULE_CMD_INIT:
1.44      pgoyette  730: #ifdef _MODULE
1.57      nakayama  731:                pad_cfattach[1] = cfattach_ioconf_pad[0];
                    732:                error = config_init_component(cfdriver_ioconf_pad,
                    733:                    pad_cfattach, cfdata_ioconf_pad);
                    734:                if (error)
1.44      pgoyette  735:                        break;
1.13      ahoka     736:
1.25      msaitoh   737:                error = devsw_attach(pad_cd.cd_name, NULL, &bmajor,
1.57      nakayama  738:                            &pad_cdevsw, &cmajor);
1.13      ahoka     739:                if (error) {
1.57      nakayama  740:                        config_fini_component(cfdriver_ioconf_pad,
                    741:                            pad_cfattach, cfdata_ioconf_pad);
1.44      pgoyette  742:                        break;
1.13      ahoka     743:                }
                    744:
1.44      pgoyette  745: #endif
1.57      nakayama  746:                break;
1.54      nakayama  747:
1.13      ahoka     748:        case MODULE_CMD_FINI:
1.44      pgoyette  749: #ifdef _MODULE
1.57      nakayama  750:                error = devsw_detach(NULL, &pad_cdevsw);
                    751:                if (error)
                    752:                        break;
                    753:
                    754:                error = config_fini_component(cfdriver_ioconf_pad,
                    755:                    pad_cfattach, cfdata_ioconf_pad);
1.13      ahoka     756:                if (error) {
1.57      nakayama  757:                        devsw_attach(pad_cd.cd_name, NULL, &bmajor,
                    758:                            &pad_cdevsw, &cmajor);
1.44      pgoyette  759:                        break;
1.13      ahoka     760:                }
1.44      pgoyette  761: #endif
1.57      nakayama  762:                break;
1.54      nakayama  763:
1.13      ahoka     764:        default:
1.44      pgoyette  765:                error = ENOTTY;
1.13      ahoka     766:        }
1.44      pgoyette  767:
                    768:        return error;
1.13      ahoka     769: }

CVSweb <webmaster@jp.NetBSD.org>