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

Annotation of src/sys/dev/usb/uaudio.c, Revision 1.67.2.4

1.67.2.4! skrll       1: /*     $NetBSD: uaudio.c,v 1.67.2.3 2004/09/21 13:33:44 skrll Exp $    */
1.1       augustss    2:
                      3: /*
                      4:  * Copyright (c) 1999 The NetBSD Foundation, Inc.
                      5:  * All rights reserved.
                      6:  *
1.5       augustss    7:  * This code is derived from software contributed to The NetBSD Foundation
1.24      augustss    8:  * by Lennart Augustsson (lennart@augustsson.net) at
1.5       augustss    9:  * Carlstedt Research & Technology.
1.1       augustss   10:  *
                     11:  * Redistribution and use in source and binary forms, with or without
                     12:  * modification, are permitted provided that the following conditions
                     13:  * are met:
                     14:  * 1. Redistributions of source code must retain the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer.
                     16:  * 2. Redistributions in binary form must reproduce the above copyright
                     17:  *    notice, this list of conditions and the following disclaimer in the
                     18:  *    documentation and/or other materials provided with the distribution.
                     19:  * 3. All advertising materials mentioning features or use of this software
                     20:  *    must display the following acknowledgement:
                     21:  *        This product includes software developed by the NetBSD
                     22:  *        Foundation, Inc. and its contributors.
                     23:  * 4. Neither the name of The NetBSD Foundation nor the names of its
                     24:  *    contributors may be used to endorse or promote products derived
                     25:  *    from this software without specific prior written permission.
                     26:  *
                     27:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     28:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     29:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     30:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     31:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     32:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     33:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     34:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     35:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     36:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     37:  * POSSIBILITY OF SUCH DAMAGE.
                     38:  */
                     39:
                     40: /*
1.67.2.1  skrll      41:  * USB audio specs: http://www.usb.org/developers/devclass_docs/audio10.pdf
                     42:  *                  http://www.usb.org/developers/devclass_docs/frmts10.pdf
                     43:  *                  http://www.usb.org/developers/devclass_docs/termt10.pdf
1.1       augustss   44:  */
1.44      lukem      45:
                     46: #include <sys/cdefs.h>
1.67.2.4! skrll      47: __KERNEL_RCSID(0, "$NetBSD: uaudio.c,v 1.67.2.3 2004/09/21 13:33:44 skrll Exp $");
1.1       augustss   48:
                     49: #include <sys/param.h>
                     50: #include <sys/systm.h>
                     51: #include <sys/kernel.h>
                     52: #include <sys/malloc.h>
                     53: #include <sys/device.h>
                     54: #include <sys/ioctl.h>
                     55: #include <sys/tty.h>
                     56: #include <sys/file.h>
1.40      augustss   57: #include <sys/reboot.h>                /* for bootverbose */
1.1       augustss   58: #include <sys/select.h>
                     59: #include <sys/proc.h>
                     60: #include <sys/vnode.h>
                     61: #include <sys/device.h>
                     62: #include <sys/poll.h>
                     63:
                     64: #include <sys/audioio.h>
                     65: #include <dev/audio_if.h>
1.67.2.1  skrll      66: #include <dev/audiovar.h>
1.1       augustss   67: #include <dev/mulaw.h>
                     68: #include <dev/auconv.h>
                     69:
                     70: #include <dev/usb/usb.h>
                     71: #include <dev/usb/usbdi.h>
                     72: #include <dev/usb/usbdi_util.h>
                     73: #include <dev/usb/usb_quirks.h>
                     74:
                     75: #include <dev/usb/uaudioreg.h>
                     76:
1.67.2.4! skrll      77: /* #define UAUDIO_DEBUG */
        !            78: /* #define UAUDIO_MULTIPLE_ENDPOINTS */
1.4       augustss   79: #ifdef UAUDIO_DEBUG
1.1       augustss   80: #define DPRINTF(x)     if (uaudiodebug) logprintf x
                     81: #define DPRINTFN(n,x)  if (uaudiodebug>(n)) logprintf x
                     82: int    uaudiodebug = 0;
                     83: #else
                     84: #define DPRINTF(x)
                     85: #define DPRINTFN(n,x)
                     86: #endif
                     87:
1.22      augustss   88: #define UAUDIO_NCHANBUFS 6     /* number of outstanding request */
1.55      kent       89: #define UAUDIO_NFRAMES   10    /* ms of sound in each request */
1.1       augustss   90:
                     91:
                     92: #define MIX_MAX_CHAN 8
                     93: struct mixerctl {
                     94:        u_int16_t       wValue[MIX_MAX_CHAN]; /* using nchan */
                     95:        u_int16_t       wIndex;
                     96:        u_int8_t        nchan;
                     97:        u_int8_t        type;
                     98: #define MIX_ON_OFF     1
                     99: #define MIX_SIGNED_16  2
                    100: #define MIX_UNSIGNED_16        3
                    101: #define MIX_SIGNED_8   4
1.67.2.4! skrll     102: #define MIX_SELECTOR   5
1.1       augustss  103: #define MIX_SIZE(n) ((n) == MIX_SIGNED_16 || (n) == MIX_UNSIGNED_16 ? 2 : 1)
                    104: #define MIX_UNSIGNED(n) ((n) == MIX_UNSIGNED_16)
1.34      augustss  105:        int             minval, maxval;
                    106:        u_int           delta;
                    107:        u_int           mul;
1.1       augustss  108:        u_int8_t        class;
                    109:        char            ctlname[MAX_AUDIO_DEV_LEN];
                    110:        char            *ctlunit;
                    111: };
                    112: #define MAKE(h,l) (((h) << 8) | (l))
                    113:
                    114: struct as_info {
                    115:        u_int8_t        alt;
                    116:        u_int8_t        encoding;
1.50      kent      117:        u_int8_t        attributes; /* Copy of bmAttributes of
                    118:                                     * usb_audio_streaming_endpoint_descriptor
                    119:                                     */
1.37      mycroft   120:        usbd_interface_handle   ifaceh;
1.67.2.4! skrll     121:        const usb_interface_descriptor_t *idesc;
        !           122:        const usb_endpoint_descriptor_audio_t *edesc;
        !           123:        const usb_endpoint_descriptor_audio_t *edesc1;
        !           124:        const struct usb_audio_streaming_type1_descriptor *asf1desc;
1.47      jdolecek  125:        int             sc_busy;        /* currently used */
1.1       augustss  126: };
                    127:
                    128: struct chan {
1.67      wiz       129:        void    (*intr)(void *);        /* DMA completion intr handler */
1.1       augustss  130:        void    *arg;           /* arg for intr() */
                    131:        usbd_pipe_handle pipe;
                    132:
                    133:        u_int   sample_size;
                    134:        u_int   sample_rate;
                    135:        u_int   bytes_per_frame;
                    136:        u_int   fraction;       /* fraction/1000 is the extra samples/frame */
                    137:        u_int   residue;        /* accumulates the fractional samples */
                    138:
                    139:        u_char  *start;         /* upper layer buffer start */
                    140:        u_char  *end;           /* upper layer buffer end */
                    141:        u_char  *cur;           /* current position in upper layer buffer */
                    142:        int     blksize;        /* chunk size to report up */
                    143:        int     transferred;    /* transferred bytes not reported up */
                    144:
1.47      jdolecek  145:        int     altidx;         /* currently used altidx */
1.31      augustss  146:
1.1       augustss  147:        int     curchanbuf;
                    148:        struct chanbuf {
1.56      kent      149:                struct chan     *chan;
1.9       augustss  150:                usbd_xfer_handle xfer;
1.56      kent      151:                u_char          *buffer;
                    152:                u_int16_t       sizes[UAUDIO_NFRAMES];
1.62      toshii    153:                u_int16_t       offsets[UAUDIO_NFRAMES];
1.56      kent      154:                u_int16_t       size;
1.1       augustss  155:        } chanbufs[UAUDIO_NCHANBUFS];
1.8       augustss  156:
                    157:        struct uaudio_softc *sc; /* our softc */
1.1       augustss  158: };
                    159:
                    160: struct uaudio_softc {
                    161:        USBBASEDEVICE sc_dev;           /* base device */
                    162:        usbd_device_handle sc_udev;     /* USB device */
                    163:
                    164:        int     sc_ac_iface;    /* Audio Control interface */
                    165:        usbd_interface_handle   sc_ac_ifaceh;
                    166:
1.47      jdolecek  167:        struct chan sc_playchan;        /* play channel */
                    168:        struct chan sc_recchan;         /* record channel */
1.1       augustss  169:
                    170:        int     sc_nullalt;
                    171:
1.7       augustss  172:        int     sc_audio_rev;
                    173:
1.1       augustss  174:        struct as_info *sc_alts;
                    175:        int     sc_nalts;
                    176:
                    177:        int     sc_altflags;
1.56      kent      178: #define HAS_8          0x01
                    179: #define HAS_16         0x02
                    180: #define HAS_8U         0x04
                    181: #define HAS_ALAW       0x08
                    182: #define HAS_MULAW      0x10
1.47      jdolecek  183: #define UA_NOFRAC      0x20            /* don't do sample rate adjustment */
1.51      kent      184: #define HAS_24         0x40
1.47      jdolecek  185:
                    186:        int     sc_mode;                /* play/record capability */
1.1       augustss  187:
                    188:        struct mixerctl *sc_ctls;
                    189:        int     sc_nctls;
                    190:
                    191:        device_ptr_t sc_audiodev;
                    192:        char    sc_dying;
                    193: };
                    194:
                    195: #define UAC_OUTPUT 0
                    196: #define UAC_INPUT  1
                    197: #define UAC_EQUAL  2
1.63      augustss  198: #define UAC_NCLASSES 3
1.1       augustss  199:
1.67.2.4! skrll     200: Static usbd_status uaudio_identify_ac(struct uaudio_softc *,
        !           201:                                      const usb_config_descriptor_t *);
        !           202: Static usbd_status uaudio_identify_as(struct uaudio_softc *,
        !           203:                                      const usb_config_descriptor_t *);
        !           204: Static usbd_status uaudio_process_as(struct uaudio_softc *,
        !           205:                                     const char *, int *, int,
        !           206:                                     const usb_interface_descriptor_t *);
        !           207:
        !           208: Static void    uaudio_add_alt(struct uaudio_softc *, const struct as_info *);
        !           209: Static void    uaudio_mixer_alias_ctl(struct uaudio_softc *,
        !           210:                                       struct mixerctl *, const char *);
        !           211:
        !           212: Static const usb_interface_descriptor_t *uaudio_find_iface
        !           213:        (const char *, int, int *, int);
        !           214:
        !           215: Static void    uaudio_mixer_add_ctl(struct uaudio_softc *, struct mixerctl *);
        !           216: Static char    *uaudio_id_name(struct uaudio_softc *,
        !           217:                    const usb_descriptor_t **, int);
        !           218: Static struct usb_audio_cluster uaudio_get_cluster(int,
        !           219:                    const usb_descriptor_t **);
        !           220: Static void    uaudio_add_input(struct uaudio_softc *,
        !           221:                    const usb_descriptor_t *, const usb_descriptor_t **);
        !           222: Static void    uaudio_add_output(struct uaudio_softc *,
        !           223:                    const usb_descriptor_t *, const usb_descriptor_t **);
        !           224: Static void    uaudio_add_mixer(struct uaudio_softc *,
        !           225:                    const usb_descriptor_t *, const usb_descriptor_t **);
        !           226: Static void    uaudio_add_selector(struct uaudio_softc *,
        !           227:                    const usb_descriptor_t *, const usb_descriptor_t **);
        !           228: Static void    uaudio_add_feature(struct uaudio_softc *,
        !           229:                    const usb_descriptor_t *, const usb_descriptor_t **);
        !           230: Static void    uaudio_add_processing_updown(struct uaudio_softc *,
        !           231:                    const usb_descriptor_t *, const usb_descriptor_t **);
        !           232: Static void    uaudio_add_processing(struct uaudio_softc *,
        !           233:                    const usb_descriptor_t *, const usb_descriptor_t **);
        !           234: Static void    uaudio_add_extension(struct uaudio_softc *,
        !           235:                    const usb_descriptor_t *, const usb_descriptor_t **);
        !           236: Static usbd_status uaudio_identify(struct uaudio_softc *,
        !           237:                    const usb_config_descriptor_t *);
        !           238:
        !           239: Static int     uaudio_signext(int, int);
        !           240: Static int     uaudio_value2bsd(struct mixerctl *, int);
        !           241: Static int     uaudio_bsd2value(struct mixerctl *, int);
        !           242: Static int     uaudio_get(struct uaudio_softc *, int, int, int, int, int);
        !           243: Static int     uaudio_ctl_get(struct uaudio_softc *, int,
        !           244:                               struct mixerctl *, int);
        !           245: Static void    uaudio_set(struct uaudio_softc *, int,
        !           246:                           int, int, int, int, int);
        !           247: Static void    uaudio_ctl_set(struct uaudio_softc *, int,
        !           248:                               struct mixerctl *, int, int);
        !           249:
        !           250: Static usbd_status uaudio_set_speed(struct uaudio_softc *, int, u_int);
        !           251:
        !           252: Static usbd_status uaudio_chan_open(struct uaudio_softc *, struct chan *);
        !           253: Static void    uaudio_chan_close(struct uaudio_softc *, struct chan *);
        !           254: Static usbd_status uaudio_chan_alloc_buffers(struct uaudio_softc *,
        !           255:                                             struct chan *);
        !           256: Static void    uaudio_chan_free_buffers(struct uaudio_softc *, struct chan *);
        !           257: Static void    uaudio_chan_init(struct chan *, int,
        !           258:                                 const struct audio_params *, int);
        !           259: Static void    uaudio_chan_set_param(struct chan *, u_char *, u_char *, int);
        !           260: Static void    uaudio_chan_ptransfer(struct chan *);
        !           261: Static void    uaudio_chan_pintr(usbd_xfer_handle,
        !           262:                                  usbd_private_handle, usbd_status);
        !           263:
        !           264: Static void    uaudio_chan_rtransfer(struct chan *);
        !           265: Static void    uaudio_chan_rintr(usbd_xfer_handle,
        !           266:                                  usbd_private_handle, usbd_status);
        !           267:
        !           268: Static int     uaudio_open(void *, int);
        !           269: Static void    uaudio_close(void *);
        !           270: Static int     uaudio_drain(void *);
        !           271: Static int     uaudio_query_encoding(void *, struct audio_encoding *);
        !           272: Static void    uaudio_get_minmax_rates(int, const struct as_info *,
        !           273:                                        const struct audio_params *,
        !           274:                                        int, u_long *, u_long *);
        !           275: Static int     uaudio_match_alt_sub(int, const struct as_info *,
        !           276:                                     const struct audio_params *, int, u_long);
        !           277: Static int     uaudio_match_alt_chan(int, const struct as_info *,
        !           278:                                      struct audio_params *, int);
        !           279: Static int     uaudio_match_alt(int, const struct as_info *,
        !           280:                                 struct audio_params *, int);
        !           281: Static int     uaudio_set_params(void *, int, int, struct audio_params *,
        !           282:                                  struct audio_params *);
        !           283: Static int     uaudio_round_blocksize(void *, int);
        !           284: Static int     uaudio_trigger_output(void *, void *, void *, int,
        !           285:                    void (*)(void *), void *, struct audio_params *);
        !           286: Static int     uaudio_trigger_input (void *, void *, void *, int,
        !           287:                    void (*)(void *), void *, struct audio_params *);
        !           288: Static int     uaudio_halt_in_dma(void *);
        !           289: Static int     uaudio_halt_out_dma(void *);
        !           290: Static int     uaudio_getdev(void *, struct audio_device *);
        !           291: Static int     uaudio_mixer_set_port(void *, mixer_ctrl_t *);
        !           292: Static int     uaudio_mixer_get_port(void *, mixer_ctrl_t *);
        !           293: Static int     uaudio_query_devinfo(void *, mixer_devinfo_t *);
        !           294: Static int     uaudio_get_props(void *);
1.1       augustss  295:
1.21      augustss  296: Static struct audio_hw_if uaudio_hw_if = {
1.1       augustss  297:        uaudio_open,
                    298:        uaudio_close,
                    299:        uaudio_drain,
                    300:        uaudio_query_encoding,
                    301:        uaudio_set_params,
                    302:        uaudio_round_blocksize,
                    303:        NULL,
                    304:        NULL,
                    305:        NULL,
                    306:        NULL,
                    307:        NULL,
                    308:        uaudio_halt_out_dma,
                    309:        uaudio_halt_in_dma,
                    310:        NULL,
                    311:        uaudio_getdev,
                    312:        NULL,
                    313:        uaudio_mixer_set_port,
                    314:        uaudio_mixer_get_port,
                    315:        uaudio_query_devinfo,
                    316:        NULL,
                    317:        NULL,
                    318:        NULL,
                    319:        NULL,
                    320:        uaudio_get_props,
                    321:        uaudio_trigger_output,
                    322:        uaudio_trigger_input,
1.43      augustss  323:        NULL,
1.1       augustss  324: };
                    325:
