summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
authorjulian <julian@FreeBSD.org>2004-12-25 06:20:49 +0000
committerjulian <julian@FreeBSD.org>2004-12-25 06:20:49 +0000
commit3efa4df5f0c9864a3af4b40308c57175ea50110e (patch)
tree7dd6bd613d186624a45e3acdfa83f30cbac2d27f /sys/dev
parenta5d798fc3915f61b0712980fa1e1c536a643bb50 (diff)
downloadFreeBSD-src-3efa4df5f0c9864a3af4b40308c57175ea50110e.zip
FreeBSD-src-3efa4df5f0c9864a3af4b40308c57175ea50110e.tar.gz
MFNetBSD:
One of a set of patches submitted by Kazuhito HONDA to make the usb audio driver a lot more capable. PR: 75274 Submitted by: Kazuhito HONDA (kazuhito at ph dot noda dot tus dot ac dot jp) Obtained from: NetBSD (indirectly) MFC after: 2 weeks
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/sound/usb/uaudio.c2431
-rw-r--r--sys/dev/sound/usb/uaudio.h11
-rw-r--r--sys/dev/sound/usb/uaudio_pcm.c10
-rw-r--r--sys/dev/sound/usb/uaudioreg.h34
4 files changed, 1762 insertions, 724 deletions
diff --git a/sys/dev/sound/usb/uaudio.c b/sys/dev/sound/usb/uaudio.c
index 769caf4..b67bf39 100644
--- a/sys/dev/sound/usb/uaudio.c
+++ b/sys/dev/sound/usb/uaudio.c
@@ -1,5 +1,5 @@
-/* $NetBSD: uaudio.c,v 1.41 2001/01/23 14:04:13 augustss Exp $ */
-/* $FreeBSD$: */
+/* $NetBSD: uaudio.c,v 1.91 2004/11/05 17:46:14 kent Exp $ */
+/* $FreeBSD$ */
/*
* Copyright (c) 1999 The NetBSD Foundation, Inc.
@@ -39,11 +39,16 @@
*/
/*
- * USB audio specs: http://www.usb.org/developers/data/devclass/audio10.pdf
- * http://www.usb.org/developers/data/devclass/frmts10.pdf
- * http://www.usb.org/developers/data/devclass/termt10.pdf
+ * USB audio specs: http://www.usb.org/developers/devclass_docs/audio10.pdf
+ * http://www.usb.org/developers/devclass_docs/frmts10.pdf
+ * http://www.usb.org/developers/devclass_docs/termt10.pdf
*/
+#include <sys/cdefs.h>
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+__KERNEL_RCSID(0, "$NetBSD: uaudio.c,v 1.91 2004/11/05 17:46:14 kent Exp $");
+#endif
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
@@ -65,11 +70,14 @@
#include <sys/conf.h>
#endif
#include <sys/poll.h>
+#if defined(__FreeBSD__)
#include <sys/sysctl.h>
+#endif
#if defined(__NetBSD__) || defined(__OpenBSD__)
#include <sys/audioio.h>
#include <dev/audio_if.h>
+#include <dev/audiovar.h>
#include <dev/mulaw.h>
#include <dev/auconv.h>
#elif defined(__FreeBSD__)
@@ -82,23 +90,39 @@
#include <dev/usb/usbdi_util.h>
#include <dev/usb/usb_quirks.h>
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+#include <dev/usb/uaudioreg.h>
+#elif defined(__FreeBSD__)
#include <dev/sound/usb/uaudioreg.h>
#include <dev/sound/usb/uaudio.h>
+#endif
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+/* #define UAUDIO_DEBUG */
+#else
+/* #define USB_DEBUG */
+#endif
+/* #define UAUDIO_MULTIPLE_ENDPOINTS */
#ifdef USB_DEBUG
-#define DPRINTF(x) if (uaudiodebug) logprintf x
-#define DPRINTFN(n,x) if (uaudiodebug>(n)) logprintf x
+#define DPRINTF(x) do { if (uaudiodebug) logprintf x; } while (0)
+#define DPRINTFN(n,x) do { if (uaudiodebug>(n)) logprintf x; } while (0)
int uaudiodebug = 0;
+#if defined(__FreeBSD__)
SYSCTL_NODE(_hw_usb, OID_AUTO, uaudio, CTLFLAG_RW, 0, "USB uaudio");
SYSCTL_INT(_hw_usb_uaudio, OID_AUTO, debug, CTLFLAG_RW,
&uaudiodebug, 0, "uaudio debug level");
+#endif
#else
#define DPRINTF(x)
#define DPRINTFN(n,x)
#endif
#define UAUDIO_NCHANBUFS 6 /* number of outstanding request */
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+#define UAUDIO_NFRAMES 10 /* ms of sound in each request */
+#elif defined(__FreeBSD__)
#define UAUDIO_NFRAMES 20 /* ms of sound in each request */
+#endif
#define MIX_MAX_CHAN 8
@@ -111,6 +135,7 @@ struct mixerctl {
#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;
@@ -129,22 +154,26 @@ struct mixerctl {
struct as_info {
u_int8_t alt;
u_int8_t encoding;
+ u_int8_t attributes; /* Copy of bmAttributes of
+ * usb_audio_streaming_endpoint_descriptor
+ */
usbd_interface_handle ifaceh;
- usb_interface_descriptor_t *idesc;
- usb_endpoint_descriptor_audio_t *edesc;
- struct usb_audio_streaming_type1_descriptor *asf1desc;
+ 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;
+ int sc_busy; /* currently used */
};
struct chan {
- int terminal; /* terminal id */
#if defined(__NetBSD__) || defined(__OpenBSD__)
- void (*intr)(void *); /* dma completion intr handler */
+ void (*intr)(void *); /* DMA completion intr handler */
void *arg; /* arg for intr() */
#else
struct pcm_channel *pcm_ch;
#endif
usbd_pipe_handle pipe;
- int dir; /* direction */
+ usbd_pipe_handle sync_pipe;
u_int sample_size;
u_int sample_rate;
@@ -158,15 +187,16 @@ struct chan {
int blksize; /* chunk size to report up */
int transferred; /* transferred bytes not reported up */
- char nofrac; /* don't do sample rate adjustment */
+ int altidx; /* currently used altidx */
int curchanbuf;
struct chanbuf {
- struct chan *chan;
+ struct chan *chan;
usbd_xfer_handle xfer;
- u_char *buffer;
- u_int16_t sizes[UAUDIO_NFRAMES];
- u_int16_t size;
+ u_char *buffer;
+ u_int16_t sizes[UAUDIO_NFRAMES];
+ u_int16_t offsets[UAUDIO_NFRAMES];
+ u_int16_t size;
} chanbufs[UAUDIO_NCHANBUFS];
struct uaudio_softc *sc; /* our softc */
@@ -178,151 +208,194 @@ struct chan {
};
struct uaudio_softc {
- USBBASEDEVICE sc_dev; /* base device */
+ USBBASEDEVICE sc_dev; /* base device */
usbd_device_handle sc_udev; /* USB device */
-
- char sc_dead; /* The device is dead -- kill it */
-
- int sc_ac_iface; /* Audio Control interface */
+ int sc_ac_iface; /* Audio Control interface */
usbd_interface_handle sc_ac_ifaceh;
+ struct chan sc_playchan; /* play channel */
+ struct chan sc_recchan; /* record channel */
+ int sc_nullalt;
+ int sc_audio_rev;
+ struct as_info *sc_alts; /* alternate settings */
+ int sc_nalts; /* # of alternate settings */
+ int sc_altflags;
+#define HAS_8 0x01
+#define HAS_16 0x02
+#define HAS_8U 0x04
+#define HAS_ALAW 0x08
+#define HAS_MULAW 0x10
+#define UA_NOFRAC 0x20 /* don't do sample rate adjustment */
+#define HAS_24 0x40
+ int sc_mode; /* play/record capability */
+ struct mixerctl *sc_ctls; /* mixer controls */
+ int sc_nctls; /* # of mixer controls */
+ device_ptr_t sc_audiodev;
+ char sc_dying;
+};
- struct chan sc_chan;
-
- int sc_curaltidx;
-
- int sc_nullalt;
-
- int sc_audio_rev;
-
- struct as_info *sc_alts;
- int sc_nalts;
- int sc_props;
-
- int sc_altflags;
-#define HAS_8 0x01
-#define HAS_16 0x02
-#define HAS_8U 0x04
-#define HAS_ALAW 0x08
-#define HAS_MULAW 0x10
-
- struct mixerctl *sc_ctls;
- int sc_nctls;
-
- device_ptr_t sc_audiodev;
- char sc_dying;
+struct terminal_list {
+ int size;
+ uint16_t terminals[1];
+};
+#define TERMINAL_LIST_SIZE(N) (offsetof(struct terminal_list, terminals) \
+ + sizeof(uint16_t) * (N))
+
+struct io_terminal {
+ union {
+ const usb_descriptor_t *desc;
+ const struct usb_audio_input_terminal *it;
+ const struct usb_audio_output_terminal *ot;
+ const struct usb_audio_mixer_unit *mu;
+ const struct usb_audio_selector_unit *su;
+ const struct usb_audio_feature_unit *fu;
+ const struct usb_audio_processing_unit *pu;
+ const struct usb_audio_extension_unit *eu;
+ } d;
+ int inputs_size;
+ struct terminal_list **inputs; /* list of source input terminals */
+ struct terminal_list *output; /* list of destination output terminals */
+ int direct; /* directly connected to an output terminal */
};
-#define UAC_OUTPUT 0
-#define UAC_INPUT 1
-#define UAC_EQUAL 2
+#define UAC_OUTPUT 0
+#define UAC_INPUT 1
+#define UAC_EQUAL 2
+#define UAC_RECORD 3
+#define UAC_NCLASSES 4
+#if !defined(__FreeBSD__)
+#ifdef USB_DEBUG
+Static const char *uac_names[] = {
+ AudioCoutputs, AudioCinputs, AudioCequalization, AudioCrecord,
+};
+#endif
+#endif
-Static usbd_status uaudio_identify_ac(struct uaudio_softc *sc,
- usb_config_descriptor_t *cdesc);
-Static usbd_status uaudio_identify_as(struct uaudio_softc *sc,
- usb_config_descriptor_t *cdesc);
-Static usbd_status uaudio_process_as(struct uaudio_softc *sc,
- char *buf, int *offsp, int size,
- usb_interface_descriptor_t *id);
+Static usbd_status uaudio_identify_ac
+ (struct uaudio_softc *, const usb_config_descriptor_t *);
+Static usbd_status uaudio_identify_as
+ (struct uaudio_softc *, const usb_config_descriptor_t *);
+Static usbd_status uaudio_process_as
+ (struct uaudio_softc *, const char *, int *, int,
+ const usb_interface_descriptor_t *);
-Static void uaudio_add_alt(struct uaudio_softc *sc,
- struct as_info *ai);
+Static void uaudio_add_alt(struct uaudio_softc *, const struct as_info *);
-Static usb_interface_descriptor_t *uaudio_find_iface(char *buf,
- int size, int *offsp, int subtype);
+Static const usb_interface_descriptor_t *uaudio_find_iface
+ (const char *, int, int *, int);
-Static void uaudio_mixer_add_ctl(struct uaudio_softc *sc,
- struct mixerctl *mp);
+Static void uaudio_mixer_add_ctl(struct uaudio_softc *, struct mixerctl *);
#if defined(__NetBSD__) || defined(__OpenBSD__)
-Static char *uaudio_id_name(struct uaudio_softc *sc,
- usb_descriptor_t **dps, int id);
-#endif
-
-Static struct usb_audio_cluster uaudio_get_cluster(int id,
- usb_descriptor_t **dps);
-Static void uaudio_add_input(struct uaudio_softc *sc,
- usb_descriptor_t *v, usb_descriptor_t **dps);
-Static void uaudio_add_output(struct uaudio_softc *sc,
- usb_descriptor_t *v, usb_descriptor_t **dps);
-Static void uaudio_add_mixer(struct uaudio_softc *sc,
- usb_descriptor_t *v, usb_descriptor_t **dps);
-Static void uaudio_add_selector(struct uaudio_softc *sc,
- usb_descriptor_t *v, usb_descriptor_t **dps);
-Static void uaudio_add_feature(struct uaudio_softc *sc,
- usb_descriptor_t *v, usb_descriptor_t **dps);
-Static void uaudio_add_processing_updown(struct uaudio_softc *sc,
- usb_descriptor_t *v, usb_descriptor_t **dps);
-Static void uaudio_add_processing(struct uaudio_softc *sc,
- usb_descriptor_t *v, usb_descriptor_t **dps);
-Static void uaudio_add_extension(struct uaudio_softc *sc,
- usb_descriptor_t *v, usb_descriptor_t **dps);
-Static usbd_status uaudio_identify(struct uaudio_softc *sc,
- usb_config_descriptor_t *cdesc);
-
-Static int uaudio_signext(int type, int val);
+Static char *uaudio_id_name
+ (struct uaudio_softc *, const struct io_terminal *, int);
+#endif
+
+#ifdef USB_DEBUG
+Static void uaudio_dump_cluster(const struct usb_audio_cluster *);
+#endif
+Static struct usb_audio_cluster uaudio_get_cluster
+ (int, const struct io_terminal *);
+Static void uaudio_add_input
+ (struct uaudio_softc *, const struct io_terminal *, int);
+Static void uaudio_add_output
+ (struct uaudio_softc *, const struct io_terminal *, int);
+Static void uaudio_add_mixer
+ (struct uaudio_softc *, const struct io_terminal *, int);
+Static void uaudio_add_selector
+ (struct uaudio_softc *, const struct io_terminal *, int);
+#ifdef USB_DEBUG
+Static const char *uaudio_get_terminal_name(int);
+#endif
+#if !defined(__FreeBSD__)
+Static int uaudio_determine_class
+ (const struct io_terminal *, struct mixerctl *);
+Static const char *uaudio_feature_name
+ (const struct io_terminal *, struct mixerctl *);
+#endif
+Static void uaudio_add_feature
+ (struct uaudio_softc *, const struct io_terminal *, int);
+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_extension
+ (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 int uaudio_signext(int, int);
#if defined(__NetBSD__) || defined(__OpenBSD__)
-Static int uaudio_value2bsd(struct mixerctl *mc, int val);
+Static int uaudio_value2bsd(struct mixerctl *, int);
#endif
-Static int uaudio_bsd2value(struct mixerctl *mc, int val);
-Static int uaudio_get(struct uaudio_softc *sc, int type,
- int which, int wValue, int wIndex, int len);
+Static int uaudio_bsd2value(struct mixerctl *, int);
+Static int uaudio_get(struct uaudio_softc *, int, int, int, int, int);
#if defined(__NetBSD__) || defined(__OpenBSD__)
-Static int uaudio_ctl_get(struct uaudio_softc *sc, int which,
- struct mixerctl *mc, int chan);
+Static int uaudio_ctl_get
+ (struct uaudio_softc *, int, struct mixerctl *, int);
#endif
-Static void uaudio_set(struct uaudio_softc *sc, int type,
- int which, int wValue, int wIndex, int l, int v);
-Static void uaudio_ctl_set(struct uaudio_softc *sc, int which,
- struct mixerctl *mc, int chan, int val);
+Static void uaudio_set
+ (struct uaudio_softc *, int, int, int, int, int, int);
+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, u_int);
-Static usbd_status uaudio_chan_open(struct uaudio_softc *sc,
- struct chan *ch);
-Static void uaudio_chan_close(struct uaudio_softc *sc,
- struct chan *ch);
-Static usbd_status uaudio_chan_alloc_buffers(struct uaudio_softc *,
- struct chan *);
-Static void uaudio_chan_free_buffers(struct uaudio_softc *,
- struct chan *);
+Static usbd_status uaudio_chan_open(struct uaudio_softc *, struct chan *);
+Static void uaudio_chan_close(struct uaudio_softc *, struct chan *);
+Static usbd_status uaudio_chan_alloc_buffers
+ (struct uaudio_softc *, struct chan *);
+Static void uaudio_chan_free_buffers(struct uaudio_softc *, struct chan *);
#if defined(__NetBSD__) || defined(__OpenBSD__)
-Static void uaudio_chan_set_param(struct chan *ch,
- struct audio_params *param, u_char *start,
- u_char *end, int blksize);
+Static void uaudio_chan_init
+ (struct chan *, int, const struct audio_params *, int);
+Static void uaudio_chan_set_param(struct chan *, u_char *, u_char *, int);
#endif
-Static void uaudio_chan_ptransfer(struct chan *ch);
-Static void uaudio_chan_pintr(usbd_xfer_handle xfer,
- usbd_private_handle priv, usbd_status status);
+Static void uaudio_chan_ptransfer(struct chan *);
+Static void uaudio_chan_pintr
+ (usbd_xfer_handle, usbd_private_handle, usbd_status);
-Static void uaudio_chan_rtransfer(struct chan *ch);
-Static void uaudio_chan_rintr(usbd_xfer_handle xfer,
- usbd_private_handle priv, usbd_status status);
+Static void uaudio_chan_rtransfer(struct chan *);
+Static void uaudio_chan_rintr
+ (usbd_xfer_handle, usbd_private_handle, usbd_status);
#if defined(__NetBSD__) || defined(__OpenBSD__)
-Static int uaudio_open(void *, int);
-Static void uaudio_close(void *);
-Static int uaudio_drain(void *);
-Static int uaudio_query_encoding(void *, struct audio_encoding *);
-Static int uaudio_set_params(void *, int, int,
- struct audio_params *, struct audio_params *);
-Static int uaudio_round_blocksize(void *, int);
-Static int uaudio_trigger_output(void *, void *, void *,
- int, void (*)(void *), void *,
- struct audio_params *);
-Static int uaudio_trigger_input (void *, void *, void *,
- int, void (*)(void *), void *,
- struct audio_params *);
-Static int uaudio_halt_in_dma(void *);
-Static int uaudio_halt_out_dma(void *);
-Static int uaudio_getdev(void *, struct audio_device *);
-Static int uaudio_mixer_set_port(void *, mixer_ctrl_t *);
-Static int uaudio_mixer_get_port(void *, mixer_ctrl_t *);
-Static int uaudio_query_devinfo(void *, mixer_devinfo_t *);
-Static int uaudio_get_props(void *);
-
-Static struct audio_hw_if uaudio_hw_if = {
+Static int uaudio_open(void *, int);
+Static void uaudio_close(void *);
+Static int uaudio_drain(void *);
+Static int uaudio_query_encoding(void *, struct audio_encoding *);
+Static void uaudio_get_minmax_rates
+ (int, const struct as_info *, const struct audio_params *,
+ int, u_long *, u_long *);
+Static int uaudio_match_alt_sub
+ (int, const struct as_info *, const struct audio_params *, int, u_long);
+Static int uaudio_match_alt_chan
+ (int, const struct as_info *, struct audio_params *, int);
+Static int uaudio_match_alt
+ (int, const struct as_info *, struct audio_params *, int);
+Static int uaudio_set_params
+ (void *, int, int, struct audio_params *, struct audio_params *);
+Static int uaudio_round_blocksize(void *, int);
+Static int uaudio_trigger_output
+ (void *, void *, void *, int, void (*)(void *), void *,
+ struct audio_params *);
+Static int uaudio_trigger_input
+ (void *, void *, void *, int, void (*)(void *), void *,
+ struct audio_params *);
+Static int uaudio_halt_in_dma(void *);
+Static int uaudio_halt_out_dma(void *);
+Static int uaudio_getdev(void *, struct audio_device *);
+Static int uaudio_mixer_set_port(void *, mixer_ctrl_t *);
+Static int uaudio_mixer_get_port(void *, mixer_ctrl_t *);
+Static int uaudio_query_devinfo(void *, mixer_devinfo_t *);
+Static int uaudio_get_props(void *);
+
+Static const struct audio_hw_if uaudio_hw_if = {
uaudio_open,
uaudio_close,
uaudio_drain,
@@ -349,6 +422,7 @@ Static struct audio_hw_if uaudio_hw_if = {
uaudio_get_props,
uaudio_trigger_output,
uaudio_trigger_input,
+ NULL,
};
Static struct audio_device uaudio_device = {
@@ -359,7 +433,7 @@ Static struct audio_device uaudio_device = {
#elif defined(__FreeBSD__)
Static int audio_attach_mi(device_t);
-Static void uaudio_init_params(struct uaudio_softc * sc, struct chan *ch);
+Static int uaudio_init_params(struct uaudio_softc * sc, struct chan *ch, int mode);
/* for NetBSD compatibirity */
#define AUMODE_PLAY 0x01
@@ -396,13 +470,13 @@ USB_MATCH(uaudio)
{
USB_MATCH_START(uaudio, uaa);
usb_interface_descriptor_t *id;
-
+
if (uaa->iface == NULL)
return (UMATCH_NONE);
id = usbd_get_interface_descriptor(uaa->iface);
/* Trigger on the control interface. */
- if (id == NULL ||
+ if (id == NULL ||
id->bInterfaceClass != UICLASS_AUDIO ||
id->bInterfaceSubClass != UISUBCLASS_AUDIOCONTROL ||
(usbd_get_quirks(uaa->device)->uq_flags & UQ_BAD_AUDIO))
@@ -420,8 +494,12 @@ USB_ATTACH(uaudio)
usbd_status err;
int i, j, found;
+#if defined(__FreeBSD__)
usbd_devinfo(uaa->device, 0, devinfo);
USB_ATTACH_SETUP;
+#else
+ usbd_devinfo(uaa->device, 0, devinfo, sizeof(devinfo));
+#endif
#if !defined(__FreeBSD__)
printf(": %s\n", devinfo);
@@ -474,10 +552,12 @@ USB_ATTACH(uaudio)
printf("%s: audio rev %d.%02x\n", USBDEVNAME(sc->sc_dev),
sc->sc_audio_rev >> 8, sc->sc_audio_rev & 0xff);
- sc->sc_chan.sc = sc;
+ sc->sc_playchan.sc = sc->sc_recchan.sc = sc;
+ sc->sc_playchan.altidx = -1;
+ sc->sc_recchan.altidx = -1;
if (usbd_get_quirks(sc->sc_udev)->uq_flags & UQ_AU_NO_FRAC)
- sc->sc_chan.nofrac = 1;
+ sc->sc_altflags |= UA_NOFRAC;
#ifndef USB_DEBUG
if (bootverbose)
@@ -565,7 +645,7 @@ USB_DETACH(uaudio)
#endif
#if defined(__NetBSD__) || defined(__OpenBSD__)
-int
+Static int
uaudio_query_encoding(void *addr, struct audio_encoding *fp)
{
struct uaudio_softc *sc = addr;
@@ -574,56 +654,56 @@ uaudio_query_encoding(void *addr, struct audio_encoding *fp)
if (sc->sc_dying)
return (EIO);
-
+
if (sc->sc_nalts == 0 || flags == 0)
return (ENXIO);
idx = fp->index;
switch (idx) {
case 0:
- strcpy(fp->name, AudioEulinear);
+ strlcpy(fp->name, AudioEulinear, sizeof(fp->name));
fp->encoding = AUDIO_ENCODING_ULINEAR;
fp->precision = 8;
fp->flags = flags&HAS_8U ? 0 : AUDIO_ENCODINGFLAG_EMULATED;
return (0);
case 1:
- strcpy(fp->name, AudioEmulaw);
+ strlcpy(fp->name, AudioEmulaw, sizeof(fp->name));
fp->encoding = AUDIO_ENCODING_ULAW;
fp->precision = 8;
fp->flags = flags&HAS_MULAW ? 0 : AUDIO_ENCODINGFLAG_EMULATED;
return (0);
case 2:
- strcpy(fp->name, AudioEalaw);
+ strlcpy(fp->name, AudioEalaw, sizeof(fp->name));
fp->encoding = AUDIO_ENCODING_ALAW;
fp->precision = 8;
fp->flags = flags&HAS_ALAW ? 0 : AUDIO_ENCODINGFLAG_EMULATED;
return (0);
case 3:
- strcpy(fp->name, AudioEslinear);
+ strlcpy(fp->name, AudioEslinear, sizeof(fp->name));
fp->encoding = AUDIO_ENCODING_SLINEAR;
fp->precision = 8;
fp->flags = flags&HAS_8 ? 0 : AUDIO_ENCODINGFLAG_EMULATED;
return (0);
- case 4:
- strcpy(fp->name, AudioEslinear_le);
+ case 4:
+ strlcpy(fp->name, AudioEslinear_le, sizeof(fp->name));
fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
fp->precision = 16;
fp->flags = 0;
return (0);
case 5:
- strcpy(fp->name, AudioEulinear_le);
+ strlcpy(fp->name, AudioEulinear_le, sizeof(fp->name));
fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
fp->precision = 16;
fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
return (0);
case 6:
- strcpy(fp->name, AudioEslinear_be);
+ strlcpy(fp->name, AudioEslinear_be, sizeof(fp->name));
fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
fp->precision = 16;
fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
return (0);
case 7:
- strcpy(fp->name, AudioEulinear_be);
+ strlcpy(fp->name, AudioEulinear_be, sizeof(fp->name));
fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
fp->precision = 16;
fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
@@ -634,13 +714,13 @@ uaudio_query_encoding(void *addr, struct audio_encoding *fp)
}
#endif
-usb_interface_descriptor_t *
-uaudio_find_iface(char *buf, int size, int *offsp, int subtype)
+Static const usb_interface_descriptor_t *
+uaudio_find_iface(const char *buf, int size, int *offsp, int subtype)
{
- usb_interface_descriptor_t *d;
+ const usb_interface_descriptor_t *d;
while (*offsp < size) {
- d = (void *)(buf + *offsp);
+ d = (const void *)(buf + *offsp);
*offsp += d->bLength;
if (d->bDescriptorType == UDESC_INTERFACE &&
d->bInterfaceClass == UICLASS_AUDIO &&
@@ -650,29 +730,47 @@ uaudio_find_iface(char *buf, int size, int *offsp, int subtype)
return (NULL);
}
-void
+Static void
uaudio_mixer_add_ctl(struct uaudio_softc *sc, struct mixerctl *mc)
{
int res;
- size_t len = sizeof(*mc) * (sc->sc_nctls + 1);
- struct mixerctl *nmc = sc->sc_nctls == 0 ?
- malloc(len, M_USBDEV, M_NOWAIT) :
- realloc(sc->sc_ctls, len, M_USBDEV, M_NOWAIT);
+ size_t len;
+ struct mixerctl *nmc;
- if(nmc == NULL){
+#if !defined(__FreeBSD__)
+ if (mc->class < UAC_NCLASSES) {
+ DPRINTF(("%s: adding %s.%s\n",
+ __func__, uac_names[mc->class], mc->ctlname));
+ } else {
+ DPRINTF(("%s: adding %s\n", __func__, mc->ctlname));
+ }
+#endif
+ len = sizeof(*mc) * (sc->sc_nctls + 1);
+ nmc = malloc(len, M_USBDEV, M_NOWAIT);
+ if (nmc == NULL) {
printf("uaudio_mixer_add_ctl: no memory\n");
return;
}
+ /* Copy old data, if there was any */
+ if (sc->sc_nctls != 0) {
+ memcpy(nmc, sc->sc_ctls, sizeof(*mc) * (sc->sc_nctls));
+ free(sc->sc_ctls, M_USBDEV);
+ }
sc->sc_ctls = nmc;
mc->delta = 0;
- if (mc->type != MIX_ON_OFF) {
+ if (mc->type == MIX_ON_OFF) {
+ mc->minval = 0;
+ mc->maxval = 1;
+ } else if (mc->type == MIX_SELECTOR) {
+ ;
+ } else {
/* Determine min and max values. */
- mc->minval = uaudio_signext(mc->type,
- uaudio_get(sc, GET_MIN, UT_READ_CLASS_INTERFACE,
- mc->wValue[0], mc->wIndex,
+ mc->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->maxval = 1 + uaudio_signext(mc->type,
uaudio_get(sc, GET_MAX, UT_READ_CLASS_INTERFACE,
mc->wValue[0], mc->wIndex,
MIX_SIZE(mc->type)));
@@ -683,10 +781,7 @@ uaudio_mixer_add_ctl(struct uaudio_softc *sc, struct mixerctl *mc)
mc->wValue[0], mc->wIndex,
MIX_SIZE(mc->type));
if (res > 0)
- mc->delta = (res * 256 + mc->mul/2) / mc->mul;
- } else {
- mc->minval = 0;
- mc->maxval = 1;
+ mc->delta = (res * 255 + mc->mul/2) / mc->mul;
}
sc->sc_ctls[sc->sc_nctls++] = *mc;
@@ -713,67 +808,80 @@ uaudio_mixer_add_ctl(struct uaudio_softc *sc, struct mixerctl *mc)
}
#if defined(__NetBSD__) || defined(__OpenBSD__)
-char *
-uaudio_id_name(struct uaudio_softc *sc, usb_descriptor_t **dps, int id)
+Static char *
+uaudio_id_name(struct uaudio_softc *sc, const struct io_terminal *iot, int id)
{
static char buf[32];
- sprintf(buf, "i%d", id);
+ snprintf(buf, sizeof(buf), "i%d", id);
return (buf);
}
#endif
-struct usb_audio_cluster
-uaudio_get_cluster(int id, usb_descriptor_t **dps)
+#ifdef USB_DEBUG
+Static void
+uaudio_dump_cluster(const struct usb_audio_cluster *cl)
+{
+ static const char *channel_names[16] = {
+ "LEFT", "RIGHT", "CENTER", "LFE",
+ "LEFT_SURROUND", "RIGHT_SURROUND", "LEFT_CENTER", "RIGHT_CENTER",
+ "SURROUND", "LEFT_SIDE", "RIGHT_SIDE", "TOP",
+ "RESERVED12", "RESERVED13", "RESERVED14", "RESERVED15",
+ };
+ int cc, i, first;
+
+ cc = UGETW(cl->wChannelConfig);
+ logprintf("cluster: bNrChannels=%u wChannelConfig=0x%.4x",
+ cl->bNrChannels, cc);
+ first = TRUE;
+ for (i = 0; cc != 0; i++) {
+ if (cc & 1) {
+ logprintf("%c%s", first ? '<' : ',', channel_names[i]);
+ first = FALSE;
+ }
+ cc = cc >> 1;
+ }
+ logprintf("> iChannelNames=%u", cl->iChannelNames);
+}
+#endif
+
+Static struct usb_audio_cluster
+uaudio_get_cluster(int id, const struct io_terminal *iot)
{
struct usb_audio_cluster r;
- usb_descriptor_t *dp;
+ const usb_descriptor_t *dp;
int i;
for (i = 0; i < 25; i++) { /* avoid infinite loops */
- dp = dps[id];
+ dp = iot[id].d.desc;
if (dp == 0)
goto bad;
switch (dp->bDescriptorSubtype) {
case UDESCSUB_AC_INPUT:
-#define p ((struct usb_audio_input_terminal *)dp)
- r.bNrChannels = p->bNrChannels;
- USETW(r.wChannelConfig, UGETW(p->wChannelConfig));
- r.iChannelNames = p->iChannelNames;
-#undef p
+ r.bNrChannels = iot[id].d.it->bNrChannels;
+ USETW(r.wChannelConfig, UGETW(iot[id].d.it->wChannelConfig));
+ r.iChannelNames = iot[id].d.it->iChannelNames;
return (r);
case UDESCSUB_AC_OUTPUT:
-#define p ((struct usb_audio_output_terminal *)dp)
- id = p->bSourceId;
-#undef p
+ id = iot[id].d.ot->bSourceId;
break;
case UDESCSUB_AC_MIXER:
-#define p ((struct usb_audio_mixer_unit *)dp)
- r = *(struct usb_audio_cluster *)
- &p->baSourceId[p->bNrInPins];
-#undef p
+ r = *(const struct usb_audio_cluster *)
+ &iot[id].d.mu->baSourceId[iot[id].d.mu->bNrInPins];
return (r);
case UDESCSUB_AC_SELECTOR:
/* XXX This is not really right */
-#define p ((struct usb_audio_selector_unit *)dp)
- id = p->baSourceId[0];
-#undef p
+ id = iot[id].d.su->baSourceId[0];
break;
case UDESCSUB_AC_FEATURE:
-#define p ((struct usb_audio_feature_unit *)dp)
- id = p->bSourceId;
-#undef p
+ id = iot[id].d.fu->bSourceId;
break;
case UDESCSUB_AC_PROCESSING:
-#define p ((struct usb_audio_processing_unit *)dp)
- r = *(struct usb_audio_cluster *)
- &p->baSourceId[p->bNrInPins];
-#undef p
+ r = *(const struct usb_audio_cluster *)
+ &iot[id].d.pu->baSourceId[iot[id].d.pu->bNrInPins];
return (r);
case UDESCSUB_AC_EXTENSION:
-#define p ((struct usb_audio_extension_unit *)dp)
- r = *(struct usb_audio_cluster *)
- &p->baSourceId[p->bNrInPins];
-#undef p
+ r = *(const struct usb_audio_cluster *)
+ &iot[id].d.eu->baSourceId[iot[id].d.eu->bNrInPins];
return (r);
default:
goto bad;
@@ -786,13 +894,11 @@ uaudio_get_cluster(int id, usb_descriptor_t **dps)
}
-void
-uaudio_add_input(struct uaudio_softc *sc, usb_descriptor_t *v,
- usb_descriptor_t **dps)
+Static void
+uaudio_add_input(struct uaudio_softc *sc, const struct io_terminal *iot, int id)
{
#ifdef USB_DEBUG
- struct usb_audio_input_terminal *d =
- (struct usb_audio_input_terminal *)v;
+ const struct usb_audio_input_terminal *d = iot[id].d.it;
DPRINTFN(2,("uaudio_add_input: bTerminalId=%d wTerminalType=0x%04x "
"bAssocTerminal=%d bNrChannels=%d wChannelConfig=%d "
@@ -803,13 +909,11 @@ uaudio_add_input(struct uaudio_softc *sc, usb_descriptor_t *v,
#endif
}
-void
-uaudio_add_output(struct uaudio_softc *sc, usb_descriptor_t *v,
- usb_descriptor_t **dps)
+Static void
+uaudio_add_output(struct uaudio_softc *sc, const struct io_terminal *iot, int id)
{
#ifdef USB_DEBUG
- struct usb_audio_output_terminal *d =
- (struct usb_audio_output_terminal *)v;
+ const struct usb_audio_output_terminal *d = iot[id].d.ot;
DPRINTFN(2,("uaudio_add_output: bTerminalId=%d wTerminalType=0x%04x "
"bAssocTerminal=%d bSourceId=%d iTerminal=%d\n",
@@ -818,33 +922,32 @@ uaudio_add_output(struct uaudio_softc *sc, usb_descriptor_t *v,
#endif
}
-void
-uaudio_add_mixer(struct uaudio_softc *sc, usb_descriptor_t *v,
- usb_descriptor_t **dps)
+Static void
+uaudio_add_mixer(struct uaudio_softc *sc, const struct io_terminal *iot, int id)
{
- struct usb_audio_mixer_unit *d = (struct usb_audio_mixer_unit *)v;
- struct usb_audio_mixer_unit_1 *d1;
+ const struct usb_audio_mixer_unit *d = iot[id].d.mu;
+ const struct usb_audio_mixer_unit_1 *d1;
int c, chs, ichs, ochs, i, o, bno, p, mo, mc, k;
- uByte *bm;
+ const uByte *bm;
struct mixerctl mix;
DPRINTFN(2,("uaudio_add_mixer: bUnitId=%d bNrInPins=%d\n",
d->bUnitId, d->bNrInPins));
-
+
/* Compute the number of input channels */
ichs = 0;
for (i = 0; i < d->bNrInPins; i++)
- ichs += uaudio_get_cluster(d->baSourceId[i], dps).bNrChannels;
+ ichs += uaudio_get_cluster(d->baSourceId[i], iot).bNrChannels;
/* and the number of output channels */
- d1 = (struct usb_audio_mixer_unit_1 *)&d->baSourceId[d->bNrInPins];
+ d1 = (const struct usb_audio_mixer_unit_1 *)&d->baSourceId[d->bNrInPins];
ochs = d1->bNrChannels;
DPRINTFN(2,("uaudio_add_mixer: ichs=%d ochs=%d\n", ichs, ochs));
bm = d1->bmControls;
mix.wIndex = MAKE(d->bUnitId, sc->sc_ac_iface);
#if !defined(__FreeBSD__)
- mix.class = -1;
+ uaudio_determine_class(&iot[id], &mix);
#endif
mix.type = MIX_SIGNED_16;
#if !defined(__FreeBSD__) /* XXXXX */
@@ -853,7 +956,7 @@ uaudio_add_mixer(struct uaudio_softc *sc, usb_descriptor_t *v,
#define BIT(bno) ((bm[bno / 8] >> (7 - bno % 8)) & 1)
for (p = i = 0; i < d->bNrInPins; i++) {
- chs = uaudio_get_cluster(d->baSourceId[i], dps).bNrChannels;
+ chs = uaudio_get_cluster(d->baSourceId[i], iot).bNrChannels;
mc = 0;
for (c = 0; c < chs; c++) {
mo = 0;
@@ -871,12 +974,13 @@ uaudio_add_mixer(struct uaudio_softc *sc, usb_descriptor_t *v,
for (o = 0; o < ochs; o++) {
bno = (p + c) * ochs + o;
if (BIT(bno))
- mix.wValue[k++] =
+ mix.wValue[k++] =
MAKE(p+c+1, o+1);
}
#if !defined(__FreeBSD__)
- sprintf(mix.ctlname, "mix%d-%s", d->bUnitId,
- uaudio_id_name(sc, dps, d->baSourceId[i]));
+ snprintf(mix.ctlname, sizeof(mix.ctlname), "mix%d-%s",
+ d->bUnitId, uaudio_id_name(sc, iot,
+ d->baSourceId[i]));
#endif
mix.nchan = chs;
uaudio_mixer_add_ctl(sc, &mix);
@@ -889,34 +993,286 @@ uaudio_add_mixer(struct uaudio_softc *sc, usb_descriptor_t *v,
}
-void
-uaudio_add_selector(struct uaudio_softc *sc, usb_descriptor_t *v,
- usb_descriptor_t **dps)
+Static void
+uaudio_add_selector(struct uaudio_softc *sc, const struct io_terminal *iot, int id)
{
-#ifdef USB_DEBUG
- struct usb_audio_selector_unit *d =
- (struct usb_audio_selector_unit *)v;
+#if !defined(__FreeBSD__) || defined(USB_DEBUG)
+ const struct usb_audio_selector_unit *d = iot[id].d.su;
+#endif
+#if !defined(__FreeBSD__)
+ struct mixerctl mix;
+ int i, wp;
+#endif
DPRINTFN(2,("uaudio_add_selector: bUnitId=%d bNrInPins=%d\n",
d->bUnitId, d->bNrInPins));
-#endif
+#if defined(__FreeBSD__)
printf("uaudio_add_selector: NOT IMPLEMENTED\n");
+#else
+ mix.wIndex = MAKE(d->bUnitId, sc->sc_ac_iface);
+ mix.wValue[0] = MAKE(0, 0);
+ uaudio_determine_class(&iot[id], &mix);
+ mix.nchan = 1;
+ mix.type = MIX_SELECTOR;
+ mix.ctlunit = "";
+ mix.minval = 1;
+ mix.maxval = d->bNrInPins;
+ mix.mul = mix.maxval - mix.minval;
+ wp = snprintf(mix.ctlname, MAX_AUDIO_DEV_LEN, "sel%d-", d->bUnitId);
+ for (i = 1; i <= d->bNrInPins; i++) {
+ wp += snprintf(mix.ctlname + wp, MAX_AUDIO_DEV_LEN - wp,
+ "i%d", d->baSourceId[i - 1]);
+ if (wp > MAX_AUDIO_DEV_LEN - 1)
+ break;
+ }
+ uaudio_mixer_add_ctl(sc, &mix);
+#endif
}
-void
-uaudio_add_feature(struct uaudio_softc *sc, usb_descriptor_t *v,
- usb_descriptor_t **dps)
+#ifdef USB_DEBUG
+Static const char *
+uaudio_get_terminal_name(int terminal_type)
+{
+ static char buf[100];
+
+ switch (terminal_type) {
+ /* USB terminal types */
+ case UAT_UNDEFINED: return "UAT_UNDEFINED";
+ case UAT_STREAM: return "UAT_STREAM";
+ case UAT_VENDOR: return "UAT_VENDOR";
+ /* input terminal types */
+ case UATI_UNDEFINED: return "UATI_UNDEFINED";
+ case UATI_MICROPHONE: return "UATI_MICROPHONE";
+ case UATI_DESKMICROPHONE: return "UATI_DESKMICROPHONE";
+ case UATI_PERSONALMICROPHONE: return "UATI_PERSONALMICROPHONE";
+ case UATI_OMNIMICROPHONE: return "UATI_OMNIMICROPHONE";
+ case UATI_MICROPHONEARRAY: return "UATI_MICROPHONEARRAY";
+ case UATI_PROCMICROPHONEARR: return "UATI_PROCMICROPHONEARR";
+ /* output terminal types */
+ case UATO_UNDEFINED: return "UATO_UNDEFINED";
+ case UATO_SPEAKER: return "UATO_SPEAKER";
+ case UATO_HEADPHONES: return "UATO_HEADPHONES";
+ case UATO_DISPLAYAUDIO: return "UATO_DISPLAYAUDIO";
+ case UATO_DESKTOPSPEAKER: return "UATO_DESKTOPSPEAKER";
+ case UATO_ROOMSPEAKER: return "UATO_ROOMSPEAKER";
+ case UATO_COMMSPEAKER: return "UATO_COMMSPEAKER";
+ case UATO_SUBWOOFER: return "UATO_SUBWOOFER";
+ /* bidir terminal types */
+ case UATB_UNDEFINED: return "UATB_UNDEFINED";
+ case UATB_HANDSET: return "UATB_HANDSET";
+ case UATB_HEADSET: return "UATB_HEADSET";
+ case UATB_SPEAKERPHONE: return "UATB_SPEAKERPHONE";
+ case UATB_SPEAKERPHONEESUP: return "UATB_SPEAKERPHONEESUP";
+ case UATB_SPEAKERPHONEECANC: return "UATB_SPEAKERPHONEECANC";
+ /* telephony terminal types */
+ case UATT_UNDEFINED: return "UATT_UNDEFINED";
+ case UATT_PHONELINE: return "UATT_PHONELINE";
+ case UATT_TELEPHONE: return "UATT_TELEPHONE";
+ case UATT_DOWNLINEPHONE: return "UATT_DOWNLINEPHONE";
+ /* external terminal types */
+ case UATE_UNDEFINED: return "UATE_UNDEFINED";
+ case UATE_ANALOGCONN: return "UATE_ANALOGCONN";
+ case UATE_LINECONN: return "UATE_LINECONN";
+ case UATE_LEGACYCONN: return "UATE_LEGACYCONN";
+ case UATE_DIGITALAUIFC: return "UATE_DIGITALAUIFC";
+ case UATE_SPDIF: return "UATE_SPDIF";
+ case UATE_1394DA: return "UATE_1394DA";
+ case UATE_1394DV: return "UATE_1394DV";
+ /* embedded function terminal types */
+ case UATF_UNDEFINED: return "UATF_UNDEFINED";
+ case UATF_CALIBNOISE: return "UATF_CALIBNOISE";
+ case UATF_EQUNOISE: return "UATF_EQUNOISE";
+ case UATF_CDPLAYER: return "UATF_CDPLAYER";
+ case UATF_DAT: return "UATF_DAT";
+ case UATF_DCC: return "UATF_DCC";
+ case UATF_MINIDISK: return "UATF_MINIDISK";
+ case UATF_ANALOGTAPE: return "UATF_ANALOGTAPE";
+ case UATF_PHONOGRAPH: return "UATF_PHONOGRAPH";
+ case UATF_VCRAUDIO: return "UATF_VCRAUDIO";
+ case UATF_VIDEODISCAUDIO: return "UATF_VIDEODISCAUDIO";
+ case UATF_DVDAUDIO: return "UATF_DVDAUDIO";
+ case UATF_TVTUNERAUDIO: return "UATF_TVTUNERAUDIO";
+ case UATF_SATELLITE: return "UATF_SATELLITE";
+ case UATF_CABLETUNER: return "UATF_CABLETUNER";
+ case UATF_DSS: return "UATF_DSS";
+ case UATF_RADIORECV: return "UATF_RADIORECV";
+ case UATF_RADIOXMIT: return "UATF_RADIOXMIT";
+ case UATF_MULTITRACK: return "UATF_MULTITRACK";
+ case UATF_SYNTHESIZER: return "UATF_SYNTHESIZER";
+ default:
+ snprintf(buf, sizeof(buf), "unknown type (0x%.4x)", terminal_type);
+ return buf;
+ }
+}
+#endif
+
+#if !defined(__FreeBSD__)
+Static int
+uaudio_determine_class(const struct io_terminal *iot, struct mixerctl *mix)
{
- struct usb_audio_feature_unit *d = (struct usb_audio_feature_unit *)v;
+ int terminal_type;
+
+ if (iot == NULL || iot->output == NULL) {
+ mix->class = UAC_OUTPUT;
+ return 0;
+ }
+ terminal_type = 0;
+ if (iot->output->size == 1)
+ terminal_type = iot->output->terminals[0];
+ /*
+ * If the only output terminal is USB,
+ * the class is UAC_RECORD.
+ */
+ if ((terminal_type & 0xff00) == (UAT_UNDEFINED & 0xff00)) {
+ mix->class = UAC_RECORD;
+ if (iot->inputs_size == 1
+ && iot->inputs[0] != NULL
+ && iot->inputs[0]->size == 1)
+ return iot->inputs[0]->terminals[0];
+ else
+ return 0;
+ }
+ /*
+ * If the ultimate destination of the unit is just one output
+ * terminal and the unit is connected to the output terminal
+ * directly, the class is UAC_OUTPUT.
+ */
+ if (terminal_type != 0 && iot->direct) {
+ mix->class = UAC_OUTPUT;
+ return terminal_type;
+ }
+ /*
+ * If the unit is connected to just one input terminal,
+ * the class is UAC_INPUT.
+ */
+ if (iot->inputs_size == 1 && iot->inputs[0] != NULL
+ && iot->inputs[0]->size == 1) {
+ mix->class = UAC_INPUT;
+ return iot->inputs[0]->terminals[0];
+ }
+ /*
+ * Otherwise, the class is UAC_OUTPUT.
+ */
+ mix->class = UAC_OUTPUT;
+ return terminal_type;
+}
+
+Static const char *
+uaudio_feature_name(const struct io_terminal *iot, struct mixerctl *mix)
+{
+ int terminal_type;
+
+ terminal_type = uaudio_determine_class(iot, mix);
+ if (mix->class == UAC_RECORD && terminal_type == 0)
+ return AudioNmixerout;
+ DPRINTF(("%s: terminal_type=%s\n", __func__,
+ uaudio_get_terminal_name(terminal_type)));
+ switch (terminal_type) {
+ case UAT_STREAM:
+ return AudioNdac;
+
+ case UATI_MICROPHONE:
+ case UATI_DESKMICROPHONE:
+ case UATI_PERSONALMICROPHONE:
+ case UATI_OMNIMICROPHONE:
+ case UATI_MICROPHONEARRAY:
+ case UATI_PROCMICROPHONEARR:
+ return AudioNmicrophone;
+
+ case UATO_SPEAKER:
+ case UATO_DESKTOPSPEAKER:
+ case UATO_ROOMSPEAKER:
+ case UATO_COMMSPEAKER:
+ return AudioNspeaker;
+
+ case UATO_HEADPHONES:
+ return AudioNheadphone;
+
+ case UATO_SUBWOOFER:
+ return AudioNlfe;
+
+ /* telephony terminal types */
+ case UATT_UNDEFINED:
+ case UATT_PHONELINE:
+ case UATT_TELEPHONE:
+ case UATT_DOWNLINEPHONE:
+ return "phone";
+
+ case UATE_ANALOGCONN:
+ case UATE_LINECONN:
+ case UATE_LEGACYCONN:
+ return AudioNline;
+
+ case UATE_DIGITALAUIFC:
+ case UATE_SPDIF:
+ case UATE_1394DA:
+ case UATE_1394DV:
+ return AudioNaux;
+
+ case UATF_CDPLAYER:
+ return AudioNcd;
+
+ case UATF_SYNTHESIZER:
+ return AudioNfmsynth;
+
+ case UATF_VIDEODISCAUDIO:
+ case UATF_DVDAUDIO:
+ case UATF_TVTUNERAUDIO:
+ return AudioNvideo;
+
+ case UAT_UNDEFINED:
+ case UAT_VENDOR:
+ case UATI_UNDEFINED:
+/* output terminal types */
+ case UATO_UNDEFINED:
+ case UATO_DISPLAYAUDIO:
+/* bidir terminal types */
+ case UATB_UNDEFINED:
+ case UATB_HANDSET:
+ case UATB_HEADSET:
+ case UATB_SPEAKERPHONE:
+ case UATB_SPEAKERPHONEESUP:
+ case UATB_SPEAKERPHONEECANC:
+/* external terminal types */
+ case UATE_UNDEFINED:
+/* embedded function terminal types */
+ case UATF_UNDEFINED:
+ case UATF_CALIBNOISE:
+ case UATF_EQUNOISE:
+ case UATF_DAT:
+ case UATF_DCC:
+ case UATF_MINIDISK:
+ case UATF_ANALOGTAPE:
+ case UATF_PHONOGRAPH:
+ case UATF_VCRAUDIO:
+ case UATF_SATELLITE:
+ case UATF_CABLETUNER:
+ case UATF_DSS:
+ case UATF_RADIORECV:
+ case UATF_RADIOXMIT:
+ case UATF_MULTITRACK:
+ case 0xffff:
+ default:
+ DPRINTF(("%s: 'master' for 0x%.4x\n", __func__, terminal_type));
+ return AudioNmaster;
+ }
+ return AudioNmaster;
+}
+#endif
+
+Static void
+uaudio_add_feature(struct uaudio_softc *sc, const struct io_terminal *iot, int id)
+{
+ const struct usb_audio_feature_unit *d = iot[id].d.fu;
uByte *ctls = d->bmaControls;
int ctlsize = d->bControlSize;
int nchan = (d->bLength - 7) / ctlsize;
-#if !defined(__FreeBSD__)
- int srcId = d->bSourceId;
-#endif
u_int fumask, mmask, cmask;
struct mixerctl mix;
int chan, ctl, i, unit;
+#if !defined(__FreeBSD__)
+ const char *mixername;
+#endif
#define GET(i) (ctls[(i)*ctlsize] | \
(ctlsize > 1 ? ctls[(i)*ctlsize+1] << 8 : 0))
@@ -930,9 +1286,9 @@ uaudio_add_feature(struct uaudio_softc *sc, usb_descriptor_t *v,
}
#if !defined(__FreeBSD__)
- DPRINTFN(1,("uaudio_add_feature: bUnitId=%d bSourceId=%d, "
- "%d channels, mmask=0x%04x, cmask=0x%04x\n",
- d->bUnitId, srcId, nchan, mmask, cmask));
+ DPRINTFN(1,("uaudio_add_feature: bUnitId=%d, "
+ "%d channels, mmask=0x%04x, cmask=0x%04x\n",
+ d->bUnitId, nchan, mmask, cmask));
#endif
if (nchan > MIX_MAX_CHAN)
@@ -960,7 +1316,7 @@ uaudio_add_feature(struct uaudio_softc *sc, usb_descriptor_t *v,
#undef GET
#if !defined(__FreeBSD__)
- mix.class = -1; /* XXX */
+ mixername = uaudio_feature_name(&iot[id], &mix);
#endif
switch (ctl) {
case MUTE_CONTROL:
@@ -968,10 +1324,9 @@ uaudio_add_feature(struct uaudio_softc *sc, usb_descriptor_t *v,
#if defined(__FreeBSD__)
mix.ctl = SOUND_MIXER_NRDEVICES;
#else
- sprintf(mix.ctlname, "fea%d-%s-%s", unit,
- uaudio_id_name(sc, dps, srcId),
- AudioNmute);
mix.ctlunit = "";
+ snprintf(mix.ctlname, sizeof(mix.ctlname),
+ "%s.%s", mixername, AudioNmute);
#endif
break;
case VOLUME_CONTROL:
@@ -980,10 +1335,8 @@ uaudio_add_feature(struct uaudio_softc *sc, usb_descriptor_t *v,
/* mix.ctl = SOUND_MIXER_VOLUME; */
mix.ctl = SOUND_MIXER_PCM;
#else
- sprintf(mix.ctlname, "fea%d-%s-%s", unit,
- uaudio_id_name(sc, dps, srcId),
- AudioNmaster);
mix.ctlunit = AudioNvolume;
+ strlcpy(mix.ctlname, mixername, sizeof(mix.ctlname));
#endif
break;
case BASS_CONTROL:
@@ -991,10 +1344,9 @@ uaudio_add_feature(struct uaudio_softc *sc, usb_descriptor_t *v,
#if defined(__FreeBSD__)
mix.ctl = SOUND_MIXER_BASS;
#else
- sprintf(mix.ctlname, "fea%d-%s-%s", unit,
- uaudio_id_name(sc, dps, srcId),
- AudioNbass);
mix.ctlunit = AudioNbass;
+ snprintf(mix.ctlname, sizeof(mix.ctlname),
+ "%s.%s", mixername, AudioNbass);
#endif
break;
case MID_CONTROL:
@@ -1002,10 +1354,9 @@ uaudio_add_feature(struct uaudio_softc *sc, usb_descriptor_t *v,
#if defined(__FreeBSD__)
mix.ctl = SOUND_MIXER_NRDEVICES; /* XXXXX */
#else
- sprintf(mix.ctlname, "fea%d-%s-%s", unit,
- uaudio_id_name(sc, dps, srcId),
- AudioNmid);
mix.ctlunit = AudioNmid;
+ snprintf(mix.ctlname, sizeof(mix.ctlname),
+ "%s.%s", mixername, AudioNmid);
#endif
break;
case TREBLE_CONTROL:
@@ -1013,10 +1364,9 @@ uaudio_add_feature(struct uaudio_softc *sc, usb_descriptor_t *v,
#if defined(__FreeBSD__)
mix.ctl = SOUND_MIXER_TREBLE;
#else
- sprintf(mix.ctlname, "fea%d-%s-%s", unit,
- uaudio_id_name(sc, dps, srcId),
- AudioNtreble);
mix.ctlunit = AudioNtreble;
+ snprintf(mix.ctlname, sizeof(mix.ctlname),
+ "%s.%s", mixername, AudioNtreble);
#endif
break;
case GRAPHIC_EQUALIZER_CONTROL:
@@ -1027,10 +1377,9 @@ uaudio_add_feature(struct uaudio_softc *sc, usb_descriptor_t *v,
#if defined(__FreeBSD__)
mix.ctl = SOUND_MIXER_NRDEVICES; /* XXXXX */
#else
- sprintf(mix.ctlname, "fea%d-%s-%s", unit,
- uaudio_id_name(sc, dps, srcId),
- AudioNagc);
mix.ctlunit = "";
+ snprintf(mix.ctlname, sizeof(mix.ctlname), "%s.%s",
+ mixername, AudioNagc);
#endif
break;
case DELAY_CONTROL:
@@ -1038,10 +1387,9 @@ uaudio_add_feature(struct uaudio_softc *sc, usb_descriptor_t *v,
#if defined(__FreeBSD__)
mix.ctl = SOUND_MIXER_NRDEVICES; /* XXXXX */
#else
- sprintf(mix.ctlname, "fea%d-%s-%s", unit,
- uaudio_id_name(sc, dps, srcId),
- AudioNdelay);
mix.ctlunit = "4 ms";
+ snprintf(mix.ctlname, sizeof(mix.ctlname),
+ "%s.%s", mixername, AudioNdelay);
#endif
break;
case BASS_BOOST_CONTROL:
@@ -1049,10 +1397,9 @@ uaudio_add_feature(struct uaudio_softc *sc, usb_descriptor_t *v,
#if defined(__FreeBSD__)
mix.ctl = SOUND_MIXER_NRDEVICES; /* XXXXX */
#else
- sprintf(mix.ctlname, "fea%d-%s-%s", unit,
- uaudio_id_name(sc, dps, srcId),
- AudioNbassboost);
mix.ctlunit = "";
+ snprintf(mix.ctlname, sizeof(mix.ctlname),
+ "%s.%s", mixername, AudioNbassboost);
#endif
break;
case LOUDNESS_CONTROL:
@@ -1060,10 +1407,9 @@ uaudio_add_feature(struct uaudio_softc *sc, usb_descriptor_t *v,
#if defined(__FreeBSD__)
mix.ctl = SOUND_MIXER_LOUD; /* Is this correct ? */
#else
- sprintf(mix.ctlname, "fea%d-%s-%s", unit,
- uaudio_id_name(sc, dps, srcId),
- AudioNloudness);
mix.ctlunit = "";
+ snprintf(mix.ctlname, sizeof(mix.ctlname),
+ "%s.%s", mixername, AudioNloudness);
#endif
break;
}
@@ -1071,16 +1417,15 @@ uaudio_add_feature(struct uaudio_softc *sc, usb_descriptor_t *v,
}
}
-void
-uaudio_add_processing_updown(struct uaudio_softc *sc, usb_descriptor_t *v,
- usb_descriptor_t **dps)
-{
- struct usb_audio_processing_unit *d =
- (struct usb_audio_processing_unit *)v;
- struct usb_audio_processing_unit_1 *d1 =
- (struct usb_audio_processing_unit_1 *)&d->baSourceId[d->bNrInPins];
- struct usb_audio_processing_unit_updown *ud =
- (struct usb_audio_processing_unit_updown *)
+Static void
+uaudio_add_processing_updown(struct uaudio_softc *sc,
+ const struct io_terminal *iot, int id)
+{
+ const struct usb_audio_processing_unit *d = iot[id].d.pu;
+ const struct usb_audio_processing_unit_1 *d1 =
+ (const struct usb_audio_processing_unit_1 *)&d->baSourceId[d->bNrInPins];
+ const struct usb_audio_processing_unit_updown *ud =
+ (const struct usb_audio_processing_unit_updown *)
&d1->bmControls[d1->bControlSize];
struct mixerctl mix;
int i;
@@ -1097,12 +1442,12 @@ uaudio_add_processing_updown(struct uaudio_softc *sc, usb_descriptor_t *v,
mix.nchan = 1;
mix.wValue[0] = MAKE(UD_MODE_SELECT_CONTROL, 0);
#if !defined(__FreeBSD__)
- mix.class = -1;
+ uaudio_determine_class(&iot[id], &mix);
#endif
mix.type = MIX_ON_OFF; /* XXX */
#if !defined(__FreeBSD__)
mix.ctlunit = "";
- sprintf(mix.ctlname, "pro%d-mode", d->bUnitId);
+ snprintf(mix.ctlname, sizeof(mix.ctlname), "pro%d-mode", d->bUnitId);
#endif
for (i = 0; i < ud->bNrModes; i++) {
@@ -1113,14 +1458,12 @@ uaudio_add_processing_updown(struct uaudio_softc *sc, usb_descriptor_t *v,
uaudio_mixer_add_ctl(sc, &mix);
}
-void
-uaudio_add_processing(struct uaudio_softc *sc, usb_descriptor_t *v,
- usb_descriptor_t **dps)
+Static void
+uaudio_add_processing(struct uaudio_softc *sc, const struct io_terminal *iot, int id)
{
- struct usb_audio_processing_unit *d =
- (struct usb_audio_processing_unit *)v;
- struct usb_audio_processing_unit_1 *d1 =
- (struct usb_audio_processing_unit_1 *)&d->baSourceId[d->bNrInPins];
+ const struct usb_audio_processing_unit *d = iot[id].d.pu;
+ const struct usb_audio_processing_unit_1 *d1 =
+ (const struct usb_audio_processing_unit_1 *)&d->baSourceId[d->bNrInPins];
int ptype = UGETW(d->wProcessType);
struct mixerctl mix;
@@ -1132,19 +1475,20 @@ uaudio_add_processing(struct uaudio_softc *sc, usb_descriptor_t *v,
mix.nchan = 1;
mix.wValue[0] = MAKE(XX_ENABLE_CONTROL, 0);
#if !defined(__FreeBSD__)
- mix.class = -1;
+ uaudio_determine_class(&iot[id], &mix);
#endif
mix.type = MIX_ON_OFF;
#if !defined(__FreeBSD__)
mix.ctlunit = "";
- sprintf(mix.ctlname, "pro%d.%d-enable", d->bUnitId, ptype);
+ snprintf(mix.ctlname, sizeof(mix.ctlname), "pro%d.%d-enable",
+ d->bUnitId, ptype);
#endif
uaudio_mixer_add_ctl(sc, &mix);
}
switch(ptype) {
case UPDOWNMIX_PROCESS:
- uaudio_add_processing_updown(sc, v, dps);
+ uaudio_add_processing_updown(sc, iot, id);
break;
case DOLBY_PROLOGIC_PROCESS:
case P3D_STEREO_EXTENDER_PROCESS:
@@ -1160,14 +1504,12 @@ uaudio_add_processing(struct uaudio_softc *sc, usb_descriptor_t *v,
}
}
-void
-uaudio_add_extension(struct uaudio_softc *sc, usb_descriptor_t *v,
- usb_descriptor_t **dps)
+Static void
+uaudio_add_extension(struct uaudio_softc *sc, const struct io_terminal *iot, int id)
{
- struct usb_audio_extension_unit *d =
- (struct usb_audio_extension_unit *)v;
- struct usb_audio_extension_unit_1 *d1 =
- (struct usb_audio_extension_unit_1 *)&d->baSourceId[d->bNrInPins];
+ const struct usb_audio_extension_unit *d = iot[id].d.eu;
+ const struct usb_audio_extension_unit_1 *d1 =
+ (const struct usb_audio_extension_unit_1 *)&d->baSourceId[d->bNrInPins];
struct mixerctl mix;
DPRINTFN(2,("uaudio_add_extension: bUnitId=%d bNrInPins=%d\n",
@@ -1181,19 +1523,206 @@ uaudio_add_extension(struct uaudio_softc *sc, usb_descriptor_t *v,
mix.nchan = 1;
mix.wValue[0] = MAKE(UA_EXT_ENABLE, 0);
#if !defined(__FreeBSD__)
- mix.class = -1;
+ uaudio_determine_class(&iot[id], &mix);
#endif
mix.type = MIX_ON_OFF;
#if !defined(__FreeBSD__)
mix.ctlunit = "";
- sprintf(mix.ctlname, "ext%d-enable", d->bUnitId);
+ snprintf(mix.ctlname, sizeof(mix.ctlname), "ext%d-enable",
+ d->bUnitId);
#endif
uaudio_mixer_add_ctl(sc, &mix);
}
}
-usbd_status
-uaudio_identify(struct uaudio_softc *sc, usb_config_descriptor_t *cdesc)
+Static struct terminal_list*
+uaudio_merge_terminal_list(const struct io_terminal *iot)
+{
+ struct terminal_list *tml;
+ uint16_t *ptm;
+ int i, len;
+
+ len = 0;
+ if (iot->inputs == NULL)
+ return NULL;
+ for (i = 0; i < iot->inputs_size; i++) {
+ if (iot->inputs[i] != NULL)
+ len += iot->inputs[i]->size;
+ }
+ tml = malloc(TERMINAL_LIST_SIZE(len), M_TEMP, M_NOWAIT);
+ if (tml == NULL) {
+ printf("uaudio_merge_terminal_list: no memory\n");
+ return NULL;
+ }
+ tml->size = 0;
+ ptm = tml->terminals;
+ for (i = 0; i < iot->inputs_size; i++) {
+ if (iot->inputs[i] == NULL)
+ continue;
+ if (iot->inputs[i]->size > len)
+ break;
+ memcpy(ptm, iot->inputs[i]->terminals,
+ iot->inputs[i]->size * sizeof(uint16_t));
+ tml->size += iot->inputs[i]->size;
+ ptm += iot->inputs[i]->size;
+ len -= iot->inputs[i]->size;
+ }
+ return tml;
+}
+
+Static struct terminal_list *
+uaudio_io_terminaltype(int outtype, struct io_terminal *iot, int id)
+{
+ struct terminal_list *tml;
+ struct io_terminal *it;
+ int src_id, i;
+
+ it = &iot[id];
+ if (it->output != NULL) {
+ /* already has outtype? */
+ for (i = 0; i < it->output->size; i++)
+ if (it->output->terminals[i] == outtype)
+ return uaudio_merge_terminal_list(it);
+ tml = malloc(TERMINAL_LIST_SIZE(it->output->size + 1),
+ M_TEMP, M_NOWAIT);
+ if (tml == NULL) {
+ printf("uaudio_io_terminaltype: no memory\n");
+ return uaudio_merge_terminal_list(it);
+ }
+ memcpy(tml, it->output, TERMINAL_LIST_SIZE(it->output->size));
+ tml->terminals[it->output->size] = outtype;
+ tml->size++;
+ free(it->output, M_TEMP);
+ it->output = tml;
+ if (it->inputs != NULL) {
+ for (i = 0; i < it->inputs_size; i++)
+ if (it->inputs[i] != NULL)
+ free(it->inputs[i], M_TEMP);
+ free(it->inputs, M_TEMP);
+ }
+ it->inputs_size = 0;
+ it->inputs = NULL;
+ } else { /* end `iot[id] != NULL' */
+ it->inputs_size = 0;
+ it->inputs = NULL;
+ it->output = malloc(TERMINAL_LIST_SIZE(1), M_TEMP, M_NOWAIT);
+ if (it->output == NULL) {
+ printf("uaudio_io_terminaltype: no memory\n");
+ return NULL;
+ }
+ it->output->terminals[0] = outtype;
+ it->output->size = 1;
+ it->direct = FALSE;
+ }
+
+ switch (it->d.desc->bDescriptorSubtype) {
+ case UDESCSUB_AC_INPUT:
+ it->inputs = malloc(sizeof(struct terminal_list *), M_TEMP, M_NOWAIT);
+ if (it->inputs == NULL) {
+ printf("uaudio_io_terminaltype: no memory\n");
+ return NULL;
+ }
+ tml = malloc(TERMINAL_LIST_SIZE(1), M_TEMP, M_NOWAIT);
+ if (tml == NULL) {
+ printf("uaudio_io_terminaltype: no memory\n");
+ free(it->inputs, M_TEMP);
+ it->inputs = NULL;
+ return NULL;
+ }
+ it->inputs[0] = tml;
+ tml->terminals[0] = UGETW(it->d.it->wTerminalType);
+ tml->size = 1;
+ it->inputs_size = 1;
+ return uaudio_merge_terminal_list(it);
+ case UDESCSUB_AC_FEATURE:
+ src_id = it->d.fu->bSourceId;
+ it->inputs = malloc(sizeof(struct terminal_list *), M_TEMP, M_NOWAIT);
+ if (it->inputs == NULL) {
+ printf("uaudio_io_terminaltype: no memory\n");
+ return uaudio_io_terminaltype(outtype, iot, src_id);
+ }
+ it->inputs[0] = uaudio_io_terminaltype(outtype, iot, src_id);
+ it->inputs_size = 1;
+ return uaudio_merge_terminal_list(it);
+ case UDESCSUB_AC_OUTPUT:
+ it->inputs = malloc(sizeof(struct terminal_list *), M_TEMP, M_NOWAIT);
+ if (it->inputs == NULL) {
+ printf("uaudio_io_terminaltype: no memory\n");
+ return NULL;
+ }
+ src_id = it->d.ot->bSourceId;
+ it->inputs[0] = uaudio_io_terminaltype(outtype, iot, src_id);
+ it->inputs_size = 1;
+ iot[src_id].direct = TRUE;
+ return NULL;
+ case UDESCSUB_AC_MIXER:
+ it->inputs_size = 0;
+ it->inputs = malloc(sizeof(struct terminal_list *)
+ * it->d.mu->bNrInPins, M_TEMP, M_NOWAIT);
+ if (it->inputs == NULL) {
+ printf("uaudio_io_terminaltype: no memory\n");
+ return NULL;
+ }
+ for (i = 0; i < it->d.mu->bNrInPins; i++) {
+ src_id = it->d.mu->baSourceId[i];
+ it->inputs[i] = uaudio_io_terminaltype(outtype, iot,
+ src_id);
+ it->inputs_size++;
+ }
+ return uaudio_merge_terminal_list(it);
+ case UDESCSUB_AC_SELECTOR:
+ it->inputs_size = 0;
+ it->inputs = malloc(sizeof(struct terminal_list *)
+ * it->d.su->bNrInPins, M_TEMP, M_NOWAIT);
+ if (it->inputs == NULL) {
+ printf("uaudio_io_terminaltype: no memory\n");
+ return NULL;
+ }
+ for (i = 0; i < it->d.su->bNrInPins; i++) {
+ src_id = it->d.su->baSourceId[i];
+ it->inputs[i] = uaudio_io_terminaltype(outtype, iot,
+ src_id);
+ it->inputs_size++;
+ }
+ return uaudio_merge_terminal_list(it);
+ case UDESCSUB_AC_PROCESSING:
+ it->inputs_size = 0;
+ it->inputs = malloc(sizeof(struct terminal_list *)
+ * it->d.pu->bNrInPins, M_TEMP, M_NOWAIT);
+ if (it->inputs == NULL) {
+ printf("uaudio_io_terminaltype: no memory\n");
+ return NULL;
+ }
+ for (i = 0; i < it->d.pu->bNrInPins; i++) {
+ src_id = it->d.pu->baSourceId[i];
+ it->inputs[i] = uaudio_io_terminaltype(outtype, iot,
+ src_id);
+ it->inputs_size++;
+ }
+ return uaudio_merge_terminal_list(it);
+ case UDESCSUB_AC_EXTENSION:
+ it->inputs_size = 0;
+ it->inputs = malloc(sizeof(struct terminal_list *)
+ * it->d.eu->bNrInPins, M_TEMP, M_NOWAIT);
+ if (it->inputs == NULL) {
+ printf("uaudio_io_terminaltype: no memory\n");
+ return NULL;
+ }
+ for (i = 0; i < it->d.eu->bNrInPins; i++) {
+ src_id = it->d.eu->baSourceId[i];
+ it->inputs[i] = uaudio_io_terminaltype(outtype, iot,
+ src_id);
+ it->inputs_size++;
+ }
+ return uaudio_merge_terminal_list(it);
+ case UDESCSUB_AC_HEADER:
+ default:
+ return NULL;
+ }
+}
+
+Static usbd_status
+uaudio_identify(struct uaudio_softc *sc, const usb_config_descriptor_t *cdesc)
{
usbd_status err;
@@ -1203,46 +1732,55 @@ uaudio_identify(struct uaudio_softc *sc, usb_config_descriptor_t *cdesc)
return (uaudio_identify_as(sc, cdesc));
}
-void
-uaudio_add_alt(struct uaudio_softc *sc, struct as_info *ai)
+Static void
+uaudio_add_alt(struct uaudio_softc *sc, const struct as_info *ai)
{
- size_t len = sizeof(*ai) * (sc->sc_nalts + 1);
- struct as_info *nai = sc->sc_nalts == 0 ?
- malloc(len, M_USBDEV, M_NOWAIT) :
- realloc(sc->sc_alts, len, M_USBDEV, M_NOWAIT);
+ size_t len;
+ struct as_info *nai;
+ len = sizeof(*ai) * (sc->sc_nalts + 1);
+ nai = malloc(len, M_USBDEV, M_NOWAIT);
if (nai == NULL) {
printf("uaudio_add_alt: no memory\n");
return;
}
-
+ /* Copy old data, if there was any */
+ if (sc->sc_nalts != 0) {
+ memcpy(nai, sc->sc_alts, sizeof(*ai) * (sc->sc_nalts));
+ free(sc->sc_alts, M_USBDEV);
+ }
sc->sc_alts = nai;
DPRINTFN(2,("uaudio_add_alt: adding alt=%d, enc=%d\n",
ai->alt, ai->encoding));
sc->sc_alts[sc->sc_nalts++] = *ai;
}
-usbd_status
-uaudio_process_as(struct uaudio_softc *sc, char *buf, int *offsp,
- int size, usb_interface_descriptor_t *id)
+Static usbd_status
+uaudio_process_as(struct uaudio_softc *sc, const char *buf, int *offsp,
+ int size, const usb_interface_descriptor_t *id)
#define offs (*offsp)
{
- struct usb_audio_streaming_interface_descriptor *asid;
- struct usb_audio_streaming_type1_descriptor *asf1d;
- usb_endpoint_descriptor_audio_t *ed;
- struct usb_audio_streaming_endpoint_descriptor *sed;
+ const struct usb_audio_streaming_interface_descriptor *asid;
+ const struct usb_audio_streaming_type1_descriptor *asf1d;
+ const usb_endpoint_descriptor_audio_t *ed;
+ const usb_endpoint_descriptor_audio_t *epdesc1;
+ const struct usb_audio_streaming_endpoint_descriptor *sed;
int format, chan, prec, enc;
- int dir, type;
+ int dir, type, sync;
struct as_info ai;
+ const char *format_str;
- asid = (void *)(buf + offs);
+ asid = (const void *)(buf + offs);
if (asid->bDescriptorType != UDESC_CS_INTERFACE ||
asid->bDescriptorSubtype != AS_GENERAL)
return (USBD_INVAL);
+ DPRINTF(("uaudio_process_as: asid: bTerminakLink=%d wFormatTag=%d\n",
+ asid->bTerminalLink, UGETW(asid->wFormatTag)));
offs += asid->bLength;
if (offs > size)
return (USBD_INVAL);
- asf1d = (void *)(buf + offs);
+
+ asf1d = (const void *)(buf + offs);
if (asf1d->bDescriptorType != UDESC_CS_INTERFACE ||
asf1d->bDescriptorSubtype != FORMAT_TYPE)
return (USBD_INVAL);
@@ -1256,10 +1794,10 @@ uaudio_process_as(struct uaudio_softc *sc, char *buf, int *offsp,
return (USBD_NORMAL_COMPLETION);
}
- ed = (void *)(buf + offs);
+ ed = (const void *)(buf + offs);
if (ed->bDescriptorType != UDESC_ENDPOINT)
return (USBD_INVAL);
- DPRINTF(("uaudio_process_as: endpoint bLength=%d bDescriptorType=%d "
+ DPRINTF(("uaudio_process_as: endpoint[0] bLength=%d bDescriptorType=%d "
"bEndpointAddress=%d bmAttributes=0x%x wMaxPacketSize=%d "
"bInterval=%d bRefresh=%d bSynchAddress=%d\n",
ed->bLength, ed->bDescriptorType, ed->bEndpointAddress,
@@ -1278,78 +1816,166 @@ uaudio_process_as(struct uaudio_softc *sc, char *buf, int *offsp,
type = UE_ISO_ASYNC;
/* We can't handle endpoints that need a sync pipe yet. */
- if (dir == UE_DIR_IN ? type == UE_ISO_ADAPT : type == UE_ISO_ASYNC) {
- printf("%s: ignored %sput endpoint of type %s\n",
- USBDEVNAME(sc->sc_dev),
- dir == UE_DIR_IN ? "in" : "out",
- dir == UE_DIR_IN ? "adaptive" : "async");
+ sync = FALSE;
+ if (dir == UE_DIR_IN && type == UE_ISO_ADAPT) {
+ sync = TRUE;
+#ifndef UAUDIO_MULTIPLE_ENDPOINTS
+ printf("%s: ignored input endpoint of type adaptive\n",
+ USBDEVNAME(sc->sc_dev));
return (USBD_NORMAL_COMPLETION);
+#endif
}
-
- sed = (void *)(buf + offs);
+ if (dir != UE_DIR_IN && type == UE_ISO_ASYNC) {
+ sync = TRUE;
+#ifndef UAUDIO_MULTIPLE_ENDPOINTS
+ printf("%s: ignored output endpoint of type async\n",
+ USBDEVNAME(sc->sc_dev));
+ return (USBD_NORMAL_COMPLETION);
+#endif
+ }
+
+ sed = (const void *)(buf + offs);
if (sed->bDescriptorType != UDESC_CS_ENDPOINT ||
sed->bDescriptorSubtype != AS_GENERAL)
return (USBD_INVAL);
+ DPRINTF((" streadming_endpoint: offset=%d bLength=%d\n", offs, sed->bLength));
offs += sed->bLength;
if (offs > size)
return (USBD_INVAL);
-
+
+ if (sync && id->bNumEndpoints <= 1) {
+ printf("%s: a sync-pipe endpoint but no other endpoint\n",
+ USBDEVNAME(sc->sc_dev));
+ return USBD_INVAL;
+ }
+ if (!sync && id->bNumEndpoints > 1) {
+ printf("%s: non sync-pipe endpoint but multiple endpoints\n",
+ USBDEVNAME(sc->sc_dev));
+ return USBD_INVAL;
+ }
+ epdesc1 = NULL;
+ if (id->bNumEndpoints > 1) {
+ epdesc1 = (const void*)(buf + offs);
+ if (epdesc1->bDescriptorType != UDESC_ENDPOINT)
+ return USBD_INVAL;
+ DPRINTF(("uaudio_process_as: endpoint[1] bLength=%d "
+ "bDescriptorType=%d bEndpointAddress=%d "
+ "bmAttributes=0x%x wMaxPacketSize=%d bInterval=%d "
+ "bRefresh=%d bSynchAddress=%d\n",
+ epdesc1->bLength, epdesc1->bDescriptorType,
+ epdesc1->bEndpointAddress, epdesc1->bmAttributes,
+ UGETW(epdesc1->wMaxPacketSize), epdesc1->bInterval,
+ epdesc1->bRefresh, epdesc1->bSynchAddress));
+ offs += epdesc1->bLength;
+ if (offs > size)
+ return USBD_INVAL;
+ if (epdesc1->bSynchAddress != 0) {
+ printf("%s: invalid endpoint: bSynchAddress=0\n",
+ USBDEVNAME(sc->sc_dev));
+ return USBD_INVAL;
+ }
+ if (UE_GET_XFERTYPE(epdesc1->bmAttributes) != UE_ISOCHRONOUS) {
+ printf("%s: invalid endpoint: bmAttributes=0x%x\n",
+ USBDEVNAME(sc->sc_dev), epdesc1->bmAttributes);
+ return USBD_INVAL;
+ }
+ if (epdesc1->bEndpointAddress != ed->bSynchAddress) {
+ printf("%s: invalid endpoint addresses: "
+ "ep[0]->bSynchAddress=0x%x "
+ "ep[1]->bEndpointAddress=0x%x\n",
+ USBDEVNAME(sc->sc_dev), ed->bSynchAddress,
+ epdesc1->bEndpointAddress);
+ return USBD_INVAL;
+ }
+ /* UE_GET_ADDR(epdesc1->bEndpointAddress), and epdesc1->bRefresh */
+ }
+
format = UGETW(asid->wFormatTag);
chan = asf1d->bNrChannels;
prec = asf1d->bBitResolution;
- if (prec != 8 && prec != 16) {
-#ifdef USB_DEBUG
+ if (prec != 8 && prec != 16 && prec != 24) {
printf("%s: ignored setting with precision %d\n",
USBDEVNAME(sc->sc_dev), prec);
-#endif
return (USBD_NORMAL_COMPLETION);
}
switch (format) {
case UA_FMT_PCM:
- sc->sc_altflags |= prec == 8 ? HAS_8 : HAS_16;
+ if (prec == 8) {
+ sc->sc_altflags |= HAS_8;
+ } else if (prec == 16) {
+ sc->sc_altflags |= HAS_16;
+ } else if (prec == 24) {
+ sc->sc_altflags |= HAS_24;
+ }
enc = AUDIO_ENCODING_SLINEAR_LE;
+ format_str = "pcm";
break;
case UA_FMT_PCM8:
enc = AUDIO_ENCODING_ULINEAR_LE;
sc->sc_altflags |= HAS_8U;
+ format_str = "pcm8";
break;
case UA_FMT_ALAW:
enc = AUDIO_ENCODING_ALAW;
sc->sc_altflags |= HAS_ALAW;
+ format_str = "alaw";
break;
case UA_FMT_MULAW:
enc = AUDIO_ENCODING_ULAW;
sc->sc_altflags |= HAS_MULAW;
+ format_str = "mulaw";
break;
+ case UA_FMT_IEEE_FLOAT:
default:
printf("%s: ignored setting with format %d\n",
USBDEVNAME(sc->sc_dev), format);
return (USBD_NORMAL_COMPLETION);
}
- DPRINTFN(1,("uaudio_identify: alt=%d enc=%d chan=%d prec=%d\n",
- id->bAlternateSetting, enc, chan, prec));
+#ifdef USB_DEBUG
+ printf("%s: %s: %dch, %d/%dbit, %s,", USBDEVNAME(sc->sc_dev),
+ dir == UE_DIR_IN ? "recording" : "playback",
+ chan, prec, asf1d->bSubFrameSize * 8, format_str);
+ if (asf1d->bSamFreqType == UA_SAMP_CONTNUOUS) {
+ printf(" %d-%dHz\n", UA_SAMP_LO(asf1d), UA_SAMP_HI(asf1d));
+ } else {
+ int r;
+ printf(" %d", UA_GETSAMP(asf1d, 0));
+ for (r = 1; r < asf1d->bSamFreqType; r++)
+ printf(",%d", UA_GETSAMP(asf1d, r));
+ printf("Hz\n");
+ }
+#endif
ai.alt = id->bAlternateSetting;
ai.encoding = enc;
+ ai.attributes = sed->bmAttributes;
ai.idesc = id;
ai.edesc = ed;
+ ai.edesc1 = epdesc1;
ai.asf1desc = asf1d;
+ ai.sc_busy = 0;
uaudio_add_alt(sc, &ai);
- sc->sc_chan.terminal = asid->bTerminalLink; /* XXX */
- sc->sc_chan.dir |= dir == UE_DIR_OUT ? AUMODE_PLAY : AUMODE_RECORD;
+#ifdef USB_DEBUG
+ if (ai.attributes & UA_SED_FREQ_CONTROL)
+ DPRINTFN(1, ("uaudio_process_as: FREQ_CONTROL\n"));
+ if (ai.attributes & UA_SED_PITCH_CONTROL)
+ DPRINTFN(1, ("uaudio_process_as: PITCH_CONTROL\n"));
+#endif
+ sc->sc_mode |= (dir == UE_DIR_OUT) ? AUMODE_PLAY : AUMODE_RECORD;
+
return (USBD_NORMAL_COMPLETION);
}
#undef offs
-
-usbd_status
-uaudio_identify_as(struct uaudio_softc *sc, usb_config_descriptor_t *cdesc)
+
+Static usbd_status
+uaudio_identify_as(struct uaudio_softc *sc,
+ const usb_config_descriptor_t *cdesc)
{
- usb_interface_descriptor_t *id;
- usbd_status err;
- char *buf;
+ const usb_interface_descriptor_t *id;
+ const char *buf;
int size, offs;
size = UGETW(cdesc->wTotalLength);
- buf = (char *)cdesc;
+ buf = (const char *)cdesc;
/* Locate the AudioStreaming interface descriptor. */
offs = 0;
@@ -1357,13 +1983,10 @@ uaudio_identify_as(struct uaudio_softc *sc, usb_config_descriptor_t *cdesc)
if (id == NULL)
return (USBD_INVAL);
- sc->sc_chan.terminal = -1;
- sc->sc_chan.dir = 0;
-
/* Loop through all the alternate settings. */
while (offs <= size) {
- DPRINTFN(2, ("uaudio_identify: interface %d\n",
- id->bInterfaceNumber));
+ DPRINTFN(2, ("uaudio_identify: interface=%d offset=%d\n",
+ id->bInterfaceNumber, offs));
switch (id->bNumEndpoints) {
case 0:
DPRINTFN(2, ("uaudio_identify: AS null alt=%d\n",
@@ -1371,14 +1994,15 @@ uaudio_identify_as(struct uaudio_softc *sc, usb_config_descriptor_t *cdesc)
sc->sc_nullalt = id->bAlternateSetting;
break;
case 1:
- err = uaudio_process_as(sc, buf, &offs, size, id);
+#ifdef UAUDIO_MULTIPLE_ENDPOINTS
+ case 2:
+#endif
+ uaudio_process_as(sc, buf, &offs, size, id);
break;
default:
-#ifdef USB_DEBUG
printf("%s: ignored audio interface with %d "
"endpoints\n",
USBDEVNAME(sc->sc_dev), id->bNumEndpoints);
-#endif
break;
}
id = uaudio_find_iface(buf, size, &offs,UISUBCLASS_AUDIOSTREAM);
@@ -1388,30 +2012,30 @@ uaudio_identify_as(struct uaudio_softc *sc, usb_config_descriptor_t *cdesc)
if (offs > size)
return (USBD_INVAL);
DPRINTF(("uaudio_identify_as: %d alts available\n", sc->sc_nalts));
- if (sc->sc_chan.terminal < 0) {
- printf("%s: no useable endpoint found\n",
+
+ if (sc->sc_mode == 0) {
+ printf("%s: no usable endpoint found\n",
USBDEVNAME(sc->sc_dev));
return (USBD_INVAL);
}
-#ifndef NO_RECORDING
- if (sc->sc_chan.dir == (AUMODE_PLAY | AUMODE_RECORD))
- sc->sc_props |= AUDIO_PROP_FULLDUPLEX;
-#endif
return (USBD_NORMAL_COMPLETION);
}
-usbd_status
-uaudio_identify_ac(struct uaudio_softc *sc, usb_config_descriptor_t *cdesc)
+Static usbd_status
+uaudio_identify_ac(struct uaudio_softc *sc, const usb_config_descriptor_t *cdesc)
{
- usb_interface_descriptor_t *id;
- struct usb_audio_control_descriptor *acdp;
- usb_descriptor_t *dp, *dps[256];
- char *buf, *ibuf, *ibufend;
- int size, offs, aclen, ndps, i;
+ struct io_terminal* iot;
+ const usb_interface_descriptor_t *id;
+ const struct usb_audio_control_descriptor *acdp;
+ const usb_descriptor_t *dp;
+ const struct usb_audio_output_terminal *pot;
+ struct terminal_list *tml;
+ const char *buf, *ibuf, *ibufend;
+ int size, offs, aclen, ndps, i, j;
size = UGETW(cdesc->wTotalLength);
- buf = (char *)cdesc;
+ buf = (const char *)cdesc;
/* Locate the AudioControl interface descriptor. */
offs = 0;
@@ -1421,11 +2045,11 @@ uaudio_identify_ac(struct uaudio_softc *sc, usb_config_descriptor_t *cdesc)
if (offs + sizeof *acdp > size)
return (USBD_INVAL);
sc->sc_ac_iface = id->bInterfaceNumber;
- DPRINTFN(2,("uaudio_identify: AC interface is %d\n", sc->sc_ac_iface));
+ DPRINTFN(2,("uaudio_identify_ac: AC interface is %d\n", sc->sc_ac_iface));
/* A class-specific AC interface header should follow. */
ibuf = buf + offs;
- acdp = (struct usb_audio_control_descriptor *)ibuf;
+ acdp = (const struct usb_audio_control_descriptor *)ibuf;
if (acdp->bDescriptorType != UDESC_CS_INTERFACE ||
acdp->bDescriptorSubtype != UDESCSUB_AC_HEADER)
return (USBD_INVAL);
@@ -1438,127 +2062,266 @@ uaudio_identify_ac(struct uaudio_softc *sc, usb_config_descriptor_t *cdesc)
return (USBD_INVAL);
sc->sc_audio_rev = UGETW(acdp->bcdADC);
- DPRINTFN(2,("uaudio_identify: found AC header, vers=%03x, len=%d\n",
+ DPRINTFN(2,("uaudio_identify_ac: found AC header, vers=%03x, len=%d\n",
sc->sc_audio_rev, aclen));
sc->sc_nullalt = -1;
/* Scan through all the AC specific descriptors */
ibufend = ibuf + aclen;
- dp = (usb_descriptor_t *)ibuf;
+ dp = (const usb_descriptor_t *)ibuf;
ndps = 0;
- memset(dps, 0, sizeof dps);
+ iot = malloc(sizeof(struct io_terminal) * 256, M_TEMP, M_NOWAIT | M_ZERO);
+ if (iot == NULL) {
+ printf("%s: no memory\n", __func__);
+ return USBD_NOMEM;
+ }
for (;;) {
ibuf += dp->bLength;
if (ibuf >= ibufend)
break;
- dp = (usb_descriptor_t *)ibuf;
+ dp = (const usb_descriptor_t *)ibuf;
if (ibuf + dp->bLength > ibufend)
return (USBD_INVAL);
if (dp->bDescriptorType != UDESC_CS_INTERFACE) {
- printf("uaudio_identify: skip desc type=0x%02x\n",
+ printf("uaudio_identify_ac: skip desc type=0x%02x\n",
dp->bDescriptorType);
continue;
}
- i = ((struct usb_audio_input_terminal *)dp)->bTerminalId;
- dps[i] = dp;
+ i = ((const struct usb_audio_input_terminal *)dp)->bTerminalId;
+ iot[i].d.desc = dp;
if (i > ndps)
ndps = i;
}
ndps++;
+ /* construct io_terminal */
+ for (i = 0; i < ndps; i++) {
+ dp = iot[i].d.desc;
+ if (dp == NULL)
+ continue;
+ if (dp->bDescriptorSubtype != UDESCSUB_AC_OUTPUT)
+ continue;
+ pot = iot[i].d.ot;
+ tml = uaudio_io_terminaltype(UGETW(pot->wTerminalType), iot, i);
+ if (tml != NULL)
+ free(tml, M_TEMP);
+ }
+
+#ifdef USB_DEBUG
+ for (i = 0; i < 256; i++) {
+ struct usb_audio_cluster cluster;
+
+ if (iot[i].d.desc == NULL)
+ continue;
+ logprintf("id %d:\t", i);
+ switch (iot[i].d.desc->bDescriptorSubtype) {
+ case UDESCSUB_AC_INPUT:
+ logprintf("AC_INPUT type=%s\n", uaudio_get_terminal_name
+ (UGETW(iot[i].d.it->wTerminalType)));
+ logprintf("\t");
+ cluster = uaudio_get_cluster(i, iot);
+ uaudio_dump_cluster(&cluster);
+ logprintf("\n");
+ break;
+ case UDESCSUB_AC_OUTPUT:
+ logprintf("AC_OUTPUT type=%s ", uaudio_get_terminal_name
+ (UGETW(iot[i].d.ot->wTerminalType)));
+ logprintf("src=%d\n", iot[i].d.ot->bSourceId);
+ break;
+ case UDESCSUB_AC_MIXER:
+ logprintf("AC_MIXER src=");
+ for (j = 0; j < iot[i].d.mu->bNrInPins; j++)
+ logprintf("%d ", iot[i].d.mu->baSourceId[j]);
+ logprintf("\n\t");
+ cluster = uaudio_get_cluster(i, iot);
+ uaudio_dump_cluster(&cluster);
+ logprintf("\n");
+ break;
+ case UDESCSUB_AC_SELECTOR:
+ logprintf("AC_SELECTOR src=");
+ for (j = 0; j < iot[i].d.su->bNrInPins; j++)
+ logprintf("%d ", iot[i].d.su->baSourceId[j]);
+ logprintf("\n");
+ break;
+ case UDESCSUB_AC_FEATURE:
+ logprintf("AC_FEATURE src=%d\n", iot[i].d.fu->bSourceId);
+ break;
+ case UDESCSUB_AC_PROCESSING:
+ logprintf("AC_PROCESSING src=");
+ for (j = 0; j < iot[i].d.pu->bNrInPins; j++)
+ logprintf("%d ", iot[i].d.pu->baSourceId[j]);
+ logprintf("\n\t");
+ cluster = uaudio_get_cluster(i, iot);
+ uaudio_dump_cluster(&cluster);
+ logprintf("\n");
+ break;
+ case UDESCSUB_AC_EXTENSION:
+ logprintf("AC_EXTENSION src=");
+ for (j = 0; j < iot[i].d.eu->bNrInPins; j++)
+ logprintf("%d ", iot[i].d.eu->baSourceId[j]);
+ logprintf("\n\t");
+ cluster = uaudio_get_cluster(i, iot);
+ uaudio_dump_cluster(&cluster);
+ logprintf("\n");
+ break;
+ default:
+ logprintf("unknown audio control (subtype=%d)\n",
+ iot[i].d.desc->bDescriptorSubtype);
+ }
+ for (j = 0; j < iot[i].inputs_size; j++) {
+ int k;
+ logprintf("\tinput%d: ", j);
+ tml = iot[i].inputs[j];
+ if (tml == NULL) {
+ logprintf("NULL\n");
+ continue;
+ }
+ for (k = 0; k < tml->size; k++)
+ logprintf("%s ", uaudio_get_terminal_name
+ (tml->terminals[k]));
+ logprintf("\n");
+ }
+ logprintf("\toutput: ");
+ tml = iot[i].output;
+ for (j = 0; j < tml->size; j++)
+ logprintf("%s ", uaudio_get_terminal_name(tml->terminals[j]));
+ logprintf("\n");
+ }
+#endif
+
for (i = 0; i < ndps; i++) {
- dp = dps[i];
+ dp = iot[i].d.desc;
if (dp == NULL)
continue;
- DPRINTF(("uaudio_identify: subtype=%d\n",
- dp->bDescriptorSubtype));
+ DPRINTF(("uaudio_identify_ac: id=%d subtype=%d\n",
+ i, dp->bDescriptorSubtype));
switch (dp->bDescriptorSubtype) {
case UDESCSUB_AC_HEADER:
- printf("uaudio_identify: unexpected AC header\n");
+ printf("uaudio_identify_ac: unexpected AC header\n");
break;
case UDESCSUB_AC_INPUT:
- uaudio_add_input(sc, dp, dps);
+ uaudio_add_input(sc, iot, i);
break;
case UDESCSUB_AC_OUTPUT:
- uaudio_add_output(sc, dp, dps);
+ uaudio_add_output(sc, iot, i);
break;
case UDESCSUB_AC_MIXER:
- uaudio_add_mixer(sc, dp, dps);
+ uaudio_add_mixer(sc, iot, i);
break;
case UDESCSUB_AC_SELECTOR:
- uaudio_add_selector(sc, dp, dps);
+ uaudio_add_selector(sc, iot, i);
break;
case UDESCSUB_AC_FEATURE:
- uaudio_add_feature(sc, dp, dps);
+ uaudio_add_feature(sc, iot, i);
break;
case UDESCSUB_AC_PROCESSING:
- uaudio_add_processing(sc, dp, dps);
+ uaudio_add_processing(sc, iot, i);
break;
case UDESCSUB_AC_EXTENSION:
- uaudio_add_extension(sc, dp, dps);
+ uaudio_add_extension(sc, iot, i);
break;
default:
- printf("uaudio_identify: bad AC desc subtype=0x%02x\n",
+ printf("uaudio_identify_ac: bad AC desc subtype=0x%02x\n",
dp->bDescriptorSubtype);
break;
}
}
+
+ /* delete io_terminal */
+ for (i = 0; i < 256; i++) {
+ if (iot[i].d.desc == NULL)
+ continue;
+ if (iot[i].inputs != NULL) {
+ for (j = 0; j < iot[i].inputs_size; j++) {
+ if (iot[i].inputs[j] != NULL)
+ free(iot[i].inputs[j], M_TEMP);
+ }
+ free(iot[i].inputs, M_TEMP);
+ }
+ if (iot[i].output != NULL)
+ free(iot[i].output, M_TEMP);
+ iot[i].d.desc = NULL;
+ }
+ free(iot, M_TEMP);
+
return (USBD_NORMAL_COMPLETION);
}
#if defined(__NetBSD__) || defined(__OpenBSD__)
-int
+Static int
uaudio_query_devinfo(void *addr, mixer_devinfo_t *mi)
{
struct uaudio_softc *sc = addr;
struct mixerctl *mc;
- int n, nctls;
+ int n, nctls, i;
DPRINTFN(2,("uaudio_query_devinfo: index=%d\n", mi->index));
if (sc->sc_dying)
return (EIO);
-
+
n = mi->index;
nctls = sc->sc_nctls;
- if (n < 0 || n >= nctls) {
- switch (n - nctls) {
- case UAC_OUTPUT:
- mi->type = AUDIO_MIXER_CLASS;
- mi->mixer_class = nctls + UAC_OUTPUT;
- mi->next = mi->prev = AUDIO_MIXER_LAST;
- strcpy(mi->label.name, AudioCoutputs);
- return (0);
- case UAC_INPUT:
- mi->type = AUDIO_MIXER_CLASS;
- mi->mixer_class = nctls + UAC_INPUT;
- mi->next = mi->prev = AUDIO_MIXER_LAST;
- strcpy(mi->label.name, AudioCinputs);
- return (0);
- case UAC_EQUAL:
- mi->type = AUDIO_MIXER_CLASS;
- mi->mixer_class = nctls + UAC_EQUAL;
- mi->next = mi->prev = AUDIO_MIXER_LAST;
- strcpy(mi->label.name, AudioCequalization);
- return (0);
- default:
- return (ENXIO);
- }
+ switch (n) {
+ case UAC_OUTPUT:
+ mi->type = AUDIO_MIXER_CLASS;
+ mi->mixer_class = UAC_OUTPUT;
+ mi->next = mi->prev = AUDIO_MIXER_LAST;
+ strlcpy(mi->label.name, AudioCoutputs, sizeof(mi->label.name));
+ return (0);
+ case UAC_INPUT:
+ mi->type = AUDIO_MIXER_CLASS;
+ mi->mixer_class = UAC_INPUT;
+ mi->next = mi->prev = AUDIO_MIXER_LAST;
+ strlcpy(mi->label.name, AudioCinputs, sizeof(mi->label.name));
+ return (0);
+ case UAC_EQUAL:
+ mi->type = AUDIO_MIXER_CLASS;
+ mi->mixer_class = UAC_EQUAL;
+ mi->next = mi->prev = AUDIO_MIXER_LAST;
+ strlcpy(mi->label.name, AudioCequalization,
+ sizeof(mi->label.name));
+ return (0);
+ case UAC_RECORD:
+ mi->type = AUDIO_MIXER_CLASS;
+ mi->mixer_class = UAC_RECORD;
+ mi->next = mi->prev = AUDIO_MIXER_LAST;
+ strlcpy(mi->label.name, AudioCrecord, sizeof(mi->label.name));
+ return 0;
+ default:
+ break;
}
+
+ n -= UAC_NCLASSES;
+ if (n < 0 || n >= nctls)
+ return (ENXIO);
+
mc = &sc->sc_ctls[n];
- strncpy(mi->label.name, mc->ctlname, MAX_AUDIO_DEV_LEN);
+ strlcpy(mi->label.name, mc->ctlname, sizeof(mi->label.name));
mi->mixer_class = mc->class;
mi->next = mi->prev = AUDIO_MIXER_LAST; /* XXX */
switch (mc->type) {
case MIX_ON_OFF:
mi->type = AUDIO_MIXER_ENUM;
mi->un.e.num_mem = 2;
- strcpy(mi->un.e.member[0].label.name, AudioNoff);
+ strlcpy(mi->un.e.member[0].label.name, AudioNoff,
+ sizeof(mi->un.e.member[0].label.name));
mi->un.e.member[0].ord = 0;
- strcpy(mi->un.e.member[1].label.name, AudioNon);
+ strlcpy(mi->un.e.member[1].label.name, AudioNon,
+ sizeof(mi->un.e.member[1].label.name));
mi->un.e.member[1].ord = 1;
break;
+ case MIX_SELECTOR:
+ mi->type = AUDIO_MIXER_ENUM;
+ mi->un.e.num_mem = mc->maxval - mc->minval + 1;
+ for (i = 0; i <= mc->maxval - mc->minval; i++) {
+ snprintf(mi->un.e.member[i].label.name,
+ sizeof(mi->un.e.member[i].label.name),
+ "%d", i + mc->minval);
+ mi->un.e.member[i].ord = i + mc->minval;
+ }
+ break;
default:
mi->type = AUDIO_MIXER_VALUE;
strncpy(mi->un.v.units.name, mc->ctlunit, MAX_AUDIO_DEV_LEN);
@@ -1569,60 +2332,42 @@ uaudio_query_devinfo(void *addr, mixer_devinfo_t *mi)
return (0);
}
-int
+Static int
uaudio_open(void *addr, int flags)
{
struct uaudio_softc *sc = addr;
- DPRINTF(("uaudio_open: sc=%p\n", sc));
+ DPRINTF(("uaudio_open: sc=%p\n", sc));
if (sc->sc_dying)
return (EIO);
- if (sc->sc_chan.terminal < 0)
- return (ENXIO);
-
- if ((flags & FREAD) && !(sc->sc_chan.dir & AUMODE_RECORD))
+ if ((flags & FWRITE) && !(sc->sc_mode & AUMODE_PLAY))
return (EACCES);
- if ((flags & FWRITE) && !(sc->sc_chan.dir & AUMODE_PLAY))
+ if ((flags & FREAD) && !(sc->sc_mode & AUMODE_RECORD))
return (EACCES);
- sc->sc_chan.intr = 0;
-
- return (0);
+ return (0);
}
/*
* Close function is called at splaudio().
*/
-void
+Static void
uaudio_close(void *addr)
{
- struct uaudio_softc *sc = addr;
-
- if (sc->sc_dying)
- return (EIO);
-
- DPRINTF(("uaudio_close: sc=%p\n", sc));
- uaudio_halt_in_dma(sc);
- uaudio_halt_out_dma(sc);
-
- sc->sc_chan.intr = 0;
}
-int
+Static int
uaudio_drain(void *addr)
{
struct uaudio_softc *sc = addr;
- if (sc->sc_dying)
- return (EIO);
-
usbd_delay_ms(sc->sc_udev, UAUDIO_NCHANBUFS * UAUDIO_NFRAMES);
return (0);
}
-int
+Static int
uaudio_halt_out_dma(void *addr)
{
struct uaudio_softc *sc = addr;
@@ -1631,29 +2376,31 @@ uaudio_halt_out_dma(void *addr)
return (EIO);
DPRINTF(("uaudio_halt_out_dma: enter\n"));
- if (sc->sc_chan.pipe != NULL) {
- uaudio_chan_close(sc, &sc->sc_chan);
- sc->sc_chan.pipe = 0;
- uaudio_chan_free_buffers(sc, &sc->sc_chan);
+ if (sc->sc_playchan.pipe != NULL) {
+ uaudio_chan_close(sc, &sc->sc_playchan);
+ sc->sc_playchan.pipe = NULL;
+ uaudio_chan_free_buffers(sc, &sc->sc_playchan);
+ sc->sc_playchan.intr = NULL;
}
- return (0);
+ return (0);
}
-int
+Static int
uaudio_halt_in_dma(void *addr)
{
struct uaudio_softc *sc = addr;
DPRINTF(("uaudio_halt_in_dma: enter\n"));
- if (sc->sc_chan.pipe != NULL) {
- uaudio_chan_close(sc, &sc->sc_chan);
- sc->sc_chan.pipe = 0;
- uaudio_chan_free_buffers(sc, &sc->sc_chan);
+ if (sc->sc_recchan.pipe != NULL) {
+ uaudio_chan_close(sc, &sc->sc_recchan);
+ sc->sc_recchan.pipe = NULL;
+ uaudio_chan_free_buffers(sc, &sc->sc_recchan);
+ sc->sc_recchan.intr = NULL;
}
- return (0);
+ return (0);
}
-int
+Static int
uaudio_getdev(void *addr, struct audio_device *retp)
{
struct uaudio_softc *sc = addr;
@@ -1661,24 +2408,30 @@ uaudio_getdev(void *addr, struct audio_device *retp)
DPRINTF(("uaudio_mixer_getdev:\n"));
if (sc->sc_dying)
return (EIO);
-
+
*retp = uaudio_device;
- return (0);
+ return (0);
}
/*
* Make sure the block size is large enough to hold all outstanding transfers.
*/
-int
+Static int
uaudio_round_blocksize(void *addr, int blk)
{
struct uaudio_softc *sc = addr;
int bpf;
- if (sc->sc_dying)
- return (EIO);
-
- bpf = sc->sc_chan.bytes_per_frame + sc->sc_chan.sample_size;
+ DPRINTF(("uaudio_round_blocksize: p.bpf=%d r.bpf=%d\n",
+ sc->sc_playchan.bytes_per_frame,
+ sc->sc_recchan.bytes_per_frame));
+ if (sc->sc_playchan.bytes_per_frame > sc->sc_recchan.bytes_per_frame) {
+ bpf = sc->sc_playchan.bytes_per_frame
+ + sc->sc_playchan.sample_size;
+ } else {
+ bpf = sc->sc_recchan.bytes_per_frame
+ + sc->sc_recchan.sample_size;
+ }
/* XXX */
bpf *= UAUDIO_NFRAMES * UAUDIO_NCHANBUFS;
@@ -1698,17 +2451,15 @@ uaudio_round_blocksize(void *addr, int blk)
return (blk);
}
-int
+Static int
uaudio_get_props(void *addr)
{
- struct uaudio_softc *sc = addr;
+ return (AUDIO_PROP_FULLDUPLEX | AUDIO_PROP_INDEPENDENT);
- return (sc->sc_props);
}
#endif /* NetBSD or OpenBSD */
-
-int
+Static int
uaudio_get(struct uaudio_softc *sc, int which, int type, int wValue,
int wIndex, int len)
{
@@ -1717,8 +2468,10 @@ uaudio_get(struct uaudio_softc *sc, int which, int type, int wValue,
usbd_status err;
int val;
+#if defined(__FreeBSD__)
if (sc->sc_dying)
return (EIO);
+#endif
if (wValue == -1)
return (0);
@@ -1729,9 +2482,9 @@ uaudio_get(struct uaudio_softc *sc, int which, int type, int wValue,
USETW(req.wIndex, wIndex);
USETW(req.wLength, len);
DPRINTFN(2,("uaudio_get: type=0x%02x req=0x%02x wValue=0x%04x "
- "wIndex=0x%04x len=%d\n",
+ "wIndex=0x%04x len=%d\n",
type, which, wValue, wIndex, len));
- err = usbd_do_request(sc->sc_udev, &req, &data);
+ err = usbd_do_request(sc->sc_udev, &req, data);
if (err) {
DPRINTF(("uaudio_get: err=%s\n", usbd_errstr(err)));
return (-1);
@@ -1751,7 +2504,7 @@ uaudio_get(struct uaudio_softc *sc, int which, int type, int wValue,
return (val);
}
-void
+Static void
uaudio_set(struct uaudio_softc *sc, int which, int type, int wValue,
int wIndex, int len, int val)
{
@@ -1759,8 +2512,10 @@ uaudio_set(struct uaudio_softc *sc, int which, int type, int wValue,
u_int8_t data[4];
usbd_status err;
+#if defined(__FreeBSD__)
if (sc->sc_dying)
return;
+#endif
if (wValue == -1)
return;
@@ -1782,16 +2537,16 @@ uaudio_set(struct uaudio_softc *sc, int which, int type, int wValue,
return;
}
DPRINTFN(2,("uaudio_set: type=0x%02x req=0x%02x wValue=0x%04x "
- "wIndex=0x%04x len=%d, val=%d\n",
+ "wIndex=0x%04x len=%d, val=%d\n",
type, which, wValue, wIndex, len, val & 0xffff));
- err = usbd_do_request(sc->sc_udev, &req, &data);
+ err = usbd_do_request(sc->sc_udev, &req, data);
#ifdef USB_DEBUG
if (err)
DPRINTF(("uaudio_set: err=%d\n", err));
#endif
}
-int
+Static int
uaudio_signext(int type, int val)
{
if (!MIX_UNSIGNED(type)) {
@@ -1804,15 +2559,18 @@ uaudio_signext(int type, int val)
}
#if defined(__NetBSD__) || defined(__OpenBSD__)
-int
+Static int
uaudio_value2bsd(struct mixerctl *mc, int val)
{
DPRINTFN(5, ("uaudio_value2bsd: type=%03x val=%d min=%d max=%d ",
mc->type, val, mc->minval, mc->maxval));
- if (mc->type == MIX_ON_OFF)
- val = val != 0;
- else
- val = ((uaudio_signext(mc->type, val) - mc->minval) * 256
+ if (mc->type == MIX_ON_OFF) {
+ val = (val != 0);
+ } else if (mc->type == MIX_SELECTOR) {
+ if (val < mc->minval || val > mc->maxval)
+ val = mc->minval;
+ } else
+ val = ((uaudio_signext(mc->type, val) - mc->minval) * 255
+ mc->mul/2) / mc->mul;
DPRINTFN(5, ("val'=%d\n", val));
return (val);
@@ -1824,17 +2582,20 @@ uaudio_bsd2value(struct mixerctl *mc, int val)
{
DPRINTFN(5,("uaudio_bsd2value: type=%03x val=%d min=%d max=%d ",
mc->type, val, mc->minval, mc->maxval));
- if (mc->type == MIX_ON_OFF)
- val = val != 0;
- else
- val = (val + mc->delta/2) * mc->mul / 256 + mc->minval;
+ if (mc->type == MIX_ON_OFF) {
+ val = (val != 0);
+ } else if (mc->type == MIX_SELECTOR) {
+ if (val < mc->minval || val > mc->maxval)
+ val = mc->minval;
+ } else
+ val = (val + mc->delta/2) * mc->mul / 255 + mc->minval;
DPRINTFN(5, ("val'=%d\n", val));
return (val);
}
#if defined(__NetBSD__) || defined(__OpenBSD__)
-int
-uaudio_ctl_get(struct uaudio_softc *sc, int which, struct mixerctl *mc,
+Static int
+uaudio_ctl_get(struct uaudio_softc *sc, int which, struct mixerctl *mc,
int chan)
{
int val;
@@ -1846,7 +2607,7 @@ uaudio_ctl_get(struct uaudio_softc *sc, int which, struct mixerctl *mc,
}
#endif
-void
+Static void
uaudio_ctl_set(struct uaudio_softc *sc, int which, struct mixerctl *mc,
int chan, int val)
{
@@ -1856,7 +2617,7 @@ uaudio_ctl_set(struct uaudio_softc *sc, int which, struct mixerctl *mc,
}
#if defined(__NetBSD__) || defined(__OpenBSD__)
-int
+Static int
uaudio_mixer_get_port(void *addr, mixer_ctrl_t *cp)
{
struct uaudio_softc *sc = addr;
@@ -1867,8 +2628,8 @@ uaudio_mixer_get_port(void *addr, mixer_ctrl_t *cp)
if (sc->sc_dying)
return (EIO);
-
- n = cp->dev;
+
+ n = cp->dev - UAC_NCLASSES;
if (n < 0 || n >= sc->sc_nctls)
return (ENXIO);
mc = &sc->sc_ctls[n];
@@ -1877,6 +2638,10 @@ uaudio_mixer_get_port(void *addr, mixer_ctrl_t *cp)
if (cp->type != AUDIO_MIXER_ENUM)
return (EINVAL);
cp->un.ord = uaudio_ctl_get(sc, GET_CUR, mc, 0);
+ } else if (mc->type == MIX_SELECTOR) {
+ if (cp->type != AUDIO_MIXER_ENUM)
+ return (EINVAL);
+ cp->un.ord = uaudio_ctl_get(sc, GET_CUR, mc, 0);
} else {
if (cp->type != AUDIO_MIXER_VALUE)
return (EINVAL);
@@ -1896,8 +2661,8 @@ uaudio_mixer_get_port(void *addr, mixer_ctrl_t *cp)
return (0);
}
-
-int
+
+Static int
uaudio_mixer_set_port(void *addr, mixer_ctrl_t *cp)
{
struct uaudio_softc *sc = addr;
@@ -1907,8 +2672,8 @@ uaudio_mixer_set_port(void *addr, mixer_ctrl_t *cp)
DPRINTFN(2,("uaudio_mixer_set_port: index = %d\n", cp->dev));
if (sc->sc_dying)
return (EIO);
-
- n = cp->dev;
+
+ n = cp->dev - UAC_NCLASSES;
if (n < 0 || n >= sc->sc_nctls)
return (ENXIO);
mc = &sc->sc_ctls[n];
@@ -1917,6 +2682,10 @@ uaudio_mixer_set_port(void *addr, mixer_ctrl_t *cp)
if (cp->type != AUDIO_MIXER_ENUM)
return (EINVAL);
uaudio_ctl_set(sc, SET_CUR, mc, 0, cp->un.ord);
+ } else if (mc->type == MIX_SELECTOR) {
+ if (cp->type != AUDIO_MIXER_ENUM)
+ return (EINVAL);
+ uaudio_ctl_set(sc, SET_CUR, mc, 0, cp->un.ord);
} else {
if (cp->type != AUDIO_MIXER_VALUE)
return (EINVAL);
@@ -1934,13 +2703,13 @@ uaudio_mixer_set_port(void *addr, mixer_ctrl_t *cp)
return (0);
}
-int
+Static int
uaudio_trigger_input(void *addr, void *start, void *end, int blksize,
void (*intr)(void *), void *arg,
struct audio_params *param)
{
struct uaudio_softc *sc = addr;
- struct chan *ch = &sc->sc_chan;
+ struct chan *ch = &sc->sc_recchan;
usbd_status err;
int i, s;
@@ -1950,7 +2719,7 @@ uaudio_trigger_input(void *addr, void *start, void *end, int blksize,
DPRINTFN(3,("uaudio_trigger_input: sc=%p start=%p end=%p "
"blksize=%d\n", sc, start, end, blksize));
- uaudio_chan_set_param(ch, param, start, end, blksize);
+ uaudio_chan_set_param(ch, start, end, blksize);
DPRINTFN(3,("uaudio_trigger_input: sample_size=%d bytes/frame=%d "
"fraction=0.%03d\n", ch->sample_size, ch->bytes_per_frame,
ch->fraction));
@@ -1965,24 +2734,24 @@ uaudio_trigger_input(void *addr, void *start, void *end, int blksize,
return (EIO);
}
- sc->sc_chan.intr = intr;
- sc->sc_chan.arg = arg;
+ ch->intr = intr;
+ ch->arg = arg;
s = splusb();
for (i = 0; i < UAUDIO_NCHANBUFS-1; i++) /* XXX -1 shouldn't be needed */
uaudio_chan_rtransfer(ch);
splx(s);
- return (0);
+ return (0);
}
-
-int
+
+Static int
uaudio_trigger_output(void *addr, void *start, void *end, int blksize,
void (*intr)(void *), void *arg,
struct audio_params *param)
{
struct uaudio_softc *sc = addr;
- struct chan *ch = &sc->sc_chan;
+ struct chan *ch = &sc->sc_playchan;
usbd_status err;
int i, s;
@@ -1992,7 +2761,7 @@ uaudio_trigger_output(void *addr, void *start, void *end, int blksize,
DPRINTFN(3,("uaudio_trigger_output: sc=%p start=%p end=%p "
"blksize=%d\n", sc, start, end, blksize));
- uaudio_chan_set_param(ch, param, start, end, blksize);
+ uaudio_chan_set_param(ch, start, end, blksize);
DPRINTFN(3,("uaudio_trigger_output: sample_size=%d bytes/frame=%d "
"fraction=0.%03d\n", ch->sample_size, ch->bytes_per_frame,
ch->fraction));
@@ -2007,30 +2776,32 @@ uaudio_trigger_output(void *addr, void *start, void *end, int blksize,
return (EIO);
}
- sc->sc_chan.intr = intr;
- sc->sc_chan.arg = arg;
+ ch->intr = intr;
+ ch->arg = arg;
s = splusb();
for (i = 0; i < UAUDIO_NCHANBUFS-1; i++) /* XXX */
uaudio_chan_ptransfer(ch);
splx(s);
- return (0);
+ return (0);
}
#endif /* NetBSD or OpenBSD */
/* Set up a pipe for a channel. */
-usbd_status
+Static usbd_status
uaudio_chan_open(struct uaudio_softc *sc, struct chan *ch)
{
- struct as_info *as = &sc->sc_alts[sc->sc_curaltidx];
+ struct as_info *as = &sc->sc_alts[ch->altidx];
int endpt = as->edesc->bEndpointAddress;
usbd_status err;
+#if defined(__FreeBSD__)
if (sc->sc_dying)
return (EIO);
+#endif
- DPRINTF(("uaudio_open_chan: endpt=0x%02x, speed=%d, alt=%d\n",
+ DPRINTF(("uaudio_chan_open: endpt=0x%02x, speed=%d, alt=%d\n",
endpt, ch->sample_rate, as->alt));
/* Set alternate interface corresponding to the mode. */
@@ -2038,39 +2809,59 @@ uaudio_chan_open(struct uaudio_softc *sc, struct chan *ch)
if (err)
return (err);
- /* Some devices do not support this request, so ignore errors. */
-#ifdef USB_DEBUG
- err = uaudio_set_speed(sc, endpt, ch->sample_rate);
- if (err)
- DPRINTF(("uaudio_chan_open: set_speed failed err=%s\n",
- usbd_errstr(err)));
-#else
- (void)uaudio_set_speed(sc, endpt, ch->sample_rate);
-#endif
+ /*
+ * If just one sampling rate is supported,
+ * no need to call uaudio_set_speed().
+ * Roland SD-90 freezes by a SAMPLING_FREQ_CONTROL request.
+ */
+ if (as->asf1desc->bSamFreqType != 1) {
+ err = uaudio_set_speed(sc, endpt, ch->sample_rate);
+ if (err)
+ DPRINTF(("uaudio_chan_open: set_speed failed err=%s\n",
+ usbd_errstr(err)));
+ }
- DPRINTF(("uaudio_open_chan: create pipe to 0x%02x\n", endpt));
+ ch->pipe = 0;
+ ch->sync_pipe = 0;
+ DPRINTF(("uaudio_chan_open: create pipe to 0x%02x\n", endpt));
err = usbd_open_pipe(as->ifaceh, endpt, 0, &ch->pipe);
- return (err);
+ if (err)
+ return err;
+ if (as->edesc1 != NULL) {
+ endpt = as->edesc1->bEndpointAddress;
+ DPRINTF(("uaudio_chan_open: create sync-pipe to 0x%02x\n", endpt));
+ err = usbd_open_pipe(as->ifaceh, endpt, 0, &ch->sync_pipe);
+ }
+ return err;
}
-void
+Static void
uaudio_chan_close(struct uaudio_softc *sc, struct chan *ch)
{
- struct as_info *as = &sc->sc_alts[sc->sc_curaltidx];
+ struct as_info *as = &sc->sc_alts[ch->altidx];
+#if defined(__FreeBSD__)
if (sc->sc_dying)
return ;
+#endif
+ as->sc_busy = 0;
if (sc->sc_nullalt >= 0) {
- DPRINTF(("uaudio_close_chan: set null alt=%d\n",
+ DPRINTF(("uaudio_chan_close: set null alt=%d\n",
sc->sc_nullalt));
usbd_set_interface(as->ifaceh, sc->sc_nullalt);
}
- usbd_abort_pipe(ch->pipe);
- usbd_close_pipe(ch->pipe);
+ if (ch->pipe) {
+ usbd_abort_pipe(ch->pipe);
+ usbd_close_pipe(ch->pipe);
+ }
+ if (ch->sync_pipe) {
+ usbd_abort_pipe(ch->sync_pipe);
+ usbd_close_pipe(ch->sync_pipe);
+ }
}
-usbd_status
+Static usbd_status
uaudio_chan_alloc_buffers(struct uaudio_softc *sc, struct chan *ch)
{
usbd_xfer_handle xfer;
@@ -2101,7 +2892,7 @@ bad:
return (USBD_NOMEM);
}
-void
+Static void
uaudio_chan_free_buffers(struct uaudio_softc *sc, struct chan *ch)
{
int i;
@@ -2111,7 +2902,7 @@ uaudio_chan_free_buffers(struct uaudio_softc *sc, struct chan *ch)
}
/* Called at splusb() */
-void
+Static void
uaudio_chan_ptransfer(struct chan *ch)
{
struct chanbuf *cb;
@@ -2132,7 +2923,7 @@ uaudio_chan_ptransfer(struct chan *ch)
size = ch->bytes_per_frame;
residue += ch->fraction;
if (residue >= USB_FRAMES_PER_SECOND) {
- if (!ch->nofrac)
+ if ((ch->sc->sc_altflags & UA_NOFRAC) == 0)
size += ch->sample_size;
residue -= USB_FRAMES_PER_SECOND;
}
@@ -2142,7 +2933,7 @@ uaudio_chan_ptransfer(struct chan *ch)
ch->residue = residue;
cb->size = total;
- /*
+ /*
* Transfer data from upper layer buffer to channel buffer, taking
* care of wrapping the upper layer buffer.
*/
@@ -2169,14 +2960,14 @@ uaudio_chan_ptransfer(struct chan *ch)
DPRINTFN(5,("uaudio_chan_transfer: ptransfer xfer=%p\n", cb->xfer));
/* Fill the request */
- usbd_setup_isoc_xfer(cb->xfer, ch->pipe, cb, cb->sizes,
- UAUDIO_NFRAMES, USBD_NO_COPY,
+ usbd_setup_isoc_xfer(cb->xfer, ch->pipe, cb, cb->sizes,
+ UAUDIO_NFRAMES, USBD_NO_COPY,
uaudio_chan_pintr);
(void)usbd_transfer(cb->xfer);
}
-void
+Static void
uaudio_chan_pintr(usbd_xfer_handle xfer, usbd_private_handle priv,
usbd_status status)
{
@@ -2210,7 +3001,7 @@ uaudio_chan_pintr(usbd_xfer_handle xfer, usbd_private_handle priv,
/* Call back to upper layer */
while (ch->transferred >= ch->blksize) {
ch->transferred -= ch->blksize;
- DPRINTFN(5,("uaudio_chan_pintr: call %p(%p)\n",
+ DPRINTFN(5,("uaudio_chan_pintr: call %p(%p)\n",
ch->intr, ch->arg));
ch->intr(ch->arg);
}
@@ -2222,7 +3013,7 @@ uaudio_chan_pintr(usbd_xfer_handle xfer, usbd_private_handle priv,
}
/* Called at splusb() */
-void
+Static void
uaudio_chan_rtransfer(struct chan *ch)
{
struct chanbuf *cb;
@@ -2241,13 +3032,8 @@ uaudio_chan_rtransfer(struct chan *ch)
total = 0;
for (i = 0; i < UAUDIO_NFRAMES; i++) {
size = ch->bytes_per_frame;
- residue += ch->fraction;
- if (residue >= USB_FRAMES_PER_SECOND) {
- if (!ch->nofrac)
- size += ch->sample_size;
- residue -= USB_FRAMES_PER_SECOND;
- }
cb->sizes[i] = size;
+ cb->offsets[i] = total;
total += size;
}
ch->residue = residue;
@@ -2265,21 +3051,21 @@ uaudio_chan_rtransfer(struct chan *ch)
DPRINTFN(5,("uaudio_chan_rtransfer: transfer xfer=%p\n", cb->xfer));
/* Fill the request */
- usbd_setup_isoc_xfer(cb->xfer, ch->pipe, cb, cb->sizes,
- UAUDIO_NFRAMES, USBD_NO_COPY,
+ usbd_setup_isoc_xfer(cb->xfer, ch->pipe, cb, cb->sizes,
+ UAUDIO_NFRAMES, USBD_NO_COPY,
uaudio_chan_rintr);
(void)usbd_transfer(cb->xfer);
}
-void
+Static void
uaudio_chan_rintr(usbd_xfer_handle xfer, usbd_private_handle priv,
usbd_status status)
{
struct chanbuf *cb = priv;
struct chan *ch = cb->chan;
u_int32_t count;
- int s, n;
+ int s, i, n, frsize;
/* Return if we are aborting. */
if (status == USBD_CANCELLED)
@@ -2289,36 +3075,34 @@ uaudio_chan_rintr(usbd_xfer_handle xfer, usbd_private_handle priv,
DPRINTFN(5,("uaudio_chan_rintr: count=%d, transferred=%d\n",
count, ch->transferred));
- if (count < cb->size) {
- /* if the device fails to keep up, copy last byte */
- u_char b = count ? cb->buffer[count-1] : 0;
- while (count < cb->size)
- cb->buffer[count++] = b;
- }
-
+ /* count < cb->size is normal for asynchronous source */
#ifdef DIAGNOSTIC
- if (count != cb->size) {
- printf("uaudio_chan_rintr: count(%d) != size(%d)\n",
+ if (count > cb->size) {
+ printf("uaudio_chan_rintr: count(%d) > size(%d)\n",
count, cb->size);
}
#endif
- /*
+ /*
* Transfer data from channel buffer to upper layer buffer, taking
* care of wrapping the upper layer buffer.
*/
- n = min(count, ch->end - ch->cur);
- memcpy(ch->cur, cb->buffer, n);
- ch->cur += n;
- if (ch->cur >= ch->end)
- ch->cur = ch->start;
- if (count > n) {
- memcpy(ch->cur, cb->buffer + n, count - n);
- ch->cur += count - n;
+ for(i = 0; i < UAUDIO_NFRAMES; i++) {
+ frsize = cb->sizes[i];
+ n = min(frsize, ch->end - ch->cur);
+ memcpy(ch->cur, cb->buffer + cb->offsets[i], n);
+ ch->cur += n;
+ if (ch->cur >= ch->end)
+ ch->cur = ch->start;
+ if (frsize > n) {
+ memcpy(ch->cur, cb->buffer + cb->offsets[i] + n,
+ frsize - n);
+ ch->cur += frsize - n;
+ }
}
/* Call back to upper layer */
- ch->transferred += cb->size;
+ ch->transferred += count;
#if defined(__FreeBSD__)
s = spltty();
chn_intr(ch->pcm_ch);
@@ -2327,7 +3111,7 @@ uaudio_chan_rintr(usbd_xfer_handle xfer, usbd_private_handle priv,
s = splaudio();
while (ch->transferred >= ch->blksize) {
ch->transferred -= ch->blksize;
- DPRINTFN(5,("uaudio_chan_rintr: call %p(%p)\n",
+ DPRINTFN(5,("uaudio_chan_rintr: call %p(%p)\n",
ch->intr, ch->arg));
ch->intr(ch->arg);
}
@@ -2339,20 +3123,30 @@ uaudio_chan_rintr(usbd_xfer_handle xfer, usbd_private_handle priv,
}
#if defined(__NetBSD__) || defined(__OpenBSD__)
-void
-uaudio_chan_set_param(struct chan *ch, struct audio_params *param,
- u_char *start, u_char *end, int blksize)
+Static void
+uaudio_chan_init(struct chan *ch, int altidx, const struct audio_params *param,
+ int maxpktsize)
{
int samples_per_frame, sample_size;
- sample_size = param->precision * param->channels / 8;
- samples_per_frame = param->sample_rate / USB_FRAMES_PER_SECOND;
- ch->fraction = param->sample_rate % USB_FRAMES_PER_SECOND;
+ ch->altidx = altidx;
+ sample_size = param->precision * param->factor * param->hw_channels / 8;
+ samples_per_frame = param->hw_sample_rate / USB_FRAMES_PER_SECOND;
ch->sample_size = sample_size;
- ch->sample_rate = param->sample_rate;
- ch->bytes_per_frame = samples_per_frame * sample_size;
+ ch->sample_rate = param->hw_sample_rate;
+ if (maxpktsize == 0) {
+ ch->fraction = param->hw_sample_rate % USB_FRAMES_PER_SECOND;
+ ch->bytes_per_frame = samples_per_frame * sample_size;
+ } else {
+ ch->fraction = 0;
+ ch->bytes_per_frame = maxpktsize;
+ }
ch->residue = 0;
+}
+Static void
+uaudio_chan_set_param(struct chan *ch, u_char *start, u_char *end, int blksize)
+{
ch->start = start;
ch->end = end;
ch->cur = start;
@@ -2362,14 +3156,164 @@ uaudio_chan_set_param(struct chan *ch, struct audio_params *param,
ch->curchanbuf = 0;
}
-int
+Static void
+uaudio_get_minmax_rates(int nalts, const struct as_info *alts,
+ const struct audio_params *p, int mode,
+ u_long *min, u_long *max)
+{
+ const struct usb_audio_streaming_type1_descriptor *a1d;
+ int i, j;
+
+ *min = ULONG_MAX;
+ *max = 0;
+ for (i = 0; i < nalts; i++) {
+ a1d = alts[i].asf1desc;
+ if (alts[i].sc_busy)
+ continue;
+ if (p->hw_channels != a1d->bNrChannels)
+ continue;
+ if (p->hw_precision != a1d->bBitResolution)
+ continue;
+ if (p->hw_encoding != alts[i].encoding)
+ continue;
+ if (mode != UE_GET_DIR(alts[i].edesc->bEndpointAddress))
+ continue;
+ if (a1d->bSamFreqType == UA_SAMP_CONTNUOUS) {
+ DPRINTFN(2,("uaudio_get_minmax_rates: cont %d-%d\n",
+ UA_SAMP_LO(a1d), UA_SAMP_HI(a1d)));
+ if (UA_SAMP_LO(a1d) < *min)
+ *min = UA_SAMP_LO(a1d);
+ if (UA_SAMP_HI(a1d) > *max)
+ *max = UA_SAMP_HI(a1d);
+ } else {
+ for (j = 0; j < a1d->bSamFreqType; j++) {
+ DPRINTFN(2,("uaudio_get_minmax_rates: disc #%d: %d\n",
+ j, UA_GETSAMP(a1d, j)));
+ if (UA_GETSAMP(a1d, j) < *min)
+ *min = UA_GETSAMP(a1d, j);
+ if (UA_GETSAMP(a1d, j) > *max)
+ *max = UA_GETSAMP(a1d, j);
+ }
+ }
+ }
+}
+
+Static int
+uaudio_match_alt_sub(int nalts, const struct as_info *alts,
+ const struct audio_params *p, int mode, u_long rate)
+{
+ const struct usb_audio_streaming_type1_descriptor *a1d;
+ int i, j;
+
+ DPRINTF(("uaudio_match_alt_sub: search for %luHz %dch\n",
+ rate, p->hw_channels));
+ for (i = 0; i < nalts; i++) {
+ a1d = alts[i].asf1desc;
+ if (alts[i].sc_busy)
+ continue;
+ if (p->hw_channels != a1d->bNrChannels)
+ continue;
+ if (p->hw_precision != a1d->bBitResolution)
+ continue;
+ if (p->hw_encoding != alts[i].encoding)
+ continue;
+ if (mode != UE_GET_DIR(alts[i].edesc->bEndpointAddress))
+ continue;
+ if (a1d->bSamFreqType == UA_SAMP_CONTNUOUS) {
+ DPRINTFN(3,("uaudio_match_alt_sub: cont %d-%d\n",
+ UA_SAMP_LO(a1d), UA_SAMP_HI(a1d)));
+ if (UA_SAMP_LO(a1d) <= rate && rate <= UA_SAMP_HI(a1d))
+ return i;
+ } else {
+ for (j = 0; j < a1d->bSamFreqType; j++) {
+ DPRINTFN(3,("uaudio_match_alt_sub: disc #%d: %d\n",
+ j, UA_GETSAMP(a1d, j)));
+ /* XXX allow for some slack */
+ if (UA_GETSAMP(a1d, j) == rate)
+ return i;
+ }
+ }
+ }
+ return -1;
+}
+
+Static int
+uaudio_match_alt_chan(int nalts, const struct as_info *alts,
+ struct audio_params *p, int mode)
+{
+ int i, n;
+ u_long min, max;
+ u_long rate;
+
+ /* Exact match */
+ DPRINTF(("uaudio_match_alt_chan: examine %ldHz %dch %dbit.\n",
+ p->sample_rate, p->hw_channels, p->hw_precision));
+ i = uaudio_match_alt_sub(nalts, alts, p, mode, p->sample_rate);
+ if (i >= 0)
+ return i;
+
+ uaudio_get_minmax_rates(nalts, alts, p, mode, &min, &max);
+ DPRINTF(("uaudio_match_alt_chan: min=%lu max=%lu\n", min, max));
+ if (max <= 0)
+ return -1;
+ /* Search for biggers */
+ n = 2;
+ while ((rate = p->sample_rate * n++) <= max) {
+ i = uaudio_match_alt_sub(nalts, alts, p, mode, rate);
+ if (i >= 0) {
+ p->hw_sample_rate = rate;
+ return i;
+ }
+ }
+ if (p->sample_rate >= min) {
+ i = uaudio_match_alt_sub(nalts, alts, p, mode, max);
+ if (i >= 0) {
+ p->hw_sample_rate = max;
+ return i;
+ }
+ } else {
+ i = uaudio_match_alt_sub(nalts, alts, p, mode, min);
+ if (i >= 0) {
+ p->hw_sample_rate = min;
+ return i;
+ }
+ }
+ return -1;
+}
+
+Static int
+uaudio_match_alt(int nalts, const struct as_info *alts,
+ struct audio_params *p, int mode)
+{
+ int i, n;
+
+ mode = mode == AUMODE_PLAY ? UE_DIR_OUT : UE_DIR_IN;
+ i = uaudio_match_alt_chan(nalts, alts, p, mode);
+ if (i >= 0)
+ return i;
+
+ for (n = p->channels + 1; n <= AUDIO_MAX_CHANNELS; n++) {
+ p->hw_channels = n;
+ i = uaudio_match_alt_chan(nalts, alts, p, mode);
+ if (i >= 0)
+ return i;
+ }
+
+ if (p->channels != 2)
+ return -1;
+ p->hw_channels = 1;
+ return uaudio_match_alt_chan(nalts, alts, p, mode);
+}
+
+Static int
uaudio_set_params(void *addr, int setmode, int usemode,
struct audio_params *play, struct audio_params *rec)
{
struct uaudio_softc *sc = addr;
int flags = sc->sc_altflags;
int factor;
- int enc, i, j;
+ int enc, i;
+ int paltidx=-1, raltidx=-1;
void (*swcode)(void *, u_char *buf, int cnt);
struct audio_params *p;
int mode;
@@ -2377,156 +3321,181 @@ uaudio_set_params(void *addr, int setmode, int usemode,
if (sc->sc_dying)
return (EIO);
- if (sc->sc_chan.pipe != NULL)
+ if (((usemode & AUMODE_PLAY) && sc->sc_playchan.pipe != NULL) ||
+ ((usemode & AUMODE_RECORD) && sc->sc_recchan.pipe != NULL))
return (EBUSY);
+ if ((usemode & AUMODE_PLAY) && sc->sc_playchan.altidx != -1)
+ sc->sc_alts[sc->sc_playchan.altidx].sc_busy = 0;
+ if ((usemode & AUMODE_RECORD) && sc->sc_recchan.altidx != -1)
+ sc->sc_alts[sc->sc_recchan.altidx].sc_busy = 0;
+
+ /* Some uaudio devices are unidirectional. Don't try to find a
+ matching mode for the unsupported direction. */
+ setmode &= sc->sc_mode;
+
for (mode = AUMODE_RECORD; mode != -1;
mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
if ((setmode & mode) == 0)
continue;
- if ((sc->sc_chan.dir & mode) == 0)
- continue;
- p = mode == AUMODE_PLAY ? play : rec;
+ p = (mode == AUMODE_PLAY) ? play : rec;
factor = 1;
swcode = 0;
enc = p->encoding;
switch (enc) {
case AUDIO_ENCODING_SLINEAR_BE:
- if (p->precision == 16) {
+ /* FALLTHROUGH */
+ case AUDIO_ENCODING_SLINEAR_LE:
+ if (enc == AUDIO_ENCODING_SLINEAR_BE
+ && p->precision == 16 && (flags & HAS_16)) {
swcode = swap_bytes;
enc = AUDIO_ENCODING_SLINEAR_LE;
- } else if (p->precision == 8 && !(flags & HAS_8)) {
- swcode = change_sign8;
- enc = AUDIO_ENCODING_ULINEAR_LE;
- }
- break;
- case AUDIO_ENCODING_SLINEAR_LE:
- if (p->precision == 8 && !(flags & HAS_8)) {
- swcode = change_sign8;
- enc = AUDIO_ENCODING_ULINEAR_LE;
+ } else if (p->precision == 8) {
+ if (flags & HAS_8) {
+ /* No conversion */
+ } else if (flags & HAS_8U) {
+ swcode = change_sign8;
+ enc = AUDIO_ENCODING_ULINEAR_LE;
+ } else if (flags & HAS_16) {
+ factor = 2;
+ p->hw_precision = 16;
+ if (mode == AUMODE_PLAY)
+ swcode = linear8_to_linear16_le;
+ else
+ swcode = linear16_to_linear8_le;
+ }
}
break;
case AUDIO_ENCODING_ULINEAR_BE:
+ /* FALLTHROUGH */
+ case AUDIO_ENCODING_ULINEAR_LE:
if (p->precision == 16) {
- if (mode == AUMODE_PLAY)
+ if (enc == AUDIO_ENCODING_ULINEAR_LE)
+ swcode = change_sign16_le;
+ else if (mode == AUMODE_PLAY)
swcode = swap_bytes_change_sign16_le;
else
swcode = change_sign16_swap_bytes_le;
enc = AUDIO_ENCODING_SLINEAR_LE;
- } else if (p->precision == 8 && !(flags & HAS_8U)) {
- swcode = change_sign8;
- enc = AUDIO_ENCODING_SLINEAR_LE;
- }
- break;
- case AUDIO_ENCODING_ULINEAR_LE:
- if (p->precision == 16) {
- swcode = change_sign16_le;
- enc = AUDIO_ENCODING_SLINEAR_LE;
- } else if (p->precision == 8 && !(flags & HAS_8U)) {
- swcode = change_sign8;
- enc = AUDIO_ENCODING_SLINEAR_LE;
- }
- break;
- case AUDIO_ENCODING_ULAW:
- if (!(flags & HAS_MULAW)) {
- if (mode == AUMODE_PLAY &&
- (flags & HAS_16)) {
- swcode = mulaw_to_slinear16_le;
- factor = 2;
- enc = AUDIO_ENCODING_SLINEAR_LE;
- } else if (flags & HAS_8U) {
- if (mode == AUMODE_PLAY)
- swcode = mulaw_to_ulinear8;
- else
- swcode = ulinear8_to_mulaw;
- enc = AUDIO_ENCODING_ULINEAR_LE;
+ } else if (p->precision == 8) {
+ if (flags & HAS_8U) {
+ /* No conversion */
} else if (flags & HAS_8) {
- if (mode == AUMODE_PLAY)
- swcode = mulaw_to_slinear8;
- else
- swcode = slinear8_to_mulaw;
+ swcode = change_sign8;
enc = AUDIO_ENCODING_SLINEAR_LE;
- } else
- return (EINVAL);
- }
- break;
- case AUDIO_ENCODING_ALAW:
- if (!(flags & HAS_ALAW)) {
- if (mode == AUMODE_PLAY &&
- (flags & HAS_16)) {
- swcode = alaw_to_slinear16_le;
+ } else if (flags & HAS_16) {
factor = 2;
+ p->hw_precision = 16;
enc = AUDIO_ENCODING_SLINEAR_LE;
- } else if (flags & HAS_8U) {
if (mode == AUMODE_PLAY)
- swcode = alaw_to_ulinear8;
+ swcode = ulinear8_to_slinear16_le;
else
- swcode = ulinear8_to_alaw;
- enc = AUDIO_ENCODING_ULINEAR_LE;
- } else if (flags & HAS_8) {
- if (mode == AUMODE_PLAY)
- swcode = alaw_to_slinear8;
- else
- swcode = slinear8_to_alaw;
- enc = AUDIO_ENCODING_SLINEAR_LE;
- } else
- return (EINVAL);
+ swcode = slinear16_to_ulinear8_le;
+ }
}
break;
+ case AUDIO_ENCODING_ULAW:
+ if (flags & HAS_MULAW)
+ break;
+ if (flags & HAS_16) {
+ if (mode == AUMODE_PLAY)
+ swcode = mulaw_to_slinear16_le;
+ else
+ swcode = slinear16_to_mulaw_le;
+ factor = 2;
+ enc = AUDIO_ENCODING_SLINEAR_LE;
+ p->hw_precision = 16;
+ } else if (flags & HAS_8U) {
+ if (mode == AUMODE_PLAY)
+ swcode = mulaw_to_ulinear8;
+ else
+ swcode = ulinear8_to_mulaw;
+ enc = AUDIO_ENCODING_ULINEAR_LE;
+ } else if (flags & HAS_8) {
+ if (mode == AUMODE_PLAY)
+ swcode = mulaw_to_slinear8;
+ else
+ swcode = slinear8_to_mulaw;
+ enc = AUDIO_ENCODING_SLINEAR_LE;
+ } else
+ return (EINVAL);
+ break;
+ case AUDIO_ENCODING_ALAW:
+ if (flags & HAS_ALAW)
+ break;
+ if (mode == AUMODE_PLAY && (flags & HAS_16)) {
+ swcode = alaw_to_slinear16_le;
+ factor = 2;
+ enc = AUDIO_ENCODING_SLINEAR_LE;
+ p->hw_precision = 16;
+ } else if (flags & HAS_8U) {
+ if (mode == AUMODE_PLAY)
+ swcode = alaw_to_ulinear8;
+ else
+ swcode = ulinear8_to_alaw;
+ enc = AUDIO_ENCODING_ULINEAR_LE;
+ } else if (flags & HAS_8) {
+ if (mode == AUMODE_PLAY)
+ swcode = alaw_to_slinear8;
+ else
+ swcode = slinear8_to_alaw;
+ enc = AUDIO_ENCODING_SLINEAR_LE;
+ } else
+ return (EINVAL);
+ break;
default:
return (EINVAL);
}
/* XXX do some other conversions... */
DPRINTF(("uaudio_set_params: chan=%d prec=%d enc=%d rate=%ld\n",
- p->channels, p->precision, enc, p->sample_rate));
+ p->channels, p->hw_precision, enc, p->sample_rate));
- for (i = 0; i < sc->sc_nalts; i++) {
- struct usb_audio_streaming_type1_descriptor *a1d =
- sc->sc_alts[i].asf1desc;
- if (p->channels == a1d->bNrChannels &&
- p->precision == a1d->bBitResolution &&
- enc == sc->sc_alts[i].encoding &&
- (mode == AUMODE_PLAY ? UE_DIR_OUT : UE_DIR_IN) ==
- UE_GET_DIR(sc->sc_alts[i].edesc->bEndpointAddress)) {
- if (a1d->bSamFreqType == UA_SAMP_CONTNUOUS) {
- DPRINTFN(2,("uaudio_set_params: cont %d-%d\n",
- UA_SAMP_LO(a1d), UA_SAMP_HI(a1d)));
- if (UA_SAMP_LO(a1d) < p->sample_rate &&
- p->sample_rate < UA_SAMP_HI(a1d))
- goto found;
- } else {
- for (j = 0; j < a1d->bSamFreqType; j++) {
- DPRINTFN(2,("uaudio_set_params: disc #"
- "%d: %d\n", j, UA_GETSAMP(a1d, j)));
- /* XXX allow for some slack */
- if (UA_GETSAMP(a1d, j) ==
- p->sample_rate)
- goto found;
- }
- }
- }
- }
- return (EINVAL);
+ p->hw_encoding = enc;
+ i = uaudio_match_alt(sc->sc_nalts, sc->sc_alts, p, mode);
+ if (i < 0)
+ return (EINVAL);
- found:
p->sw_code = swcode;
p->factor = factor;
- if (usemode == mode)
- sc->sc_curaltidx = i;
+
+ if (mode == AUMODE_PLAY)
+ paltidx = i;
+ else
+ raltidx = i;
+ }
+
+ if ((setmode & AUMODE_PLAY)) {
+ /* XXX abort transfer if currently happening? */
+ uaudio_chan_init(&sc->sc_playchan, paltidx, play, 0);
+ }
+ if ((setmode & AUMODE_RECORD)) {
+ /* XXX abort transfer if currently happening? */
+ uaudio_chan_init(&sc->sc_recchan, raltidx, rec,
+ UGETW(sc->sc_alts[raltidx].edesc->wMaxPacketSize));
}
- DPRINTF(("uaudio_set_params: use altidx=%d, altno=%d\n",
- sc->sc_curaltidx,
- sc->sc_alts[sc->sc_curaltidx].idesc->bAlternateSetting));
-
+ if ((usemode & AUMODE_PLAY) && sc->sc_playchan.altidx != -1)
+ sc->sc_alts[sc->sc_playchan.altidx].sc_busy = 1;
+ if ((usemode & AUMODE_RECORD) && sc->sc_recchan.altidx != -1)
+ sc->sc_alts[sc->sc_recchan.altidx].sc_busy = 1;
+
+ DPRINTF(("uaudio_set_params: use altidx=p%d/r%d, altno=p%d/r%d\n",
+ sc->sc_playchan.altidx, sc->sc_recchan.altidx,
+ (sc->sc_playchan.altidx >= 0)
+ ?sc->sc_alts[sc->sc_playchan.altidx].idesc->bAlternateSetting
+ : -1,
+ (sc->sc_recchan.altidx >= 0)
+ ? sc->sc_alts[sc->sc_recchan.altidx].idesc->bAlternateSetting
+ : -1));
+
return (0);
}
#endif /* NetBSD or OpenBSD */
-usbd_status
+Static usbd_status
uaudio_set_speed(struct uaudio_softc *sc, int endpt, u_int speed)
{
usb_device_request_t req;
@@ -2542,14 +3511,14 @@ uaudio_set_speed(struct uaudio_softc *sc, int endpt, u_int speed)
data[1] = speed >> 8;
data[2] = speed >> 16;
- return (usbd_do_request(sc->sc_udev, &req, &data));
+ return (usbd_do_request(sc->sc_udev, &req, data));
}
#if defined(__FreeBSD__)
/************************************************************/
-void
-uaudio_init_params(struct uaudio_softc *sc, struct chan *ch)
+int
+uaudio_init_params(struct uaudio_softc *sc, struct chan *ch, int mode)
{
int i, j, enc;
int samples_per_frame, sample_size;
@@ -2600,12 +3569,13 @@ uaudio_init_params(struct uaudio_softc *sc, struct chan *ch)
}
/* for (mode = ...... */
+/*But this function is used for output only */
for (i = 0; i < sc->sc_nalts; i++) {
- struct usb_audio_streaming_type1_descriptor *a1d =
+ const struct usb_audio_streaming_type1_descriptor *a1d =
sc->sc_alts[i].asf1desc;
if (ch->channels == a1d->bNrChannels &&
ch->precision == a1d->bBitResolution &&
-#if 1
+#if 0
enc == sc->sc_alts[i].encoding) {
#else
enc == sc->sc_alts[i].encoding &&
@@ -2617,7 +3587,10 @@ uaudio_init_params(struct uaudio_softc *sc, struct chan *ch)
UA_SAMP_LO(a1d), UA_SAMP_HI(a1d)));
if (UA_SAMP_LO(a1d) < ch->sample_rate &&
ch->sample_rate < UA_SAMP_HI(a1d)) {
- sc->sc_curaltidx = i;
+ if (mode == AUMODE_PLAY)
+ sc->sc_playchan.altidx = i;
+ else
+ sc->sc_recchan.altidx = i;
goto found;
}
} else {
@@ -2627,7 +3600,10 @@ uaudio_init_params(struct uaudio_softc *sc, struct chan *ch)
/* XXX allow for some slack */
if (UA_GETSAMP(a1d, j) ==
ch->sample_rate) {
- sc->sc_curaltidx = i;
+ if (mode == AUMODE_PLAY)
+ sc->sc_playchan.altidx = i;
+ else
+ sc->sc_recchan.altidx = i;
goto found;
}
}
@@ -2635,6 +3611,8 @@ uaudio_init_params(struct uaudio_softc *sc, struct chan *ch)
}
}
/* return (EINVAL); */
+ printf("uaudio: This device can't play in rate=%d.\n", ch->sample_rate);
+ return (-1);
found:
#if 0 /* XXX */
@@ -2655,6 +3633,7 @@ uaudio_init_params(struct uaudio_softc *sc, struct chan *ch)
ch->cur = ch->start;
ch->transferred = 0;
ch->curchanbuf = 0;
+ return (0);
}
void
@@ -2665,7 +3644,7 @@ uaudio_query_formats(device_t dev, u_int32_t *pfmt, u_int32_t *rfmt)
u_int32_t fmt;
struct uaudio_softc *sc;
- struct usb_audio_streaming_type1_descriptor *a1d;
+ const struct usb_audio_streaming_type1_descriptor *a1d;
sc = device_get_softc(dev);
@@ -2738,13 +3717,20 @@ uaudio_query_formats(device_t dev, u_int32_t *pfmt, u_int32_t *rfmt)
void
uaudio_chan_set_param_pcm_dma_buff(device_t dev, u_char *start, u_char *end,
- struct pcm_channel *pc)
+ struct pcm_channel *pc, int dir)
{
struct uaudio_softc *sc;
struct chan *ch;
sc = device_get_softc(dev);
- ch = &sc->sc_chan;
+#ifndef NO_RECORDING
+ if (dir == PCMDIR_PLAY)
+ ch = &sc->sc_playchan;
+ else
+ ch = &sc->sc_recchan;
+#else
+ ch = &sc->sc_playchan;
+#endif
ch->start = start;
ch->end = end;
@@ -2755,13 +3741,20 @@ uaudio_chan_set_param_pcm_dma_buff(device_t dev, u_char *start, u_char *end,
}
void
-uaudio_chan_set_param_blocksize(device_t dev, u_int32_t blocksize)
+uaudio_chan_set_param_blocksize(device_t dev, u_int32_t blocksize, int dir)
{
struct uaudio_softc *sc;
struct chan *ch;
sc = device_get_softc(dev);
- ch = &sc->sc_chan;
+#ifndef NO_RECORDING
+ if (dir == PCMDIR_PLAY)
+ ch = &sc->sc_playchan;
+ else
+ ch = &sc->sc_recchan;
+#else
+ ch = &sc->sc_playchan;
+#endif
ch->blksize = blocksize;
@@ -2769,13 +3762,20 @@ uaudio_chan_set_param_blocksize(device_t dev, u_int32_t blocksize)
}
void
-uaudio_chan_set_param_speed(device_t dev, u_int32_t speed)
+uaudio_chan_set_param_speed(device_t dev, u_int32_t speed, int dir)
{
struct uaudio_softc *sc;
struct chan *ch;
sc = device_get_softc(dev);
- ch = &sc->sc_chan;
+#ifndef NO_RECORDING
+ if (dir == PCMDIR_PLAY)
+ ch = &sc->sc_playchan;
+ else
+ ch = &sc->sc_recchan;
+#else
+ ch = &sc->sc_playchan;
+#endif
ch->sample_rate = speed;
@@ -2783,14 +3783,21 @@ uaudio_chan_set_param_speed(device_t dev, u_int32_t speed)
}
int
-uaudio_chan_getptr(device_t dev)
+uaudio_chan_getptr(device_t dev, int dir)
{
struct uaudio_softc *sc;
struct chan *ch;
int ptr;
sc = device_get_softc(dev);
- ch = &sc->sc_chan;
+#ifndef NO_RECORDING
+ if (dir == PCMDIR_PLAY)
+ ch = &sc->sc_playchan;
+ else
+ ch = &sc->sc_recchan;
+#else
+ ch = &sc->sc_playchan;
+#endif
ptr = ch->cur - ch->start;
@@ -2798,13 +3805,20 @@ uaudio_chan_getptr(device_t dev)
}
void
-uaudio_chan_set_param_format(device_t dev, u_int32_t format)
+uaudio_chan_set_param_format(device_t dev, u_int32_t format, int dir)
{
struct uaudio_softc *sc;
struct chan *ch;
sc = device_get_softc(dev);
- ch = &sc->sc_chan;
+#ifndef NO_RECORDING
+ if (dir == PCMDIR_PLAY)
+ ch = &sc->sc_playchan;
+ else
+ ch = &sc->sc_recchan;
+#else
+ ch = &sc->sc_playchan;
+#endif
ch->format = format;
@@ -2819,14 +3833,14 @@ uaudio_halt_out_dma(device_t dev)
sc = device_get_softc(dev);
DPRINTF(("uaudio_halt_out_dma: enter\n"));
- if (sc->sc_chan.pipe != NULL) {
- uaudio_chan_close(sc, &sc->sc_chan);
- sc->sc_chan.pipe = 0;
- uaudio_chan_free_buffers(sc, &sc->sc_chan);
+ if (sc->sc_playchan.pipe != NULL) {
+ uaudio_chan_close(sc, &sc->sc_playchan);
+ sc->sc_playchan.pipe = 0;
+ uaudio_chan_free_buffers(sc, &sc->sc_playchan);
}
return (0);
}
-
+
int
uaudio_trigger_output(device_t dev)
{
@@ -2836,12 +3850,13 @@ uaudio_trigger_output(device_t dev)
int i, s;
sc = device_get_softc(dev);
- ch = &sc->sc_chan;
+ ch = &sc->sc_playchan;
if (sc->sc_dying)
return (EIO);
- uaudio_init_params(sc, ch);
+ if (uaudio_init_params(sc, ch, AUMODE_PLAY))
+ return (EIO);
err = uaudio_chan_alloc_buffers(sc, ch);
if (err)
diff --git a/sys/dev/sound/usb/uaudio.h b/sys/dev/sound/usb/uaudio.h
index 8433c81..3f811e6 100644
--- a/sys/dev/sound/usb/uaudio.h
+++ b/sys/dev/sound/usb/uaudio.h
@@ -30,7 +30,7 @@
/* Defined in uaudio.c, used in uaudio_pcm,c */
void uaudio_chan_set_param_pcm_dma_buff(device_t dev, u_char *start,
- u_char *end, struct pcm_channel *pc);
+ u_char *end, struct pcm_channel *pc, int dir);
int uaudio_trigger_output(device_t dev);
int uaudio_halt_out_dma(device_t dev);
#ifndef NO_RECORDING
@@ -38,12 +38,11 @@ int uaudio_trigger_input(device_t dev);
int uaudio_halt_in_dma(device_t dev);
#endif
void uaudio_chan_set_param(device_t, u_char *, u_char *);
-void uaudio_chan_set_param_blocksize(device_t dev, u_int32_t blocksize);
-void uaudio_chan_set_param_speed(device_t dev, u_int32_t speed);
-void uaudio_chan_set_param_format(device_t dev, u_int32_t format);
-int uaudio_chan_getptr(device_t dev);
+void uaudio_chan_set_param_blocksize(device_t dev, u_int32_t blocksize, int dir);
+void uaudio_chan_set_param_speed(device_t dev, u_int32_t speed, int dir);
+void uaudio_chan_set_param_format(device_t dev, u_int32_t format,int dir);
+int uaudio_chan_getptr(device_t dev, int);
void uaudio_mixer_set(device_t dev, unsigned type, unsigned left,
unsigned right);
u_int32_t uaudio_query_mix_info(device_t dev);
void uaudio_query_formats(device_t dev, u_int32_t *pfmt, u_int32_t *rfmt);
-
diff --git a/sys/dev/sound/usb/uaudio_pcm.c b/sys/dev/sound/usb/uaudio_pcm.c
index cd6366c..89af390 100644
--- a/sys/dev/sound/usb/uaudio_pcm.c
+++ b/sys/dev/sound/usb/uaudio_pcm.c
@@ -89,7 +89,7 @@ ua_chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *
buf = end = sndbuf_getbuf(b);
end += sndbuf_getsize(b);
- uaudio_chan_set_param_pcm_dma_buff(pa_dev, buf, end, ch->channel);
+ uaudio_chan_set_param_pcm_dma_buff(pa_dev, buf, end, ch->channel, dir);
ch->dir = dir;
#ifndef NO_RECORDING
@@ -113,7 +113,7 @@ ua_chan_setformat(kobj_t obj, void *data, u_int32_t format)
ua = ch->parent;
pa_dev = device_get_parent(ua->sc_dev);
- uaudio_chan_set_param_format(pa_dev, format);
+ uaudio_chan_set_param_format(pa_dev, format, ch->dir);
ch->fmt = format;
return 0;
@@ -130,7 +130,7 @@ ua_chan_setspeed(kobj_t obj, void *data, u_int32_t speed)
ua = ch->parent;
pa_dev = device_get_parent(ua->sc_dev);
- uaudio_chan_set_param_speed(pa_dev, speed);
+ uaudio_chan_set_param_speed(pa_dev, speed, ch->dir);
return ch->spd;
}
@@ -151,7 +151,7 @@ ua_chan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
/* XXXXX */
ua = ch->parent;
pa_dev = device_get_parent(ua->sc_dev);
- uaudio_chan_set_param_blocksize(pa_dev, blocksize);
+ uaudio_chan_set_param_blocksize(pa_dev, blocksize, ch->dir);
return ch->blksz;
}
@@ -198,7 +198,7 @@ ua_chan_getptr(kobj_t obj, void *data)
ua = ch->parent;
pa_dev = device_get_parent(ua->sc_dev);
- return uaudio_chan_getptr(pa_dev);
+ return uaudio_chan_getptr(pa_dev, ch->dir);
}
static struct pcmchan_caps *
diff --git a/sys/dev/sound/usb/uaudioreg.h b/sys/dev/sound/usb/uaudioreg.h
index 20c87cb..dd402e2 100644
--- a/sys/dev/sound/usb/uaudioreg.h
+++ b/sys/dev/sound/usb/uaudioreg.h
@@ -1,4 +1,4 @@
-/* $NetBSD: uaudioreg.h,v 1.7 2000/12/28 00:29:58 augustss Exp $ */
+/* $NetBSD: uaudioreg.h,v 1.12 2004/11/05 19:08:29 kent Exp $ */
/* $FreeBSD$ */
/*
@@ -40,7 +40,6 @@
#define UAUDIO_VERSION 0x100
-#define UDESC_CS_DEVICE 0x21
#define UDESC_CS_CONFIG 0x22
#define UDESC_CS_STRING 0x23
#define UDESC_CS_INTERFACE 0x24
@@ -63,7 +62,7 @@ typedef struct {
uByte bmAttributes;
uWord wMaxPacketSize;
uByte bInterval;
- /*
+ /*
* The following two entries are only used by the Audio Class.
* And according to the specs the Audio Class is the only one
* allowed to extend the endpoint descriptor.
@@ -98,6 +97,9 @@ struct usb_audio_streaming_endpoint_descriptor {
uByte bDescriptorType;
uByte bDescriptorSubtype;
uByte bmAttributes;
+#define UA_SED_FREQ_CONTROL 0x01
+#define UA_SED_PITCH_CONTROL 0x02
+#define UA_SED_MAXPACKETSONLY 0x80
uByte bLockDelayUnits;
uWord wLockDelay;
} UPACKED;
@@ -121,9 +123,29 @@ struct usb_audio_streaming_type1_descriptor {
struct usb_audio_cluster {
uByte bNrChannels;
uWord wChannelConfig;
+#define UA_CHANNEL_LEFT 0x0001
+#define UA_CHANNEL_RIGHT 0x0002
+#define UA_CHANNEL_CENTER 0x0004
+#define UA_CHANNEL_LFE 0x0008
+#define UA_CHANNEL_L_SURROUND 0x0010
+#define UA_CHANNEL_R_SURROUND 0x0020
+#define UA_CHANNEL_L_CENTER 0x0040
+#define UA_CHANNEL_R_CENTER 0x0080
+#define UA_CHANNEL_SURROUND 0x0100
+#define UA_CHANNEL_L_SIDE 0x0200
+#define UA_CHANNEL_R_SIDE 0x0400
+#define UA_CHANNEL_TOP 0x0800
uByte iChannelNames;
} UPACKED;
+/* Shared by all units and terminals */
+struct usb_audio_unit {
+ uByte bLength;
+ uByte bDescriptorType;
+ uByte bDescriptorSubtype;
+ uByte bUnitId;
+};
+
/* UDESCSUB_AC_INPUT */
struct usb_audio_input_terminal {
uByte bLength;
@@ -340,8 +362,11 @@ struct usb_audio_extension_unit_1 {
#define UA_FMT_IEEE_FLOAT 3
#define UA_FMT_ALAW 4
#define UA_FMT_MULAW 5
+#define UA_FMT_MPEG 0x1001
+#define UA_FMT_AC3 0x1002
-#define SAMPLING_FREQ_CONTROL 0x01
+#define SAMPLING_FREQ_CONTROL 0x01
+#define PITCH_CONTROL 0x02
#define FORMAT_TYPE_UNDEFINED 0
#define FORMAT_TYPE_I 1
@@ -377,4 +402,3 @@ struct usb_audio_extension_unit_1 {
#define DR_THRESHOLD_CONTROL 4
#define DR_ATTACK_TIME_CONTROL 5
#define DR_RELEASE_TIME_CONTROL 6
-
OpenPOWER on IntegriCloud