Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/usb Add code for USB Audio Class 2.0.



details:   https://anonhg.NetBSD.org/src/rev/1ccef5812aef
branches:  trunk
changeset: 374132:1ccef5812aef
user:      mlelstv <mlelstv%NetBSD.org@localhost>
date:      Sun Apr 02 14:42:55 2023 +0000

description:
Add code for USB Audio Class 2.0.

This is only half of the game as UAC2 devices tend to use 24bit or 32bit
samples. This requires more support in audio(4).

diffstat:

 sys/dev/usb/uaudio.c |  872 +++++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 704 insertions(+), 168 deletions(-)

diffs (truncated from 1311 to 300 lines):

diff -r 7bfd9201f96e -r 1ccef5812aef sys/dev/usb/uaudio.c
--- a/sys/dev/usb/uaudio.c      Sun Apr 02 07:26:17 2023 +0000
+++ b/sys/dev/usb/uaudio.c      Sun Apr 02 14:42:55 2023 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: uaudio.c,v 1.174 2022/06/28 05:22:13 skrll Exp $       */
+/*     $NetBSD: uaudio.c,v 1.175 2023/04/02 14:42:55 mlelstv Exp $     */
 
 /*
  * Copyright (c) 1999, 2012 The NetBSD Foundation, Inc.
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uaudio.c,v 1.174 2022/06/28 05:22:13 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uaudio.c,v 1.175 2023/04/02 14:42:55 mlelstv Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_usb.h"
@@ -74,7 +74,7 @@
 #include <dev/usb/uaudioreg.h>
 
 /* #define UAUDIO_DEBUG */
-/* #define UAUDIO_MULTIPLE_ENDPOINTS */
+#define UAUDIO_MULTIPLE_ENDPOINTS
 #ifdef UAUDIO_DEBUG
 #define DPRINTF(x,y...)                do { \
                if (uaudiodebug) { \
@@ -104,21 +104,36 @@ int       uaudiodebug = 0;
 
 
 #define MIX_MAX_CHAN 8
+struct range {
+       int minval, maxval, resval;
+};
+
 struct mixerctl {
        uint16_t        wValue[MIX_MAX_CHAN]; /* using nchan */
        uint16_t        wIndex;
        uint8_t         nchan;
        uint8_t         type;
-#define MIX_ON_OFF     1
-#define MIX_SIGNED_16  2
-#define MIX_UNSIGNED_16        3
-#define MIX_SIGNED_8   4
-#define MIX_SELECTOR   5
-#define MIX_SIZE(n) ((n) == MIX_SIGNED_16 || (n) == MIX_UNSIGNED_16 ? 2 : 1)
-#define MIX_UNSIGNED(n) ((n) == MIX_UNSIGNED_16)
-       int             minval, maxval;
+#define MIX_ON_OFF     0x01
+#define MIX_SELECTOR   0x02
+#define MIX_SIGNED_8   0x10
+#define MIX_UNSIGNED_8 0x18
+#define MIX_SIGNED_16  0x20
+#define MIX_UNSIGNED_16        0x28
+#define MIX_SIGNED_32  0x40
+#define MIX_UNSIGNED_32        0x48
+#define MIX_SIZE(n) ( \
+       ((n) == MIX_UNSIGNED_32 || (n) == MIX_SIGNED_32) ? 4 : \
+       ((n) == MIX_SIGNED_16 || (n) == MIX_UNSIGNED_16) ? 2 : 1 )
+#define MIX_UNSIGNED(n) ( \
+       (n) == MIX_UNSIGNED_8 || \
+       (n) == MIX_UNSIGNED_16 || \
+       (n) == MIX_UNSIGNED_32 )
+       struct range    range0;
+       struct range    *ranges;
+       u_int           nranges;
        u_int           delta;
        u_int           mul;
+       u_int           high;
        uint8_t         class;
        char            ctlname[MAX_AUDIO_DEV_LEN];
        const char      *ctlunit;