1.21      augustss  326: Static struct audio_device uaudio_device = {
1.1       augustss  327:        "USB audio",
                    328:        "",
                    329:        "uaudio"
                    330: };
                    331:
                    332: USB_DECLARE_DRIVER(uaudio);
                    333:
                    334: USB_MATCH(uaudio)
                    335: {
                    336:        USB_MATCH_START(uaudio, uaa);
                    337:        usb_interface_descriptor_t *id;
1.56      kent      338:
1.9       augustss  339:        if (uaa->iface == NULL)
1.1       augustss  340:                return (UMATCH_NONE);
                    341:
                    342:        id = usbd_get_interface_descriptor(uaa->iface);
                    343:        /* Trigger on the control interface. */
1.56      kent      344:        if (id == NULL ||
1.19      augustss  345:            id->bInterfaceClass != UICLASS_AUDIO ||
                    346:            id->bInterfaceSubClass != UISUBCLASS_AUDIOCONTROL ||
1.10      augustss  347:            (usbd_get_quirks(uaa->device)->uq_flags & UQ_BAD_AUDIO))
1.1       augustss  348:                return (UMATCH_NONE);
                    349:
                    350:        return (UMATCH_IFACECLASS_IFACESUBCLASS);
                    351: }
                    352:
                    353: USB_ATTACH(uaudio)
                    354: {
                    355:        USB_ATTACH_START(uaudio, sc, uaa);
                    356:        usb_interface_descriptor_t *id;
                    357:        usb_config_descriptor_t *cdesc;
                    358:        char devinfo[1024];
1.9       augustss  359:        usbd_status err;
1.37      mycroft   360:        int i, j, found;
1.1       augustss  361:
1.67.2.1  skrll     362:        usbd_devinfo(uaa->device, 0, devinfo, sizeof(devinfo));
1.1       augustss  363:        printf(": %s\n", devinfo);
                    364:
                    365:        sc->sc_udev = uaa->device;
                    366:
                    367:        cdesc = usbd_get_config_descriptor(sc->sc_udev);
1.13      augustss  368:        if (cdesc == NULL) {
                    369:                printf("%s: failed to get configuration descriptor\n",
                    370:                       USBDEVNAME(sc->sc_dev));
1.1       augustss  371:                USB_ATTACH_ERROR_RETURN;
1.13      augustss  372:        }
1.1       augustss  373:
1.9       augustss  374:        err = uaudio_identify(sc, cdesc);
                    375:        if (err) {
1.1       augustss  376:                printf("%s: audio descriptors make no sense, error=%d\n",
1.9       augustss  377:                       USBDEVNAME(sc->sc_dev), err);
1.1       augustss  378:                USB_ATTACH_ERROR_RETURN;
                    379:        }
                    380:
                    381:        sc->sc_ac_ifaceh = uaa->iface;
                    382:        /* Pick up the AS interface. */
                    383:        for (i = 0; i < uaa->nifaces; i++) {
1.37      mycroft   384:                if (uaa->ifaces[i] == NULL)
                    385:                        continue;
                    386:                id = usbd_get_interface_descriptor(uaa->ifaces[i]);
                    387:                if (id == NULL)
                    388:                        continue;
                    389:                found = 0;
                    390:                for (j = 0; j < sc->sc_nalts; j++) {
                    391:                        if (id->bInterfaceNumber ==
                    392:                            sc->sc_alts[j].idesc->bInterfaceNumber) {
                    393:                                sc->sc_alts[j].ifaceh = uaa->ifaces[i];
                    394:                                found = 1;
1.1       augustss  395:                        }
                    396:                }
1.37      mycroft   397:                if (found)
                    398:                        uaa->ifaces[i] = NULL;
1.1       augustss  399:        }
                    400:
1.37      mycroft   401:        for (j = 0; j < sc->sc_nalts; j++) {
                    402:                if (sc->sc_alts[j].ifaceh == NULL) {
1.40      augustss  403:                        printf("%s: alt %d missing AS interface(s)\n",
                    404:                            USBDEVNAME(sc->sc_dev), j);
1.37      mycroft   405:                        USB_ATTACH_ERROR_RETURN;
                    406:                }
1.1       augustss  407:        }
                    408:
1.40      augustss  409:        printf("%s: audio rev %d.%02x\n", USBDEVNAME(sc->sc_dev),
1.7       augustss  410:               sc->sc_audio_rev >> 8, sc->sc_audio_rev & 0xff);
                    411:
1.47      jdolecek  412:        sc->sc_playchan.sc = sc->sc_recchan.sc = sc;
1.60      kent      413:        sc->sc_playchan.altidx = -1;
                    414:        sc->sc_recchan.altidx = -1;
1.8       augustss  415:
1.31      augustss  416:        if (usbd_get_quirks(sc->sc_udev)->uq_flags & UQ_AU_NO_FRAC)
1.47      jdolecek  417:                sc->sc_altflags |= UA_NOFRAC;
1.31      augustss  418:
1.40      augustss  419: #ifndef UAUDIO_DEBUG
                    420:        if (bootverbose)
                    421: #endif
                    422:                printf("%s: %d mixer controls\n", USBDEVNAME(sc->sc_dev),
                    423:                    sc->sc_nctls);
                    424:
1.41      augustss  425:        usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
                    426:                           USBDEV(sc->sc_dev));
                    427:
1.1       augustss  428:        DPRINTF(("uaudio_attach: doing audio_attach_mi\n"));
1.23      augustss  429: #if defined(__OpenBSD__)
                    430:        audio_attach_mi(&uaudio_hw_if, sc, &sc->sc_dev);
                    431: #else
1.1       augustss  432:        sc->sc_audiodev = audio_attach_mi(&uaudio_hw_if, sc, &sc->sc_dev);
1.23      augustss  433: #endif
1.17      augustss  434:
1.1       augustss  435:        USB_ATTACH_SUCCESS_RETURN;
                    436: }
                    437:
                    438: int
1.26      augustss  439: uaudio_activate(device_ptr_t self, enum devact act)
1.1       augustss  440: {
                    441:        struct uaudio_softc *sc = (struct uaudio_softc *)self;
1.2       augustss  442:        int rv = 0;
1.1       augustss  443:
                    444:        switch (act) {
                    445:        case DVACT_ACTIVATE:
                    446:                return (EOPNOTSUPP);
                    447:                break;
                    448:
                    449:        case DVACT_DEACTIVATE:
1.40      augustss  450:                if (sc->sc_audiodev != NULL)
1.2       augustss  451:                        rv = config_deactivate(sc->sc_audiodev);
1.1       augustss  452:                sc->sc_dying = 1;
                    453:                break;
                    454:        }
1.2       augustss  455:        return (rv);
1.1       augustss  456: }
                    457:
                    458: int
1.26      augustss  459: uaudio_detach(device_ptr_t self, int flags)
1.1       augustss  460: {
                    461:        struct uaudio_softc *sc = (struct uaudio_softc *)self;
                    462:        int rv = 0;
                    463:
1.8       augustss  464:        /* Wait for outstanding requests to complete. */
                    465:        usbd_delay_ms(sc->sc_udev, UAUDIO_NCHANBUFS * UAUDIO_NFRAMES);
                    466:
1.9       augustss  467:        if (sc->sc_audiodev != NULL)
1.1       augustss  468:                rv = config_detach(sc->sc_audiodev, flags);
1.17      augustss  469:
                    470:        usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
                    471:                           USBDEV(sc->sc_dev));
1.1       augustss  472:
                    473:        return (rv);
                    474: }
                    475:
                    476: int
1.26      augustss  477: uaudio_query_encoding(void *addr, struct audio_encoding *fp)
1.1       augustss  478: {
                    479:        struct uaudio_softc *sc = addr;
                    480:        int flags = sc->sc_altflags;
                    481:        int idx;
                    482:
                    483:        if (sc->sc_dying)
                    484:                return (EIO);
1.56      kent      485:
1.1       augustss  486:        if (sc->sc_nalts == 0 || flags == 0)
                    487:                return (ENXIO);
                    488:
                    489:        idx = fp->index;
                    490:        switch (idx) {
                    491:        case 0:
1.67.2.1  skrll     492:                strlcpy(fp->name, AudioEulinear, sizeof(fp->name));
1.1       augustss  493:                fp->encoding = AUDIO_ENCODING_ULINEAR;
                    494:                fp->precision = 8;
                    495:                fp->flags = flags&HAS_8U ? 0 : AUDIO_ENCODINGFLAG_EMULATED;
                    496:                return (0);
                    497:        case 1:
1.67.2.1  skrll     498:                strlcpy(fp->name, AudioEmulaw, sizeof(fp->name));
1.1       augustss  499:                fp->encoding = AUDIO_ENCODING_ULAW;
                    500:                fp->precision = 8;
                    501:                fp->flags = flags&HAS_MULAW ? 0 : AUDIO_ENCODINGFLAG_EMULATED;
                    502:                return (0);
                    503:        case 2:
1.67.2.1  skrll     504:                strlcpy(fp->name, AudioEalaw, sizeof(fp->name));
1.1       augustss  505:                fp->encoding = AUDIO_ENCODING_ALAW;
                    506:                fp->precision = 8;
                    507:                fp->flags = flags&HAS_ALAW ? 0 : AUDIO_ENCODINGFLAG_EMULATED;
                    508:                return (0);
                    509:        case 3:
1.67.2.1  skrll     510:                strlcpy(fp->name, AudioEslinear, sizeof(fp->name));
1.1       augustss  511:                fp->encoding = AUDIO_ENCODING_SLINEAR;
                    512:                fp->precision = 8;
                    513:                fp->flags = flags&HAS_8 ? 0 : AUDIO_ENCODINGFLAG_EMULATED;
                    514:                return (0);
1.56      kent      515:        case 4:
1.67.2.1  skrll     516:                strlcpy(fp->name, AudioEslinear_le, sizeof(fp->name));
1.1       augustss  517:                fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
                    518:                fp->precision = 16;
                    519:                fp->flags = 0;
                    520:                return (0);
                    521:        case 5:
1.67.2.1  skrll     522:                strlcpy(fp->name, AudioEulinear_le, sizeof(fp->name));
1.1       augustss  523:                fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
                    524:                fp->precision = 16;
                    525:                fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
                    526:                return (0);
                    527:        case 6:
1.67.2.1  skrll     528:                strlcpy(fp->name, AudioEslinear_be, sizeof(fp->name));
1.1       augustss  529:                fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
                    530:                fp->precision = 16;
                    531:                fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
                    532:                return (0);
                    533:        case 7:
1.67.2.1  skrll     534:                strlcpy(fp->name, AudioEulinear_be, sizeof(fp->name));
1.1       augustss  535:                fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
                    536:                fp->precision = 16;
                    537:                fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
                    538:                return (0);
                    539:        default:
                    540:                return (EINVAL);
                    541:        }
                    542: }
                    543:
1.67.2.4! skrll     544: const usb_interface_descriptor_t *
        !           545: uaudio_find_iface(const char *buf, int size, int *offsp, int subtype)
1.1       augustss  546: {
1.67.2.4! skrll     547:        const usb_interface_descriptor_t *d;
1.1       augustss  548:
                    549:        while (*offsp < size) {
1.67.2.4! skrll     550:                d = (const void *)(buf + *offsp);
1.1       augustss  551:                *offsp += d->bLength;
                    552:                if (d->bDescriptorType == UDESC_INTERFACE &&
1.19      augustss  553:                    d->bInterfaceClass == UICLASS_AUDIO &&
1.1       augustss  554:                    d->bInterfaceSubClass == subtype)
                    555:                        return (d);
                    556:        }
1.40      augustss  557:        return (NULL);
1.1       augustss  558: }
                    559:
                    560: void
1.26      augustss  561: uaudio_mixer_add_ctl(struct uaudio_softc *sc, struct mixerctl *mc)
1.1       augustss  562: {
1.33      augustss  563:        int res;
1.42      christos  564:        size_t len = sizeof(*mc) * (sc->sc_nctls + 1);
                    565:        struct mixerctl *nmc = sc->sc_nctls == 0 ?
                    566:            malloc(len, M_USBDEV, M_NOWAIT) :
                    567:            realloc(sc->sc_ctls, len, M_USBDEV, M_NOWAIT);
1.33      augustss  568:
1.42      christos  569:        if (nmc == NULL) {
1.1       augustss  570:                printf("uaudio_mixer_add_ctl: no memory\n");
                    571:                return;
                    572:        }
1.42      christos  573:        sc->sc_ctls = nmc;
1.1       augustss  574:
1.33      augustss  575:        mc->delta = 0;
1.67.2.4! skrll     576:        if (mc->type == MIX_ON_OFF) {
        !           577:                mc->minval = 0;
        !           578:                mc->maxval = 1;
        !           579:        } else if (mc->type == MIX_SELECTOR) {
        !           580:                ;
        !           581:        } else {
1.1       augustss  582:                /* Determine min and max values. */
1.56      kent      583:                mc->minval = uaudio_signext(mc->type,
                    584:                        uaudio_get(sc, GET_MIN, UT_READ_CLASS_INTERFACE,
                    585:                                   mc->wValue[0], mc->wIndex,
1.1       augustss  586:                                   MIX_SIZE(mc->type)));
1.56      kent      587:                mc->maxval = 1 + uaudio_signext(mc->type,
1.1       augustss  588:                        uaudio_get(sc, GET_MAX, UT_READ_CLASS_INTERFACE,
                    589:                                   mc->wValue[0], mc->wIndex,
                    590:                                   MIX_SIZE(mc->type)));
1.34      augustss  591:                mc->mul = mc->maxval - mc->minval;
                    592:                if (mc->mul == 0)
                    593:                        mc->mul = 1;
1.33      augustss  594:                res = uaudio_get(sc, GET_RES, UT_READ_CLASS_INTERFACE,
                    595:                                 mc->wValue[0], mc->wIndex,
                    596:                                 MIX_SIZE(mc->type));
1.34      augustss  597:                if (res > 0)
1.67.2.1  skrll     598:                        mc->delta = (res * 255 + mc->mul/2) / mc->mul;
1.1       augustss  599:        }
                    600:
                    601:        sc->sc_ctls[sc->sc_nctls++] = *mc;
                    602:
1.4       augustss  603: #ifdef UAUDIO_DEBUG
1.1       augustss  604:        if (uaudiodebug > 2) {
                    605:                int i;
                    606:                DPRINTF(("uaudio_mixer_add_ctl: wValue=%04x",mc->wValue[0]));
                    607:                for (i = 1; i < mc->nchan; i++)
                    608:                        DPRINTF((",%04x", mc->wValue[i]));
                    609:                DPRINTF((" wIndex=%04x type=%d name='%s' unit='%s' "
                    610:                         "min=%d max=%d\n",
                    611:                         mc->wIndex, mc->type, mc->ctlname, mc->ctlunit,
                    612:                         mc->minval, mc->maxval));
                    613:        }
                    614: #endif
                    615: }
                    616:
1.63      augustss  617: void
                    618: uaudio_mixer_alias_ctl(struct uaudio_softc *sc, struct mixerctl *mc,
                    619:                     const char *name)
                    620: {
                    621:        /* XXX mark as alias? */
1.67.2.1  skrll     622:        strlcpy(mc->ctlname, name, sizeof(mc->ctlname));
1.63      augustss  623:        uaudio_mixer_add_ctl(sc, mc);
                    624: }
                    625:
1.1       augustss  626: char *
1.67.2.4! skrll     627: uaudio_id_name(struct uaudio_softc *sc, const usb_descriptor_t **dps, int id)
1.1       augustss  628: {
                    629:        static char buf[32];
1.67.2.1  skrll     630:        snprintf(buf, sizeof(buf), "i%d", id);
1.1       augustss  631:        return (buf);
                    632: }
                    633:
                    634: struct usb_audio_cluster
1.67.2.4! skrll     635: uaudio_get_cluster(int id, const usb_descriptor_t **dps)
1.1       augustss  636: {
                    637:        struct usb_audio_cluster r;
1.67.2.4! skrll     638:        const usb_descriptor_t *dp;
1.1       augustss  639:        int i;
                    640:
                    641:        for (i = 0; i < 25; i++) { /* avoid infinite loops */
                    642:                dp = dps[id];
                    643:                if (dp == 0)
                    644:                        goto bad;
                    645:                switch (dp->bDescriptorSubtype) {
                    646:                case UDESCSUB_AC_INPUT:
1.67.2.4! skrll     647: #define p ((const struct usb_audio_input_terminal *)dp)
1.1       augustss  648:                        r.bNrChannels = p->bNrChannels;
                    649:                        USETW(r.wChannelConfig, UGETW(p->wChannelConfig));
                    650:                        r.iChannelNames = p->iChannelNames;
                    651: #undef p
                    652:                        return (r);
                    653:                case UDESCSUB_AC_OUTPUT:
1.67.2.4! skrll     654: #define p ((const struct usb_audio_output_terminal *)dp)
1.1       augustss  655:                        id = p->bSourceId;
                    656: #undef p
                    657:                        break;
                    658:                case UDESCSUB_AC_MIXER:
1.67.2.4! skrll     659: #define p ((const struct usb_audio_mixer_unit *)dp)
1.1       augustss  660:                        r = *(struct usb_audio_cluster *)
                    661:                                &p->baSourceId[p->bNrInPins];
                    662: #undef p
                    663:                        return (r);
                    664:                case UDESCSUB_AC_SELECTOR:
                    665:                        /* XXX This is not really right */
1.67.2.4! skrll     666: #define p ((const struct usb_audio_selector_unit *)dp)
1.1       augustss  667:                        id = p->baSourceId[0];
                    668: #undef p
                    669:                        break;
                    670:                case UDESCSUB_AC_FEATURE:
1.67.2.4! skrll     671: #define p ((const struct usb_audio_feature_unit *)dp)
1.1       augustss  672:                        id = p->bSourceId;
                    673: #undef p
                    674:                        break;
                    675:                case UDESCSUB_AC_PROCESSING:
1.67.2.4! skrll     676: #define p ((const struct usb_audio_processing_unit *)dp)
1.1       augustss  677:                        r = *(struct usb_audio_cluster *)
                    678:                                &p->baSourceId[p->bNrInPins];
                    679: #undef p
                    680:                        return (r);
                    681:                case UDESCSUB_AC_EXTENSION:
1.67.2.4! skrll     682: #define p ((const struct usb_audio_extension_unit *)dp)
1.1       augustss  683:                        r = *(struct usb_audio_cluster *)
                    684:                                &p->baSourceId[p->bNrInPins];
                    685: #undef p
                    686:                        return (r);
                    687:                default:
                    688:                        goto bad;
                    689:                }
                    690:        }
                    691:  bad:
                    692:        printf("uaudio_get_cluster: bad data\n");
                    693:        memset(&r, 0, sizeof r);
1.9       augustss  694:        return (r);
1.1       augustss  695:
                    696: }
                    697:
                    698: void
