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