summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2010-05-29 21:50:33 +0200
committerTakashi Iwai <tiwai@suse.de>2010-05-29 21:50:33 +0200
commita98d3984c85222aa9efc63c4f9dd3d805ce469f2 (patch)
treeaeb9ebdcc06ca92b8114f30cedf16b8f3780b3f2
parent52593de4c11fb24c83d8036ba34706881aab5e3d (diff)
parent55567ab70bd8551c73253e44ea5244db41eac81b (diff)
Merge branch 'fix/misc' into for-linus
-rw-r--r--include/linux/usb/audio-v2.h16
-rw-r--r--sound/mips/au1x00.c1
-rw-r--r--sound/oss/dmasound/dmasound_atari.c5
-rw-r--r--sound/pci/asihpi/hpi.h8
-rw-r--r--sound/pci/asihpi/hpi6000.c6
-rw-r--r--sound/pci/asihpi/hpi6205.c21
-rw-r--r--sound/pci/asihpi/hpi_internal.h5
-rw-r--r--sound/pci/asihpi/hpicmn.c38
-rw-r--r--sound/pci/asihpi/hpifunc.c17
-rw-r--r--sound/pci/asihpi/hpios.c23
-rw-r--r--sound/pci/asihpi/hpios.h9
-rw-r--r--sound/usb/caiaq/control.c36
-rw-r--r--sound/usb/caiaq/device.c8
-rw-r--r--sound/usb/endpoint.c64
-rw-r--r--sound/usb/format.c24
-rw-r--r--sound/usb/format.h7
-rw-r--r--sound/usb/mixer.c2
-rw-r--r--sound/usb/pcm.c37
18 files changed, 170 insertions, 157 deletions
diff --git a/include/linux/usb/audio-v2.h b/include/linux/usb/audio-v2.h
index 2389f93a28b..92f1d99f0f1 100644
--- a/include/linux/usb/audio-v2.h
+++ b/include/linux/usb/audio-v2.h
@@ -105,6 +105,22 @@ struct uac_as_header_descriptor_v2 {
__u8 iChannelNames;
} __attribute__((packed));
+/* 4.10.1.2 Class-Specific AS Isochronous Audio Data Endpoint Descriptor */
+
+struct uac2_iso_endpoint_descriptor {
+ __u8 bLength; /* in bytes: 8 */
+ __u8 bDescriptorType; /* USB_DT_CS_ENDPOINT */
+ __u8 bDescriptorSubtype; /* EP_GENERAL */
+ __u8 bmAttributes;
+ __u8 bmControls;
+ __u8 bLockDelayUnits;
+ __le16 wLockDelay;
+} __attribute__((packed));
+
+#define UAC2_CONTROL_PITCH (3 << 0)
+#define UAC2_CONTROL_DATA_OVERRUN (3 << 2)
+#define UAC2_CONTROL_DATA_UNDERRUN (3 << 4)
+
/* 6.1 Interrupt Data Message */
#define UAC2_INTERRUPT_DATA_MSG_VENDOR (1 << 0)
diff --git a/sound/mips/au1x00.c b/sound/mips/au1x00.c
index 3e763d6a5d6..446cf974866 100644
--- a/sound/mips/au1x00.c
+++ b/sound/mips/au1x00.c
@@ -516,6 +516,7 @@ get the interrupt driven case to work efficiently */
break;
if (i == 0x5000) {
printk(KERN_ERR "au1000 AC97: AC97 command read timeout\n");
+ spin_unlock(&au1000->ac97_lock);
return 0;
}
diff --git a/sound/oss/dmasound/dmasound_atari.c b/sound/oss/dmasound/dmasound_atari.c
index 1f477412306..13c214466d3 100644
--- a/sound/oss/dmasound/dmasound_atari.c
+++ b/sound/oss/dmasound/dmasound_atari.c
@@ -1277,7 +1277,7 @@ static irqreturn_t AtaInterrupt(int irq, void *dummy)
* (almost) like on the TT.
*/
write_sq_ignore_int = 0;
- return IRQ_HANDLED;
+ goto out;
}
if (!write_sq.active) {
@@ -1285,7 +1285,7 @@ static irqreturn_t AtaInterrupt(int irq, void *dummy)
* the sq variables, so better don't do anything here.
*/
WAKE_UP(write_sq.sync_queue);
- return IRQ_HANDLED;
+ goto out;
}
/* Probably ;) one frame is finished. Well, in fact it may be that a
@@ -1322,6 +1322,7 @@ static irqreturn_t AtaInterrupt(int irq, void *dummy)
/* We are not playing after AtaPlay(), so there
is nothing to play any more. Wake up a process
waiting for audio output to drain. */
+out:
spin_unlock(&dmasound.lock);
return IRQ_HANDLED;
}
diff --git a/sound/pci/asihpi/hpi.h b/sound/pci/asihpi/hpi.h
index 99400de6c07..0173bbe62b6 100644
--- a/sound/pci/asihpi/hpi.h
+++ b/sound/pci/asihpi/hpi.h
@@ -50,7 +50,7 @@ i.e 3.05.02 is a development version
#define HPI_VER_RELEASE(v) ((int)(v & 0xFF))
/* Use single digits for versions less that 10 to avoid octal. */
-#define HPI_VER HPI_VERSION_CONSTRUCTOR(4L, 3, 18)
+#define HPI_VER HPI_VERSION_CONSTRUCTOR(4L, 3, 25)
/* Library version as documented in hpi-api-versions.txt */
#define HPI_LIB_VER HPI_VERSION_CONSTRUCTOR(9, 0, 0)
@@ -1632,6 +1632,12 @@ u16 hpi_tuner_get_hd_radio_sdk_version(const struct hpi_hsubsys *ph_subsys,
u16 hpi_tuner_get_hd_radio_signal_quality(const struct hpi_hsubsys *ph_subsys,
u32 h_control, u32 *pquality);
+u16 hpi_tuner_get_hd_radio_signal_blend(const struct hpi_hsubsys *ph_subsys,
+ u32 h_control, u32 *pblend);
+
+u16 hpi_tuner_set_hd_radio_signal_blend(const struct hpi_hsubsys *ph_subsys,
+ u32 h_control, const u32 blend);
+
/****************************/
/* PADs control */
/****************************/
diff --git a/sound/pci/asihpi/hpi6000.c b/sound/pci/asihpi/hpi6000.c
index 839ecb2e4b6..12dab5e4892 100644
--- a/sound/pci/asihpi/hpi6000.c
+++ b/sound/pci/asihpi/hpi6000.c
@@ -691,9 +691,6 @@ static short hpi6000_adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
case 0x6200:
boot_load_family = HPI_ADAPTER_FAMILY_ASI(0x6200);
break;
- case 0x8800:
- boot_load_family = HPI_ADAPTER_FAMILY_ASI(0x8800);
- break;
default:
return HPI6000_ERROR_UNHANDLED_SUBSYS_ID;
}
@@ -1775,7 +1772,6 @@ static void hw_message(struct hpi_adapter_obj *pao, struct hpi_message *phm,
u16 error = 0;
u16 dsp_index = 0;
u16 num_dsp = ((struct hpi_hw_obj *)pao->priv)->num_dsp;
- hpios_dsplock_lock(pao);
if (num_dsp < 2)
dsp_index = 0;
@@ -1796,6 +1792,8 @@ static void hw_message(struct hpi_adapter_obj *pao, struct hpi_message *phm,
}
}
}
+
+ hpios_dsplock_lock(pao);
error = hpi6000_message_response_sequence(pao, dsp_index, phm, phr);
/* maybe an error response */
diff --git a/sound/pci/asihpi/hpi6205.c b/sound/pci/asihpi/hpi6205.c
index 5e88c1fc2b9..e89991ea354 100644
--- a/sound/pci/asihpi/hpi6205.c
+++ b/sound/pci/asihpi/hpi6205.c
@@ -966,23 +966,16 @@ static void outstream_write(struct hpi_adapter_obj *pao,
status = &interface->outstream_host_buffer_status[phm->obj_index];
if (phw->flag_outstream_just_reset[phm->obj_index]) {
- /* Format can only change after reset. Must tell DSP. */
- u16 function = phm->function;
- phw->flag_outstream_just_reset[phm->obj_index] = 0;
- phm->function = HPI_OSTREAM_SET_FORMAT;
- hw_message(pao, phm, phr); /* send the format to the DSP */
- phm->function = function;
- if (phr->error)
- return;
- }
-#if 1
- if (phw->flag_outstream_just_reset[phm->obj_index]) {
/* First OutStremWrite() call following reset will write data to the
- adapter's buffers, reducing delay before stream can start
+ adapter's buffers, reducing delay before stream can start. The DSP
+ takes care of setting the stream data format using format information
+ embedded in phm.
*/
int partial_write = 0;
unsigned int original_size = 0;
+ phw->flag_outstream_just_reset[phm->obj_index] = 0;
+
/* Send the first buffer to the DSP the old way. */
/* Limit size of first transfer - */
/* expect that this will not usually be triggered. */
@@ -1012,7 +1005,6 @@ static void outstream_write(struct hpi_adapter_obj *pao,
original_size - HPI6205_SIZEOF_DATA;
phm->u.d.u.data.pb_data += HPI6205_SIZEOF_DATA;
}
-#endif
space_available = outstream_get_space_available(status);
if (space_available < (long)phm->u.d.u.data.data_size) {
@@ -1369,6 +1361,9 @@ static u16 adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
case HPI_ADAPTER_FAMILY_ASI(0x6500):
firmware_id = HPI_ADAPTER_FAMILY_ASI(0x6600);
break;
+ case HPI_ADAPTER_FAMILY_ASI(0x8800):
+ firmware_id = HPI_ADAPTER_FAMILY_ASI(0x8900);
+ break;
}
boot_code_id[1] = firmware_id;
diff --git a/sound/pci/asihpi/hpi_internal.h b/sound/pci/asihpi/hpi_internal.h
index f1cd6f1a0d4..fdd0ce02aa6 100644
--- a/sound/pci/asihpi/hpi_internal.h
+++ b/sound/pci/asihpi/hpi_internal.h
@@ -232,6 +232,8 @@ enum HPI_BUSES {
#define HPI_TUNER_HDRADIO_SDK_VERSION HPI_CTL_ATTR(TUNER, 13)
/** HD Radio DSP firmware version. */
#define HPI_TUNER_HDRADIO_DSP_VERSION HPI_CTL_ATTR(TUNER, 14)
+/** HD Radio signal blend (force analog, or automatic). */
+#define HPI_TUNER_HDRADIO_BLEND HPI_CTL_ATTR(TUNER, 15)
/** \} */
@@ -478,8 +480,10 @@ Threshold is a -ve number in units of dB/100,
/** First 2 hex digits define the adapter family */
#define HPI_ADAPTER_FAMILY_MASK 0xff00
+#define HPI_MODULE_FAMILY_MASK 0xfff0
#define HPI_ADAPTER_FAMILY_ASI(f) (f & HPI_ADAPTER_FAMILY_MASK)
+#define HPI_MODULE_FAMILY_ASI(f) (f & HPI_MODULE_FAMILY_MASK)
#define HPI_ADAPTER_ASI(f) (f)
/******************************************* message types */
@@ -970,6 +974,7 @@ struct hpi_control_union_msg {
u32 mode;
u32 value;
} mode;
+ u32 blend;
} tuner;
} u;
};
diff --git a/sound/pci/asihpi/hpicmn.c b/sound/pci/asihpi/hpicmn.c
index 565102cae4f..fcd64539d9e 100644
--- a/sound/pci/asihpi/hpicmn.c
+++ b/sound/pci/asihpi/hpicmn.c
@@ -347,20 +347,15 @@ short hpi_check_control_cache(struct hpi_control_cache *p_cache,
found = 0;
break;
case HPI_CONTROL_TUNER:
- {
- struct hpi_control_cache_single *pCT =
- (struct hpi_control_cache_single *)pI;
- if (phm->u.c.attribute == HPI_TUNER_FREQ)
- phr->u.c.param1 = pCT->u.t.freq_ink_hz;
- else if (phm->u.c.attribute == HPI_TUNER_BAND)
- phr->u.c.param1 = pCT->u.t.band;
- else if ((phm->u.c.attribute == HPI_TUNER_LEVEL)
- && (phm->u.c.param1 ==
- HPI_TUNER_LEVEL_AVERAGE))
- phr->u.c.param1 = pCT->u.t.level;
- else
- found = 0;
- }
+ if (phm->u.c.attribute == HPI_TUNER_FREQ)
+ phr->u.c.param1 = pC->u.t.freq_ink_hz;
+ else if (phm->u.c.attribute == HPI_TUNER_BAND)
+ phr->u.c.param1 = pC->u.t.band;
+ else if ((phm->u.c.attribute == HPI_TUNER_LEVEL)
+ && (phm->u.c.param1 == HPI_TUNER_LEVEL_AVERAGE))
+ phr->u.c.param1 = pC->u.t.level;
+ else
+ found = 0;
break;
case HPI_CONTROL_AESEBU_RECEIVER:
if (phm->u.c.attribute == HPI_AESEBURX_ERRORSTATUS)
@@ -503,6 +498,9 @@ void hpi_sync_control_cache(struct hpi_control_cache *p_cache,
struct hpi_control_cache_single *pC;
struct hpi_control_cache_info *pI;
+ if (phr->error)
+ return;
+
if (!find_control(phm, p_cache, &pI, &control_index))
return;
@@ -520,8 +518,6 @@ void hpi_sync_control_cache(struct hpi_control_cache *p_cache,
break;
case HPI_CONTROL_MULTIPLEXER:
/* mux does not return its setting on Set command. */
- if (phr->error)
- return;
if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) {
pC->u.x.source_node_type = (u16)phm->u.c.param1;
pC->u.x.source_node_index = (u16)phm->u.c.param2;
@@ -529,8 +525,6 @@ void hpi_sync_control_cache(struct hpi_control_cache *p_cache,
break;
case HPI_CONTROL_CHANNEL_MODE:
/* mode does not return its setting on Set command. */
- if (phr->error)
- return;
if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE)
pC->u.m.mode = (u16)phm->u.c.param1;
break;
@@ -545,20 +539,14 @@ void hpi_sync_control_cache(struct hpi_control_cache *p_cache,
pC->u.phantom_power.state = (u16)phm->u.c.param1;
break;
case HPI_CONTROL_AESEBU_TRANSMITTER:
- if (phr->error)
- return;
if (phm->u.c.attribute == HPI_AESEBUTX_FORMAT)
pC->u.aes3tx.format = phm->u.c.param1;
break;
case HPI_CONTROL_AESEBU_RECEIVER:
- if (phr->error)
- return;
if (phm->u.c.attribute == HPI_AESEBURX_FORMAT)
pC->u.aes3rx.source = phm->u.c.param1;
break;
case HPI_CONTROL_SAMPLECLOCK:
- if (phr->error)
- return;
if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE)
pC->u.clk.source = (u16)phm->u.c.param1;
else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE_INDEX)
@@ -590,7 +578,7 @@ struct hpi_control_cache *hpi_alloc_control_cache(const u32
void hpi_free_control_cache(struct hpi_control_cache *p_cache)
{
- if ((p_cache->init) && (p_cache->p_info)) {
+ if (p_cache->init) {
kfree(p_cache->p_info);
p_cache->p_info = NULL;
p_cache->init = 0;
diff --git a/sound/pci/asihpi/hpifunc.c b/sound/pci/asihpi/hpifunc.c
index eda26b31232..298eef3e20e 100644
--- a/sound/pci/asihpi/hpifunc.c
+++ b/sound/pci/asihpi/hpifunc.c
@@ -2946,6 +2946,20 @@ u16 hpi_tuner_get_hd_radio_signal_quality(const struct hpi_hsubsys *ph_subsys,
HPI_TUNER_HDRADIO_SIGNAL_QUALITY, 0, 0, pquality, NULL);
}
+u16 hpi_tuner_get_hd_radio_signal_blend(const struct hpi_hsubsys *ph_subsys,
+ u32 h_control, u32 *pblend)
+{
+ return hpi_control_param_get(ph_subsys, h_control,
+ HPI_TUNER_HDRADIO_BLEND, 0, 0, pblend, NULL);
+}
+
+u16 hpi_tuner_set_hd_radio_signal_blend(const struct hpi_hsubsys *ph_subsys,
+ u32 h_control, const u32 blend)
+{
+ return hpi_control_param_set(ph_subsys, h_control,
+ HPI_TUNER_HDRADIO_BLEND, blend, 0);
+}
+
u16 hpi_tuner_getRDS(const struct hpi_hsubsys *ph_subsys, u32 h_control,
char *p_data)
{
@@ -3266,8 +3280,7 @@ u16 hpi_entity_find_next(struct hpi_entity *container_entity,
void hpi_entity_free(struct hpi_entity *entity)
{
- if (entity != NULL)
- kfree(entity);
+ kfree(entity);
}
static u16 hpi_entity_alloc_and_copy(struct hpi_entity *src,
diff --git a/sound/pci/asihpi/hpios.c b/sound/pci/asihpi/hpios.c
index de615cfdb95..742ee12a9e1 100644
--- a/sound/pci/asihpi/hpios.c
+++ b/sound/pci/asihpi/hpios.c
@@ -89,26 +89,3 @@ u16 hpios_locked_mem_free(struct consistent_dma_area *p_mem_area)
void hpios_locked_mem_free_all(void)
{
}
-
-void __iomem *hpios_map_io(struct pci_dev *pci_dev, int idx,
- unsigned int length)
-{
- HPI_DEBUG_LOG(DEBUG, "mapping %d %s %08llx-%08llx %04llx len 0x%x\n",
- idx, pci_dev->resource[idx].name,
- (unsigned long long)pci_resource_start(pci_dev, idx),
- (unsigned long long)pci_resource_end(pci_dev, idx),
- (unsigned long long)pci_resource_flags(pci_dev, idx), length);
-
- if (!(pci_resource_flags(pci_dev, idx) & IORESOURCE_MEM)) {
- HPI_DEBUG_LOG(ERROR, "not an io memory resource\n");
- return NULL;
- }
-
- if (length > pci_resource_len(pci_dev, idx)) {
- HPI_DEBUG_LOG(ERROR, "resource too small for requested %d \n",
- length);
- return NULL;
- }
-
- return ioremap(pci_resource_start(pci_dev, idx), length);
-}
diff --git a/sound/pci/asihpi/hpios.h b/sound/pci/asihpi/hpios.h
index a62c3f1e5f0..370f39b43f8 100644
--- a/sound/pci/asihpi/hpios.h
+++ b/sound/pci/asihpi/hpios.h
@@ -166,13 +166,4 @@ struct hpi_adapter {
void __iomem *ap_remapped_mem_base[HPI_MAX_ADAPTER_MEM_SPACES];
};
-static inline void hpios_unmap_io(void __iomem *addr,
- unsigned long size)
-{
- iounmap(addr);
-}
-
-void __iomem *hpios_map_io(struct pci_dev *pci_dev, int idx,
- unsigned int length);
-
#endif
diff --git a/sound/usb/caiaq/control.c b/sound/usb/caiaq/control.c
index 36ed703a741..91c804cd278 100644
--- a/sound/usb/caiaq/control.c
+++ b/sound/usb/caiaq/control.c
@@ -42,21 +42,12 @@ static int control_info(struct snd_kcontrol *kcontrol,
switch (dev->chip.usb_id) {
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ):
- if (pos == 0) {
- /* current input mode of A8DJ */
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 2;
- return 0;
- }
- break;
-
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ):
if (pos == 0) {
- /* current input mode of A4DJ */
+ /* current input mode of A8DJ and A4DJ */
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 1;
+ uinfo->value.integer.max = 2;
return 0;
}
break;
@@ -86,14 +77,6 @@ static int control_get(struct snd_kcontrol *kcontrol,
struct snd_usb_caiaqdev *dev = caiaqdev(chip->card);
int pos = kcontrol->private_value;
- if (dev->chip.usb_id ==
- USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ)) {
- /* A4DJ has only one control */
- /* do not expose hardware input mode 0 */
- ucontrol->value.integer.value[0] = dev->control_state[0] - 1;
- return 0;
- }
-
if (pos & CNT_INTVAL)
ucontrol->value.integer.value[0]
= dev->control_state[pos & ~CNT_INTVAL];
@@ -112,20 +95,9 @@ static int control_put(struct snd_kcontrol *kcontrol,
int pos = kcontrol->private_value;
unsigned char cmd = EP1_CMD_WRITE_IO;
- switch (dev->chip.usb_id) {
- case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ): {
- /* A4DJ has only one control */
- /* do not expose hardware input mode 0 */
- dev->control_state[0] = ucontrol->value.integer.value[0] + 1;
- snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO,
- dev->control_state, sizeof(dev->control_state));
- return 1;
- }
-
- case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
+ if (dev->chip.usb_id ==
+ USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1))
cmd = EP1_CMD_DIMM_LEDS;
- break;
- }
if (pos & CNT_INTVAL) {
dev->control_state[pos & ~CNT_INTVAL]
diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c
index 80527182767..cdfb856bddd 100644
--- a/sound/usb/caiaq/device.c
+++ b/sound/usb/caiaq/device.c
@@ -36,7 +36,7 @@
#include "input.h"
MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
-MODULE_DESCRIPTION("caiaq USB audio, version 1.3.20");
+MODULE_DESCRIPTION("caiaq USB audio, version 1.3.21");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2},"
"{Native Instruments, RigKontrol3},"
@@ -320,12 +320,6 @@ static void __devinit setup_card(struct snd_usb_caiaqdev *dev)
}
break;
- case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ):
- /* Audio 4 DJ - default input mode to phono */
- dev->control_state[0] = 2;
- snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO,
- dev->control_state, 1);
- break;
}
if (dev->spec.num_analog_audio_out +
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
index ef07a6d0dd5..28ee1ce3971 100644
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -149,6 +149,47 @@ int snd_usb_add_audio_endpoint(struct snd_usb_audio *chip, int stream, struct au
return 0;
}
+static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip,
+ struct usb_host_interface *alts,
+ int protocol, int iface_no)
+{
+ /* parsed with a v1 header here. that's ok as we only look at the
+ * header first which is the same for both versions */
+ struct uac_iso_endpoint_descriptor *csep;
+ struct usb_interface_descriptor *altsd = get_iface_desc(alts);
+ int attributes = 0;
+
+ csep = snd_usb_find_desc(alts->endpoint[0].extra, alts->endpoint[0].extralen, NULL, USB_DT_CS_ENDPOINT);
+
+ /* Creamware Noah has this descriptor after the 2nd endpoint */
+ if (!csep && altsd->bNumEndpoints >= 2)
+ csep = snd_usb_find_desc(alts->endpoint[1].extra, alts->endpoint[1].extralen, NULL, USB_DT_CS_ENDPOINT);
+
+ if (!csep || csep->bLength < 7 ||
+ csep->bDescriptorSubtype != UAC_EP_GENERAL) {
+ snd_printk(KERN_WARNING "%d:%u:%d : no or invalid"
+ " class specific endpoint descriptor\n",
+ chip->dev->devnum, iface_no,
+ altsd->bAlternateSetting);
+ return 0;
+ }
+
+ if (protocol == UAC_VERSION_1) {
+ attributes = csep->bmAttributes;
+ } else {
+ struct uac2_iso_endpoint_descriptor *csep2 =
+ (struct uac2_iso_endpoint_descriptor *) csep;
+
+ attributes = csep->bmAttributes & UAC_EP_CS_ATTR_FILL_MAX;
+
+ /* emulate the endpoint attributes of a v1 device */
+ if (csep2->bmControls & UAC2_CONTROL_PITCH)
+ attributes |= UAC_EP_CS_ATTR_PITCH_CONTROL;
+ }
+
+ return attributes;
+}
+
int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
{
struct usb_device *dev;
@@ -158,8 +199,8 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
int i, altno, err, stream;
int format = 0, num_channels = 0;
struct audioformat *fp = NULL;
- unsigned char *fmt, *csep;
int num, protocol;
+ struct uac_format_type_i_continuous_descriptor *fmt;
dev = chip->dev;
@@ -256,8 +297,8 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
dev->devnum, iface_no, altno);
continue;
}
- if (((protocol == UAC_VERSION_1) && (fmt[0] < 8)) ||
- ((protocol == UAC_VERSION_2) && (fmt[0] != 6))) {
+ if (((protocol == UAC_VERSION_1) && (fmt->bLength < 8)) ||
+ ((protocol == UAC_VERSION_2) && (fmt->bLength != 6))) {
snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_FORMAT_TYPE desc\n",
dev->devnum, iface_no, altno);
continue;
@@ -268,7 +309,9 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
* with the previous one, except for a larger packet size, but
* is actually a mislabeled two-channel setting; ignore it.
*/
- if (fmt[4] == 1 && fmt[5] == 2 && altno == 2 && num == 3 &&
+ if (fmt->bNrChannels == 1 &&
+ fmt->bSubframeSize == 2 &&
+ altno == 2 && num == 3 &&
fp && fp->altsetting == 1 && fp->channels == 1 &&
fp->formats == SNDRV_PCM_FMTBIT_S16_LE &&
protocol == UAC_VERSION_1 &&
@@ -276,17 +319,6 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
fp->maxpacksize * 2)
continue;
- csep = snd_usb_find_desc(alts->endpoint[0].extra, alts->endpoint[0].extralen, NULL, USB_DT_CS_ENDPOINT);
- /* Creamware Noah has this descriptor after the 2nd endpoint */
- if (!csep && altsd->bNumEndpoints >= 2)
- csep = snd_usb_find_desc(alts->endpoint[1].extra, alts->endpoint[1].extralen, NULL, USB_DT_CS_ENDPOINT);
- if (!csep || csep[0] < 7 || csep[2] != UAC_EP_GENERAL) {
- snd_printk(KERN_WARNING "%d:%u:%d : no or invalid"
- " class specific endpoint descriptor\n",
- dev->devnum, iface_no, altno);
- csep = NULL;
- }
-
fp = kzalloc(sizeof(*fp), GFP_KERNEL);
if (! fp) {
snd_printk(KERN_ERR "cannot malloc\n");
@@ -305,7 +337,7 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
if (snd_usb_get_speed(dev) == USB_SPEED_HIGH)
fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1)
* (fp->maxpacksize & 0x7ff);
- fp->attributes = csep ? csep[3] : 0;
+ fp->attributes = parse_uac_endpoint_attributes(chip, alts, protocol, iface_no);
/* some quirks for attributes here */
diff --git a/sound/usb/format.c b/sound/usb/format.c
index b87cf87c4e7..fe29d61de19 100644
--- a/sound/usb/format.c
+++ b/sound/usb/format.c
@@ -278,12 +278,11 @@ err:
* parse the format type I and III descriptors
*/
static int parse_audio_format_i(struct snd_usb_audio *chip,
- struct audioformat *fp,
- int format, void *_fmt,
+ struct audioformat *fp, int format,
+ struct uac_format_type_i_continuous_descriptor *fmt,
struct usb_host_interface *iface)
{
struct usb_interface_descriptor *altsd = get_iface_desc(iface);
- struct uac_format_type_i_discrete_descriptor *fmt = _fmt;
int protocol = altsd->bInterfaceProtocol;
int pcm_format, ret;
@@ -320,7 +319,7 @@ static int parse_audio_format_i(struct snd_usb_audio *chip,
switch (protocol) {
case UAC_VERSION_1:
fp->channels = fmt->bNrChannels;
- ret = parse_audio_format_rates_v1(chip, fp, _fmt, 7);
+ ret = parse_audio_format_rates_v1(chip, fp, (unsigned char *) fmt, 7);
break;
case UAC_VERSION_2:
/* fp->channels is already set in this case */
@@ -392,12 +391,12 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip,
}
int snd_usb_parse_audio_format(struct snd_usb_audio *chip, struct audioformat *fp,
- int format, unsigned char *fmt, int stream,
- struct usb_host_interface *iface)
+ int format, struct uac_format_type_i_continuous_descriptor *fmt,
+ int stream, struct usb_host_interface *iface)
{
int err;
- switch (fmt[3]) {
+ switch (fmt->bFormatType) {
case UAC_FORMAT_TYPE_I:
case UAC_FORMAT_TYPE_III:
err = parse_audio_format_i(chip, fp, format, fmt, iface);
@@ -407,10 +406,11 @@ int snd_usb_parse_audio_format(struct snd_usb_audio *chip, struct audioformat *f
break;
default:
snd_printd(KERN_INFO "%d:%u:%d : format type %d is not supported yet\n",
- chip->dev->devnum, fp->iface, fp->altsetting, fmt[3]);
- return -1;
+ chip->dev->devnum, fp->iface, fp->altsetting,
+ fmt->bFormatType);
+ return -ENOTSUPP;
}
- fp->fmt_type = fmt[3];
+ fp->fmt_type = fmt->bFormatType;
if (err < 0)
return err;
#if 1
@@ -421,10 +421,10 @@ int snd_usb_parse_audio_format(struct snd_usb_audio *chip, struct audioformat *f
if (chip->usb_id == USB_ID(0x041e, 0x3000) ||
chip->usb_id == USB_ID(0x041e, 0x3020) ||
chip->usb_id == USB_ID(0x041e, 0x3061)) {
- if (fmt[3] == UAC_FORMAT_TYPE_I &&
+ if (fmt->bFormatType == UAC_FORMAT_TYPE_I &&
fp->rates != SNDRV_PCM_RATE_48000 &&
fp->rates != SNDRV_PCM_RATE_96000)
- return -1;
+ return -ENOTSUPP;
}
#endif
return 0;
diff --git a/sound/usb/format.h b/sound/usb/format.h
index 8298c4e8ddf..387924f0af8 100644
--- a/sound/usb/format.h
+++ b/sound/usb/format.h
@@ -1,8 +1,9 @@
#ifndef __USBAUDIO_FORMAT_H
#define __USBAUDIO_FORMAT_H
-int snd_usb_parse_audio_format(struct snd_usb_audio *chip, struct audioformat *fp,
- int format, unsigned char *fmt, int stream,
- struct usb_host_interface *iface);
+int snd_usb_parse_audio_format(struct snd_usb_audio *chip,
+ struct audioformat *fp, int format,
+ struct uac_format_type_i_continuous_descriptor *fmt,
+ int stream, struct usb_host_interface *iface);
#endif /* __USBAUDIO_FORMAT_H */
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 97dd1765510..03ce971e002 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -1126,7 +1126,7 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void
} else {
struct uac2_feature_unit_descriptor *ftr = _ftr;
csize = 4;
- channels = (hdr->bLength - 6) / 4;
+ channels = (hdr->bLength - 6) / 4 - 1;
bmaControls = ftr->bmaControls;
}
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index 2bf0d77d176..056587de7be 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -120,10 +120,6 @@ static int init_pitch_v1(struct snd_usb_audio *chip, int iface,
ep = get_endpoint(alts, 0)->bEndpointAddress;
- /* if endpoint doesn't have pitch control, bail out */
- if (!(fmt->attributes & UAC_EP_CS_ATTR_PITCH_CONTROL))
- return 0;
-
data[0] = 1;
if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR,
USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT,
@@ -137,8 +133,32 @@ static int init_pitch_v1(struct snd_usb_audio *chip, int iface,
return 0;
}
+static int init_pitch_v2(struct snd_usb_audio *chip, int iface,
+ struct usb_host_interface *alts,
+ struct audioformat *fmt)
+{
+ struct usb_device *dev = chip->dev;
+ unsigned char data[1];
+ unsigned int ep;
+ int err;
+
+ ep = get_endpoint(alts, 0)->bEndpointAddress;
+
+ data[0] = 1;
+ if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR,
+ USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT,
+ UAC2_EP_CS_PITCH << 8, 0,
+ data, sizeof(data), 1000)) < 0) {
+ snd_printk(KERN_ERR "%d:%d:%d: cannot set enable PITCH (v2)\n",
+ dev->devnum, iface, fmt->altsetting);
+ return err;
+ }
+
+ return 0;
+}
+
/*
- * initialize the picth control and sample rate
+ * initialize the pitch control and sample rate
*/
int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface,
struct usb_host_interface *alts,
@@ -146,13 +166,16 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface,
{
struct usb_interface_descriptor *altsd = get_iface_desc(alts);
+ /* if endpoint doesn't have pitch control, bail out */
+ if (!(fmt->attributes & UAC_EP_CS_ATTR_PITCH_CONTROL))
+ return 0;
+
switch (altsd->bInterfaceProtocol) {
case UAC_VERSION_1:
return init_pitch_v1(chip, iface, alts, fmt);
case UAC_VERSION_2:
- /* not implemented yet */
- return 0;
+ return init_pitch_v2(chip, iface, alts, fmt);
}
return -EINVAL;