1.67.2.4! skrll     699: uaudio_add_input(struct uaudio_softc *sc, const usb_descriptor_t *v,
        !           700:                 const usb_descriptor_t **dps)
1.1       augustss  701: {
1.4       augustss  702: #ifdef UAUDIO_DEBUG
1.67.2.4! skrll     703:        const struct usb_audio_input_terminal *d =
        !           704:                (const struct usb_audio_input_terminal *)v;
1.1       augustss  705:
                    706:        DPRINTFN(2,("uaudio_add_input: bTerminalId=%d wTerminalType=0x%04x "
                    707:                    "bAssocTerminal=%d bNrChannels=%d wChannelConfig=%d "
                    708:                    "iChannelNames=%d iTerminal=%d\n",
                    709:                    d->bTerminalId, UGETW(d->wTerminalType), d->bAssocTerminal,
                    710:                    d->bNrChannels, UGETW(d->wChannelConfig),
                    711:                    d->iChannelNames, d->iTerminal));
                    712: #endif
                    713: }
                    714:
                    715: void
1.67.2.4! skrll     716: uaudio_add_output(struct uaudio_softc *sc, const usb_descriptor_t *v,
        !           717:                  const usb_descriptor_t **dps)
1.1       augustss  718: {
1.4       augustss  719: #ifdef UAUDIO_DEBUG
1.67.2.4! skrll     720:        const struct usb_audio_output_terminal *d =
        !           721:                (const struct usb_audio_output_terminal *)v;
1.1       augustss  722:
                    723:        DPRINTFN(2,("uaudio_add_output: bTerminalId=%d wTerminalType=0x%04x "
                    724:                    "bAssocTerminal=%d bSourceId=%d iTerminal=%d\n",
                    725:                    d->bTerminalId, UGETW(d->wTerminalType), d->bAssocTerminal,
                    726:                    d->bSourceId, d->iTerminal));
                    727: #endif
                    728: }
                    729:
                    730: void
1.67.2.4! skrll     731: uaudio_add_mixer(struct uaudio_softc *sc, const usb_descriptor_t *v,
        !           732:                 const usb_descriptor_t **dps)
1.1       augustss  733: {
1.67.2.4! skrll     734:        const struct usb_audio_mixer_unit *d = (const struct usb_audio_mixer_unit *)v;
1.1       augustss  735:        struct usb_audio_mixer_unit_1 *d1;
                    736:        int c, chs, ichs, ochs, i, o, bno, p, mo, mc, k;
                    737:        uByte *bm;
                    738:        struct mixerctl mix;
                    739:
                    740:        DPRINTFN(2,("uaudio_add_mixer: bUnitId=%d bNrInPins=%d\n",
                    741:                    d->bUnitId, d->bNrInPins));
1.56      kent      742:
1.1       augustss  743:        /* Compute the number of input channels */
                    744:        ichs = 0;
                    745:        for (i = 0; i < d->bNrInPins; i++)
                    746:                ichs += uaudio_get_cluster(d->baSourceId[i], dps).bNrChannels;
                    747:
                    748:        /* and the number of output channels */
                    749:        d1 = (struct usb_audio_mixer_unit_1 *)&d->baSourceId[d->bNrInPins];
                    750:        ochs = d1->bNrChannels;
                    751:        DPRINTFN(2,("uaudio_add_mixer: ichs=%d ochs=%d\n", ichs, ochs));
                    752:
                    753:        bm = d1->bmControls;
                    754:        mix.wIndex = MAKE(d->bUnitId, sc->sc_ac_iface);
                    755:        mix.class = -1;
                    756:        mix.type = MIX_SIGNED_16;
                    757:        mix.ctlunit = AudioNvolume;
                    758: #define BIT(bno) ((bm[bno / 8] >> (7 - bno % 8)) & 1)
                    759:        for (p = i = 0; i < d->bNrInPins; i++) {
                    760:                chs = uaudio_get_cluster(d->baSourceId[i], dps).bNrChannels;
                    761:                mc = 0;
                    762:                for (c = 0; c < chs; c++) {
                    763:                        mo = 0;
                    764:                        for (o = 0; o < ochs; o++) {
                    765:                                bno = (p + c) * ochs + o;
                    766:                                if (BIT(bno))
                    767:                                        mo++;
                    768:                        }
                    769:                        if (mo == 1)
                    770:                                mc++;
                    771:                }
                    772:                if (mc == chs && chs <= MIX_MAX_CHAN) {
                    773:                        k = 0;
                    774:                        for (c = 0; c < chs; c++)
                    775:                                for (o = 0; o < ochs; o++) {
                    776:                                        bno = (p + c) * ochs + o;
                    777:                                        if (BIT(bno))
1.56      kent      778:                                                mix.wValue[k++] =
1.1       augustss  779:                                                        MAKE(p+c+1, o+1);
                    780:                                }
1.67.2.1  skrll     781:                        snprintf(mix.ctlname, sizeof(mix.ctlname), "mix%d-%s",
                    782:                            d->bUnitId, uaudio_id_name(sc, dps,
                    783:                            d->baSourceId[i]));
1.1       augustss  784:                        mix.nchan = chs;
                    785:                        uaudio_mixer_add_ctl(sc, &mix);
                    786:                } else {
                    787:                        /* XXX */
                    788:                }
                    789: #undef BIT
                    790:                p += chs;
                    791:        }
                    792:
                    793: }
                    794:
                    795: void
1.67.2.4! skrll     796: uaudio_add_selector(struct uaudio_softc *sc, const usb_descriptor_t *v,
        !           797:                    const usb_descriptor_t **dps)
1.1       augustss  798: {
1.67.2.4! skrll     799:        const struct usb_audio_selector_unit *d =
        !           800:                (const struct usb_audio_selector_unit *)v;
        !           801:        struct mixerctl mix;
        !           802:        int i, wp;
1.1       augustss  803:
                    804:        DPRINTFN(2,("uaudio_add_selector: bUnitId=%d bNrInPins=%d\n",
                    805:                    d->bUnitId, d->bNrInPins));
1.67.2.4! skrll     806:        mix.wIndex = MAKE(d->bUnitId, sc->sc_ac_iface);
        !           807:        mix.wValue[0] = MAKE(0, 0);
        !           808:        mix.class = UAC_OUTPUT;
        !           809:        mix.nchan = 1;
        !           810:        mix.type = MIX_SELECTOR;
        !           811:        mix.ctlunit = "";
        !           812:        mix.minval = 1;
        !           813:        mix.maxval = d->bNrInPins;
        !           814:        mix.mul = mix.maxval - mix.minval;
        !           815:        wp = snprintf(mix.ctlname, MAX_AUDIO_DEV_LEN, "fea%d-", d->bUnitId);
        !           816:        for (i = 1; i <= d->bNrInPins; i++) {
        !           817:                wp += snprintf(mix.ctlname + wp, MAX_AUDIO_DEV_LEN - wp,
        !           818:                               "i%d", d->baSourceId[i - 1]);
        !           819:                if (wp > MAX_AUDIO_DEV_LEN - 1)
        !           820:                        break;
        !           821:        }
        !           822:        uaudio_mixer_add_ctl(sc, &mix);
1.1       augustss  823: }
                    824:
                    825: void
1.67.2.4! skrll     826: uaudio_add_feature(struct uaudio_softc *sc, const usb_descriptor_t *v,
        !           827:                   const usb_descriptor_t **dps)
1.1       augustss  828: {
1.67.2.4! skrll     829:        const struct usb_audio_feature_unit *d
        !           830:                = (const struct usb_audio_feature_unit *)v;
1.1       augustss  831:        uByte *ctls = d->bmaControls;
                    832:        int ctlsize = d->bControlSize;
                    833:        int nchan = (d->bLength - 7) / ctlsize;
                    834:        int srcId = d->bSourceId;
                    835:        u_int fumask, mmask, cmask;
                    836:        struct mixerctl mix;
                    837:        int chan, ctl, i, unit;
                    838:
                    839: #define GET(i) (ctls[(i)*ctlsize] | \
                    840:                (ctlsize > 1 ? ctls[(i)*ctlsize+1] << 8 : 0))
                    841:
                    842:        mmask = GET(0);
                    843:        /* Figure out what we can control */
                    844:        for (cmask = 0, chan = 1; chan < nchan; chan++) {
                    845:                DPRINTFN(9,("uaudio_add_feature: chan=%d mask=%x\n",
                    846:                            chan, GET(chan)));
                    847:                cmask |= GET(chan);
                    848:        }
                    849:
                    850:        DPRINTFN(1,("uaudio_add_feature: bUnitId=%d bSourceId=%d, "
1.56      kent      851:                    "%d channels, mmask=0x%04x, cmask=0x%04x\n",
1.1       augustss  852:                    d->bUnitId, srcId, nchan, mmask, cmask));
                    853:
                    854:        if (nchan > MIX_MAX_CHAN)
                    855:                nchan = MIX_MAX_CHAN;
                    856:        unit = d->bUnitId;
                    857:        mix.wIndex = MAKE(unit, sc->sc_ac_iface);
                    858:        for (ctl = MUTE_CONTROL; ctl < LOUDNESS_CONTROL; ctl++) {
                    859:                fumask = FU_MASK(ctl);
                    860:                DPRINTFN(4,("uaudio_add_feature: ctl=%d fumask=0x%04x\n",
                    861:                            ctl, fumask));
                    862:                if (mmask & fumask) {
                    863:                        mix.nchan = 1;
                    864:                        mix.wValue[0] = MAKE(ctl, 0);
                    865:                } else if (cmask & fumask) {
                    866:                        mix.nchan = nchan - 1;
                    867:                        for (i = 1; i < nchan; i++) {
                    868:                                if (GET(i) & fumask)
                    869:                                        mix.wValue[i-1] = MAKE(ctl, i);
                    870:                                else
                    871:                                        mix.wValue[i-1] = -1;
                    872:                        }
                    873:                } else {
                    874:                        continue;
                    875:                }
                    876: #undef GET
1.63      augustss  877:                mix.class = UAC_OUTPUT; /* XXX we don't really know this */
1.1       augustss  878:                switch (ctl) {
                    879:                case MUTE_CONTROL:
                    880:                        mix.type = MIX_ON_OFF;
1.63      augustss  881:                        mix.ctlunit = "";
                    882:                        uaudio_mixer_alias_ctl(sc, &mix, AudioNmute);
1.67.2.1  skrll     883:                        snprintf(mix.ctlname, sizeof(mix.ctlname),
                    884:                            "fea%d-%s-%s", unit, uaudio_id_name(sc, dps, srcId),
                    885:                            AudioNmute);
1.1       augustss  886:                        break;
                    887:                case VOLUME_CONTROL:
                    888:                        mix.type = MIX_SIGNED_16;
1.63      augustss  889:                        mix.ctlunit = AudioNvolume;
                    890:                        uaudio_mixer_alias_ctl(sc, &mix, AudioNmaster);
1.67.2.1  skrll     891:                        snprintf(mix.ctlname, sizeof(mix.ctlname),
                    892:                            "fea%d-%s-%s", unit, uaudio_id_name(sc, dps, srcId),
                    893:                            AudioNmaster);
1.1       augustss  894:                        break;
                    895:                case BASS_CONTROL:
                    896:                        mix.type = MIX_SIGNED_8;
1.63      augustss  897:                        mix.ctlunit = AudioNbass;
                    898:                        uaudio_mixer_alias_ctl(sc, &mix, AudioNbass);
1.67.2.1  skrll     899:                        snprintf(mix.ctlname, sizeof(mix.ctlname),
                    900:                            "fea%d-%s-%s", unit, uaudio_id_name(sc, dps, srcId),
                    901:                            AudioNbass);
1.1       augustss  902:                        break;
                    903:                case MID_CONTROL:
                    904:                        mix.type = MIX_SIGNED_8;
1.63      augustss  905:                        mix.ctlunit = AudioNmid;
1.67.2.1  skrll     906:                        snprintf(mix.ctlname, sizeof(mix.ctlname),
                    907:                            "fea%d-%s-%s", unit, uaudio_id_name(sc, dps, srcId),
                    908:                            AudioNmid);
1.1       augustss  909:                        break;
                    910:                case TREBLE_CONTROL:
                    911:                        mix.type = MIX_SIGNED_8;
1.63      augustss  912:                        mix.ctlunit = AudioNtreble;
                    913:                        uaudio_mixer_alias_ctl(sc, &mix, AudioNtreble);
1.67.2.1  skrll     914:                        snprintf(mix.ctlname, sizeof(mix.ctlname),
                    915:                            "fea%d-%s-%s", unit, uaudio_id_name(sc, dps, srcId),
                    916:                            AudioNtreble);
1.1       augustss  917:                        break;
                    918:                case GRAPHIC_EQUALIZER_CONTROL:
1.7       augustss  919:                        continue; /* XXX don't add anything */
1.1       augustss  920:                        break;
                    921:                case AGC_CONTROL:
                    922:                        mix.type = MIX_ON_OFF;
1.67.2.1  skrll     923:                        snprintf(mix.ctlname, sizeof(mix.ctlname),
                    924:                            "fea%d-%s-%s", unit, uaudio_id_name(sc, dps, srcId),
                    925:                            AudioNagc);
1.1       augustss  926:                        mix.ctlunit = "";
                    927:                        break;
                    928:                case DELAY_CONTROL:
                    929:                        mix.type = MIX_UNSIGNED_16;
1.67.2.1  skrll     930:                        snprintf(mix.ctlname, sizeof(mix.ctlname),
                    931:                            "fea%d-%s-%s", unit, uaudio_id_name(sc, dps, srcId),
                    932:                            AudioNdelay);
1.1       augustss  933:                        mix.ctlunit = "4 ms";
                    934:                        break;
                    935:                case BASS_BOOST_CONTROL:
                    936:                        mix.type = MIX_ON_OFF;
1.67.2.1  skrll     937:                        snprintf(mix.ctlname, sizeof(mix.ctlname),
                    938:                            "fea%d-%s-%s", unit, uaudio_id_name(sc, dps, srcId),
                    939:                            AudioNbassboost);
1.1       augustss  940:                        mix.ctlunit = "";
                    941:                        break;
                    942:                case LOUDNESS_CONTROL:
                    943:                        mix.type = MIX_ON_OFF;
1.67.2.1  skrll     944:                        snprintf(mix.ctlname, sizeof(mix.ctlname),
                    945:                            "fea%d-%s-%s", unit, uaudio_id_name(sc, dps, srcId),
                    946:                            AudioNloudness);
1.1       augustss  947:                        mix.ctlunit = "";
                    948:                        break;
                    949:                }
                    950:                uaudio_mixer_add_ctl(sc, &mix);
                    951:        }
                    952: }
                    953:
                    954: void
1.67.2.4! skrll     955: uaudio_add_processing_updown(struct uaudio_softc *sc,
        !           956:                             const usb_descriptor_t *v,
        !           957:                             const usb_descriptor_t **dps)
        !           958: {
        !           959:        const struct usb_audio_processing_unit *d =
        !           960:            (const struct usb_audio_processing_unit *)v;
        !           961:        const struct usb_audio_processing_unit_1 *d1 =
        !           962:            (const struct usb_audio_processing_unit_1 *)&d->baSourceId[d->bNrInPins];
        !           963:        const struct usb_audio_processing_unit_updown *ud =
        !           964:            (const struct usb_audio_processing_unit_updown *)
1.16      augustss  965:                &d1->bmControls[d1->bControlSize];
                    966:        struct mixerctl mix;
                    967:        int i;
                    968:
                    969:        DPRINTFN(2,("uaudio_add_processing_updown: bUnitId=%d bNrModes=%d\n",
                    970:                    d->bUnitId, ud->bNrModes));
                    971:
                    972:        if (!(d1->bmControls[0] & UA_PROC_MASK(UD_MODE_SELECT_CONTROL))) {
                    973:                DPRINTF(("uaudio_add_processing_updown: no mode select\n"));
                    974:                return;
                    975:        }
                    976:
                    977:        mix.wIndex = MAKE(d->bUnitId, sc->sc_ac_iface);
                    978:        mix.nchan = 1;
                    979:        mix.wValue[0] = MAKE(UD_MODE_SELECT_CONTROL, 0);
                    980:        mix.class = -1;
                    981:        mix.type = MIX_ON_OFF;  /* XXX */
                    982:        mix.ctlunit = "";
1.67.2.1  skrll     983:        snprintf(mix.ctlname, sizeof(mix.ctlname), "pro%d-mode", d->bUnitId);
1.16      augustss  984:
                    985:        for (i = 0; i < ud->bNrModes; i++) {
                    986:                DPRINTFN(2,("uaudio_add_processing_updown: i=%d bm=0x%x\n",
                    987:                            i, UGETW(ud->waModes[i])));
                    988:                /* XXX */
                    989:        }
                    990:        uaudio_mixer_add_ctl(sc, &mix);
                    991: }
                    992:
                    993: void
1.67.2.4! skrll     994: uaudio_add_processing(struct uaudio_softc *sc, const usb_descriptor_t *v,
        !           995:                      const usb_descriptor_t **dps)
