diff options
author | Takashi Iwai <tiwai@suse.de> | 2010-05-29 21:50:33 +0200 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2010-05-29 21:50:33 +0200 |
commit | a98d3984c85222aa9efc63c4f9dd3d805ce469f2 (patch) | |
tree | aeb9ebdcc06ca92b8114f30cedf16b8f3780b3f2 | |
parent | 52593de4c11fb24c83d8036ba34706881aab5e3d (diff) | |
parent | 55567ab70bd8551c73253e44ea5244db41eac81b (diff) | |
download | talos-obmc-linux-a98d3984c85222aa9efc63c4f9dd3d805ce469f2.tar.gz talos-obmc-linux-a98d3984c85222aa9efc63c4f9dd3d805ce469f2.zip |
Merge branch 'fix/misc' into for-linus
-rw-r--r-- | include/linux/usb/audio-v2.h | 16 | ||||
-rw-r--r-- | sound/mips/au1x00.c | 1 | ||||
-rw-r--r-- | sound/oss/dmasound/dmasound_atari.c | 5 | ||||
-rw-r--r-- | sound/pci/asihpi/hpi.h | 8 | ||||
-rw-r--r-- | sound/pci/asihpi/hpi6000.c | 6 | ||||
-rw-r--r-- | sound/pci/asihpi/hpi6205.c | 21 | ||||
-rw-r--r-- | sound/pci/asihpi/hpi_internal.h | 5 | ||||
-rw-r--r-- | sound/pci/asihpi/hpicmn.c | 38 | ||||
-rw-r--r-- | sound/pci/asihpi/hpifunc.c | 17 | ||||
-rw-r--r-- | sound/pci/asihpi/hpios.c | 23 | ||||
-rw-r--r-- | sound/pci/asihpi/hpios.h | 9 | ||||
-rw-r--r-- | sound/usb/caiaq/control.c | 36 | ||||
-rw-r--r-- | sound/usb/caiaq/device.c | 8 | ||||
-rw-r--r-- | sound/usb/endpoint.c | 64 | ||||
-rw-r--r-- | sound/usb/format.c | 24 | ||||
-rw-r--r-- | sound/usb/format.h | 7 | ||||
-rw-r--r-- | sound/usb/mixer.c | 2 | ||||
-rw-r--r-- | sound/usb/pcm.c | 37 |
18 files changed, 170 insertions, 157 deletions
diff --git a/include/linux/usb/audio-v2.h b/include/linux/usb/audio-v2.h index 2389f93a28b5..92f1d99f0f17 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 3e763d6a5d67..446cf9748664 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 1f4774123064..13c214466d3b 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 99400de6c075..0173bbe62b67 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 839ecb2e4b64..12dab5e4892c 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 5e88c1fc2b9e..e89991ea3543 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 f1cd6f1a0d44..fdd0ce02aa68 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 565102cae4f8..fcd64539d9ef 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 eda26b312324..298eef3e20e9 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 de615cfdb950..742ee12a9e17 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 a62c3f1e5f09..370f39b43f85 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 36ed703a7416..91c804cd2782 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 805271827675..cdfb856bddd2 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 ef07a6d0dd5f..28ee1ce3971a 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 b87cf87c4e7b..fe29d61de19b 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 8298c4e8ddfa..387924f0af85 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 97dd17655104..03ce971e0027 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 2bf0d77d1768..056587de7be4 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; |