svn commit: r240609 - head/sys/dev/sound/usb
Hans Petter Selasky
hselasky at FreeBSD.org
Mon Sep 17 15:43:58 UTC 2012
Author: hselasky
Date: Mon Sep 17 15:43:57 2012
New Revision: 240609
URL: http://svn.freebsd.org/changeset/base/240609
Log:
Implement support for USB Audio v2.0. Remove some redundant
USB audio v1.0 debug data, hence userspace tools like lsusb
exist to show this information properly.
Modified:
head/sys/dev/sound/usb/uaudio.c
head/sys/dev/sound/usb/uaudioreg.h
Modified: head/sys/dev/sound/usb/uaudio.c
==============================================================================
--- head/sys/dev/sound/usb/uaudio.c Mon Sep 17 15:27:30 2012 (r240608)
+++ head/sys/dev/sound/usb/uaudio.c Mon Sep 17 15:43:57 2012 (r240609)
@@ -115,13 +115,28 @@ SYSCTL_INT(_hw_usb_uaudio, OID_AUTO, def
#endif
#define UAUDIO_NFRAMES 64 /* must be factor of 8 due HS-USB */
-#define UAUDIO_NCHANBUFS 2 /* number of outstanding request */
-#define UAUDIO_RECURSE_LIMIT 24 /* rounds */
+#define UAUDIO_NCHANBUFS 2 /* number of outstanding request */
+#define UAUDIO_RECURSE_LIMIT 255 /* rounds */
#define MAKE_WORD(h,l) (((h) << 8) | (l))
#define BIT_TEST(bm,bno) (((bm)[(bno) / 8] >> (7 - ((bno) % 8))) & 1)
#define UAUDIO_MAX_CHAN(x) (x)
+union uaudio_asid {
+ const struct usb_audio_streaming_interface_descriptor *v1;
+ const struct usb_audio20_streaming_interface_descriptor *v2;
+};
+
+union uaudio_asf1d {
+ const struct usb_audio_streaming_type1_descriptor *v1;
+ const struct usb_audio20_streaming_type1_descriptor *v2;
+};
+
+union uaudio_sed {
+ const struct usb_audio_streaming_endpoint_descriptor *v1;
+ const struct usb_audio20_streaming_endpoint_descriptor *v2;
+};
+
struct uaudio_mixer_node {
int32_t minval;
int32_t maxval;
@@ -162,11 +177,9 @@ struct uaudio_chan {
struct uaudio_softc *priv_sc;
struct pcm_channel *pcm_ch;
struct usb_xfer *xfer[UAUDIO_NCHANBUFS];
- const struct usb_audio_streaming_interface_descriptor *p_asid;
- const struct usb_audio_streaming_type1_descriptor *p_asf1d;
- const struct usb_audio_streaming_endpoint_descriptor *p_sed;
+ union uaudio_asf1d p_asf1d;
+ union uaudio_sed p_sed;
const usb_endpoint_descriptor_audio_t *p_ed1;
- const usb_endpoint_descriptor_audio_t *p_ed2;
const struct uaudio_format *p_fmt;
uint8_t *buf; /* pointer to buffer */
@@ -192,6 +205,7 @@ struct uaudio_chan {
uint8_t valid;
uint8_t iface_index;
uint8_t iface_alt_index;
+ uint8_t channels;
};
#define UMIDI_CABLES_MAX 16 /* units */
@@ -242,12 +256,21 @@ struct umidi_chan {
uint8_t single_command;
};
+struct uaudio_search_result {
+ uint8_t bit_input[(256 + 7) / 8];
+ uint8_t bit_output[(256 + 7) / 8];
+ uint8_t recurse_level;
+ uint8_t id_max;
+ uint8_t is_input;
+};
+
struct uaudio_softc {
struct sbuf sc_sndstat;
struct sndcard_func sc_sndcard_func;
struct uaudio_chan sc_rec_chan;
struct uaudio_chan sc_play_chan;
struct umidi_chan sc_midi_chan;
+ struct uaudio_search_result sc_mixer_clocks;
struct usb_device *sc_udev;
struct usb_xfer *sc_mixer_xfer[1];
@@ -273,24 +296,28 @@ struct uaudio_softc {
uint8_t sc_uq_au_vendor_class:1;
};
-struct uaudio_search_result {
- uint8_t bit_input[(256 + 7) / 8];
- uint8_t bit_output[(256 + 7) / 8];
- uint8_t bit_visited[(256 + 7) / 8];
- uint8_t recurse_level;
- uint8_t id_max;
-};
-
struct uaudio_terminal_node {
union {
const struct usb_descriptor *desc;
- const struct usb_audio_input_terminal *it;
- const struct usb_audio_output_terminal *ot;
- const struct usb_audio_mixer_unit_0 *mu;
- const struct usb_audio_selector_unit *su;
- const struct usb_audio_feature_unit *fu;
- const struct usb_audio_processing_unit_0 *pu;
- const struct usb_audio_extension_unit_0 *eu;
+ const struct usb_audio_input_terminal *it_v1;
+ const struct usb_audio_output_terminal *ot_v1;
+ const struct usb_audio_mixer_unit_0 *mu_v1;
+ const struct usb_audio_selector_unit *su_v1;
+ const struct usb_audio_feature_unit *fu_v1;
+ const struct usb_audio_processing_unit_0 *pu_v1;
+ const struct usb_audio_extension_unit_0 *eu_v1;
+ const struct usb_audio20_clock_source_unit *csrc_v2;
+ const struct usb_audio20_clock_selector_unit_0 *csel_v2;
+ const struct usb_audio20_clock_multiplier_unit *cmul_v2;
+ const struct usb_audio20_input_terminal *it_v2;
+ const struct usb_audio20_output_terminal *ot_v2;
+ const struct usb_audio20_mixer_unit_0 *mu_v2;
+ const struct usb_audio20_selector_unit *su_v2;
+ const struct usb_audio20_feature_unit *fu_v2;
+ const struct usb_audio20_sample_rate_unit *ru_v2;
+ const struct usb_audio20_processing_unit_0 *pu_v2;
+ const struct usb_audio20_extension_unit_0 *eu_v2;
+ const struct usb_audio20_effect_unit *ef_v2;
} u;
struct uaudio_search_result usr;
struct uaudio_terminal_node *root;
@@ -303,7 +330,7 @@ struct uaudio_format {
const char *description;
};
-static const struct uaudio_format uaudio_formats[] = {
+static const struct uaudio_format uaudio10_formats[] = {
{UA_FMT_PCM8, 8, AFMT_U8, "8-bit U-LE PCM"},
{UA_FMT_PCM8, 16, AFMT_U16_LE, "16-bit U-LE PCM"},
@@ -321,6 +348,24 @@ static const struct uaudio_format uaudio
{0, 0, 0, NULL}
};
+static const struct uaudio_format uaudio20_formats[] = {
+
+ {UA20_FMT_PCM, 8, AFMT_S8, "8-bit S-LE PCM"},
+ {UA20_FMT_PCM, 16, AFMT_S16_LE, "16-bit S-LE PCM"},
+ {UA20_FMT_PCM, 24, AFMT_S24_LE, "24-bit S-LE PCM"},
+ {UA20_FMT_PCM, 32, AFMT_S32_LE, "32-bit S-LE PCM"},
+
+ {UA20_FMT_PCM8, 8, AFMT_U8, "8-bit U-LE PCM"},
+ {UA20_FMT_PCM8, 16, AFMT_U16_LE, "16-bit U-LE PCM"},
+ {UA20_FMT_PCM8, 24, AFMT_U24_LE, "24-bit U-LE PCM"},
+ {UA20_FMT_PCM8, 32, AFMT_U32_LE, "32-bit U-LE PCM"},
+
+ {UA20_FMT_ALAW, 8, AFMT_A_LAW, "8-bit A-Law"},
+ {UA20_FMT_MULAW, 8, AFMT_MU_LAW, "8-bit mu-Law"},
+
+ {0, 0, 0, NULL}
+};
+
#define UAC_OUTPUT 0
#define UAC_INPUT 1
#define UAC_EQUAL 2
@@ -346,18 +391,8 @@ static usb_callback_t uaudio_mixer_write
static usb_callback_t umidi_bulk_read_callback;
static usb_callback_t umidi_bulk_write_callback;
-static void uaudio_chan_fill_info_sub(struct uaudio_softc *,
- struct usb_device *, uint32_t, uint8_t, uint8_t);
-static void uaudio_chan_fill_info(struct uaudio_softc *,
- struct usb_device *);
-static void uaudio_mixer_add_ctl_sub(struct uaudio_softc *,
- struct uaudio_mixer_node *);
-static void uaudio_mixer_add_ctl(struct uaudio_softc *,
- struct uaudio_mixer_node *);
-static void uaudio_mixer_add_input(struct uaudio_softc *,
- const struct uaudio_terminal_node *, int);
-static void uaudio_mixer_add_output(struct uaudio_softc *,
- const struct uaudio_terminal_node *, int);
+/* ==== USB audio v1.0 ==== */
+
static void uaudio_mixer_add_mixer(struct uaudio_softc *,
const struct uaudio_terminal_node *, int);
static void uaudio_mixer_add_selector(struct uaudio_softc *,
@@ -378,25 +413,56 @@ static uint16_t uaudio_mixer_determine_c
struct uaudio_mixer_node *);
static uint16_t uaudio_mixer_feature_name(const struct uaudio_terminal_node *,
struct uaudio_mixer_node *);
-static const struct uaudio_terminal_node *uaudio_mixer_get_input(
- const struct uaudio_terminal_node *, uint8_t);
-static const struct uaudio_terminal_node *uaudio_mixer_get_output(
- const struct uaudio_terminal_node *, uint8_t);
static void uaudio_mixer_find_inputs_sub(struct uaudio_terminal_node *,
const uint8_t *, uint8_t, struct uaudio_search_result *);
-static void uaudio_mixer_find_outputs_sub(struct uaudio_terminal_node *,
- uint8_t, uint8_t, struct uaudio_search_result *);
+static const void *uaudio_mixer_verify_desc(const void *, uint32_t);
+static usb_error_t uaudio_set_speed(struct usb_device *, uint8_t, uint32_t);
+static int uaudio_mixer_get(struct usb_device *, uint16_t, uint8_t,
+ struct uaudio_mixer_node *);
+
+/* ==== USB audio v2.0 ==== */
+
+static void uaudio20_mixer_add_mixer(struct uaudio_softc *,
+ const struct uaudio_terminal_node *, int);
+static void uaudio20_mixer_add_selector(struct uaudio_softc *,
+ const struct uaudio_terminal_node *, int);
+static void uaudio20_mixer_add_feature(struct uaudio_softc *,
+ const struct uaudio_terminal_node *, int);
+static struct usb_audio20_cluster uaudio20_mixer_get_cluster(uint8_t,
+ const struct uaudio_terminal_node *);
+static uint16_t uaudio20_mixer_determine_class(const struct uaudio_terminal_node *,
+ struct uaudio_mixer_node *);
+static uint16_t uaudio20_mixer_feature_name(const struct uaudio_terminal_node *,
+ struct uaudio_mixer_node *);
+static void uaudio20_mixer_find_inputs_sub(struct uaudio_terminal_node *,
+ const uint8_t *, uint8_t, struct uaudio_search_result *);
+static const void *uaudio20_mixer_verify_desc(const void *, uint32_t);
+static usb_error_t uaudio20_set_speed(struct usb_device *, uint8_t,
+ uint8_t, uint32_t);
+
+/* USB audio v1.0 and v2.0 */
+
+static void uaudio_chan_fill_info_sub(struct uaudio_softc *,
+ struct usb_device *, uint32_t, uint8_t, uint8_t);
+static void uaudio_chan_fill_info(struct uaudio_softc *,
+ struct usb_device *);
+static void uaudio_mixer_add_ctl_sub(struct uaudio_softc *,
+ struct uaudio_mixer_node *);
+static void uaudio_mixer_add_ctl(struct uaudio_softc *,
+ struct uaudio_mixer_node *);
static void uaudio_mixer_fill_info(struct uaudio_softc *,
struct usb_device *, void *);
-static uint16_t uaudio_mixer_get(struct usb_device *, uint8_t,
- struct uaudio_mixer_node *);
static void uaudio_mixer_ctl_set(struct uaudio_softc *,
struct uaudio_mixer_node *, uint8_t, int32_t val);
-static usb_error_t uaudio_set_speed(struct usb_device *, uint8_t, uint32_t);
static int uaudio_mixer_signext(uint8_t, int);
static int uaudio_mixer_bsd2value(struct uaudio_mixer_node *, int32_t val);
-static const void *uaudio_mixer_verify_desc(const void *, uint32_t);
static void uaudio_mixer_init(struct uaudio_softc *);
+static const struct uaudio_terminal_node *uaudio_mixer_get_input(
+ const struct uaudio_terminal_node *, uint8_t);
+static const struct uaudio_terminal_node *uaudio_mixer_get_output(
+ const struct uaudio_terminal_node *, uint8_t);
+static void uaudio_mixer_find_outputs_sub(struct uaudio_terminal_node *,
+ uint8_t, uint8_t, struct uaudio_search_result *);
static uint8_t umidi_convert_to_usb(struct umidi_sub_chan *, uint8_t, uint8_t);
static struct umidi_sub_chan *umidi_sub_by_fifo(struct usb_fifo *);
static void umidi_start_read(struct usb_fifo *);
@@ -413,9 +479,6 @@ static int umidi_detach(device_t dev);
#ifdef USB_DEBUG
static void uaudio_chan_dump_ep_desc(
const usb_endpoint_descriptor_audio_t *);
-static void uaudio_mixer_dump_cluster(uint8_t,
- const struct uaudio_terminal_node *);
-static const char *uaudio_mixer_get_terminal_name(uint16_t);
#endif
static const struct usb_config
@@ -614,10 +677,12 @@ uaudio_attach(device_t dev)
id = usbd_get_interface_descriptor(uaa->iface);
- uaudio_chan_fill_info(sc, uaa->device);
-
+ /* must fill mixer info before channel info */
uaudio_mixer_fill_info(sc, uaa->device, id);
+ /* fill channel info */
+ uaudio_chan_fill_info(sc, uaa->device);
+
DPRINTF("audio rev %d.%02x\n",
sc->sc_audio_rev >> 8,
sc->sc_audio_rev & 0xff);
@@ -628,7 +693,7 @@ uaudio_attach(device_t dev)
if (sc->sc_play_chan.valid) {
device_printf(dev, "Play: %d Hz, %d ch, %s format.\n",
sc->sc_play_chan.sample_rate,
- sc->sc_play_chan.p_asf1d->bNrChannels,
+ sc->sc_play_chan.channels,
sc->sc_play_chan.p_fmt->description);
} else {
device_printf(dev, "No playback.\n");
@@ -637,7 +702,7 @@ uaudio_attach(device_t dev)
if (sc->sc_rec_chan.valid) {
device_printf(dev, "Record: %d Hz, %d ch, %s format.\n",
sc->sc_rec_chan.sample_rate,
- sc->sc_rec_chan.p_asf1d->bNrChannels,
+ sc->sc_play_chan.channels,
sc->sc_rec_chan.p_fmt->description);
} else {
device_printf(dev, "No recording.\n");
@@ -857,28 +922,88 @@ uaudio_record_fix_fs(usb_endpoint_descri
}
}
+static usb_error_t
+uaudio20_check_rate(struct usb_device *udev, uint8_t iface_no,
+ uint8_t clockid, uint32_t rate)
+{
+ struct usb_device_request req;
+ usb_error_t error;
+ uint8_t data[255];
+ uint16_t actlen;
+ uint16_t rates;
+ uint16_t x;
+
+ DPRINTFN(6, "ifaceno=%d clockid=%d rate=%u\n",
+ iface_no, clockid, rate);
+
+ req.bmRequestType = UT_READ_CLASS_INTERFACE;
+ req.bRequest = UA20_CS_RANGE;
+ USETW2(req.wValue, UA20_CS_SAM_FREQ_CONTROL, 0);
+ USETW2(req.wIndex, clockid, iface_no);
+ USETW(req.wLength, 255);
+
+ error = usbd_do_request_flags(udev, NULL, &req, data,
+ USB_SHORT_XFER_OK, &actlen, USB_DEFAULT_TIMEOUT);
+
+ if (error != 0 || actlen < 2)
+ return (USB_ERR_INVAL);
+
+ rates = data[0] | (data[1] << 8);
+ actlen = (actlen - 2) / 12;
+
+ if (rates > actlen) {
+ DPRINTF("Too many rates\n");
+ rates = actlen;
+ }
+
+ for (x = 0; x != rates; x++) {
+ uint32_t min = UGETDW(data + 2 + (12 * x));
+ uint32_t max = UGETDW(data + 6 + (12 * x));
+ uint32_t res = UGETDW(data + 10 + (12 * x));
+
+ if (res == 0) {
+ DPRINTF("Zero residue\n");
+ res = 1;
+ }
+
+ if (min > max) {
+ DPRINTF("Swapped max and min\n");
+ uint32_t temp;
+ temp = min;
+ min = max;
+ max = temp;
+ }
+
+ if (rate >= min && rate <= max &&
+ (((rate - min) % res) == 0)) {
+ return (0);
+ }
+ }
+ return (USB_ERR_INVAL);
+}
+
static void
uaudio_chan_fill_info_sub(struct uaudio_softc *sc, struct usb_device *udev,
uint32_t rate, uint8_t channels, uint8_t bit_resolution)
{
struct usb_descriptor *desc = NULL;
- const struct usb_audio_streaming_interface_descriptor *asid = NULL;
- const struct usb_audio_streaming_type1_descriptor *asf1d = NULL;
- const struct usb_audio_streaming_endpoint_descriptor *sed = NULL;
+ union uaudio_asid asid = { NULL };
+ union uaudio_asf1d asf1d = { NULL };
+ union uaudio_sed sed = { NULL };
usb_endpoint_descriptor_audio_t *ed1 = NULL;
- const usb_endpoint_descriptor_audio_t *ed2 = NULL;
+ const struct usb_audio_control_descriptor *acdp = NULL;
struct usb_config_descriptor *cd = usbd_get_config_descriptor(udev);
struct usb_interface_descriptor *id;
- const struct uaudio_format *p_fmt;
+ const struct uaudio_format *p_fmt = NULL;
struct uaudio_chan *chan;
uint16_t curidx = 0xFFFF;
uint16_t lastidx = 0xFFFF;
uint16_t alt_index = 0;
- uint16_t wFormat;
+ uint16_t audio_rev = 0;
+ uint16_t x;
uint8_t ep_dir;
uint8_t bChannels;
uint8_t bBitResolution;
- uint8_t x;
uint8_t audio_if = 0;
uint8_t uma_if_class;
@@ -923,171 +1048,258 @@ uaudio_chan_fill_info_sub(struct uaudio_
sc->sc_midi_chan.valid = 1;
}
}
- asid = NULL;
- asf1d = NULL;
+ asid.v1 = NULL;
+ asf1d.v1 = NULL;
ed1 = NULL;
- ed2 = NULL;
- sed = NULL;
+ sed.v1 = NULL;
+ }
+
+ if ((acdp == NULL) &&
+ (desc->bDescriptorType == UDESC_CS_INTERFACE) &&
+ (desc->bDescriptorSubtype == AS_GENERAL) &&
+ (desc->bDescriptorSubtype == UDESCSUB_AC_HEADER) &&
+ (desc->bLength >= sizeof(*acdp))) {
+ acdp = (void *)desc;
+ audio_rev = UGETW(acdp->bcdADC);
}
- if ((desc->bDescriptorType == UDESC_CS_INTERFACE) &&
+
+ if ((acdp != NULL) &&
+ (desc->bDescriptorType == UDESC_CS_INTERFACE) &&
(desc->bDescriptorSubtype == AS_GENERAL) &&
- (desc->bLength >= sizeof(*asid))) {
- if (asid == NULL) {
- asid = (void *)desc;
+ (asid.v1 == NULL)) {
+ if (audio_rev >= UAUDIO_VERSION_30) {
+ /* FALLTHROUGH */
+ } else if (audio_rev >= UAUDIO_VERSION_20) {
+ if (desc->bLength >= sizeof(*asid.v2)) {
+ asid.v2 = (void *)desc;
+ }
+ } else {
+ if (desc->bLength >= sizeof(*asid.v1)) {
+ asid.v1 = (void *)desc;
+ }
}
}
- if ((desc->bDescriptorType == UDESC_CS_INTERFACE) &&
+ if ((acdp != NULL) &&
+ (desc->bDescriptorType == UDESC_CS_INTERFACE) &&
(desc->bDescriptorSubtype == FORMAT_TYPE) &&
- (desc->bLength >= sizeof(*asf1d))) {
- if (asf1d == NULL) {
- asf1d = (void *)desc;
- if (asf1d->bFormatType != FORMAT_TYPE_I) {
- DPRINTFN(11, "ignored bFormatType = %d\n",
- asf1d->bFormatType);
- asf1d = NULL;
- continue;
- }
- if (asf1d->bLength < (sizeof(*asf1d) +
- ((asf1d->bSamFreqType == 0) ? 6 :
- (asf1d->bSamFreqType * 3)))) {
- DPRINTFN(11, "'asf1d' descriptor is too short\n");
- asf1d = NULL;
- continue;
+ (asf1d.v1 == NULL)) {
+ if (audio_rev >= UAUDIO_VERSION_30) {
+ /* FALLTHROUGH */
+ } else if (audio_rev >= UAUDIO_VERSION_20) {
+ if (desc->bLength >= sizeof(*asf1d.v2))
+ asf1d.v2 = (void *)desc;
+ } else {
+ if (desc->bLength >= sizeof(*asf1d.v1)) {
+ asf1d.v1 = (void *)desc;
+
+ if (asf1d.v1->bFormatType != FORMAT_TYPE_I) {
+ DPRINTFN(11, "ignored bFormatType = %d\n",
+ asf1d.v1->bFormatType);
+ asf1d.v1 = NULL;
+ continue;
+ }
+ if (desc->bLength < (sizeof(*asf1d.v1) +
+ ((asf1d.v1->bSamFreqType == 0) ? 6 :
+ (asf1d.v1->bSamFreqType * 3)))) {
+ DPRINTFN(11, "invalid descriptor, "
+ "too short\n");
+ asf1d.v1 = NULL;
+ continue;
+ }
}
}
}
if ((desc->bDescriptorType == UDESC_ENDPOINT) &&
- (desc->bLength >= UEP_MINSIZE)) {
- if (ed1 == NULL) {
- ed1 = (void *)desc;
- if (UE_GET_XFERTYPE(ed1->bmAttributes) != UE_ISOCHRONOUS) {
- ed1 = NULL;
- }
+ (desc->bLength >= UEP_MINSIZE) &&
+ (ed1 == NULL)) {
+ ed1 = (void *)desc;
+ if (UE_GET_XFERTYPE(ed1->bmAttributes) != UE_ISOCHRONOUS) {
+ ed1 = NULL;
+ continue;
}
}
- if ((desc->bDescriptorType == UDESC_CS_ENDPOINT) &&
+ if ((acdp != NULL) &&
+ (desc->bDescriptorType == UDESC_CS_ENDPOINT) &&
(desc->bDescriptorSubtype == AS_GENERAL) &&
- (desc->bLength >= sizeof(*sed))) {
- if (sed == NULL) {
- sed = (void *)desc;
+ (sed.v1 == NULL)) {
+ if (audio_rev >= UAUDIO_VERSION_30) {
+ /* FALLTHROUGH */
+ } else if (audio_rev >= UAUDIO_VERSION_20) {
+ if (desc->bLength >= sizeof(*sed.v2))
+ sed.v2 = (void *)desc;
+ } else {
+ if (desc->bLength >= sizeof(*sed.v1))
+ sed.v1 = (void *)desc;
}
}
- if (audio_if && asid && asf1d && ed1 && sed) {
+ if (audio_if == 0 || asid.v1 == NULL ||
+ asf1d.v1 == NULL || ed1 == NULL ||
+ sed.v1 == NULL) {
+ /* need more descriptors */
+ continue;
+ }
+
+ ep_dir = UE_GET_DIR(ed1->bEndpointAddress);
+
+ /* We ignore sync endpoint information until further. */
+
+ if (audio_rev >= UAUDIO_VERSION_30) {
+ goto next_ep;
+ } else if (audio_rev >= UAUDIO_VERSION_20) {
+
+ uint32_t dwFormat;
+ uint8_t bSubslotSize;
+
+ dwFormat = UGETDW(asid.v2->bmFormats);
+ bChannels = asid.v2->bNrChannels;
+ bBitResolution = asf1d.v2->bBitResolution;
+ bSubslotSize = asf1d.v2->bSubslotSize;
+
+ if (bBitResolution != (bSubslotSize * 8)) {
+ DPRINTF("Invalid bSubslotSize\n");
+ goto next_ep;
+ }
+
+ if ((bChannels != channels) ||
+ (bBitResolution != bit_resolution)) {
+ DPRINTF("Wrong number of channels\n");
+ goto next_ep;
+ }
+
+ for (p_fmt = uaudio20_formats;
+ p_fmt->wFormat != 0; p_fmt++) {
+ if ((p_fmt->wFormat & dwFormat) &&
+ (p_fmt->bPrecision == bBitResolution))
+ break;
+ }
+
+ if (p_fmt->wFormat == 0) {
+ DPRINTF("Unsupported audio format\n");
+ goto next_ep;
+ }
+
+ for (x = 0; x != 256; x++) {
+ if (ep_dir == UE_DIR_OUT) {
+ if (!(sc->sc_mixer_clocks.bit_output[x / 8] &
+ (1 << (x % 8)))) {
+ continue;
+ }
+ } else {
+ if (!(sc->sc_mixer_clocks.bit_input[x / 8] &
+ (1 << (x % 8)))) {
+ continue;
+ }
+ }
- ep_dir = UE_GET_DIR(ed1->bEndpointAddress);
+ DPRINTF("Checking clock ID=%d\n", x);
- /* We ignore sync endpoint information until further. */
+ if (uaudio20_check_rate(udev,
+ sc->sc_mixer_iface_no, x, rate)) {
+ DPRINTF("Unsupported sampling "
+ "rate, id=%d\n", x);
+ goto next_ep;
+ }
+ }
+ } else {
+ uint16_t wFormat;
- wFormat = UGETW(asid->wFormatTag);
- bChannels = UAUDIO_MAX_CHAN(asf1d->bNrChannels);
- bBitResolution = asf1d->bBitResolution;
+ wFormat = UGETW(asid.v1->wFormatTag);
+ bChannels = UAUDIO_MAX_CHAN(asf1d.v1->bNrChannels);
+ bBitResolution = asf1d.v1->bBitResolution;
- if (asf1d->bSamFreqType == 0) {
+ if (asf1d.v1->bSamFreqType == 0) {
DPRINTFN(16, "Sample rate: %d-%dHz\n",
- UA_SAMP_LO(asf1d), UA_SAMP_HI(asf1d));
+ UA_SAMP_LO(asf1d.v1),
+ UA_SAMP_HI(asf1d.v1));
- if ((rate >= UA_SAMP_LO(asf1d)) &&
- (rate <= UA_SAMP_HI(asf1d))) {
+ if ((rate >= UA_SAMP_LO(asf1d.v1)) &&
+ (rate <= UA_SAMP_HI(asf1d.v1)))
goto found_rate;
- }
} else {
- for (x = 0; x < asf1d->bSamFreqType; x++) {
+ for (x = 0; x < asf1d.v1->bSamFreqType; x++) {
DPRINTFN(16, "Sample rate = %dHz\n",
- UA_GETSAMP(asf1d, x));
+ UA_GETSAMP(asf1d.v1, x));
- if (rate == UA_GETSAMP(asf1d, x)) {
+ if (rate == UA_GETSAMP(asf1d.v1, x))
goto found_rate;
- }
}
}
-
- audio_if = 0;
- continue;
+ goto next_ep;
found_rate:
-
- for (p_fmt = uaudio_formats;
- p_fmt->wFormat;
- p_fmt++) {
+ for (p_fmt = uaudio10_formats;
+ p_fmt->wFormat != 0; p_fmt++) {
if ((p_fmt->wFormat == wFormat) &&
- (p_fmt->bPrecision == bBitResolution)) {
- goto found_format;
- }
+ (p_fmt->bPrecision == bBitResolution))
+ break;
+ }
+ if (p_fmt->wFormat == 0) {
+ DPRINTF("Unsupported audio format\n");
+ goto next_ep;
}
- audio_if = 0;
- continue;
-
- found_format:
-
- if ((bChannels == channels) &&
- (bBitResolution == bit_resolution)) {
+ if ((bChannels != channels) ||
+ (bBitResolution != bit_resolution)) {
+ DPRINTF("Wrong number of channels\n");
+ goto next_ep;
+ }
+ }
- chan = (ep_dir == UE_DIR_IN) ?
- &sc->sc_rec_chan :
- &sc->sc_play_chan;
+ chan = (ep_dir == UE_DIR_IN) ?
+ &sc->sc_rec_chan : &sc->sc_play_chan;
- if ((chan->valid == 0) && usbd_get_iface(udev, curidx)) {
+ if (chan->valid != 0 ||
+ usbd_get_iface(udev, curidx) == NULL) {
+ DPRINTF("Channel already exists or "
+ "interface is not valid\n");
+ goto next_ep;
+ }
- chan->valid = 1;
+ chan->valid = 1;
#ifdef USB_DEBUG
- uaudio_chan_dump_ep_desc(ed1);
- uaudio_chan_dump_ep_desc(ed2);
-
- if (sed->bmAttributes & UA_SED_FREQ_CONTROL) {
- DPRINTFN(2, "FREQ_CONTROL\n");
- }
- if (sed->bmAttributes & UA_SED_PITCH_CONTROL) {
- DPRINTFN(2, "PITCH_CONTROL\n");
- }
+ uaudio_chan_dump_ep_desc(ed1);
#endif
- DPRINTF("Sample rate = %dHz, channels = %d, "
- "bits = %d, format = %s\n", rate, channels,
- bit_resolution, p_fmt->description);
-
- chan->sample_rate = rate;
- chan->p_asid = asid;
- chan->p_asf1d = asf1d;
- chan->p_ed1 = ed1;
- chan->p_ed2 = ed2;
- chan->p_fmt = p_fmt;
- chan->p_sed = sed;
- chan->iface_index = curidx;
- chan->iface_alt_index = alt_index;
-
- if (ep_dir == UE_DIR_IN)
- chan->usb_cfg =
- uaudio_cfg_record;
- else
- chan->usb_cfg =
- uaudio_cfg_play;
-
- chan->sample_size = ((
- UAUDIO_MAX_CHAN(chan->p_asf1d->bNrChannels) *
- chan->p_asf1d->bBitResolution) / 8);
-
- if (ep_dir == UE_DIR_IN &&
- usbd_get_speed(udev) == USB_SPEED_FULL) {
- uaudio_record_fix_fs(ed1,
- chan->sample_size * (rate / 1000),
- chan->sample_size * (rate / 4000));
- }
+ DPRINTF("Sample rate = %dHz, channels = %d, "
+ "bits = %d, format = %s\n", rate, channels,
+ bit_resolution, p_fmt->description);
+
+ chan->sample_rate = rate;
+ chan->p_asf1d = asf1d;
+ chan->p_ed1 = ed1;
+ chan->p_fmt = p_fmt;
+ chan->p_sed = sed;
+ chan->iface_index = curidx;
+ chan->iface_alt_index = alt_index;
- if (sc->sc_sndstat_valid) {
- sbuf_printf(&sc->sc_sndstat, "\n\t"
- "mode %d.%d:(%s) %dch, %d/%dbit, %s, %dHz",
- curidx, alt_index,
- (ep_dir == UE_DIR_IN) ? "input" : "output",
- asf1d->bNrChannels, asf1d->bBitResolution,
- asf1d->bSubFrameSize * 8,
- p_fmt->description, rate);
- }
- }
- }
- audio_if = 0;
- continue;
- }
+ if (ep_dir == UE_DIR_IN)
+ chan->usb_cfg = uaudio_cfg_record;
+ else
+ chan->usb_cfg = uaudio_cfg_play;
+
+ chan->sample_size = (UAUDIO_MAX_CHAN(channels) *
+ p_fmt->bPrecision) / 8;
+ chan->channels = channels;
+
+ if (ep_dir == UE_DIR_IN &&
+ usbd_get_speed(udev) == USB_SPEED_FULL) {
+ uaudio_record_fix_fs(ed1,
+ chan->sample_size * (rate / 1000),
+ chan->sample_size * (rate / 4000));
+ }
+
+ if (sc->sc_sndstat_valid != 0) {
+ sbuf_printf(&sc->sc_sndstat, "\n\t"
+ "mode %d.%d:(%s) %dch, %dbit, %s, %dHz",
+ curidx, alt_index,
+ (ep_dir == UE_DIR_IN) ? "input" : "output",
+ channels, p_fmt->bPrecision,
+ p_fmt->description, rate);
+ }
+
+ next_ep:
+ sed.v1 = NULL;
+ ed1 = NULL;
}
}
@@ -1390,7 +1602,7 @@ uaudio_chan_init(struct uaudio_softc *sc
format = ch->p_fmt->freebsd_fmt;
- switch (ch->p_asf1d->bNrChannels) {
+ switch (ch->channels) {
case 2:
/* stereo */
format = SND_FORMAT(format, 2, 0);
@@ -1402,7 +1614,7 @@ uaudio_chan_init(struct uaudio_softc *sc
default:
/* surround and more */
format = feeder_matrix_default_format(
- SND_FORMAT(format, ch->p_asf1d->bNrChannels, 0));
+ SND_FORMAT(format, ch->channels, 0));
break;
}
@@ -1438,13 +1650,43 @@ uaudio_chan_init(struct uaudio_softc *sc
* Only set the sample rate if the channel reports that it
* supports the frequency control.
*/
- if (ch->p_sed->bmAttributes & UA_SED_FREQ_CONTROL) {
+
+ if (sc->sc_audio_rev >= UAUDIO_VERSION_30) {
+ /* FALLTHROUGH */
+ } else if (sc->sc_audio_rev >= UAUDIO_VERSION_20) {
+ unsigned int x;
+
+ for (x = 0; x != 256; x++) {
+ if (dir == PCMDIR_PLAY) {
+ if (!(sc->sc_mixer_clocks.bit_output[x / 8] &
+ (1 << (x % 8)))) {
+ continue;
+ }
+ } else {
+ if (!(sc->sc_mixer_clocks.bit_input[x / 8] &
+ (1 << (x % 8)))) {
+ continue;
+ }
+ }
+
+ if (uaudio20_set_speed(sc->sc_udev,
+ sc->sc_mixer_iface_no, x, ch->sample_rate)) {
+ /*
+ * If the endpoint is adaptive setting
+ * the speed may fail.
+ */
+ DPRINTF("setting of sample rate failed! "
+ "(continuing anyway)\n");
+ }
+ }
+ } else if (ch->p_sed.v1->bmAttributes & UA_SED_FREQ_CONTROL) {
if (uaudio_set_speed(sc->sc_udev, endpoint, ch->sample_rate)) {
/*
- * If the endpoint is adaptive setting the speed may
- * fail.
+ * If the endpoint is adaptive setting the
+ * speed may fail.
*/
- DPRINTF("setting of sample rate failed! (continuing anyway)\n");
+ DPRINTF("setting of sample rate failed! "
+ "(continuing anyway)\n");
}
}
if (usbd_transfer_setup(sc->sc_udev, &iface_index, ch->xfer,
@@ -1679,13 +1921,10 @@ uaudio_mixer_add_ctl(struct uaudio_softc
/* determine min and max values */
- mc->minval = uaudio_mixer_get(sc->sc_udev, GET_MIN, mc);
-
- mc->minval = uaudio_mixer_signext(mc->type, mc->minval);
-
- mc->maxval = uaudio_mixer_get(sc->sc_udev, GET_MAX, mc);
-
- mc->maxval = uaudio_mixer_signext(mc->type, mc->maxval);
+ mc->minval = uaudio_mixer_get(sc->sc_udev,
+ sc->sc_audio_rev, GET_MIN, mc);
+ mc->maxval = uaudio_mixer_get(sc->sc_udev,
+ sc->sc_audio_rev, GET_MAX, mc);
/* check if max and min was swapped */
@@ -1701,7 +1940,8 @@ uaudio_mixer_add_ctl(struct uaudio_softc
mc->mul = 1;
/* compute value alignment */
- res = uaudio_mixer_get(sc->sc_udev, GET_RES, mc);
+ res = uaudio_mixer_get(sc->sc_udev,
+ sc->sc_audio_rev, GET_RES, mc);
DPRINTF("Resolution = %d\n", (int)res);
}
@@ -1724,42 +1964,12 @@ uaudio_mixer_add_ctl(struct uaudio_softc
}
static void
-uaudio_mixer_add_input(struct uaudio_softc *sc,
- const struct uaudio_terminal_node *iot, int id)
-{
-#ifdef USB_DEBUG
- const struct usb_audio_input_terminal *d = iot[id].u.it;
-
- DPRINTFN(3, "bTerminalId=%d wTerminalType=0x%04x "
- "bAssocTerminal=%d bNrChannels=%d wChannelConfig=%d "
- "iChannelNames=%d\n",
- d->bTerminalId, UGETW(d->wTerminalType), d->bAssocTerminal,
- d->bNrChannels, UGETW(d->wChannelConfig),
- d->iChannelNames);
-#endif
-}
-
-static void
-uaudio_mixer_add_output(struct uaudio_softc *sc,
- const struct uaudio_terminal_node *iot, int id)
-{
-#ifdef USB_DEBUG
- const struct usb_audio_output_terminal *d = iot[id].u.ot;
-
- DPRINTFN(3, "bTerminalId=%d wTerminalType=0x%04x "
- "bAssocTerminal=%d bSourceId=%d iTerminal=%d\n",
- d->bTerminalId, UGETW(d->wTerminalType), d->bAssocTerminal,
- d->bSourceId, d->iTerminal);
-#endif
-}
-
-static void
uaudio_mixer_add_mixer(struct uaudio_softc *sc,
const struct uaudio_terminal_node *iot, int id)
{
struct uaudio_mixer_node mix;
- const struct usb_audio_mixer_unit_0 *d0 = iot[id].u.mu;
+ const struct usb_audio_mixer_unit_0 *d0 = iot[id].u.mu_v1;
const struct usb_audio_mixer_unit_1 *d1;
uint32_t bno; /* bit number */
@@ -1780,8 +1990,8 @@ uaudio_mixer_add_mixer(struct uaudio_sof
ichs = 0;
for (i = 0; i < d0->bNrInPins; i++) {
- ichs += (uaudio_mixer_get_cluster(d0->baSourceId[i], iot)
- .bNrChannels);
+ ichs += uaudio_mixer_get_cluster(
+ d0->baSourceId[i], iot).bNrChannels;
}
d1 = (const void *)(d0->baSourceId + d0->bNrInPins);
@@ -1798,23 +2008,22 @@ uaudio_mixer_add_mixer(struct uaudio_sof
uaudio_mixer_determine_class(&iot[id], &mix);
mix.type = MIX_SIGNED_16;
- if (uaudio_mixer_verify_desc(d0, ((ichs * ochs) + 7) / 8) == NULL) {
+ if (uaudio_mixer_verify_desc(d0, ((ichs * ochs) + 7) / 8) == NULL)
return;
- }
+
for (p = i = 0; i < d0->bNrInPins; i++) {
- chs = uaudio_mixer_get_cluster(d0->baSourceId[i], iot).bNrChannels;
+ chs = uaudio_mixer_get_cluster(
+ d0->baSourceId[i], iot).bNrChannels;
mc = 0;
for (c = 0; c < chs; c++) {
mo = 0;
for (o = 0; o < ochs; o++) {
bno = ((p + c) * ochs) + o;
- if (BIT_TEST(d1->bmControls, bno)) {
+ if (BIT_TEST(d1->bmControls, bno))
mo++;
- }
}
- if (mo == 1) {
+ if (mo == 1)
mc++;
- }
}
if ((mc == chs) && (chs <= MIX_MAX_CHAN)) {
@@ -1824,62 +2033,183 @@ uaudio_mixer_add_mixer(struct uaudio_sof
for (c = 0; c < chs; c++) {
for (o = 0; o < ochs; o++) {
bno = ((p + c) * ochs) + o;
- if (BIT_TEST(d1->bmControls, bno)) {
+ if (BIT_TEST(d1->bmControls, bno))
mix.wValue[mc++] = MAKE_WORD(p + c + 1, o + 1);
- }
}
}
mix.nchan = chs;
uaudio_mixer_add_ctl(sc, &mix);
- } else {
- /* XXX */
}
p += chs;
}
}
static void
-uaudio_mixer_add_selector(struct uaudio_softc *sc,
+uaudio20_mixer_add_mixer(struct uaudio_softc *sc,
const struct uaudio_terminal_node *iot, int id)
{
- const struct usb_audio_selector_unit *d = iot[id].u.su;
struct uaudio_mixer_node mix;
- uint16_t i;
- DPRINTFN(3, "bUnitId=%d bNrInPins=%d\n",
- d->bUnitId, d->bNrInPins);
+ const struct usb_audio20_mixer_unit_0 *d0 = iot[id].u.mu_v2;
+ const struct usb_audio20_mixer_unit_1 *d1;
- if (d->bNrInPins == 0) {
- return;
- }
- memset(&mix, 0, sizeof(mix));
+ uint32_t bno; /* bit number */
+ uint32_t p; /* bit number accumulator */
+ uint32_t mo; /* matching outputs */
+ uint32_t mc; /* matching channels */
+ uint32_t ichs; /* input channels */
+ uint32_t ochs; /* output channels */
+ uint32_t c;
+ uint32_t chs; /* channels */
+ uint32_t i;
+ uint32_t o;
- mix.wIndex = MAKE_WORD(d->bUnitId, sc->sc_mixer_iface_no);
- mix.wValue[0] = MAKE_WORD(0, 0);
- uaudio_mixer_determine_class(&iot[id], &mix);
- mix.nchan = 1;
- mix.type = MIX_SELECTOR;
+ DPRINTFN(3, "bUnitId=%d bNrInPins=%d\n",
+ d0->bUnitId, d0->bNrInPins);
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-head
mailing list