1.1       augustss  996: {
1.67.2.4! skrll     997:        const struct usb_audio_processing_unit *d =
        !           998:            (const struct usb_audio_processing_unit *)v;
        !           999:        const struct usb_audio_processing_unit_1 *d1 =
        !          1000:            (const struct usb_audio_processing_unit_1 *)&d->baSourceId[d->bNrInPins];
1.15      augustss 1001:        int ptype = UGETW(d->wProcessType);
                   1002:        struct mixerctl mix;
                   1003:
                   1004:        DPRINTFN(2,("uaudio_add_processing: wProcessType=%d bUnitId=%d "
                   1005:                    "bNrInPins=%d\n", ptype, d->bUnitId, d->bNrInPins));
                   1006:
                   1007:        if (d1->bmControls[0] & UA_PROC_ENABLE_MASK) {
                   1008:                mix.wIndex = MAKE(d->bUnitId, sc->sc_ac_iface);
                   1009:                mix.nchan = 1;
                   1010:                mix.wValue[0] = MAKE(XX_ENABLE_CONTROL, 0);
                   1011:                mix.class = -1;
                   1012:                mix.type = MIX_ON_OFF;
                   1013:                mix.ctlunit = "";
1.67.2.1  skrll    1014:                snprintf(mix.ctlname, sizeof(mix.ctlname), "pro%d.%d-enable",
                   1015:                    d->bUnitId, ptype);
1.15      augustss 1016:                uaudio_mixer_add_ctl(sc, &mix);
                   1017:        }
1.1       augustss 1018:
1.15      augustss 1019:        switch(ptype) {
                   1020:        case UPDOWNMIX_PROCESS:
1.16      augustss 1021:                uaudio_add_processing_updown(sc, v, dps);
                   1022:                break;
1.15      augustss 1023:        case DOLBY_PROLOGIC_PROCESS:
                   1024:        case P3D_STEREO_EXTENDER_PROCESS:
                   1025:        case REVERBATION_PROCESS:
                   1026:        case CHORUS_PROCESS:
                   1027:        case DYN_RANGE_COMP_PROCESS:
                   1028:        default:
                   1029: #ifdef UAUDIO_DEBUG
                   1030:                printf("uaudio_add_processing: unit %d, type=%d not impl.\n",
                   1031:                       d->bUnitId, ptype);
1.1       augustss 1032: #endif
1.15      augustss 1033:                break;
                   1034:        }
1.1       augustss 1035: }
                   1036:
                   1037: void
1.67.2.4! skrll    1038: uaudio_add_extension(struct uaudio_softc *sc, const usb_descriptor_t *v,
        !          1039:                     const usb_descriptor_t **dps)
1.1       augustss 1040: {
1.67.2.4! skrll    1041:        const struct usb_audio_extension_unit *d =
        !          1042:            (const struct usb_audio_extension_unit *)v;
        !          1043:        const struct usb_audio_extension_unit_1 *d1 =
        !          1044:            (const struct usb_audio_extension_unit_1 *)&d->baSourceId[d->bNrInPins];
1.1       augustss 1045:        struct mixerctl mix;
                   1046:
                   1047:        DPRINTFN(2,("uaudio_add_extension: bUnitId=%d bNrInPins=%d\n",
                   1048:                    d->bUnitId, d->bNrInPins));
1.28      augustss 1049:
1.31      augustss 1050:        if (usbd_get_quirks(sc->sc_udev)->uq_flags & UQ_AU_NO_XU)
1.28      augustss 1051:                return;
1.1       augustss 1052:
1.15      augustss 1053:        if (d1->bmControls[0] & UA_EXT_ENABLE_MASK) {
1.1       augustss 1054:                mix.wIndex = MAKE(d->bUnitId, sc->sc_ac_iface);
                   1055:                mix.nchan = 1;
                   1056:                mix.wValue[0] = MAKE(UA_EXT_ENABLE, 0);
                   1057:                mix.class = -1;
                   1058:                mix.type = MIX_ON_OFF;
                   1059:                mix.ctlunit = "";
1.67.2.1  skrll    1060:                snprintf(mix.ctlname, sizeof(mix.ctlname), "ext%d-enable",
                   1061:                    d->bUnitId);
1.1       augustss 1062:                uaudio_mixer_add_ctl(sc, &mix);
                   1063:        }
                   1064: }
                   1065:
                   1066: usbd_status
1.67.2.4! skrll    1067: uaudio_identify(struct uaudio_softc *sc, const usb_config_descriptor_t *cdesc)
1.1       augustss 1068: {
1.9       augustss 1069:        usbd_status err;
1.1       augustss 1070:
1.9       augustss 1071:        err = uaudio_identify_ac(sc, cdesc);
                   1072:        if (err)
                   1073:                return (err);
1.1       augustss 1074:        return (uaudio_identify_as(sc, cdesc));
                   1075: }
                   1076:
                   1077: void
1.67.2.4! skrll    1078: uaudio_add_alt(struct uaudio_softc *sc, const struct as_info *ai)
1.1       augustss 1079: {
1.42      christos 1080:        size_t len = sizeof(*ai) * (sc->sc_nalts + 1);
1.47      jdolecek 1081:        struct as_info *nai = (sc->sc_nalts == 0) ?
1.42      christos 1082:            malloc(len, M_USBDEV, M_NOWAIT) :
                   1083:            realloc(sc->sc_alts, len, M_USBDEV, M_NOWAIT);
                   1084:
                   1085:        if (nai == NULL) {
1.1       augustss 1086:                printf("uaudio_add_alt: no memory\n");
                   1087:                return;
                   1088:        }
1.42      christos 1089:
                   1090:        sc->sc_alts = nai;
1.1       augustss 1091:        DPRINTFN(2,("uaudio_add_alt: adding alt=%d, enc=%d\n",
                   1092:                    ai->alt, ai->encoding));
                   1093:        sc->sc_alts[sc->sc_nalts++] = *ai;
                   1094: }
                   1095:
                   1096: usbd_status
1.67.2.4! skrll    1097: uaudio_process_as(struct uaudio_softc *sc, const char *buf, int *offsp,
        !          1098:                  int size, const usb_interface_descriptor_t *id)
1.1       augustss 1099: #define offs (*offsp)
                   1100: {
1.67.2.4! skrll    1101:        const struct usb_audio_streaming_interface_descriptor *asid;
        !          1102:        const struct usb_audio_streaming_type1_descriptor *asf1d;
        !          1103:        const usb_endpoint_descriptor_audio_t *ed;
        !          1104:        const usb_endpoint_descriptor_audio_t *epdesc1;
        !          1105:        const struct usb_audio_streaming_endpoint_descriptor *sed;
1.1       augustss 1106:        int format, chan, prec, enc;
1.67.2.4! skrll    1107:        int dir, type, sync;
1.1       augustss 1108:        struct as_info ai;
1.67.2.4! skrll    1109:        const char *format_str;
1.1       augustss 1110:
1.67.2.4! skrll    1111:        asid = (const void *)(buf + offs);
1.1       augustss 1112:        if (asid->bDescriptorType != UDESC_CS_INTERFACE ||
                   1113:            asid->bDescriptorSubtype != AS_GENERAL)
                   1114:                return (USBD_INVAL);
1.67.2.4! skrll    1115:        DPRINTF(("uaudio_process_as: asid: bTerminakLink=%d wFormatTag=%d\n",
        !          1116:                 asid->bTerminalLink, UGETW(asid->wFormatTag)));
1.1       augustss 1117:        offs += asid->bLength;
                   1118:        if (offs > size)
                   1119:                return (USBD_INVAL);
1.67.2.4! skrll    1120:
        !          1121:        asf1d = (const void *)(buf + offs);
1.1       augustss 1122:        if (asf1d->bDescriptorType != UDESC_CS_INTERFACE ||
                   1123:            asf1d->bDescriptorSubtype != FORMAT_TYPE)
                   1124:                return (USBD_INVAL);
                   1125:        offs += asf1d->bLength;
                   1126:        if (offs > size)
                   1127:                return (USBD_INVAL);
                   1128:
1.3       augustss 1129:        if (asf1d->bFormatType != FORMAT_TYPE_I) {
                   1130:                printf("%s: ignored setting with type %d format\n",
                   1131:                       USBDEVNAME(sc->sc_dev), UGETW(asid->wFormatTag));
                   1132:                return (USBD_NORMAL_COMPLETION);
                   1133:        }
                   1134:
1.67.2.4! skrll    1135:        ed = (const void *)(buf + offs);
1.1       augustss 1136:        if (ed->bDescriptorType != UDESC_ENDPOINT)
                   1137:                return (USBD_INVAL);
1.67.2.4! skrll    1138:        DPRINTF(("uaudio_process_as: endpoint[0] bLength=%d bDescriptorType=%d "
1.5       augustss 1139:                 "bEndpointAddress=%d bmAttributes=0x%x wMaxPacketSize=%d "
                   1140:                 "bInterval=%d bRefresh=%d bSynchAddress=%d\n",
                   1141:                 ed->bLength, ed->bDescriptorType, ed->bEndpointAddress,
                   1142:                 ed->bmAttributes, UGETW(ed->wMaxPacketSize),
                   1143:                 ed->bInterval, ed->bRefresh, ed->bSynchAddress));
1.1       augustss 1144:        offs += ed->bLength;
                   1145:        if (offs > size)
                   1146:                return (USBD_INVAL);
1.5       augustss 1147:        if (UE_GET_XFERTYPE(ed->bmAttributes) != UE_ISOCHRONOUS)
1.1       augustss 1148:                return (USBD_INVAL);
1.5       augustss 1149:
                   1150:        dir = UE_GET_DIR(ed->bEndpointAddress);
                   1151:        type = UE_GET_ISO_TYPE(ed->bmAttributes);
1.31      augustss 1152:        if ((usbd_get_quirks(sc->sc_udev)->uq_flags & UQ_AU_INP_ASYNC) &&
                   1153:            dir == UE_DIR_IN && type == UE_ISO_ADAPT)
                   1154:                type = UE_ISO_ASYNC;
                   1155:
1.40      augustss 1156:        /* We can't handle endpoints that need a sync pipe yet. */
1.67.2.4! skrll    1157:        sync = FALSE;
        !          1158:        if (dir == UE_DIR_IN && type == UE_ISO_ADAPT) {
        !          1159:                sync = TRUE;
        !          1160: #ifndef UAUDIO_MULTIPLE_ENDPOINTS
        !          1161:                printf("%s: ignored input endpoint of type adaptive\n",
        !          1162:                       USBDEVNAME(sc->sc_dev));
1.1       augustss 1163:                return (USBD_NORMAL_COMPLETION);
1.67.2.4! skrll    1164: #endif
        !          1165:        }
        !          1166:        if (dir != UE_DIR_IN && type == UE_ISO_ASYNC) {
        !          1167:                sync = TRUE;
        !          1168: #ifndef UAUDIO_MULTIPLE_ENDPOINTS
        !          1169:                printf("%s: ignored output endpoint of type async\n",
        !          1170:                       USBDEVNAME(sc->sc_dev));
        !          1171:                return (USBD_NORMAL_COMPLETION);
        !          1172: #endif
1.1       augustss 1173:        }
1.56      kent     1174:
1.67.2.4! skrll    1175:        sed = (const void *)(buf + offs);
1.1       augustss 1176:        if (sed->bDescriptorType != UDESC_CS_ENDPOINT ||
                   1177:            sed->bDescriptorSubtype != AS_GENERAL)
                   1178:                return (USBD_INVAL);
1.67.2.4! skrll    1179:        DPRINTF((" streadming_endpoint: offset=%d bLength=%d\n", offs, sed->bLength));
1.1       augustss 1180:        offs += sed->bLength;
                   1181:        if (offs > size)
                   1182:                return (USBD_INVAL);
1.56      kent     1183:
1.67.2.4! skrll    1184:        if (sync && id->bNumEndpoints <= 1) {
        !          1185:                printf("%s: a sync-pipe endpoint but no other endpoint\n",
        !          1186:                       USBDEVNAME(sc->sc_dev));
        !          1187:                return USBD_INVAL;
        !          1188:        }
        !          1189:        if (!sync && id->bNumEndpoints > 1) {
        !          1190:                printf("%s: non sync-pipe endpoint but multiple endpoints\n",
        !          1191:                       USBDEVNAME(sc->sc_dev));
        !          1192:                return USBD_INVAL;
        !          1193:        }
        !          1194:        epdesc1 = NULL;
        !          1195:        if (id->bNumEndpoints > 1) {
        !          1196:                epdesc1 = (const void*)(buf + offs);
        !          1197:                if (epdesc1->bDescriptorType != UDESC_ENDPOINT)
        !          1198:                        return USBD_INVAL;
        !          1199:                DPRINTF(("uaudio_process_as: endpoint[1] bLength=%d "
        !          1200:                         "bDescriptorType=%d bEndpointAddress=%d "
        !          1201:                         "bmAttributes=0x%x wMaxPacketSize=%d bInterval=%d "
        !          1202:                         "bRefresh=%d bSynchAddress=%d\n",
        !          1203:                         epdesc1->bLength, epdesc1->bDescriptorType,
        !          1204:                         epdesc1->bEndpointAddress, epdesc1->bmAttributes,
        !          1205:                         UGETW(epdesc1->wMaxPacketSize), epdesc1->bInterval,
        !          1206:                         epdesc1->bRefresh, epdesc1->bSynchAddress));
        !          1207:                offs += epdesc1->bLength;
        !          1208:                if (offs > size)
        !          1209:                        return USBD_INVAL;
        !          1210:                if (epdesc1->bSynchAddress != 0) {
        !          1211:                        printf("%s: invalid endpoint: bSynchAddress=0\n",
        !          1212:                               USBDEVNAME(sc->sc_dev));
        !          1213:                        return USBD_INVAL;
        !          1214:                }
        !          1215:                if (UE_GET_XFERTYPE(epdesc1->bmAttributes) != UE_ISOCHRONOUS) {
        !          1216:                        printf("%s: invalid endpoint: bmAttributes=0x%x\n",
        !          1217:                               USBDEVNAME(sc->sc_dev), epdesc1->bmAttributes);
        !          1218:                        return USBD_INVAL;
        !          1219:                }
        !          1220:                if (epdesc1->bEndpointAddress != ed->bSynchAddress) {
        !          1221:                        printf("%s: invalid endpoint addresses: "
        !          1222:                               "ep[0]->bSynchAddress=0x%x "
        !          1223:                               "ep[1]->bEndpointAddress=0x%x\n",
        !          1224:                               USBDEVNAME(sc->sc_dev), ed->bSynchAddress,
        !          1225:                               epdesc1->bEndpointAddress);
        !          1226:                        return USBD_INVAL;
        !          1227:                }
        !          1228:                /* UE_GET_ADDR(epdesc1->bEndpointAddress), and epdesc1->bRefresh */
        !          1229:        }
        !          1230:
1.3       augustss 1231:        format = UGETW(asid->wFormatTag);
1.1       augustss 1232:        chan = asf1d->bNrChannels;
                   1233:        prec = asf1d->bBitResolution;
1.51      kent     1234:        if (prec != 8 && prec != 16 && prec != 24) {
1.1       augustss 1235:                printf("%s: ignored setting with precision %d\n",
                   1236:                       USBDEVNAME(sc->sc_dev), prec);
                   1237:                return (USBD_NORMAL_COMPLETION);
                   1238:        }
                   1239:        switch (format) {
1.3       augustss 1240:        case UA_FMT_PCM:
1.51      kent     1241:                if (prec == 8) {
                   1242:                        sc->sc_altflags |= HAS_8;
                   1243:                } else if (prec == 16) {
                   1244:                        sc->sc_altflags |= HAS_16;
                   1245:                } else if (prec == 24) {
                   1246:                        sc->sc_altflags |= HAS_24;
                   1247:                }
1.5       augustss 1248:                enc = AUDIO_ENCODING_SLINEAR_LE;
1.67.2.4! skrll    1249:                format_str = "pcm";
1.1       augustss 1250:                break;
1.3       augustss 1251:        case UA_FMT_PCM8:
1.5       augustss 1252:                enc = AUDIO_ENCODING_ULINEAR_LE;
1.1       augustss 1253:                sc->sc_altflags |= HAS_8U;
1.67.2.4! skrll    1254:                format_str = "pcm8";
1.1       augustss 1255:                break;
1.3       augustss 1256:        case UA_FMT_ALAW:
1.5       augustss 1257:                enc = AUDIO_ENCODING_ALAW;
1.1       augustss 1258:                sc->sc_altflags |= HAS_ALAW;
1.67.2.4! skrll    1259:                format_str = "alaw";
1.1       augustss 1260:                break;
1.3       augustss 1261:        case UA_FMT_MULAW:
1.5       augustss 1262:                enc = AUDIO_ENCODING_ULAW;
1.1       augustss 1263:                sc->sc_altflags |= HAS_MULAW;
1.67.2.4! skrll    1264:                format_str = "mulaw";
1.1       augustss 1265:                break;
1.67.2.4! skrll    1266:        case UA_FMT_IEEE_FLOAT:
1.1       augustss 1267:        default:
                   1268:                printf("%s: ignored setting with format %d\n",
                   1269:                       USBDEVNAME(sc->sc_dev), format);
                   1270:                return (USBD_NORMAL_COMPLETION);
                   1271:        }
1.67.2.4! skrll    1272: #ifdef UAUDIO_DEBUG
        !          1273:        printf("%s: %s: %dch, %d/%dbit, %s,", USBDEVNAME(sc->sc_dev),
        !          1274:               dir == UE_DIR_IN ? "recording" : "playback",
        !          1275:               chan, prec, asf1d->bSubFrameSize * 8, format_str);
        !          1276:        if (asf1d->bSamFreqType == UA_SAMP_CONTNUOUS) {
        !          1277:                printf(" %d-%dHz\n", UA_SAMP_LO(asf1d), UA_SAMP_HI(asf1d));
        !          1278:        } else {
        !          1279:                int r;
        !          1280:                printf(" %d", UA_GETSAMP(asf1d, 0));
        !          1281:                for (r = 1; r < asf1d->bSamFreqType; r++)
        !          1282:                        printf(",%d", UA_GETSAMP(asf1d, r));
        !          1283:                printf("Hz\n");
        !          1284:        }
        !          1285: #endif
1.1       augustss 1286:        ai.alt = id->bAlternateSetting;
                   1287:        ai.encoding = enc;
1.50      kent     1288:        ai.attributes = sed->bmAttributes;
1.1       augustss 1289:        ai.idesc = id;
                   1290:        ai.edesc = ed;
1.67.2.4! skrll    1291:        ai.edesc1 = epdesc1;
1.1       augustss 1292:        ai.asf1desc = asf1d;
1.50      kent     1293:        ai.sc_busy = 0;
1.1       augustss 1294:        uaudio_add_alt(sc, &ai);
1.50      kent     1295: #ifdef UAUDIO_DEBUG
1.67.2.4! skrll    1296:        if (ai.attributes & UA_SED_FREQ_CONTROL)
        !          1297:                DPRINTFN(1, ("uaudio_process_as:  FREQ_CONTROL\n"));
        !          1298:        if (ai.attributes & UA_SED_PITCH_CONTROL)
        !          1299:                DPRINTFN(1, ("uaudio_process_as:  PITCH_CONTROL\n"));
1.50      kent     1300: #endif
1.47      jdolecek 1301:        sc->sc_mode |= (dir == UE_DIR_OUT) ? AUMODE_PLAY : AUMODE_RECORD;
                   1302:
1.1       augustss 1303:        return (USBD_NORMAL_COMPLETION);
                   1304: }
                   1305: #undef offs