@@ -128,6 +143,7 @@ struct mixerctl {
 struct as_info {
        uint8_t         alt;
        uint8_t         encoding;
+       uint8_t         nchan;
        uint8_t         attributes; /* Copy of bmAttributes of
                                     * usb_audio_streaming_endpoint_descriptor
                                     */
@@ -135,7 +151,7 @@ struct as_info {
        const usb_interface_descriptor_t *idesc;
        const usb_endpoint_descriptor_audio_t *edesc;
        const usb_endpoint_descriptor_audio_t *edesc1;
-       const struct usb_audio_streaming_type1_descriptor *asf1desc;
+       const union usb_audio_streaming_type1_descriptor *asf1desc;
        struct audio_format *aformat;
        int             sc_busy;        /* currently used */
 };
@@ -182,6 +198,7 @@ struct uaudio_softc {
        kmutex_t        sc_lock;
        kmutex_t        sc_intr_lock;
        struct usbd_device *sc_udev;    /* USB device */
+       int             sc_version;
        int             sc_ac_iface;    /* Audio Control interface */
        struct usbd_interface * sc_ac_ifaceh;
        struct chan     sc_playchan;    /* play channel */
@@ -198,10 +215,13 @@ struct uaudio_softc {
 #define HAS_MULAW      0x10
 #define UA_NOFRAC      0x20            /* don't do sample rate adjustment */
 #define HAS_24         0x40
+#define HAS_32         0x80
        int             sc_mode;        /* play/record capability */
        struct mixerctl *sc_ctls;       /* mixer controls */
        int             sc_nctls;       /* # of mixer controls */
        device_t        sc_audiodev;
+       int             sc_nratectls;   /* V2 sample rates */
+       int             sc_ratectls[AUFMT_MAX_FREQUENCIES];
        struct audio_format *sc_formats;
        int             sc_nformats;
        u_int           sc_channel_config;
@@ -226,6 +246,8 @@ struct io_terminal {
                const struct usb_audio_feature_unit *fu;
                const struct usb_audio_processing_unit *pu;
                const struct usb_audio_extension_unit *eu;
+               const struct usb_audio_clksrc_unit *cu;
+               const struct usb_audio_clksel_unit *lu;
        } d;
        int inputs_size;
        struct terminal_list **inputs; /* list of source input terminals */
@@ -240,7 +262,7 @@ struct io_terminal {
 #define UAC_NCLASSES   4
 #ifdef UAUDIO_DEBUG
 Static const char *uac_names[] = {
-       AudioCoutputs, AudioCinputs, AudioCequalization, AudioCrecord,
+       AudioCoutputs, AudioCinputs, AudioCequalization, AudioCrecord
 };
 #endif
 
@@ -290,19 +312,33 @@ Static void       uaudio_add_processing_updown
        (struct uaudio_softc *, const struct io_terminal *, int);
 Static void    uaudio_add_processing
        (struct uaudio_softc *, const struct io_terminal *, int);
+Static void    uaudio_add_effect
+       (struct uaudio_softc *, const struct io_terminal *, int);
 Static void    uaudio_add_extension
        (struct uaudio_softc *, const struct io_terminal *, int);
+Static void    uaudio_add_clksrc
+       (struct uaudio_softc *, const struct io_terminal *, int);
+Static void    uaudio_add_clksel
+       (struct uaudio_softc *, const struct io_terminal *, int);
 Static struct terminal_list *uaudio_merge_terminal_list
        (const struct io_terminal *);
 Static struct terminal_list *uaudio_io_terminaltype
        (int, struct io_terminal *, int);
 Static usbd_status uaudio_identify
        (struct uaudio_softc *, const usb_config_descriptor_t *);
+Static u_int uaudio_get_rates
+       (struct uaudio_softc *, u_int *, u_int);
+Static void uaudio_build_formats
+       (struct uaudio_softc *);
 
 Static int     uaudio_signext(int, int);
 Static int     uaudio_value2bsd(struct mixerctl *, int);
 Static int     uaudio_bsd2value(struct mixerctl *, int);
+Static const char *uaudio_clockname(u_int);
+Static int     uaudio_makename
+       (struct uaudio_softc *, uByte, const char *, uByte, char *, size_t);
 Static int     uaudio_get(struct uaudio_softc *, int, int, int, int, int);
+Static int     uaudio_getbuf(struct uaudio_softc *, int, int, int, int, int, uint8_t *);
 Static int     uaudio_ctl_get
        (struct uaudio_softc *, int, struct mixerctl *, int);
 Static void    uaudio_set
@@ -310,7 +346,7 @@ Static void uaudio_set
 Static void    uaudio_ctl_set
        (struct uaudio_softc *, int, struct mixerctl *, int, int);
 
-Static usbd_status uaudio_set_speed(struct uaudio_softc *, int, u_int);
+Static usbd_status uaudio_set_speed(struct uaudio_softc *, int, int, u_int);
 
 Static usbd_status uaudio_chan_open(struct uaudio_softc *, struct chan *);
 Static void    uaudio_chan_abort(struct uaudio_softc *, struct chan *);
@@ -519,7 +555,7 @@ static int
 uaudio_detach(device_t self, int flags)
 {
        struct uaudio_softc *sc = device_private(self);
-       int rv;
+       int rv, i;
 
        sc->sc_dying = 1;
 
@@ -541,6 +577,19 @@ uaudio_detach(device_t self, int flags)
                kmem_free(sc->sc_formats,
                    sizeof(struct audio_format) * sc->sc_nformats);
 
+       if (sc->sc_ctls != NULL) {
+               for (i=0; i<sc->sc_nctls; ++i) {
+                       if (sc->sc_ctls[i].nranges == 0)
+                               continue;
+                       kmem_free( sc->sc_ctls[i].ranges,
+                           sc->sc_ctls[i].nranges * sizeof(struct range));
+               }
+               kmem_free(sc->sc_ctls, sizeof(struct mixerctl) * sc->sc_nctls);
+       }
+
+       if (sc->sc_alts != NULL)
+               kmem_free(sc->sc_alts, sizeof(struct as_info) * sc->sc_nalts);
+
        mutex_destroy(&sc->sc_lock);
        mutex_destroy(&sc->sc_intr_lock);
 
@@ -582,8 +631,11 @@ Static void
 uaudio_mixer_add_ctl(struct uaudio_softc *sc, struct mixerctl *mc)
 {
        int res;
-       size_t len;
+       size_t len, count, msz;
        struct mixerctl *nmc;
+       struct range *r;
+       uint8_t *buf, *p;
+       int i;
 
        if (mc->class < UAC_NCLASSES) {
                DPRINTF("adding %s.%s\n", uac_names[mc->class], mc->ctlname);
@@ -591,53 +643,161 @@ uaudio_mixer_add_ctl(struct uaudio_softc
                DPRINTF("adding %s\n", mc->ctlname);
        }
        len = sizeof(*mc) * (sc->sc_nctls + 1);
+KASSERT(len > 0);
        nmc = kmem_alloc(len, KM_SLEEP);
        /* Copy old data, if there was any */
        if (sc->sc_nctls != 0) {
-               memcpy(nmc, sc->sc_ctls, sizeof(*mc) * (sc->sc_nctls));
+               memcpy(nmc, sc->sc_ctls, sizeof(*mc) * sc->sc_nctls);
+               for (i = 0; i<sc->sc_nctls; ++i) {
+                       if (sc->sc_ctls[i].ranges == &sc->sc_ctls[i].range0)
+                               nmc[i].ranges = &nmc[i].range0;
+               }
                kmem_free(sc->sc_ctls, sizeof(*mc) * sc->sc_nctls);
        }
        sc->sc_ctls = nmc;
 
+       /*
+        * preset
+        * - mc->class
+        * - mc->ctlname
+        * - mc->ctlunit
+        * - mc->wIndex
+        * - mc->wValue[]
+        * - mc->type
+        * - mc->nchan
+        *
+        * - mc->range0, mc->mul for MIX_SELECTOR
+        */
+       sc->sc_ctls[sc->sc_nctls] = *mc;
+       mc = &sc->sc_ctls[sc->sc_nctls++];
+       msz = MIX_SIZE(mc->type);
+
        mc->delta = 0;
+       mc->nranges = 0;
+       mc->ranges = r = &mc->range0;
+       mc->mul = 0;
        if (mc->type == MIX_ON_OFF) {
-               mc->minval = 0;
-               mc->maxval = 1;
+               r->minval = 0;
+               r->maxval = 1;
+               r->resval = 1;
+               res = r->resval;
        } else if (mc->type == MIX_SELECTOR) {
-               ;
-       } else {
+               /* range0 already set by uaudio_add_selector */
+               res = r->resval;
+       } else if (sc->sc_version == UAUDIO_VERSION1) {
                /* Determine min and max values. */
-               mc->minval = uaudio_signext(mc->type,
+               r->minval = uaudio_signext(mc->type,
                        uaudio_get(sc, GET_MIN, UT_READ_CLASS_INTERFACE,
-                                  mc->wValue[0], mc->wIndex,
-                                  MIX_SIZE(mc->type)));
-               mc->maxval = 1 + uaudio_signext(mc->type,
+                                  mc->wValue[0], mc->wIndex, msz));
+               r->maxval = uaudio_signext(mc->type,
                        uaudio_get(sc, GET_MAX, UT_READ_CLASS_INTERFACE,
-                                  mc->wValue[0], mc->wIndex,
-                                  MIX_SIZE(mc->type)));
-               mc->mul = mc->maxval - mc->minval;
-               if (mc->mul == 0)
-                       mc->mul = 1;
-               res = uaudio_get(sc, GET_RES, UT_READ_CLASS_INTERFACE,
-                                mc->wValue[0], mc->wIndex,
-                                MIX_SIZE(mc->type));
-               if (res > 0)
-                       mc->delta = (res * 255 + mc->mul/2) / mc->mul;
+                                  mc->wValue[0], mc->wIndex, msz));
+               r->resval = uaudio_get(sc, GET_RES, UT_READ_CLASS_INTERFACE,
+                        mc->wValue[0], mc->wIndex, msz);
+               mc->mul = r->maxval - r->minval;
+               res = r->resval;
+       } else { /* UAUDIO_VERSION2 */
+               count = (uint16_t)uaudio_get(sc, V2_RANGES, UT_READ_CLASS_INTERFACE,
+                                mc->wValue[0], mc->wIndex, 2);
+
+               if (count > 1) {
+                       r = kmem_alloc(sizeof(struct range) * count,
+                           KM_SLEEP);
+                       mc->ranges = r;
+                       mc->nranges = count;
+               }



Home | Main Index | Thread Index | Old Index