1.56      kent     1306:
1.1       augustss 1307: usbd_status
1.67.2.4! skrll    1308: uaudio_identify_as(struct uaudio_softc *sc,
        !          1309:                   const usb_config_descriptor_t *cdesc)
1.1       augustss 1310: {
1.67.2.4! skrll    1311:        const usb_interface_descriptor_t *id;
        !          1312:        const char *buf;
1.1       augustss 1313:        int size, offs;
                   1314:
                   1315:        size = UGETW(cdesc->wTotalLength);
1.67.2.4! skrll    1316:        buf = (const char *)cdesc;
1.1       augustss 1317:
                   1318:        /* Locate the AudioStreaming interface descriptor. */
                   1319:        offs = 0;
1.19      augustss 1320:        id = uaudio_find_iface(buf, size, &offs, UISUBCLASS_AUDIOSTREAM);
1.9       augustss 1321:        if (id == NULL)
1.1       augustss 1322:                return (USBD_INVAL);
                   1323:
                   1324:        /* Loop through all the alternate settings. */
                   1325:        while (offs <= size) {
1.67.2.4! skrll    1326:                DPRINTFN(2, ("uaudio_identify: interface=%d offset=%d\n",
        !          1327:                    id->bInterfaceNumber, offs));
1.1       augustss 1328:                switch (id->bNumEndpoints) {
                   1329:                case 0:
                   1330:                        DPRINTFN(2, ("uaudio_identify: AS null alt=%d\n",
                   1331:                                     id->bAlternateSetting));
                   1332:                        sc->sc_nullalt = id->bAlternateSetting;
                   1333:                        break;
                   1334:                case 1:
1.67.2.4! skrll    1335: #ifdef UAUDIO_MULTIPLE_ENDPOINTS
        !          1336:                case 2:
        !          1337: #endif
1.64      simonb   1338:                        uaudio_process_as(sc, buf, &offs, size, id);
1.1       augustss 1339:                        break;
                   1340:                default:
                   1341:                        printf("%s: ignored audio interface with %d "
                   1342:                               "endpoints\n",
                   1343:                               USBDEVNAME(sc->sc_dev), id->bNumEndpoints);
                   1344:                        break;
                   1345:                }
1.19      augustss 1346:                id = uaudio_find_iface(buf, size, &offs,UISUBCLASS_AUDIOSTREAM);
1.9       augustss 1347:                if (id == NULL)
1.1       augustss 1348:                        break;
                   1349:        }
                   1350:        if (offs > size)
                   1351:                return (USBD_INVAL);
                   1352:        DPRINTF(("uaudio_identify_as: %d alts available\n", sc->sc_nalts));
1.47      jdolecek 1353:
1.67.2.1  skrll    1354:        if (sc->sc_mode == 0) {
1.56      kent     1355:                printf("%s: no usable endpoint found\n",
1.5       augustss 1356:                       USBDEVNAME(sc->sc_dev));
                   1357:                return (USBD_INVAL);
                   1358:        }
1.47      jdolecek 1359:
1.1       augustss 1360:        return (USBD_NORMAL_COMPLETION);
                   1361: }
                   1362:
                   1363: usbd_status
1.67.2.4! skrll    1364: uaudio_identify_ac(struct uaudio_softc *sc, const usb_config_descriptor_t *cdesc)
1.1       augustss 1365: {
1.67.2.4! skrll    1366:        const usb_interface_descriptor_t *id;
        !          1367:        const struct usb_audio_control_descriptor *acdp;
        !          1368:        const usb_descriptor_t *dp, *dps[256];
        !          1369:        const char *buf, *ibuf, *ibufend;
1.1       augustss 1370:        int size, offs, aclen, ndps, i;
                   1371:
                   1372:        size = UGETW(cdesc->wTotalLength);
                   1373:        buf = (char *)cdesc;
                   1374:
                   1375:        /* Locate the AudioControl interface descriptor. */
                   1376:        offs = 0;
1.19      augustss 1377:        id = uaudio_find_iface(buf, size, &offs, UISUBCLASS_AUDIOCONTROL);
1.14      augustss 1378:        if (id == NULL)
1.1       augustss 1379:                return (USBD_INVAL);
                   1380:        if (offs + sizeof *acdp > size)
                   1381:                return (USBD_INVAL);
                   1382:        sc->sc_ac_iface = id->bInterfaceNumber;
                   1383:        DPRINTFN(2,("uaudio_identify: AC interface is %d\n", sc->sc_ac_iface));
                   1384:
                   1385:        /* A class-specific AC interface header should follow. */
                   1386:        ibuf = buf + offs;
1.67.2.4! skrll    1387:        acdp = (const struct usb_audio_control_descriptor *)ibuf;
1.1       augustss 1388:        if (acdp->bDescriptorType != UDESC_CS_INTERFACE ||
                   1389:            acdp->bDescriptorSubtype != UDESCSUB_AC_HEADER)
                   1390:                return (USBD_INVAL);
                   1391:        aclen = UGETW(acdp->wTotalLength);
                   1392:        if (offs + aclen > size)
                   1393:                return (USBD_INVAL);
1.5       augustss 1394:
1.1       augustss 1395:        if (!(usbd_get_quirks(sc->sc_udev)->uq_flags & UQ_BAD_ADC) &&
                   1396:             UGETW(acdp->bcdADC) != UAUDIO_VERSION)
                   1397:                return (USBD_INVAL);
                   1398:
1.7       augustss 1399:        sc->sc_audio_rev = UGETW(acdp->bcdADC);
1.1       augustss 1400:        DPRINTFN(2,("uaudio_identify: found AC header, vers=%03x, len=%d\n",
1.7       augustss 1401:                 sc->sc_audio_rev, aclen));
1.1       augustss 1402:
                   1403:        sc->sc_nullalt = -1;
                   1404:
                   1405:        /* Scan through all the AC specific descriptors */
                   1406:        ibufend = ibuf + aclen;
                   1407:        dp = (usb_descriptor_t *)ibuf;
                   1408:        ndps = 0;
                   1409:        memset(dps, 0, sizeof dps);
                   1410:        for (;;) {
                   1411:                ibuf += dp->bLength;
                   1412:                if (ibuf >= ibufend)
                   1413:                        break;
                   1414:                dp = (usb_descriptor_t *)ibuf;
                   1415:                if (ibuf + dp->bLength > ibufend)
                   1416:                        return (USBD_INVAL);
                   1417:                if (dp->bDescriptorType != UDESC_CS_INTERFACE) {
                   1418:                        printf("uaudio_identify: skip desc type=0x%02x\n",
                   1419:                               dp->bDescriptorType);
                   1420:                        continue;
                   1421:                }
                   1422:                i = ((struct usb_audio_input_terminal *)dp)->bTerminalId;
                   1423:                dps[i] = dp;
                   1424:                if (i > ndps)
                   1425:                        ndps = i;
                   1426:        }
                   1427:        ndps++;
                   1428:
                   1429:        for (i = 0; i < ndps; i++) {
                   1430:                dp = dps[i];
1.14      augustss 1431:                if (dp == NULL)
1.1       augustss 1432:                        continue;
1.56      kent     1433:                DPRINTF(("uaudio_identify: subtype=%d\n",
1.1       augustss 1434:                         dp->bDescriptorSubtype));
                   1435:                switch (dp->bDescriptorSubtype) {
                   1436:                case UDESCSUB_AC_HEADER:
                   1437:                        printf("uaudio_identify: unexpected AC header\n");
                   1438:                        break;
                   1439:                case UDESCSUB_AC_INPUT:
                   1440:                        uaudio_add_input(sc, dp, dps);
                   1441:                        break;
                   1442:                case UDESCSUB_AC_OUTPUT:
                   1443:                        uaudio_add_output(sc, dp, dps);
                   1444:                        break;
                   1445:                case UDESCSUB_AC_MIXER:
                   1446:                        uaudio_add_mixer(sc, dp, dps);
                   1447:                        break;
                   1448:                case UDESCSUB_AC_SELECTOR:
                   1449:                        uaudio_add_selector(sc, dp, dps);
                   1450:                        break;
                   1451:                case UDESCSUB_AC_FEATURE:
                   1452:                        uaudio_add_feature(sc, dp, dps);
                   1453:                        break;
                   1454:                case UDESCSUB_AC_PROCESSING:
                   1455:                        uaudio_add_processing(sc, dp, dps);
                   1456:                        break;
                   1457:                case UDESCSUB_AC_EXTENSION:
                   1458:                        uaudio_add_extension(sc, dp, dps);
                   1459:                        break;
                   1460:                default:
                   1461:                        printf("uaudio_identify: bad AC desc subtype=0x%02x\n",
                   1462:                               dp->bDescriptorSubtype);
                   1463:                        break;
                   1464:                }
                   1465:        }
                   1466:        return (USBD_NORMAL_COMPLETION);
                   1467: }
                   1468:
                   1469: int
1.26      augustss 1470: uaudio_query_devinfo(void *addr, mixer_devinfo_t *mi)
1.1       augustss 1471: {
                   1472:        struct uaudio_softc *sc = addr;
                   1473:        struct mixerctl *mc;
1.67.2.4! skrll    1474:        int n, nctls, i;
1.1       augustss 1475:
                   1476:        DPRINTFN(2,("uaudio_query_devinfo: index=%d\n", mi->index));
                   1477:        if (sc->sc_dying)
                   1478:                return (EIO);
1.56      kent     1479:
1.1       augustss 1480:        n = mi->index;
                   1481:        nctls = sc->sc_nctls;
                   1482:
1.63      augustss 1483:        switch (n) {
                   1484:        case UAC_OUTPUT:
                   1485:                mi->type = AUDIO_MIXER_CLASS;
                   1486:                mi->mixer_class = UAC_OUTPUT;
                   1487:                mi->next = mi->prev = AUDIO_MIXER_LAST;
1.67.2.1  skrll    1488:                strlcpy(mi->label.name, AudioCoutputs, sizeof(mi->label.name));
1.63      augustss 1489:                return (0);
                   1490:        case UAC_INPUT:
                   1491:                mi->type = AUDIO_MIXER_CLASS;
                   1492:                mi->mixer_class = UAC_INPUT;
                   1493:                mi->next = mi->prev = AUDIO_MIXER_LAST;
1.67.2.1  skrll    1494:                strlcpy(mi->label.name, AudioCinputs, sizeof(mi->label.name));
1.63      augustss 1495:                return (0);
                   1496:        case UAC_EQUAL:
                   1497:                mi->type = AUDIO_MIXER_CLASS;
                   1498:                mi->mixer_class = UAC_EQUAL;
                   1499:                mi->next = mi->prev = AUDIO_MIXER_LAST;
1.67.2.1  skrll    1500:                strlcpy(mi->label.name, AudioCequalization,
                   1501:                    sizeof(mi->label.name));
1.63      augustss 1502:                return (0);
                   1503:        default:
                   1504:                break;
1.1       augustss 1505:        }
1.63      augustss 1506:
                   1507:        n -= UAC_NCLASSES;
                   1508:        if (n < 0 || n >= nctls)
                   1509:                return (ENXIO);
                   1510:
1.1       augustss 1511:        mc = &sc->sc_ctls[n];
1.67.2.1  skrll    1512:        strlcpy(mi->label.name, mc->ctlname, sizeof(mi->label.name));
1.1       augustss 1513:        mi->mixer_class = mc->class;
                   1514:        mi->next = mi->prev = AUDIO_MIXER_LAST; /* XXX */
                   1515:        switch (mc->type) {
                   1516:        case MIX_ON_OFF:
                   1517:                mi->type = AUDIO_MIXER_ENUM;
                   1518:                mi->un.e.num_mem = 2;
1.67.2.1  skrll    1519:                strlcpy(mi->un.e.member[0].label.name, AudioNoff,
                   1520:                    sizeof(mi->un.e.member[0].label.name));
1.1       augustss 1521:                mi->un.e.member[0].ord = 0;
1.67.2.1  skrll    1522:                strlcpy(mi->un.e.member[1].label.name, AudioNon,
                   1523:                    sizeof(mi->un.e.member[1].label.name));
1.1       augustss 1524:                mi->un.e.member[1].ord = 1;
                   1525:                break;
1.67.2.4! skrll    1526:        case MIX_SELECTOR:
        !          1527:                mi->type = AUDIO_MIXER_ENUM;
        !          1528:                mi->un.e.num_mem = mc->maxval - mc->minval + 1;
        !          1529:                for (i = 0; i <= mc->maxval - mc->minval; i++) {
        !          1530:                        snprintf(mi->un.e.member[i].label.name,
        !          1531:                                 sizeof(mi->un.e.member[i].label.name),
        !          1532:                                 "%d", i + mc->minval);
        !          1533:                        mi->un.e.member[i].ord = i + mc->minval;
        !          1534:                }
        !          1535:                break;
1.1       augustss 1536:        default:
                   1537:                mi->type = AUDIO_MIXER_VALUE;
                   1538:                strncpy(mi->un.v.units.name, mc->ctlunit, MAX_AUDIO_DEV_LEN);
                   1539:                mi->un.v.num_channels = mc->nchan;
1.33      augustss 1540:                mi->un.v.delta = mc->delta;
1.1       augustss 1541:                break;
                   1542:        }
                   1543:        return (0);
                   1544: }
                   1545:
                   1546: int
1.26      augustss 1547: uaudio_open(void *addr, int flags)
1.1       augustss 1548: {
                   1549:        struct uaudio_softc *sc = addr;
                   1550:
1.56      kent     1551:        DPRINTF(("uaudio_open: sc=%p\n", sc));
1.1       augustss 1552:        if (sc->sc_dying)
                   1553:                return (EIO);
                   1554:
1.67.2.1  skrll    1555:        if ((flags & FWRITE) && !(sc->sc_mode & AUMODE_PLAY))
                   1556:                return (EACCES);
                   1557:        if ((flags & FREAD) && !(sc->sc_mode & AUMODE_RECORD))
                   1558:                return (EACCES);
1.1       augustss 1559:
1.56      kent     1560:        return (0);
1.1       augustss 1561: }
                   1562:
                   1563: /*
                   1564:  * Close function is called at splaudio().
                   1565:  */
                   1566: void
1.26      augustss 1567: uaudio_close(void *addr)
1.1       augustss 1568: {
                   1569: }
                   1570:
                   1571: int
1.26      augustss 1572: uaudio_drain(void *addr)
1.1       augustss 1573: {
                   1574:        struct uaudio_softc *sc = addr;
                   1575:
                   1576:        usbd_delay_ms(sc->sc_udev, UAUDIO_NCHANBUFS * UAUDIO_NFRAMES);
                   1577:
                   1578:        return (0);
                   1579: }
                   1580:
                   1581: int
1.26      augustss 1582: uaudio_halt_out_dma(void *addr)
1.1       augustss 1583: {
                   1584:        struct uaudio_softc *sc = addr;
                   1585:
                   1586:        DPRINTF(("uaudio_halt_out_dma: enter\n"));
1.47      jdolecek 1587:        if (sc->sc_playchan.pipe != NULL) {
                   1588:                uaudio_chan_close(sc, &sc->sc_playchan);
                   1589:                sc->sc_playchan.pipe = NULL;
                   1590:                uaudio_chan_free_buffers(sc, &sc->sc_playchan);
1.67.2.1  skrll    1591:                sc->sc_playchan.intr = NULL;
1.1       augustss 1592:        }
1.56      kent     1593:        return (0);
1.1       augustss 1594: }
                   1595:
                   1596: int
1.26      augustss 1597: uaudio_halt_in_dma(void *addr)
1.1       augustss 1598: {
                   1599:        struct uaudio_softc *sc = addr;
                   1600:
                   1601:        DPRINTF(("uaudio_halt_in_dma: enter\n"));
1.47      jdolecek 1602:        if (sc->sc_recchan.pipe != NULL) {
                   1603:                uaudio_chan_close(sc, &sc->sc_recchan);
                   1604:                sc->sc_recchan.pipe = NULL;
                   1605:                uaudio_chan_free_buffers(sc, &sc->sc_recchan);
1.67.2.1  skrll    1606:                sc->sc_recchan.intr = NULL;
1.5       augustss 1607:        }
1.56      kent     1608:        return (0);
1.1       augustss 1609: }
                   1610:
                   1611: int
1.26      augustss 1612: uaudio_getdev(void *addr, struct audio_device *retp)
1.1       augustss 1613: {
                   1614:        struct uaudio_softc *sc = addr;
                   1615:
                   1616:        DPRINTF(("uaudio_mixer_getdev:\n"));
                   1617:        if (sc->sc_dying)
                   1618:                return (EIO);
1.56      kent     1619:
1.1       augustss 1620:        *retp = uaudio_device;
1.56      kent     1621:        return (0);
1.1       augustss 1622: }
                   1623:
                   1624: /*
                   1625:  * Make sure the block size is large enough to hold all outstanding transfers.
                   1626:  */
                   1627: int
1.26      augustss 1628: uaudio_round_blocksize(void *addr, int blk)
1.1       augustss 1629: {
                   1630:        struct uaudio_softc *sc = addr;
                   1631:        int bpf;
                   1632:
1.54      kent     1633:        DPRINTF(("uaudio_round_blocksize: p.bpf=%d r.bpf=%d\n",
1.56      kent     1634:                 sc->sc_playchan.bytes_per_frame,
                   1635:                 sc->sc_recchan.bytes_per_frame));
1.47      jdolecek 1636:        if (sc->sc_playchan.bytes_per_frame > sc->sc_recchan.bytes_per_frame) {
                   1637:                bpf = sc->sc_playchan.bytes_per_frame
                   1638:                    + sc->sc_playchan.sample_size;
                   1639:        } else {
                   1640:                bpf = sc->sc_recchan.bytes_per_frame
                   1641:                    + sc->sc_recchan.sample_size;
                   1642:        }
1.1       augustss 1643:        /* XXX */
                   1644:        bpf *= UAUDIO_NFRAMES * UAUDIO_NCHANBUFS;
                   1645:
                   1646:        bpf = (bpf + 15) &~ 15;
                   1647:
                   1648:        if (blk < bpf)
                   1649:                blk = bpf;
                   1650:
1.5       augustss 1651: #ifdef DIAGNOSTIC
                   1652:        if (blk <= 0) {
                   1653:                printf("uaudio_round_blocksize: blk=%d\n", blk);
                   1654:                blk = 512;
                   1655:        }
                   1656: #endif
                   1657:
1.1       augustss 1658:        DPRINTFN(1,("uaudio_round_blocksize: blk=%d\n", blk));
                   1659:        return (blk);
                   1660: }
                   1661:
                   1662: int
1.26      augustss 1663: uaudio_get_props(void *addr)
1.1       augustss 1664: {
1.47      jdolecek 1665:        return (AUDIO_PROP_FULLDUPLEX | AUDIO_PROP_INDEPENDENT);
1.1       augustss 1666:
                   1667: }
                   1668:
                   1669: int
1.27      augustss 1670: uaudio_get(struct uaudio_softc *sc, int which, int type, int wValue,
1.26      augustss 1671:           int wIndex, int len)
1.1       augustss 1672: {
                   1673:        usb_device_request_t req;
                   1674:        u_int8_t data[4];
1.9       augustss 1675:        usbd_status err;
1.1       augustss 1676:        int val;
                   1677:
                   1678:        if (wValue == -1)
                   1679:                return (0);
                   1680:
                   1681:        req.bmRequestType = type;
                   1682:        req.bRequest = which;
                   1683:        USETW(req.wValue, wValue);
                   1684:        USETW(req.wIndex, wIndex);
                   1685:        USETW(req.wLength, len);
                   1686:        DPRINTFN(2,("uaudio_get: type=0x%02x req=0x%02x wValue=0x%04x "
1.56      kent     1687:                    "wIndex=0x%04x len=%d\n",
1.1       augustss 1688:                    type, which, wValue, wIndex, len));
1.47      jdolecek 1689:        err = usbd_do_request(sc->sc_udev, &req, data);
1.9       augustss 1690:        if (err) {
1.20      augustss 1691:                DPRINTF(("uaudio_get: err=%s\n", usbd_errstr(err)));
1.1       augustss 1692:                return (-1);
                   1693:        }
                   1694:        switch (len) {
                   1695:        case 1:
                   1696:                val = data[0];
                   1697:                break;
                   1698:        case 2:
                   1699:                val = data[0] | (data[1] << 8);
                   1700:                break;
                   1701:        default:
                   1702:                DPRINTF(("uaudio_get: bad length=%d\n", len));
                   1703:                return (-1);
                   1704:        }
                   1705:        DPRINTFN(2,("uaudio_get: val=%d\n", val));
                   1706:        return (val);
                   1707: }
                   1708:
                   1709: void
1.27      augustss 1710: uaudio_set(struct uaudio_softc *sc, int which, int type, int wValue,
1.26      augustss 1711:           int wIndex, int len, int val)
1.1       augustss 1712: {
                   1713:        usb_device_request_t req;
                   1714:        u_int8_t data[4];
1.9       augustss 1715:        usbd_status err;
1.1       augustss 1716:
                   1717:        if (wValue == -1)
                   1718:                return;
                   1719:
                   1720:        req.bmRequestType = type;
                   1721:        req.bRequest = which;
                   1722:        USETW(req.wValue, wValue);
                   1723:        USETW(req.wIndex, wIndex);
                   1724:        USETW(req.wLength, len);
                   1725:        switch (len) {
                   1726:        case 1:
                   1727:                data[0] = val;
                   1728:                break;
                   1729:        case 2:
                   1730:                data[0] = val;
                   1731:                data[1] = val >> 8;
                   1732:                break;
                   1733:        default:
                   1734:                return;
                   1735:        }
                   1736:        DPRINTFN(2,("uaudio_set: type=0x%02x req=0x%02x wValue=0x%04x "
1.56      kent     1737:                    "wIndex=0x%04x len=%d, val=%d\n",
1.1       augustss 1738:                    type, which, wValue, wIndex, len, val & 0xffff));
1.47      jdolecek 1739:        err = usbd_do_request(sc->sc_udev, &req, data);
1.4       augustss 1740: #ifdef UAUDIO_DEBUG
1.12      augustss 1741:        if (err)
1.9       augustss 1742:                DPRINTF(("uaudio_set: err=%d\n", err));
1.1       augustss 1743: #endif
                   1744: }
                   1745:
                   1746: int
1.26      augustss 1747: uaudio_signext(int type, int val)
1.1       augustss 1748: {
                   1749:        if (!MIX_UNSIGNED(type)) {
                   1750:                if (MIX_SIZE(type) == 2)
                   1751:                        val = (int16_t)val;
                   1752:                else
                   1753:                        val = (int8_t)val;
                   1754:        }
                   1755:        return (val);
                   1756: }
                   1757:
                   1758: int
1.26      augustss 1759: uaudio_value2bsd(struct mixerctl *mc, int val)
1.1       augustss 1760: {
                   1761:        DPRINTFN(5, ("uaudio_value2bsd: type=%03x val=%d min=%d max=%d ",
                   1762:                     mc->type, val, mc->minval, mc->maxval));
1.67.2.4! skrll    1763:        if (mc->type == MIX_ON_OFF) {
1.47      jdolecek 1764:                val = (val != 0);
1.67.2.4! skrll    1765:        } else if (mc->type == MIX_SELECTOR) {
        !          1766:                if (val < mc->minval || val > mc->maxval)
        !          1767:                        val = mc->minval;
        !          1768:        } else
1.67.2.1  skrll    1769:                val = ((uaudio_signext(mc->type, val) - mc->minval) * 255
1.34      augustss 1770:                        + mc->mul/2) / mc->mul;
1.1       augustss 1771:        DPRINTFN(5, ("val'=%d\n", val));
                   1772:        return (val);
                   1773: }
                   1774:
                   1775: int
1.26      augustss 1776: uaudio_bsd2value(struct mixerctl *mc, int val)
1.1       augustss 1777: {
                   1778:        DPRINTFN(5,("uaudio_bsd2value: type=%03x val=%d min=%d max=%d ",
                   1779:                    mc->type, val, mc->minval, mc->maxval));
1.67.2.4! skrll    1780:        if (mc->type == MIX_ON_OFF) {
1.47      jdolecek 1781:                val = (val != 0);
1.67.2.4! skrll    1782:        } else if (mc->type == MIX_SELECTOR) {
        !          1783:                if (val < mc->minval || val > mc->maxval)
        !          1784:                        val = mc->minval;
        !          1785:        } else
1.67.2.1  skrll    1786:                val = (val + mc->delta/2) * mc->mul / 255 + mc->minval;
1.1       augustss 1787:        DPRINTFN(5, ("val'=%d\n", val));
                   1788:        return (val);
                   1789: }
                   1790:
                   1791: int
1.56      kent     1792: uaudio_ctl_get(struct uaudio_softc *sc, int which, struct mixerctl *mc,
1.26      augustss 1793:               int chan)
1.1       augustss 1794: {
                   1795:        int val;
                   1796:
                   1797:        DPRINTFN(5,("uaudio_ctl_get: which=%d chan=%d\n", which, chan));
                   1798:        val = uaudio_get(sc, which, UT_READ_CLASS_INTERFACE, mc->wValue[chan],
                   1799:                         mc->wIndex, MIX_SIZE(mc->type));
                   1800:        return (uaudio_value2bsd(mc, val));
                   1801: }
                   1802:
                   1803: void
1.26      augustss 1804: uaudio_ctl_set(struct uaudio_softc *sc, int which, struct mixerctl *mc,
                   1805:               int chan, int val)
1.1       augustss 1806: {
                   1807:        val = uaudio_bsd2value(mc, val);
                   1808:        uaudio_set(sc, which, UT_WRITE_CLASS_INTERFACE, mc->wValue[chan],
                   1809:                   mc->wIndex, MIX_SIZE(mc->type), val);
                   1810: }
                   1811:
                   1812: int
1.26      augustss 1813: uaudio_mixer_get_port(void *addr, mixer_ctrl_t *cp)
1.1       augustss 1814: {
                   1815:        struct uaudio_softc *sc = addr;
                   1816:        struct mixerctl *mc;
                   1817:        int i, n, vals[MIX_MAX_CHAN], val;
                   1818:
                   1819:        DPRINTFN(2,("uaudio_mixer_get_port: index=%d\n", cp->dev));
                   1820:
                   1821:        if (sc->sc_dying)
                   1822:                return (EIO);
1.56      kent     1823:
1.63      augustss 1824:        n = cp->dev - UAC_NCLASSES;
1.1       augustss 1825:        if (n < 0 || n >= sc->sc_nctls)
                   1826:                return (ENXIO);
                   1827:        mc = &sc->sc_ctls[n];
                   1828:
                   1829:        if (mc->type == MIX_ON_OFF) {
                   1830:                if (cp->type != AUDIO_MIXER_ENUM)
                   1831:                        return (EINVAL);
                   1832:                cp->un.ord = uaudio_ctl_get(sc, GET_CUR, mc, 0);
1.67.2.4! skrll    1833:        } else if (mc->type == MIX_SELECTOR) {
        !          1834:                if (cp->type != AUDIO_MIXER_ENUM)
        !          1835:                        return (EINVAL);
        !          1836:                cp->un.ord = uaudio_ctl_get(sc, GET_CUR, mc, 0);
1.1       augustss 1837:        } else {
                   1838:                if (cp->type != AUDIO_MIXER_VALUE)
                   1839:                        return (EINVAL);
                   1840:                if (cp->un.value.num_channels != 1 &&
                   1841:                    cp->un.value.num_channels != mc->nchan)
                   1842:                        return (EINVAL);
                   1843:                for (i = 0; i < mc->nchan; i++)
                   1844:                        vals[i] = uaudio_ctl_get(sc, GET_CUR, mc, i);
                   1845:                if (cp->un.value.num_channels == 1 && mc->nchan != 1) {
                   1846:                        for (val = 0, i = 0; i < mc->nchan; i++)
                   1847:                                val += vals[i];
                   1848:                        vals[0] = val / mc->nchan;
                   1849:                }
                   1850:                for (i = 0; i < cp->un.value.num_channels; i++)
                   1851:                        cp->un.value.level[i] = vals[i];
                   1852:        }
                   1853:
                   1854:        return (0);
                   1855: }
1.56      kent     1856:
1.1       augustss 1857: int
1.26      augustss 1858: uaudio_mixer_set_port(void *addr, mixer_ctrl_t *cp)
1.1       augustss 1859: {
                   1860:        struct uaudio_softc *sc = addr;
                   1861:        struct mixerctl *mc;
                   1862:        int i, n, vals[MIX_MAX_CHAN];
                   1863:
                   1864:        DPRINTFN(2,("uaudio_mixer_set_port: index = %d\n", cp->dev));
                   1865:        if (sc->sc_dying)
                   1866:                return (EIO);
1.56      kent     1867:
1.63      augustss 1868:        n = cp->dev - UAC_NCLASSES;
1.1       augustss 1869:        if (n < 0 || n >= sc->sc_nctls)
                   1870:                return (ENXIO);
                   1871:        mc = &sc->sc_ctls[n];
                   1872:
                   1873:        if (mc->type == MIX_ON_OFF) {
                   1874:                if (cp->type != AUDIO_MIXER_ENUM)
                   1875:                        return (EINVAL);
                   1876:                uaudio_ctl_set(sc, SET_CUR, mc, 0, cp->un.ord);
1.67.2.4! skrll    1877:        } else if (mc->type == MIX_SELECTOR) {
        !          1878:                if (cp->type != AUDIO_MIXER_ENUM)
        !          1879:                        return (EINVAL);
        !          1880:                uaudio_ctl_set(sc, SET_CUR, mc, 0, cp->un.ord);
1.1       augustss 1881:        } else {
                   1882:                if (cp->type != AUDIO_MIXER_VALUE)
                   1883:                        return (EINVAL);
                   1884:                if (cp->un.value.num_channels == 1)
                   1885:                        for (i = 0; i < mc->nchan; i++)
                   1886:                                vals[i] = cp->un.value.level[0];
                   1887:                else if (cp->un.value.num_channels == mc->nchan)
                   1888:                        for (i = 0; i < mc->nchan; i++)
                   1889:                                vals[i] = cp->un.value.level[i];
                   1890:                else
                   1891:                        return (EINVAL);
                   1892:                for (i = 0; i < mc->nchan; i++)
                   1893:                        uaudio_ctl_set(sc, SET_CUR, mc, i, vals[i]);
                   1894:        }
                   1895:        return (0);
                   1896: }
                   1897:
                   1898: int
1.26      augustss 1899: uaudio_trigger_input(void *addr, void *start, void *end, int blksize,
                   1900:                     void (*intr)(void *), void *arg,
                   1901:                     struct audio_params *param)
1.1       augustss 1902: {
                   1903:        struct uaudio_softc *sc = addr;
1.47      jdolecek 1904:        struct chan *ch = &sc->sc_recchan;
1.9       augustss 1905:        usbd_status err;
1.5       augustss 1906:        int i, s;
1.1       augustss 1907:
                   1908:        if (sc->sc_dying)
                   1909:                return (EIO);
                   1910:
1.5       augustss 1911:        DPRINTFN(3,("uaudio_trigger_input: sc=%p start=%p end=%p "
1.1       augustss 1912:                    "blksize=%d\n", sc, start, end, blksize));
                   1913:
1.54      kent     1914:        uaudio_chan_set_param(ch, start, end, blksize);
1.5       augustss 1915:        DPRINTFN(3,("uaudio_trigger_input: sample_size=%d bytes/frame=%d "
                   1916:                    "fraction=0.%03d\n", ch->sample_size, ch->bytes_per_frame,
                   1917:                    ch->fraction));
                   1918:
1.9       augustss 1919:        err = uaudio_chan_alloc_buffers(sc, ch);
                   1920:        if (err)
1.5       augustss 1921:                return (EIO);
                   1922:
1.9       augustss 1923:        err = uaudio_chan_open(sc, ch);
                   1924:        if (err) {
1.5       augustss 1925:                uaudio_chan_free_buffers(sc, ch);
                   1926:                return (EIO);
                   1927:        }
                   1928:
1.47      jdolecek 1929:        ch->intr = intr;
                   1930:        ch->arg = arg;
1.5       augustss 1931:
                   1932:        s = splusb();
1.22      augustss 1933:        for (i = 0; i < UAUDIO_NCHANBUFS-1; i++) /* XXX -1 shouldn't be needed */
1.5       augustss 1934:                uaudio_chan_rtransfer(ch);
                   1935:        splx(s);
                   1936:
1.56      kent     1937:        return (0);
1.1       augustss 1938: }
1.56      kent     1939:
1.1       augustss 1940: int
1.26      augustss 1941: uaudio_trigger_output(void *addr, void *start, void *end, int blksize,
                   1942:                      void (*intr)(void *), void *arg,
                   1943:                      struct audio_params *param)
1.1       augustss 1944: {
                   1945:        struct uaudio_softc *sc = addr;
1.47      jdolecek 1946:        struct chan *ch = &sc->sc_playchan;
1.9       augustss 1947:        usbd_status err;
1.1       augustss 1948:        int i, s;
                   1949:
                   1950:        if (sc->sc_dying)
                   1951:                return (EIO);
                   1952:
                   1953:        DPRINTFN(3,("uaudio_trigger_output: sc=%p start=%p end=%p "
                   1954:                    "blksize=%d\n", sc, start, end, blksize));
                   1955:
1.54      kent     1956:        uaudio_chan_set_param(ch, start, end, blksize);
1.1       augustss 1957:        DPRINTFN(3,("uaudio_trigger_output: sample_size=%d bytes/frame=%d "
                   1958:                    "fraction=0.%03d\n", ch->sample_size, ch->bytes_per_frame,
                   1959:                    ch->fraction));
                   1960:
1.9       augustss 1961:        err = uaudio_chan_alloc_buffers(sc, ch);
                   1962:        if (err)
1.1       augustss 1963:                return (EIO);
                   1964:
1.9       augustss 1965:        err = uaudio_chan_open(sc, ch);
                   1966:        if (err) {
1.1       augustss 1967:                uaudio_chan_free_buffers(sc, ch);
                   1968:                return (EIO);
                   1969:        }
                   1970:
1.47      jdolecek 1971:        ch->intr = intr;
                   1972:        ch->arg = arg;
1.1       augustss 1973:
                   1974:        s = splusb();
1.22      augustss 1975:        for (i = 0; i < UAUDIO_NCHANBUFS-1; i++) /* XXX */
1.5       augustss 1976:                uaudio_chan_ptransfer(ch);
1.1       augustss 1977:        splx(s);
                   1978:
1.56      kent     1979:        return (0);
1.1       augustss 1980: }
                   1981:
                   1982: /* Set up a pipe for a channel. */
                   1983: usbd_status
1.26      augustss 1984: uaudio_chan_open(struct uaudio_softc *sc, struct chan *ch)
1.1       augustss 1985: {
1.47      jdolecek 1986:        struct as_info *as = &sc->sc_alts[ch->altidx];
1.1       augustss 1987:        int endpt = as->edesc->bEndpointAddress;
1.9       augustss 1988:        usbd_status err;
1.1       augustss 1989:
1.56      kent     1990:        DPRINTF(("uaudio_chan_open: endpt=0x%02x, speed=%d, alt=%d\n",
1.1       augustss 1991:                 endpt, ch->sample_rate, as->alt));
                   1992:
                   1993:        /* Set alternate interface corresponding to the mode. */
1.37      mycroft  1994:        err = usbd_set_interface(as->ifaceh, as->alt);
1.9       augustss 1995:        if (err)
                   1996:                return (err);
1.1       augustss 1997:
                   1998:        /* Some devices do not support this request, so ignore errors. */
1.4       augustss 1999: #ifdef UAUDIO_DEBUG
1.9       augustss 2000:        err = uaudio_set_speed(sc, endpt, ch->sample_rate);
                   2001:        if (err)
                   2002:                DPRINTF(("uaudio_chan_open: set_speed failed err=%s\n",
                   2003:                         usbd_errstr(err)));
1.1       augustss 2004: #else
                   2005:        (void)uaudio_set_speed(sc, endpt, ch->sample_rate);
                   2006: #endif
                   2007:
1.47      jdolecek 2008:        DPRINTF(("uaudio_chan_open: create pipe to 0x%02x\n", endpt));
1.37      mycroft  2009:        err = usbd_open_pipe(as->ifaceh, endpt, 0, &ch->pipe);
1.9       augustss 2010:        return (err);
1.1       augustss 2011: }
                   2012:
                   2013: void
1.26      augustss 2014: uaudio_chan_close(struct uaudio_softc *sc, struct chan *ch)
1.1       augustss 2015: {
1.47      jdolecek 2016:        struct as_info *as = &sc->sc_alts[ch->altidx];
1.37      mycroft  2017:
1.58      kent     2018:        as->sc_busy = 0;
1.1       augustss 2019:        if (sc->sc_nullalt >= 0) {
1.47      jdolecek 2020:                DPRINTF(("uaudio_chan_close: set null alt=%d\n",
1.1       augustss 2021:                         sc->sc_nullalt));
1.37      mycroft  2022:                usbd_set_interface(as->ifaceh, sc->sc_nullalt);
1.1       augustss 2023:        }
                   2024:        usbd_abort_pipe(ch->pipe);
                   2025:        usbd_close_pipe(ch->pipe);
                   2026: }
                   2027:
                   2028: usbd_status
1.26      augustss 2029: uaudio_chan_alloc_buffers(struct uaudio_softc *sc, struct chan *ch)
1.1       augustss 2030: {
1.9       augustss 2031:        usbd_xfer_handle xfer;
1.1       augustss 2032:        void *buf;
                   2033:        int i, size;
                   2034:
                   2035:        size = (ch->bytes_per_frame + ch->sample_size) * UAUDIO_NFRAMES;
                   2036:        for (i = 0; i < UAUDIO_NCHANBUFS; i++) {
1.11      augustss 2037:                xfer = usbd_alloc_xfer(sc->sc_udev);
1.9       augustss 2038:                if (xfer == 0)
1.1       augustss 2039:                        goto bad;
1.9       augustss 2040:                ch->chanbufs[i].xfer = xfer;
                   2041:                buf = usbd_alloc_buffer(xfer, size);
1.1       augustss 2042:                if (buf == 0) {
                   2043:                        i++;
                   2044:                        goto bad;
                   2045:                }
                   2046:                ch->chanbufs[i].buffer = buf;
                   2047:                ch->chanbufs[i].chan = ch;
                   2048:        }
                   2049:
                   2050:        return (USBD_NORMAL_COMPLETION);
                   2051:
                   2052: bad:
                   2053:        while (--i >= 0)
                   2054:                /* implicit buffer free */
1.11      augustss 2055:                usbd_free_xfer(ch->chanbufs[i].xfer);
1.1       augustss 2056:        return (USBD_NOMEM);
                   2057: }
                   2058:
                   2059: void
1.26      augustss 2060: uaudio_chan_free_buffers(struct uaudio_softc *sc, struct chan *ch)
1.1       augustss 2061: {
                   2062:        int i;
                   2063:
                   2064:        for (i = 0; i < UAUDIO_NCHANBUFS; i++)
1.11      augustss 2065:                usbd_free_xfer(ch->chanbufs[i].xfer);
1.1       augustss 2066: }
                   2067:
                   2068: /* Called at splusb() */
                   2069: void
1.26      augustss 2070: uaudio_chan_ptransfer(struct chan *ch)
1.1       augustss 2071: {
                   2072:        struct chanbuf *cb;
                   2073:        int i, n, size, residue, total;
                   2074:
1.8       augustss 2075:        if (ch->sc->sc_dying)
                   2076:                return;
                   2077:
1.1       augustss 2078:        /* Pick the next channel buffer. */
                   2079:        cb = &ch->chanbufs[ch->curchanbuf];
                   2080:        if (++ch->curchanbuf >= UAUDIO_NCHANBUFS)
                   2081:                ch->curchanbuf = 0;
                   2082:
                   2083:        /* Compute the size of each frame in the next transfer. */
                   2084:        residue = ch->residue;
                   2085:        total = 0;
                   2086:        for (i = 0; i < UAUDIO_NFRAMES; i++) {
                   2087:                size = ch->bytes_per_frame;
                   2088:                residue += ch->fraction;
                   2089:                if (residue >= USB_FRAMES_PER_SECOND) {
1.47      jdolecek 2090:                        if ((ch->sc->sc_altflags & UA_NOFRAC) == 0)
1.31      augustss 2091:                                size += ch->sample_size;
1.1       augustss 2092:                        residue -= USB_FRAMES_PER_SECOND;
                   2093:                }
                   2094:                cb->sizes[i] = size;
                   2095:                total += size;
                   2096:        }
                   2097:        ch->residue = residue;
                   2098:        cb->size = total;
                   2099:
1.56      kent     2100:        /*
1.1       augustss 2101:         * Transfer data from upper layer buffer to channel buffer, taking
                   2102:         * care of wrapping the upper layer buffer.
                   2103:         */
                   2104:        n = min(total, ch->end - ch->cur);
                   2105:        memcpy(cb->buffer, ch->cur, n);
                   2106:        ch->cur += n;
                   2107:        if (ch->cur >= ch->end)
                   2108:                ch->cur = ch->start;
                   2109:        if (total > n) {
                   2110:                total -= n;
                   2111:                memcpy(cb->buffer + n, ch->cur, total);
                   2112:                ch->cur += total;
                   2113:        }
                   2114:
1.4       augustss 2115: #ifdef UAUDIO_DEBUG
1.1       augustss 2116:        if (uaudiodebug > 8) {
1.5       augustss 2117:                DPRINTF(("uaudio_chan_ptransfer: buffer=%p, residue=0.%03d\n",
1.1       augustss 2118:                         cb->buffer, ch->residue));
                   2119:                for (i = 0; i < UAUDIO_NFRAMES; i++) {
                   2120:                        DPRINTF(("   [%d] length %d\n", i, cb->sizes[i]));
                   2121:                }
                   2122:        }
                   2123: #endif
                   2124:
1.9       augustss 2125:        DPRINTFN(5,("uaudio_chan_transfer: ptransfer xfer=%p\n", cb->xfer));
1.1       augustss 2126:        /* Fill the request */
1.56      kent     2127:        usbd_setup_isoc_xfer(cb->xfer, ch->pipe, cb, cb->sizes,
                   2128:                             UAUDIO_NFRAMES, USBD_NO_COPY,
1.11      augustss 2129:                             uaudio_chan_pintr);
1.1       augustss 2130:
1.9       augustss 2131:        (void)usbd_transfer(cb->xfer);
1.1       augustss 2132: }
                   2133:
                   2134: void
1.26      augustss 2135: uaudio_chan_pintr(usbd_xfer_handle xfer, usbd_private_handle priv,
                   2136:                  usbd_status status)
1.1       augustss 2137: {
                   2138:        struct chanbuf *cb = priv;
                   2139:        struct chan *ch = cb->chan;
                   2140:        u_int32_t count;
                   2141:        int s;
                   2142:
                   2143:        /* Return if we are aborting. */
                   2144:        if (status == USBD_CANCELLED)
                   2145:                return;
                   2146:
1.18      augustss 2147:        usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL);
1.5       augustss 2148:        DPRINTFN(5,("uaudio_chan_pintr: count=%d, transferred=%d\n",
                   2149:                    count, ch->transferred));
                   2150: #ifdef DIAGNOSTIC
                   2151:        if (count != cb->size) {
                   2152:                printf("uaudio_chan_pintr: count(%d) != size(%d)\n",
                   2153:                       count, cb->size);
                   2154:        }
                   2155: #endif
                   2156:
                   2157:        ch->transferred += cb->size;
                   2158:        s = splaudio();
1.1       augustss 2159:        /* Call back to upper layer */
1.5       augustss 2160:        while (ch->transferred >= ch->blksize) {
                   2161:                ch->transferred -= ch->blksize;
1.56      kent     2162:                DPRINTFN(5,("uaudio_chan_pintr: call %p(%p)\n",
1.5       augustss 2163:                            ch->intr, ch->arg));
                   2164:                ch->intr(ch->arg);
                   2165:        }
                   2166:        splx(s);
                   2167:
                   2168:        /* start next transfer */
                   2169:        uaudio_chan_ptransfer(ch);
                   2170: }
                   2171:
                   2172: /* Called at splusb() */
                   2173: void
1.26      augustss 2174: uaudio_chan_rtransfer(struct chan *ch)
1.5       augustss 2175: {
                   2176:        struct chanbuf *cb;
                   2177:        int i, size, residue, total;
1.8       augustss 2178:
                   2179:        if (ch->sc->sc_dying)
                   2180:                return;
1.5       augustss 2181:
                   2182:        /* Pick the next channel buffer. */
                   2183:        cb = &ch->chanbufs[ch->curchanbuf];
                   2184:        if (++ch->curchanbuf >= UAUDIO_NCHANBUFS)
                   2185:                ch->curchanbuf = 0;
                   2186:
                   2187:        /* Compute the size of each frame in the next transfer. */
                   2188:        residue = ch->residue;
                   2189:        total = 0;
                   2190:        for (i = 0; i < UAUDIO_NFRAMES; i++) {
                   2191:                size = ch->bytes_per_frame;
                   2192:                cb->sizes[i] = size;
1.62      toshii   2193:                cb->offsets[i] = total;
1.5       augustss 2194:                total += size;
                   2195:        }
                   2196:        ch->residue = residue;
                   2197:        cb->size = total;
                   2198:
                   2199: #ifdef UAUDIO_DEBUG
                   2200:        if (uaudiodebug > 8) {
                   2201:                DPRINTF(("uaudio_chan_rtransfer: buffer=%p, residue=0.%03d\n",
                   2202:                         cb->buffer, ch->residue));
                   2203:                for (i = 0; i < UAUDIO_NFRAMES; i++) {
                   2204:                        DPRINTF(("   [%d] length %d\n", i, cb->sizes[i]));
                   2205:                }
                   2206:        }
                   2207: #endif
                   2208:
1.9       augustss 2209:        DPRINTFN(5,("uaudio_chan_rtransfer: transfer xfer=%p\n", cb->xfer));
1.5       augustss 2210:        /* Fill the request */
1.56      kent     2211:        usbd_setup_isoc_xfer(cb->xfer, ch->pipe, cb, cb->sizes,
                   2212:                             UAUDIO_NFRAMES, USBD_NO_COPY,
1.11      augustss 2213:                             uaudio_chan_rintr);
1.5       augustss 2214:
1.9       augustss 2215:        (void)usbd_transfer(cb->xfer);
1.5       augustss 2216: }
                   2217:
                   2218: void
1.26      augustss 2219: uaudio_chan_rintr(usbd_xfer_handle xfer, usbd_private_handle priv,
                   2220:                  usbd_status status)
1.5       augustss 2221: {
                   2222:        struct chanbuf *cb = priv;
                   2223:        struct chan *ch = cb->chan;
                   2224:        u_int32_t count;
1.62      toshii   2225:        int s, i, n, frsize;
1.5       augustss 2226:
                   2227:        /* Return if we are aborting. */
                   2228:        if (status == USBD_CANCELLED)
                   2229:                return;
                   2230:
1.18      augustss 2231:        usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL);
1.5       augustss 2232:        DPRINTFN(5,("uaudio_chan_rintr: count=%d, transferred=%d\n",
1.1       augustss 2233:                    count, ch->transferred));
1.31      augustss 2234:
1.62      toshii   2235:        /* count < cb->size is normal for asynchronous source */
1.1       augustss 2236: #ifdef DIAGNOSTIC
1.62      toshii   2237:        if (count > cb->size) {
                   2238:                printf("uaudio_chan_rintr: count(%d) > size(%d)\n",
1.1       augustss 2239:                       count, cb->size);
                   2240:        }
                   2241: #endif
                   2242:
1.56      kent     2243:        /*
1.5       augustss 2244:         * Transfer data from channel buffer to upper layer buffer, taking
                   2245:         * care of wrapping the upper layer buffer.
                   2246:         */
1.62      toshii   2247:        for(i = 0; i < UAUDIO_NFRAMES; i++) {
                   2248:                frsize = cb->sizes[i];
                   2249:                n = min(frsize, ch->end - ch->cur);
                   2250:                memcpy(ch->cur, cb->buffer + cb->offsets[i], n);
                   2251:                ch->cur += n;
                   2252:                if (ch->cur >= ch->end)
                   2253:                        ch->cur = ch->start;
                   2254:                if (frsize > n) {
                   2255:                        memcpy(ch->cur, cb->buffer + cb->offsets[i] + n,
                   2256:                            frsize - n);
                   2257:                        ch->cur += frsize - n;
                   2258:                }
1.5       augustss 2259:        }
                   2260:
                   2261:        /* Call back to upper layer */
1.62      toshii   2262:        ch->transferred += count;
1.1       augustss 2263:        s = splaudio();
                   2264:        while (ch->transferred >= ch->blksize) {
                   2265:                ch->transferred -= ch->blksize;
1.56      kent     2266:                DPRINTFN(5,("uaudio_chan_rintr: call %p(%p)\n",
1.1       augustss 2267:                            ch->intr, ch->arg));
                   2268:                ch->intr(ch->arg);
                   2269:        }
                   2270:        splx(s);
                   2271:
                   2272:        /* start next transfer */
1.5       augustss 2273:        uaudio_chan_rtransfer(ch);
1.1       augustss 2274: }
                   2275:
                   2276: void
1.65      toshii   2277: uaudio_chan_init(struct chan *ch, int altidx, const struct audio_params *param,
                   2278:     int maxpktsize)
1.1       augustss 2279: {
                   2280:        int samples_per_frame, sample_size;
                   2281:
1.54      kent     2282:        ch->altidx = altidx;
1.50      kent     2283:        sample_size = param->precision * param->factor * param->hw_channels / 8;
                   2284:        samples_per_frame = param->hw_sample_rate / USB_FRAMES_PER_SECOND;
1.1       augustss 2285:        ch->sample_size = sample_size;
1.50      kent     2286:        ch->sample_rate = param->hw_sample_rate;
1.65      toshii   2287:        if (maxpktsize == 0) {
                   2288:                ch->fraction = param->hw_sample_rate % USB_FRAMES_PER_SECOND;
                   2289:                ch->bytes_per_frame = samples_per_frame * sample_size;
                   2290:        } else {
                   2291:                ch->fraction = 0;
                   2292:                ch->bytes_per_frame = maxpktsize;
                   2293:        }
1.1       augustss 2294:        ch->residue = 0;
1.54      kent     2295: }
1.1       augustss 2296:
1.54      kent     2297: void
                   2298: uaudio_chan_set_param(struct chan *ch, u_char *start, u_char *end, int blksize)
                   2299: {
1.1       augustss 2300:        ch->start = start;
                   2301:        ch->end = end;
                   2302:        ch->cur = start;
                   2303:        ch->blksize = blksize;
                   2304:        ch->transferred = 0;
                   2305:
                   2306:        ch->curchanbuf = 0;
                   2307: }
                   2308:
1.50      kent     2309: void
                   2310: uaudio_get_minmax_rates(int nalts, const struct as_info *alts,
                   2311:                        const struct audio_params *p, int mode,
                   2312:                        u_long *min, u_long *max)
                   2313: {
1.67.2.4! skrll    2314:        const struct usb_audio_streaming_type1_descriptor *a1d;
1.50      kent     2315:        int i, j;
                   2316:
                   2317:        *min = ULONG_MAX;
                   2318:        *max = 0;
                   2319:        for (i = 0; i < nalts; i++) {
                   2320:                a1d = alts[i].asf1desc;
                   2321:                if (alts[i].sc_busy)
                   2322:                        continue;
                   2323:                if (p->hw_channels != a1d->bNrChannels)
                   2324:                        continue;
                   2325:                if (p->hw_precision != a1d->bBitResolution)
                   2326:                        continue;
                   2327:                if (p->hw_encoding != alts[i].encoding)
                   2328:                        continue;
                   2329:                if (mode != UE_GET_DIR(alts[i].edesc->bEndpointAddress))
                   2330:                        continue;
                   2331:                if (a1d->bSamFreqType == UA_SAMP_CONTNUOUS) {
                   2332:                        DPRINTFN(2,("uaudio_get_minmax_rates: cont %d-%d\n",
                   2333:                                    UA_SAMP_LO(a1d), UA_SAMP_HI(a1d)));
                   2334:                        if (UA_SAMP_LO(a1d) < *min)
                   2335:                                *min = UA_SAMP_LO(a1d);
                   2336:                        if (UA_SAMP_HI(a1d) > *max)
                   2337:                                *max = UA_SAMP_HI(a1d);
                   2338:                } else {
                   2339:                        for (j = 0; j < a1d->bSamFreqType; j++) {
                   2340:                                DPRINTFN(2,("uaudio_get_minmax_rates: disc #%d: %d\n",
                   2341:                                            j, UA_GETSAMP(a1d, j)));
                   2342:                                if (UA_GETSAMP(a1d, j) < *min)
                   2343:                                        *min = UA_GETSAMP(a1d, j);
                   2344:                                if (UA_GETSAMP(a1d, j) > *max)
                   2345:                                        *max = UA_GETSAMP(a1d, j);
                   2346:                        }
                   2347:                }
                   2348:        }
                   2349: }
                   2350:
                   2351: int
                   2352: uaudio_match_alt_sub(int nalts, const struct as_info *alts,
                   2353:                     const struct audio_params *p, int mode, u_long rate)
                   2354: {
1.67.2.4! skrll    2355:        const struct usb_audio_streaming_type1_descriptor *a1d;
1.50      kent     2356:        int i, j;
                   2357:
1.53      kent     2358:        DPRINTF(("uaudio_match_alt_sub: search for %luHz %dch\n",
1.50      kent     2359:                 rate, p->hw_channels));
                   2360:        for (i = 0; i < nalts; i++) {
                   2361:                a1d = alts[i].asf1desc;
                   2362:                if (alts[i].sc_busy)
                   2363:                        continue;
                   2364:                if (p->hw_channels != a1d->bNrChannels)
                   2365:                        continue;
                   2366:                if (p->hw_precision != a1d->bBitResolution)
                   2367:                        continue;
                   2368:                if (p->hw_encoding != alts[i].encoding)
                   2369:                        continue;
                   2370:                if (mode != UE_GET_DIR(alts[i].edesc->bEndpointAddress))
                   2371:                        continue;
                   2372:                if (a1d->bSamFreqType == UA_SAMP_CONTNUOUS) {
1.67.2.4! skrll    2373:                        DPRINTFN(3,("uaudio_match_alt_sub: cont %d-%d\n",
1.50      kent     2374:                                    UA_SAMP_LO(a1d), UA_SAMP_HI(a1d)));
1.66      jdolecek 2375:                        if (UA_SAMP_LO(a1d) <= rate && rate <= UA_SAMP_HI(a1d))
1.50      kent     2376:                                return i;
                   2377:                } else {
                   2378:                        for (j = 0; j < a1d->bSamFreqType; j++) {
1.67.2.4! skrll    2379:                                DPRINTFN(3,("uaudio_match_alt_sub: disc #%d: %d\n",
1.50      kent     2380:                                            j, UA_GETSAMP(a1d, j)));
                   2381:                                /* XXX allow for some slack */
                   2382:                                if (UA_GETSAMP(a1d, j) == rate)
                   2383:                                        return i;
                   2384:                        }
                   2385:                }
                   2386:        }
                   2387:        return -1;
                   2388: }
                   2389:
                   2390: int
1.53      kent     2391: uaudio_match_alt_chan(int nalts, const struct as_info *alts,
                   2392:                      struct audio_params *p, int mode)
1.50      kent     2393: {
                   2394:        int i, n;
                   2395:        u_long min, max;
                   2396:        u_long rate;
                   2397:
                   2398:        /* Exact match */
1.53      kent     2399:        DPRINTF(("uaudio_match_alt_chan: examine %ldHz %dch %dbit.\n",
                   2400:                 p->sample_rate, p->hw_channels, p->hw_precision));
1.50      kent     2401:        i = uaudio_match_alt_sub(nalts, alts, p, mode, p->sample_rate);
                   2402:        if (i >= 0)
                   2403:                return i;
                   2404:
                   2405:        uaudio_get_minmax_rates(nalts, alts, p, mode, &min, &max);
1.53      kent     2406:        DPRINTF(("uaudio_match_alt_chan: min=%lu max=%lu\n", min, max));
1.50      kent     2407:        if (max <= 0)
                   2408:                return -1;
                   2409:        /* Search for biggers */
                   2410:        n = 2;
                   2411:        while ((rate = p->sample_rate * n++) <= max) {
                   2412:                i = uaudio_match_alt_sub(nalts, alts, p, mode, rate);
                   2413:                if (i >= 0) {
                   2414:                        p->hw_sample_rate = rate;
                   2415:                        return i;
                   2416:                }
                   2417:        }
                   2418:        if (p->sample_rate >= min) {
                   2419:                i = uaudio_match_alt_sub(nalts, alts, p, mode, max);
                   2420:                if (i >= 0) {
                   2421:                        p->hw_sample_rate = max;
                   2422:                        return i;
                   2423:                }
                   2424:        } else {
                   2425:                i = uaudio_match_alt_sub(nalts, alts, p, mode, min);
                   2426:                if (i >= 0) {
                   2427:                        p->hw_sample_rate = min;
                   2428:                        return i;
                   2429:                }
                   2430:        }
1.53      kent     2431:        return -1;
                   2432: }
                   2433:
                   2434: int
                   2435: uaudio_match_alt(int nalts, const struct as_info *alts,
                   2436:                 struct audio_params *p, int mode)
                   2437: {
                   2438:        int i, n;
1.50      kent     2439:
1.53      kent     2440:        mode = mode == AUMODE_PLAY ? UE_DIR_OUT : UE_DIR_IN;
                   2441:        i = uaudio_match_alt_chan(nalts, alts, p, mode);
                   2442:        if (i >= 0)
                   2443:                return i;
                   2444:
                   2445:        for (n = p->channels + 1; n <= AUDIO_MAX_CHANNELS; n++) {
                   2446:                p->hw_channels = n;
                   2447:                i = uaudio_match_alt_chan(nalts, alts, p, mode);
                   2448:                if (i >= 0)
                   2449:                        return i;
                   2450:        }
                   2451:
                   2452:        if (p->channels != 2)
                   2453:                return -1;
                   2454:        p->hw_channels = 1;
                   2455:        return uaudio_match_alt_chan(nalts, alts, p, mode);
1.50      kent     2456: }
                   2457:
1.1       augustss 2458: int
1.26      augustss 2459: uaudio_set_params(void *addr, int setmode, int usemode,
1.38      mycroft  2460:                  struct audio_params *play, struct audio_params *rec)
1.1       augustss 2461: {
                   2462:        struct uaudio_softc *sc = addr;
                   2463:        int flags = sc->sc_altflags;
1.50      kent     2464:        int factor;
                   2465:        int enc, i;
1.47      jdolecek 2466:        int paltidx=-1, raltidx=-1;
1.38      mycroft  2467:        void (*swcode)(void *, u_char *buf, int cnt);
                   2468:        struct audio_params *p;
                   2469:        int mode;
1.1       augustss 2470:
                   2471:        if (sc->sc_dying)
                   2472:                return (EIO);
                   2473:
1.67.2.1  skrll    2474:        if (((usemode & AUMODE_PLAY) && sc->sc_playchan.pipe != NULL) ||
                   2475:            ((usemode & AUMODE_RECORD) && sc->sc_recchan.pipe != NULL))
1.1       augustss 2476:                return (EBUSY);
                   2477:
1.67.2.1  skrll    2478:        if ((usemode & AUMODE_PLAY) && sc->sc_playchan.altidx != -1)
1.47      jdolecek 2479:                sc->sc_alts[sc->sc_playchan.altidx].sc_busy = 0;
1.67.2.1  skrll    2480:        if ((usemode & AUMODE_RECORD) && sc->sc_recchan.altidx != -1)
1.47      jdolecek 2481:                sc->sc_alts[sc->sc_recchan.altidx].sc_busy = 0;
                   2482:
1.67.2.1  skrll    2483:        /* Some uaudio devices are unidirectional.  Don't try to find a
                   2484:           matching mode for the unsupported direction. */
                   2485:        setmode &= sc->sc_mode;
                   2486:
1.38      mycroft  2487:        for (mode = AUMODE_RECORD; mode != -1;
                   2488:             mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
                   2489:                if ((setmode & mode) == 0)
                   2490:                        continue;
1.56      kent     2491:
1.47      jdolecek 2492:                p = (mode == AUMODE_PLAY) ? play : rec;
1.38      mycroft  2493:
                   2494:                factor = 1;
                   2495:                swcode = 0;
                   2496:                enc = p->encoding;
                   2497:                switch (enc) {
                   2498:                case AUDIO_ENCODING_SLINEAR_BE:
1.52      kent     2499:                        /* FALLTHROUGH */
                   2500:                case AUDIO_ENCODING_SLINEAR_LE:
                   2501:                        if (enc == AUDIO_ENCODING_SLINEAR_BE
                   2502:                            && p->precision == 16 && (flags & HAS_16)) {
1.38      mycroft  2503:                                swcode = swap_bytes;
1.37      mycroft  2504:                                enc = AUDIO_ENCODING_SLINEAR_LE;
1.52      kent     2505:                        } else if (p->precision == 8) {
                   2506:                                if (flags & HAS_8) {
                   2507:                                        /* No conversion */
                   2508:                                } else if (flags & HAS_8U) {
                   2509:                                        swcode = change_sign8;
                   2510:                                        enc = AUDIO_ENCODING_ULINEAR_LE;
                   2511:                                } else if (flags & HAS_16) {
                   2512:                                        factor = 2;
                   2513:                                        p->hw_precision = 16;
                   2514:                                        if (mode == AUMODE_PLAY)
                   2515:                                                swcode = linear8_to_linear16_le;
                   2516:                                        else
                   2517:                                                swcode = linear16_to_linear8_le;
                   2518:                                }
1.38      mycroft  2519:                        }
                   2520:                        break;
                   2521:                case AUDIO_ENCODING_ULINEAR_BE:
1.52      kent     2522:                        /* FALLTHROUGH */
                   2523:                case AUDIO_ENCODING_ULINEAR_LE:
1.38      mycroft  2524:                        if (p->precision == 16) {
1.52      kent     2525:                                if (enc == AUDIO_ENCODING_ULINEAR_LE)
                   2526:                                        swcode = change_sign16_le;
                   2527:                                else if (mode == AUMODE_PLAY)
1.38      mycroft  2528:                                        swcode = swap_bytes_change_sign16_le;
                   2529:                                else
                   2530:                                        swcode = change_sign16_swap_bytes_le;
1.1       augustss 2531:                                enc = AUDIO_ENCODING_SLINEAR_LE;
1.52      kent     2532:                        } else if (p->precision == 8) {
                   2533:                                if (flags & HAS_8U) {
                   2534:                                        /* No conversion */
                   2535:                                } else if (flags & HAS_8) {
                   2536:                                        swcode = change_sign8;
                   2537:                                        enc = AUDIO_ENCODING_SLINEAR_LE;
                   2538:                                } else if (flags & HAS_16) {
                   2539:                                        factor = 2;
                   2540:                                        p->hw_precision = 16;
                   2541:                                        enc = AUDIO_ENCODING_SLINEAR_LE;
                   2542:                                        if (mode == AUMODE_PLAY)
                   2543:                                                swcode = ulinear8_to_slinear16_le;
                   2544:                                        else
                   2545:                                                swcode = slinear16_to_ulinear8_le;
                   2546:                                }
1.38      mycroft  2547:                        }
                   2548:                        break;
                   2549:                case AUDIO_ENCODING_ULAW:
1.45      kent     2550:                        if (flags & HAS_MULAW)
                   2551:                                break;
1.48      kent     2552:                        if (flags & HAS_16) {
                   2553:                                if (mode == AUMODE_PLAY)
                   2554:                                        swcode = mulaw_to_slinear16_le;
                   2555:                                else
                   2556:                                        swcode = slinear16_to_mulaw_le;
                   2557:                                factor = 2;
                   2558:                                enc = AUDIO_ENCODING_SLINEAR_LE;
1.50      kent     2559:                                p->hw_precision = 16;
1.48      kent     2560:                        } else if (flags & HAS_8U) {
1.45      kent     2561:                                if (mode == AUMODE_PLAY)
                   2562:                                        swcode = mulaw_to_ulinear8;
                   2563:                                else
                   2564:                                        swcode = ulinear8_to_mulaw;
                   2565:                                enc = AUDIO_ENCODING_ULINEAR_LE;
                   2566:                        } else if (flags & HAS_8) {
                   2567:                                if (mode == AUMODE_PLAY)
                   2568:                                        swcode = mulaw_to_slinear8;
                   2569:                                else
                   2570:                                        swcode = slinear8_to_mulaw;
                   2571:                                enc = AUDIO_ENCODING_SLINEAR_LE;
                   2572:                        } else
                   2573:                                return (EINVAL);
1.38      mycroft  2574:                        break;
                   2575:                case AUDIO_ENCODING_ALAW:
1.46      kent     2576:                        if (flags & HAS_ALAW)
                   2577:                                break;
                   2578:                        if (mode == AUMODE_PLAY && (flags & HAS_16)) {
                   2579:                                swcode = alaw_to_slinear16_le;
                   2580:                                factor = 2;
                   2581:                                enc = AUDIO_ENCODING_SLINEAR_LE;
1.50      kent     2582:                                p->hw_precision = 16;
1.46      kent     2583:                        } else if (flags & HAS_8U) {
                   2584:                                if (mode == AUMODE_PLAY)
                   2585:                                        swcode = alaw_to_ulinear8;
                   2586:                                else
                   2587:                                        swcode = ulinear8_to_alaw;
                   2588:                                enc = AUDIO_ENCODING_ULINEAR_LE;
                   2589:                        } else if (flags & HAS_8) {
                   2590:                                if (mode == AUMODE_PLAY)
                   2591:                                        swcode = alaw_to_slinear8;
                   2592:                                else
                   2593:                                        swcode = slinear8_to_alaw;
                   2594:                                enc = AUDIO_ENCODING_SLINEAR_LE;
                   2595:                        } else
                   2596:                                return (EINVAL);
1.38      mycroft  2597:                        break;
                   2598:                default:
                   2599:                        return (EINVAL);
1.1       augustss 2600:                }
1.38      mycroft  2601:                /* XXX do some other conversions... */
                   2602:
                   2603:                DPRINTF(("uaudio_set_params: chan=%d prec=%d enc=%d rate=%ld\n",
1.50      kent     2604:                         p->channels, p->hw_precision, enc, p->sample_rate));
1.38      mycroft  2605:
1.50      kent     2606:                p->hw_encoding = enc;
                   2607:                i = uaudio_match_alt(sc->sc_nalts, sc->sc_alts, p, mode);
                   2608:                if (i < 0)
                   2609:                        return (EINVAL);
1.38      mycroft  2610:
                   2611:                p->sw_code = swcode;
                   2612:                p->factor  = factor;
1.67.2.1  skrll    2613:
                   2614:                if (mode == AUMODE_PLAY)
                   2615:                        paltidx = i;
                   2616:                else
                   2617:                        raltidx = i;
1.1       augustss 2618:        }
                   2619:
1.67.2.1  skrll    2620:        if ((setmode & AUMODE_PLAY)) {
1.47      jdolecek 2621:                /* XXX abort transfer if currently happening? */
1.65      toshii   2622:                uaudio_chan_init(&sc->sc_playchan, paltidx, play, 0);
1.47      jdolecek 2623:        }
1.67.2.1  skrll    2624:        if ((setmode & AUMODE_RECORD)) {
1.47      jdolecek 2625:                /* XXX abort transfer if currently happening? */
1.65      toshii   2626:                uaudio_chan_init(&sc->sc_recchan, raltidx, rec,
                   2627:                    UGETW(sc->sc_alts[raltidx].edesc->wMaxPacketSize));
1.47      jdolecek 2628:        }
                   2629:
1.67.2.1  skrll    2630:        if ((usemode & AUMODE_PLAY) && sc->sc_playchan.altidx != -1)
                   2631:                sc->sc_alts[sc->sc_playchan.altidx].sc_busy = 1;
                   2632:        if ((usemode & AUMODE_RECORD) && sc->sc_recchan.altidx != -1)
                   2633:                sc->sc_alts[sc->sc_recchan.altidx].sc_busy = 1;
                   2634:
1.56      kent     2635:        DPRINTF(("uaudio_set_params: use altidx=p%d/r%d, altno=p%d/r%d\n",
                   2636:                 sc->sc_playchan.altidx, sc->sc_recchan.altidx,
1.47      jdolecek 2637:                 (sc->sc_playchan.altidx >= 0)
                   2638:                   ?sc->sc_alts[sc->sc_playchan.altidx].idesc->bAlternateSetting
                   2639:                   : -1,
                   2640:                 (sc->sc_recchan.altidx >= 0)
                   2641:                   ? sc->sc_alts[sc->sc_recchan.altidx].idesc->bAlternateSetting
                   2642:                   : -1));
1.56      kent     2643:
1.38      mycroft  2644:        return (0);
1.1       augustss 2645: }
                   2646:
                   2647: usbd_status
1.26      augustss 2648: uaudio_set_speed(struct uaudio_softc *sc, int endpt, u_int speed)
1.1       augustss 2649: {
                   2650:        usb_device_request_t req;
                   2651:        u_int8_t data[3];
                   2652:
                   2653:        DPRINTFN(5,("uaudio_set_speed: endpt=%d speed=%u\n", endpt, speed));
                   2654:        req.bmRequestType = UT_WRITE_CLASS_ENDPOINT;
                   2655:        req.bRequest = SET_CUR;
                   2656:        USETW2(req.wValue, SAMPLING_FREQ_CONTROL, 0);
                   2657:        USETW(req.wIndex, endpt);
                   2658:        USETW(req.wLength, 3);
                   2659:        data[0] = speed;
                   2660:        data[1] = speed >> 8;
                   2661:        data[2] = speed >> 16;
                   2662:
1.47      jdolecek 2663:        return (usbd_do_request(sc->sc_udev, &req, data));
1.1       augustss 2664: }

CVSweb <webmaster@jp.NetBSD.org>