Merge tag 'sound-3.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai: "This became a fairly large pull request. In addition to the usual driver updates / fixes, there have been a high amount of cleanups in ASoC area, as well as control API helpers and kernel documentations fixes touching through the whole tree. In the driver side, the biggest changes are the support for new Intel SoC found on new x86 machines, and the updates of FireWire dice and oxfw drivers. Some remarkable items are below: ALSA core: - PCM mmap code cleanup, removal of arch-dependent codes - PCM xrun injection support - PCM hwptr tracepoint support - Refactoring of snd_pcm_action(), simplification of PCM locking - Robustified sequecner auto-load functionality - New control API helpers and lots of cleanups along with them - Lots of kerneldoc fixes and cleanups USB-audio: - The mixer resume code was largely rewritten, and the devices with quirks are resumed properly. - New hardware support: Focusrite Scarlett, Digidesign Mbox1, Denon/Marantz DACs, Zoom R16/24 FireWire: - DICE driver updates with better duplex and sync support, including MIDI support - New OXFW driver for Oxford Semiconductor FW970/971 chipset, including the previous LaCie Speakers device. Fullduplex and MIDI support included as well as DICE driver. HD-audio: - Refactoring the driver-caps quirk handling in snd-hda-intel - More consistent control names representing the topology better - Fixups: HP mute LED with ALC268 codec, Ideapad S210 built-in mic fix, ASUS Z99He laptop EAPD ASoC: - Conversion of AC'97 drivers to use regmap, bringing us closer to the removal of the ASoC level I/O code - Clean up a lot of old drivers that were open coding things that have subsequently been implemented in the core - Some DAPM performance improvements - Removal of the now seldom used CODEC mutex - Lots of updates for the newer Intel SoC support, including support for the DSP and some Cherrytrail and Braswell machine drivers - Support for Samsung boards using rt5631 as the CODEC - Removal of the obsolete AFEB9260 machine driver - Driver support for the TI TS3A227E headset driver used in some Chrombeooks Others: - ASIHPI driver update and cleanups - Lots of dev_*() printk conversions - Lots of trivial cleanups for the codes spotted by Coccinelle" * tag 'sound-3.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (594 commits) ALSA: pcxhr: NULL dereference on probe failure ALSA: lola: NULL dereference on probe failure ALSA: hda - Add "eapd" model string for AD1986A codec ALSA: hda - Add EAPD fixup for ASUS Z99He laptop ALSA: oxfw: Add hwdep interface ALSA: oxfw: Add support for capture/playback MIDI messages ALSA: oxfw: add support for capturing PCM samples ALSA: oxfw: Add support AMDTP in-stream ALSA: oxfw: Add support for Behringer/Mackie devices ALSA: oxfw: Change the way to start stream ALSA: oxfw: Add proc interface for debugging purpose ALSA: oxfw: Change the way to make PCM rules/constraints ALSA: oxfw: Add support for AV/C stream format command to get/set supported stream formation ALSA: oxfw: Change the way to name card ALSA: dice: Add support for MIDI capture/playback ALSA: dice: Add support for capturing PCM samples ALSA: dice: Support for non SYT-Match sampling clock source mode ALSA: dice: Add support for duplex streams with synchronization ALSA: dice: Change the way to start stream ALSA: jack: Add dummy snd_jack_set_key() definition ...
このコミットが含まれているのは:
@@ -25,8 +25,8 @@
|
||||
#include "comm.h"
|
||||
#include "chip.h"
|
||||
|
||||
static char *opt_coax_texts[2] = { "Optical", "Coax" };
|
||||
static char *line_phono_texts[2] = { "Line", "Phono" };
|
||||
static const char * const opt_coax_texts[2] = { "Optical", "Coax" };
|
||||
static const char * const line_phono_texts[2] = { "Line", "Phono" };
|
||||
|
||||
/*
|
||||
* data that needs to be sent to device. sets up card internal stuff.
|
||||
@@ -327,14 +327,7 @@ static int usb6fire_control_input_vol_get(struct snd_kcontrol *kcontrol,
|
||||
static int usb6fire_control_line_phono_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
|
||||
uinfo->count = 1;
|
||||
uinfo->value.enumerated.items = 2;
|
||||
if (uinfo->value.enumerated.item > 1)
|
||||
uinfo->value.enumerated.item = 1;
|
||||
strcpy(uinfo->value.enumerated.name,
|
||||
line_phono_texts[uinfo->value.enumerated.item]);
|
||||
return 0;
|
||||
return snd_ctl_enum_info(uinfo, 1, 2, line_phono_texts);
|
||||
}
|
||||
|
||||
static int usb6fire_control_line_phono_put(struct snd_kcontrol *kcontrol,
|
||||
@@ -361,14 +354,7 @@ static int usb6fire_control_line_phono_get(struct snd_kcontrol *kcontrol,
|
||||
static int usb6fire_control_opt_coax_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
|
||||
uinfo->count = 1;
|
||||
uinfo->value.enumerated.items = 2;
|
||||
if (uinfo->value.enumerated.item > 1)
|
||||
uinfo->value.enumerated.item = 1;
|
||||
strcpy(uinfo->value.enumerated.name,
|
||||
opt_coax_texts[uinfo->value.enumerated.item]);
|
||||
return 0;
|
||||
return snd_ctl_enum_info(uinfo, 1, 2, opt_coax_texts);
|
||||
}
|
||||
|
||||
static int usb6fire_control_opt_coax_put(struct snd_kcontrol *kcontrol,
|
||||
|
@@ -316,7 +316,7 @@ static int usb6fire_fw_fpga_upload(
|
||||
|
||||
while (c != end) {
|
||||
for (i = 0; c != end && i < FPGA_BUFSIZE; i++, c++)
|
||||
buffer[i] = byte_rev_table[(u8) *c];
|
||||
buffer[i] = bitrev8((u8)*c);
|
||||
|
||||
ret = usb6fire_fw_fpga_write(device, buffer, i);
|
||||
if (ret < 0) {
|
||||
|
@@ -679,25 +679,16 @@ int usb6fire_pcm_init(struct sfire_chip *chip)
|
||||
void usb6fire_pcm_abort(struct sfire_chip *chip)
|
||||
{
|
||||
struct pcm_runtime *rt = chip->pcm;
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
if (rt) {
|
||||
rt->panic = true;
|
||||
|
||||
if (rt->playback.instance) {
|
||||
snd_pcm_stream_lock_irqsave(rt->playback.instance, flags);
|
||||
snd_pcm_stop(rt->playback.instance,
|
||||
SNDRV_PCM_STATE_XRUN);
|
||||
snd_pcm_stream_unlock_irqrestore(rt->playback.instance, flags);
|
||||
}
|
||||
if (rt->playback.instance)
|
||||
snd_pcm_stop_xrun(rt->playback.instance);
|
||||
|
||||
if (rt->capture.instance) {
|
||||
snd_pcm_stream_lock_irqsave(rt->capture.instance, flags);
|
||||
snd_pcm_stop(rt->capture.instance,
|
||||
SNDRV_PCM_STATE_XRUN);
|
||||
snd_pcm_stream_unlock_irqrestore(rt->capture.instance, flags);
|
||||
}
|
||||
if (rt->capture.instance)
|
||||
snd_pcm_stop_xrun(rt->capture.instance);
|
||||
|
||||
for (i = 0; i < PCM_N_URBS; i++) {
|
||||
usb_poison_urb(&rt->in_urbs[i].instance);
|
||||
|
@@ -9,6 +9,7 @@ snd-usb-audio-objs := card.o \
|
||||
helper.o \
|
||||
mixer.o \
|
||||
mixer_quirks.o \
|
||||
mixer_scarlett.o \
|
||||
pcm.o \
|
||||
proc.o \
|
||||
quirks.o \
|
||||
|
109
sound/usb/card.c
109
sound/usb/card.c
@@ -112,15 +112,13 @@ static struct usb_driver usb_audio_driver;
|
||||
|
||||
/*
|
||||
* disconnect streams
|
||||
* called from snd_usb_audio_disconnect()
|
||||
* called from usb_audio_disconnect()
|
||||
*/
|
||||
static void snd_usb_stream_disconnect(struct list_head *head)
|
||||
static void snd_usb_stream_disconnect(struct snd_usb_stream *as)
|
||||
{
|
||||
int idx;
|
||||
struct snd_usb_stream *as;
|
||||
struct snd_usb_substream *subs;
|
||||
|
||||
as = list_entry(head, struct snd_usb_stream, list);
|
||||
for (idx = 0; idx < 2; idx++) {
|
||||
subs = &as->substream[idx];
|
||||
if (!subs->num_formats)
|
||||
@@ -307,10 +305,10 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
|
||||
|
||||
static int snd_usb_audio_free(struct snd_usb_audio *chip)
|
||||
{
|
||||
struct list_head *p, *n;
|
||||
struct snd_usb_endpoint *ep, *n;
|
||||
|
||||
list_for_each_safe(p, n, &chip->ep_list)
|
||||
snd_usb_endpoint_free(p);
|
||||
list_for_each_entry_safe(ep, n, &chip->ep_list, list)
|
||||
snd_usb_endpoint_free(ep);
|
||||
|
||||
mutex_destroy(&chip->mutex);
|
||||
kfree(chip);
|
||||
@@ -323,16 +321,6 @@ static int snd_usb_audio_dev_free(struct snd_device *device)
|
||||
return snd_usb_audio_free(chip);
|
||||
}
|
||||
|
||||
static void remove_trailing_spaces(char *str)
|
||||
{
|
||||
char *p;
|
||||
|
||||
if (!*str)
|
||||
return;
|
||||
for (p = str + strlen(str) - 1; p >= str && isspace(*p); p--)
|
||||
*p = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* create a chip instance and set its names.
|
||||
*/
|
||||
@@ -416,7 +404,7 @@ static int snd_usb_audio_create(struct usb_interface *intf,
|
||||
USB_ID_PRODUCT(chip->usb_id));
|
||||
}
|
||||
}
|
||||
remove_trailing_spaces(card->shortname);
|
||||
strim(card->shortname);
|
||||
|
||||
/* retrieve the vendor and device strings as longname */
|
||||
if (quirk && quirk->vendor_name && *quirk->vendor_name) {
|
||||
@@ -430,7 +418,7 @@ static int snd_usb_audio_create(struct usb_interface *intf,
|
||||
/* we don't really care if there isn't any vendor string */
|
||||
}
|
||||
if (len > 0) {
|
||||
remove_trailing_spaces(card->longname);
|
||||
strim(card->longname);
|
||||
if (*card->longname)
|
||||
strlcat(card->longname, " ", sizeof(card->longname));
|
||||
}
|
||||
@@ -475,14 +463,14 @@ static int snd_usb_audio_create(struct usb_interface *intf,
|
||||
* only at the first time. the successive calls of this function will
|
||||
* append the pcm interface to the corresponding card.
|
||||
*/
|
||||
static struct snd_usb_audio *
|
||||
snd_usb_audio_probe(struct usb_device *dev,
|
||||
struct usb_interface *intf,
|
||||
const struct usb_device_id *usb_id)
|
||||
static int usb_audio_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *usb_id)
|
||||
{
|
||||
const struct snd_usb_audio_quirk *quirk = (const struct snd_usb_audio_quirk *)usb_id->driver_info;
|
||||
int i, err;
|
||||
struct usb_device *dev = interface_to_usbdev(intf);
|
||||
const struct snd_usb_audio_quirk *quirk =
|
||||
(const struct snd_usb_audio_quirk *)usb_id->driver_info;
|
||||
struct snd_usb_audio *chip;
|
||||
int i, err;
|
||||
struct usb_host_interface *alts;
|
||||
int ifnum;
|
||||
u32 id;
|
||||
@@ -492,10 +480,11 @@ snd_usb_audio_probe(struct usb_device *dev,
|
||||
id = USB_ID(le16_to_cpu(dev->descriptor.idVendor),
|
||||
le16_to_cpu(dev->descriptor.idProduct));
|
||||
if (quirk && quirk->ifnum >= 0 && ifnum != quirk->ifnum)
|
||||
goto __err_val;
|
||||
return -ENXIO;
|
||||
|
||||
if (snd_usb_apply_boot_quirk(dev, intf, quirk) < 0)
|
||||
goto __err_val;
|
||||
err = snd_usb_apply_boot_quirk(dev, intf, quirk);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/*
|
||||
* found a config. now register to ALSA
|
||||
@@ -508,6 +497,7 @@ snd_usb_audio_probe(struct usb_device *dev,
|
||||
if (usb_chip[i] && usb_chip[i]->dev == dev) {
|
||||
if (usb_chip[i]->shutdown) {
|
||||
dev_err(&dev->dev, "USB device is in the shutdown state, cannot create a card instance\n");
|
||||
err = -EIO;
|
||||
goto __error;
|
||||
}
|
||||
chip = usb_chip[i];
|
||||
@@ -523,15 +513,16 @@ snd_usb_audio_probe(struct usb_device *dev,
|
||||
if (enable[i] && ! usb_chip[i] &&
|
||||
(vid[i] == -1 || vid[i] == USB_ID_VENDOR(id)) &&
|
||||
(pid[i] == -1 || pid[i] == USB_ID_PRODUCT(id))) {
|
||||
if (snd_usb_audio_create(intf, dev, i, quirk,
|
||||
&chip) < 0) {
|
||||
err = snd_usb_audio_create(intf, dev, i, quirk,
|
||||
&chip);
|
||||
if (err < 0)
|
||||
goto __error;
|
||||
}
|
||||
chip->pm_intf = intf;
|
||||
break;
|
||||
}
|
||||
if (!chip) {
|
||||
dev_err(&dev->dev, "no available usb audio device\n");
|
||||
err = -ENODEV;
|
||||
goto __error;
|
||||
}
|
||||
}
|
||||
@@ -548,28 +539,32 @@ snd_usb_audio_probe(struct usb_device *dev,
|
||||
err = 1; /* continue */
|
||||
if (quirk && quirk->ifnum != QUIRK_NO_INTERFACE) {
|
||||
/* need some special handlings */
|
||||
if ((err = snd_usb_create_quirk(chip, intf, &usb_audio_driver, quirk)) < 0)
|
||||
err = snd_usb_create_quirk(chip, intf, &usb_audio_driver, quirk);
|
||||
if (err < 0)
|
||||
goto __error;
|
||||
}
|
||||
|
||||
if (err > 0) {
|
||||
/* create normal USB audio interfaces */
|
||||
if (snd_usb_create_streams(chip, ifnum) < 0 ||
|
||||
snd_usb_create_mixer(chip, ifnum, ignore_ctl_error) < 0) {
|
||||
err = snd_usb_create_streams(chip, ifnum);
|
||||
if (err < 0)
|
||||
goto __error;
|
||||
err = snd_usb_create_mixer(chip, ifnum, ignore_ctl_error);
|
||||
if (err < 0)
|
||||
goto __error;
|
||||
}
|
||||
}
|
||||
|
||||
/* we are allowed to call snd_card_register() many times */
|
||||
if (snd_card_register(chip->card) < 0) {
|
||||
err = snd_card_register(chip->card);
|
||||
if (err < 0)
|
||||
goto __error;
|
||||
}
|
||||
|
||||
usb_chip[chip->index] = chip;
|
||||
chip->num_interfaces++;
|
||||
chip->probing = 0;
|
||||
usb_set_intfdata(intf, chip);
|
||||
mutex_unlock(®ister_mutex);
|
||||
return chip;
|
||||
return 0;
|
||||
|
||||
__error:
|
||||
if (chip) {
|
||||
@@ -578,17 +573,16 @@ snd_usb_audio_probe(struct usb_device *dev,
|
||||
chip->probing = 0;
|
||||
}
|
||||
mutex_unlock(®ister_mutex);
|
||||
__err_val:
|
||||
return NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* we need to take care of counter, since disconnection can be called also
|
||||
* many times as well as usb_audio_probe().
|
||||
*/
|
||||
static void snd_usb_audio_disconnect(struct usb_device *dev,
|
||||
struct snd_usb_audio *chip)
|
||||
static void usb_audio_disconnect(struct usb_interface *intf)
|
||||
{
|
||||
struct snd_usb_audio *chip = usb_get_intfdata(intf);
|
||||
struct snd_card *card;
|
||||
struct list_head *p;
|
||||
bool was_shutdown;
|
||||
@@ -604,12 +598,14 @@ static void snd_usb_audio_disconnect(struct usb_device *dev,
|
||||
|
||||
mutex_lock(®ister_mutex);
|
||||
if (!was_shutdown) {
|
||||
struct snd_usb_stream *as;
|
||||
struct snd_usb_endpoint *ep;
|
||||
struct usb_mixer_interface *mixer;
|
||||
|
||||
snd_card_disconnect(card);
|
||||
/* release the pcm resources */
|
||||
list_for_each(p, &chip->pcm_list) {
|
||||
snd_usb_stream_disconnect(p);
|
||||
list_for_each_entry(as, &chip->pcm_list, list) {
|
||||
snd_usb_stream_disconnect(as);
|
||||
}
|
||||
/* release the endpoint resources */
|
||||
list_for_each_entry(ep, &chip->ep_list, list) {
|
||||
@@ -620,8 +616,8 @@ static void snd_usb_audio_disconnect(struct usb_device *dev,
|
||||
snd_usbmidi_disconnect(p);
|
||||
}
|
||||
/* release mixer resources */
|
||||
list_for_each(p, &chip->mixer_list) {
|
||||
snd_usb_mixer_disconnect(p);
|
||||
list_for_each_entry(mixer, &chip->mixer_list, list) {
|
||||
snd_usb_mixer_disconnect(mixer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -635,27 +631,6 @@ static void snd_usb_audio_disconnect(struct usb_device *dev,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* new 2.5 USB kernel API
|
||||
*/
|
||||
static int usb_audio_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct snd_usb_audio *chip;
|
||||
chip = snd_usb_audio_probe(interface_to_usbdev(intf), intf, id);
|
||||
if (chip) {
|
||||
usb_set_intfdata(intf, chip);
|
||||
return 0;
|
||||
} else
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static void usb_audio_disconnect(struct usb_interface *intf)
|
||||
{
|
||||
snd_usb_audio_disconnect(interface_to_usbdev(intf),
|
||||
usb_get_intfdata(intf));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
int snd_usb_autoresume(struct snd_usb_audio *chip)
|
||||
|
@@ -348,6 +348,8 @@ static void snd_complete_urb(struct urb *urb)
|
||||
{
|
||||
struct snd_urb_ctx *ctx = urb->context;
|
||||
struct snd_usb_endpoint *ep = ctx->ep;
|
||||
struct snd_pcm_substream *substream;
|
||||
unsigned long flags;
|
||||
int err;
|
||||
|
||||
if (unlikely(urb->status == -ENOENT || /* unlinked */
|
||||
@@ -364,8 +366,6 @@ static void snd_complete_urb(struct urb *urb)
|
||||
goto exit_clear;
|
||||
|
||||
if (snd_usb_endpoint_implicit_feedback_sink(ep)) {
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ep->lock, flags);
|
||||
list_add_tail(&ctx->ready_list, &ep->ready_playback_urbs);
|
||||
spin_unlock_irqrestore(&ep->lock, flags);
|
||||
@@ -389,7 +389,10 @@ static void snd_complete_urb(struct urb *urb)
|
||||
return;
|
||||
|
||||
usb_audio_err(ep->chip, "cannot submit urb (err = %d)\n", err);
|
||||
//snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
|
||||
if (ep->data_subs && ep->data_subs->pcm_substream) {
|
||||
substream = ep->data_subs->pcm_substream;
|
||||
snd_pcm_stop_xrun(substream);
|
||||
}
|
||||
|
||||
exit_clear:
|
||||
clear_bit(ctx->index, &ep->active_mask);
|
||||
@@ -1002,15 +1005,12 @@ void snd_usb_endpoint_release(struct snd_usb_endpoint *ep)
|
||||
/**
|
||||
* snd_usb_endpoint_free: Free the resources of an snd_usb_endpoint
|
||||
*
|
||||
* @ep: the list header of the endpoint to free
|
||||
* @ep: the endpoint to free
|
||||
*
|
||||
* This free all resources of the given ep.
|
||||
*/
|
||||
void snd_usb_endpoint_free(struct list_head *head)
|
||||
void snd_usb_endpoint_free(struct snd_usb_endpoint *ep)
|
||||
{
|
||||
struct snd_usb_endpoint *ep;
|
||||
|
||||
ep = list_entry(head, struct snd_usb_endpoint, list);
|
||||
kfree(ep);
|
||||
}
|
||||
|
||||
|
@@ -24,7 +24,7 @@ void snd_usb_endpoint_sync_pending_stop(struct snd_usb_endpoint *ep);
|
||||
int snd_usb_endpoint_activate(struct snd_usb_endpoint *ep);
|
||||
void snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep);
|
||||
void snd_usb_endpoint_release(struct snd_usb_endpoint *ep);
|
||||
void snd_usb_endpoint_free(struct list_head *head);
|
||||
void snd_usb_endpoint_free(struct snd_usb_endpoint *ep);
|
||||
|
||||
int snd_usb_endpoint_implicit_feedback_sink(struct snd_usb_endpoint *ep);
|
||||
int snd_usb_endpoint_next_packet_size(struct snd_usb_endpoint *ep);
|
||||
|
@@ -365,6 +365,8 @@ static void snd_usbmidi_error_timer(unsigned long data)
|
||||
if (in && in->error_resubmit) {
|
||||
in->error_resubmit = 0;
|
||||
for (j = 0; j < INPUT_URBS; ++j) {
|
||||
if (atomic_read(&in->urbs[j]->use_count))
|
||||
continue;
|
||||
in->urbs[j]->dev = umidi->dev;
|
||||
snd_usbmidi_submit_urb(in->urbs[j], GFP_ATOMIC);
|
||||
}
|
||||
|
@@ -613,24 +613,14 @@ static int start_usb_playback(struct ua101 *ua)
|
||||
|
||||
static void abort_alsa_capture(struct ua101 *ua)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (test_bit(ALSA_CAPTURE_RUNNING, &ua->states)) {
|
||||
snd_pcm_stream_lock_irqsave(ua->capture.substream, flags);
|
||||
snd_pcm_stop(ua->capture.substream, SNDRV_PCM_STATE_XRUN);
|
||||
snd_pcm_stream_unlock_irqrestore(ua->capture.substream, flags);
|
||||
}
|
||||
if (test_bit(ALSA_CAPTURE_RUNNING, &ua->states))
|
||||
snd_pcm_stop_xrun(ua->capture.substream);
|
||||
}
|
||||
|
||||
static void abort_alsa_playback(struct ua101 *ua)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (test_bit(ALSA_PLAYBACK_RUNNING, &ua->states)) {
|
||||
snd_pcm_stream_lock_irqsave(ua->playback.substream, flags);
|
||||
snd_pcm_stop(ua->playback.substream, SNDRV_PCM_STATE_XRUN);
|
||||
snd_pcm_stream_unlock_irqrestore(ua->playback.substream, flags);
|
||||
}
|
||||
if (test_bit(ALSA_PLAYBACK_RUNNING, &ua->states))
|
||||
snd_pcm_stop_xrun(ua->playback.substream);
|
||||
}
|
||||
|
||||
static int set_stream_hw(struct ua101 *ua, struct snd_pcm_substream *substream,
|
||||
|
@@ -136,6 +136,10 @@ check_mapped_name(const struct usbmix_name_map *p, char *buf, int buflen)
|
||||
return strlcpy(buf, p->name, buflen);
|
||||
}
|
||||
|
||||
/* ignore the error value if ignore_ctl_error flag is set */
|
||||
#define filter_error(cval, err) \
|
||||
((cval)->head.mixer->ignore_ctl_error ? 0 : (err))
|
||||
|
||||
/* check whether the control should be ignored */
|
||||
static inline int
|
||||
check_ignored_ctl(const struct usbmix_name_map *p)
|
||||
@@ -286,13 +290,13 @@ static int get_abs_value(struct usb_mixer_elem_info *cval, int val)
|
||||
static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request,
|
||||
int validx, int *value_ret)
|
||||
{
|
||||
struct snd_usb_audio *chip = cval->mixer->chip;
|
||||
struct snd_usb_audio *chip = cval->head.mixer->chip;
|
||||
unsigned char buf[2];
|
||||
int val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1;
|
||||
int timeout = 10;
|
||||
int idx = 0, err;
|
||||
|
||||
err = snd_usb_autoresume(cval->mixer->chip);
|
||||
err = snd_usb_autoresume(chip);
|
||||
if (err < 0)
|
||||
return -EIO;
|
||||
|
||||
@@ -300,7 +304,7 @@ static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request,
|
||||
while (timeout-- > 0) {
|
||||
if (chip->shutdown)
|
||||
break;
|
||||
idx = snd_usb_ctrl_intf(chip) | (cval->id << 8);
|
||||
idx = snd_usb_ctrl_intf(chip) | (cval->head.id << 8);
|
||||
if (snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), request,
|
||||
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
|
||||
validx, idx, buf, val_len) >= val_len) {
|
||||
@@ -316,14 +320,14 @@ static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request,
|
||||
|
||||
out:
|
||||
up_read(&chip->shutdown_rwsem);
|
||||
snd_usb_autosuspend(cval->mixer->chip);
|
||||
snd_usb_autosuspend(chip);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request,
|
||||
int validx, int *value_ret)
|
||||
{
|
||||
struct snd_usb_audio *chip = cval->mixer->chip;
|
||||
struct snd_usb_audio *chip = cval->head.mixer->chip;
|
||||
unsigned char buf[2 + 3 * sizeof(__u16)]; /* enough space for one range */
|
||||
unsigned char *val;
|
||||
int idx = 0, ret, size;
|
||||
@@ -347,7 +351,7 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request,
|
||||
if (chip->shutdown) {
|
||||
ret = -ENODEV;
|
||||
} else {
|
||||
idx = snd_usb_ctrl_intf(chip) | (cval->id << 8);
|
||||
idx = snd_usb_ctrl_intf(chip) | (cval->head.id << 8);
|
||||
ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), bRequest,
|
||||
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
|
||||
validx, idx, buf, size);
|
||||
@@ -392,7 +396,7 @@ static int get_ctl_value(struct usb_mixer_elem_info *cval, int request,
|
||||
{
|
||||
validx += cval->idx_off;
|
||||
|
||||
return (cval->mixer->protocol == UAC_VERSION_1) ?
|
||||
return (cval->head.mixer->protocol == UAC_VERSION_1) ?
|
||||
get_ctl_value_v1(cval, request, validx, value_ret) :
|
||||
get_ctl_value_v2(cval, request, validx, value_ret);
|
||||
}
|
||||
@@ -412,7 +416,7 @@ static inline int get_cur_mix_raw(struct usb_mixer_elem_info *cval,
|
||||
value);
|
||||
}
|
||||
|
||||
static int get_cur_mix_value(struct usb_mixer_elem_info *cval,
|
||||
int snd_usb_get_cur_mix_value(struct usb_mixer_elem_info *cval,
|
||||
int channel, int index, int *value)
|
||||
{
|
||||
int err;
|
||||
@@ -423,8 +427,8 @@ static int get_cur_mix_value(struct usb_mixer_elem_info *cval,
|
||||
}
|
||||
err = get_cur_mix_raw(cval, channel, value);
|
||||
if (err < 0) {
|
||||
if (!cval->mixer->ignore_ctl_error)
|
||||
usb_audio_dbg(cval->mixer->chip,
|
||||
if (!cval->head.mixer->ignore_ctl_error)
|
||||
usb_audio_dbg(cval->head.mixer->chip,
|
||||
"cannot get current value for control %d ch %d: err = %d\n",
|
||||
cval->control, channel, err);
|
||||
return err;
|
||||
@@ -441,13 +445,13 @@ static int get_cur_mix_value(struct usb_mixer_elem_info *cval,
|
||||
int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
|
||||
int request, int validx, int value_set)
|
||||
{
|
||||
struct snd_usb_audio *chip = cval->mixer->chip;
|
||||
struct snd_usb_audio *chip = cval->head.mixer->chip;
|
||||
unsigned char buf[2];
|
||||
int idx = 0, val_len, err, timeout = 10;
|
||||
|
||||
validx += cval->idx_off;
|
||||
|
||||
if (cval->mixer->protocol == UAC_VERSION_1) {
|
||||
if (cval->head.mixer->protocol == UAC_VERSION_1) {
|
||||
val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1;
|
||||
} else { /* UAC_VERSION_2 */
|
||||
/* audio class v2 controls are always 2 bytes in size */
|
||||
@@ -472,7 +476,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
|
||||
while (timeout-- > 0) {
|
||||
if (chip->shutdown)
|
||||
break;
|
||||
idx = snd_usb_ctrl_intf(chip) | (cval->id << 8);
|
||||
idx = snd_usb_ctrl_intf(chip) | (cval->head.id << 8);
|
||||
if (snd_usb_ctl_msg(chip->dev,
|
||||
usb_sndctrlpipe(chip->dev, 0), request,
|
||||
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
|
||||
@@ -497,7 +501,7 @@ static int set_cur_ctl_value(struct usb_mixer_elem_info *cval,
|
||||
return snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR, validx, value);
|
||||
}
|
||||
|
||||
static int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel,
|
||||
int snd_usb_set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel,
|
||||
int index, int value)
|
||||
{
|
||||
int err;
|
||||
@@ -506,7 +510,7 @@ static int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel,
|
||||
cval->ch_readonly & (1 << (channel - 1));
|
||||
|
||||
if (read_only) {
|
||||
usb_audio_dbg(cval->mixer->chip,
|
||||
usb_audio_dbg(cval->head.mixer->chip,
|
||||
"%s(): channel %d of control %d is read_only\n",
|
||||
__func__, channel, cval->control);
|
||||
return 0;
|
||||
@@ -565,10 +569,10 @@ static int check_matrix_bitmap(unsigned char *bmap,
|
||||
* if failed, give up and free the control instance.
|
||||
*/
|
||||
|
||||
int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer,
|
||||
int snd_usb_mixer_add_control(struct usb_mixer_elem_list *list,
|
||||
struct snd_kcontrol *kctl)
|
||||
{
|
||||
struct usb_mixer_elem_info *cval = kctl->private_data;
|
||||
struct usb_mixer_interface *mixer = list->mixer;
|
||||
int err;
|
||||
|
||||
while (snd_ctl_find_id(mixer->chip->card, &kctl->id))
|
||||
@@ -578,9 +582,9 @@ int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer,
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
cval->elem_id = &kctl->id;
|
||||
cval->next_id_elem = mixer->id_elems[cval->id];
|
||||
mixer->id_elems[cval->id] = cval;
|
||||
list->kctl = kctl;
|
||||
list->next_id_elem = mixer->id_elems[list->id];
|
||||
mixer->id_elems[list->id] = list;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -815,7 +819,7 @@ static struct usb_feature_control_info audio_feature_info[] = {
|
||||
};
|
||||
|
||||
/* private_free callback */
|
||||
static void usb_mixer_elem_free(struct snd_kcontrol *kctl)
|
||||
void snd_usb_mixer_elem_free(struct snd_kcontrol *kctl)
|
||||
{
|
||||
kfree(kctl->private_data);
|
||||
kctl->private_data = NULL;
|
||||
@@ -829,7 +833,7 @@ static void usb_mixer_elem_free(struct snd_kcontrol *kctl)
|
||||
static void volume_control_quirks(struct usb_mixer_elem_info *cval,
|
||||
struct snd_kcontrol *kctl)
|
||||
{
|
||||
struct snd_usb_audio *chip = cval->mixer->chip;
|
||||
struct snd_usb_audio *chip = cval->head.mixer->chip;
|
||||
switch (chip->usb_id) {
|
||||
case USB_ID(0x0763, 0x2030): /* M-Audio Fast Track C400 */
|
||||
case USB_ID(0x0763, 0x2031): /* M-Audio Fast Track C600 */
|
||||
@@ -954,10 +958,10 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval,
|
||||
}
|
||||
if (get_ctl_value(cval, UAC_GET_MAX, (cval->control << 8) | minchn, &cval->max) < 0 ||
|
||||
get_ctl_value(cval, UAC_GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) {
|
||||
usb_audio_err(cval->mixer->chip,
|
||||
usb_audio_err(cval->head.mixer->chip,
|
||||
"%d:%d: cannot get min/max values for control %d (id %d)\n",
|
||||
cval->id, snd_usb_ctrl_intf(cval->mixer->chip),
|
||||
cval->control, cval->id);
|
||||
cval->head.id, snd_usb_ctrl_intf(cval->head.mixer->chip),
|
||||
cval->control, cval->head.id);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (get_ctl_value(cval, UAC_GET_RES,
|
||||
@@ -998,7 +1002,7 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval,
|
||||
else
|
||||
test -= cval->res;
|
||||
if (test < cval->min || test > cval->max ||
|
||||
set_cur_mix_value(cval, minchn, 0, test) ||
|
||||
snd_usb_set_cur_mix_value(cval, minchn, 0, test) ||
|
||||
get_cur_mix_raw(cval, minchn, &check)) {
|
||||
cval->res = last_valid_res;
|
||||
break;
|
||||
@@ -1007,7 +1011,7 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval,
|
||||
break;
|
||||
cval->res *= 2;
|
||||
}
|
||||
set_cur_mix_value(cval, minchn, 0, saved);
|
||||
snd_usb_set_cur_mix_value(cval, minchn, 0, saved);
|
||||
}
|
||||
|
||||
cval->initialized = 1;
|
||||
@@ -1061,7 +1065,7 @@ static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol,
|
||||
kcontrol->vd[0].access &=
|
||||
~(SNDRV_CTL_ELEM_ACCESS_TLV_READ |
|
||||
SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK);
|
||||
snd_ctl_notify(cval->mixer->chip->card,
|
||||
snd_ctl_notify(cval->head.mixer->chip->card,
|
||||
SNDRV_CTL_EVENT_MASK_INFO,
|
||||
&kcontrol->id);
|
||||
}
|
||||
@@ -1086,9 +1090,9 @@ static int mixer_ctl_feature_get(struct snd_kcontrol *kcontrol,
|
||||
for (c = 0; c < MAX_CHANNELS; c++) {
|
||||
if (!(cval->cmask & (1 << c)))
|
||||
continue;
|
||||
err = get_cur_mix_value(cval, c + 1, cnt, &val);
|
||||
err = snd_usb_get_cur_mix_value(cval, c + 1, cnt, &val);
|
||||
if (err < 0)
|
||||
return cval->mixer->ignore_ctl_error ? 0 : err;
|
||||
return filter_error(cval, err);
|
||||
val = get_relative_value(cval, val);
|
||||
ucontrol->value.integer.value[cnt] = val;
|
||||
cnt++;
|
||||
@@ -1096,9 +1100,9 @@ static int mixer_ctl_feature_get(struct snd_kcontrol *kcontrol,
|
||||
return 0;
|
||||
} else {
|
||||
/* master channel */
|
||||
err = get_cur_mix_value(cval, 0, 0, &val);
|
||||
err = snd_usb_get_cur_mix_value(cval, 0, 0, &val);
|
||||
if (err < 0)
|
||||
return cval->mixer->ignore_ctl_error ? 0 : err;
|
||||
return filter_error(cval, err);
|
||||
val = get_relative_value(cval, val);
|
||||
ucontrol->value.integer.value[0] = val;
|
||||
}
|
||||
@@ -1118,26 +1122,26 @@ static int mixer_ctl_feature_put(struct snd_kcontrol *kcontrol,
|
||||
for (c = 0; c < MAX_CHANNELS; c++) {
|
||||
if (!(cval->cmask & (1 << c)))
|
||||
continue;
|
||||
err = get_cur_mix_value(cval, c + 1, cnt, &oval);
|
||||
err = snd_usb_get_cur_mix_value(cval, c + 1, cnt, &oval);
|
||||
if (err < 0)
|
||||
return cval->mixer->ignore_ctl_error ? 0 : err;
|
||||
return filter_error(cval, err);
|
||||
val = ucontrol->value.integer.value[cnt];
|
||||
val = get_abs_value(cval, val);
|
||||
if (oval != val) {
|
||||
set_cur_mix_value(cval, c + 1, cnt, val);
|
||||
snd_usb_set_cur_mix_value(cval, c + 1, cnt, val);
|
||||
changed = 1;
|
||||
}
|
||||
cnt++;
|
||||
}
|
||||
} else {
|
||||
/* master channel */
|
||||
err = get_cur_mix_value(cval, 0, 0, &oval);
|
||||
err = snd_usb_get_cur_mix_value(cval, 0, 0, &oval);
|
||||
if (err < 0)
|
||||
return cval->mixer->ignore_ctl_error ? 0 : err;
|
||||
return filter_error(cval, err);
|
||||
val = ucontrol->value.integer.value[0];
|
||||
val = get_abs_value(cval, val);
|
||||
if (val != oval) {
|
||||
set_cur_mix_value(cval, 0, 0, val);
|
||||
snd_usb_set_cur_mix_value(cval, 0, 0, val);
|
||||
changed = 1;
|
||||
}
|
||||
}
|
||||
@@ -1231,8 +1235,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
|
||||
cval = kzalloc(sizeof(*cval), GFP_KERNEL);
|
||||
if (!cval)
|
||||
return;
|
||||
cval->mixer = state->mixer;
|
||||
cval->id = unitid;
|
||||
snd_usb_mixer_elem_init_std(&cval->head, state->mixer, unitid);
|
||||
cval->control = control;
|
||||
cval->cmask = ctl_mask;
|
||||
cval->val_type = audio_feature_info[control-1].type;
|
||||
@@ -1250,7 +1253,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
|
||||
|
||||
/*
|
||||
* If all channels in the mask are marked read-only, make the control
|
||||
* read-only. set_cur_mix_value() will check the mask again and won't
|
||||
* read-only. snd_usb_set_cur_mix_value() will check the mask again and won't
|
||||
* issue write commands to read-only channels.
|
||||
*/
|
||||
if (cval->channels == readonly_mask)
|
||||
@@ -1263,7 +1266,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
|
||||
kfree(cval);
|
||||
return;
|
||||
}
|
||||
kctl->private_free = usb_mixer_elem_free;
|
||||
kctl->private_free = snd_usb_mixer_elem_free;
|
||||
|
||||
len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name));
|
||||
mapped_name = len != 0;
|
||||
@@ -1290,9 +1293,8 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
|
||||
kctl->id.name,
|
||||
sizeof(kctl->id.name), 1);
|
||||
if (!len)
|
||||
len = snprintf(kctl->id.name,
|
||||
sizeof(kctl->id.name),
|
||||
"Feature %d", unitid);
|
||||
snprintf(kctl->id.name, sizeof(kctl->id.name),
|
||||
"Feature %d", unitid);
|
||||
}
|
||||
|
||||
if (!mapped_name)
|
||||
@@ -1305,9 +1307,9 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
|
||||
*/
|
||||
if (!mapped_name && !(state->oterm.type >> 16)) {
|
||||
if ((state->oterm.type & 0xff00) == 0x0100)
|
||||
len = append_ctl_name(kctl, " Capture");
|
||||
append_ctl_name(kctl, " Capture");
|
||||
else
|
||||
len = append_ctl_name(kctl, " Playback");
|
||||
append_ctl_name(kctl, " Playback");
|
||||
}
|
||||
append_ctl_name(kctl, control == UAC_FU_MUTE ?
|
||||
" Switch" : " Volume");
|
||||
@@ -1344,14 +1346,14 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
|
||||
range);
|
||||
usb_audio_warn(state->chip,
|
||||
"[%d] FU [%s] ch = %d, val = %d/%d/%d",
|
||||
cval->id, kctl->id.name, cval->channels,
|
||||
cval->head.id, kctl->id.name, cval->channels,
|
||||
cval->min, cval->max, cval->res);
|
||||
}
|
||||
|
||||
usb_audio_dbg(state->chip, "[%d] FU [%s] ch = %d, val = %d/%d/%d\n",
|
||||
cval->id, kctl->id.name, cval->channels,
|
||||
cval->head.id, kctl->id.name, cval->channels,
|
||||
cval->min, cval->max, cval->res);
|
||||
snd_usb_mixer_add_control(state->mixer, kctl);
|
||||
snd_usb_mixer_add_control(&cval->head, kctl);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1525,8 +1527,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state,
|
||||
if (!cval)
|
||||
return;
|
||||
|
||||
cval->mixer = state->mixer;
|
||||
cval->id = unitid;
|
||||
snd_usb_mixer_elem_init_std(&cval->head, state->mixer, unitid);
|
||||
cval->control = in_ch + 1; /* based on 1 */
|
||||
cval->val_type = USB_MIXER_S16;
|
||||
for (i = 0; i < num_outs; i++) {
|
||||
@@ -1547,7 +1548,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state,
|
||||
kfree(cval);
|
||||
return;
|
||||
}
|
||||
kctl->private_free = usb_mixer_elem_free;
|
||||
kctl->private_free = snd_usb_mixer_elem_free;
|
||||
|
||||
len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name));
|
||||
if (!len)
|
||||
@@ -1558,8 +1559,8 @@ static void build_mixer_unit_ctl(struct mixer_build *state,
|
||||
append_ctl_name(kctl, " Volume");
|
||||
|
||||
usb_audio_dbg(state->chip, "[%d] MU [%s] ch = %d, val = %d/%d\n",
|
||||
cval->id, kctl->id.name, cval->channels, cval->min, cval->max);
|
||||
snd_usb_mixer_add_control(state->mixer, kctl);
|
||||
cval->head.id, kctl->id.name, cval->channels, cval->min, cval->max);
|
||||
snd_usb_mixer_add_control(&cval->head, kctl);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1629,12 +1630,10 @@ static int mixer_ctl_procunit_get(struct snd_kcontrol *kcontrol,
|
||||
int err, val;
|
||||
|
||||
err = get_cur_ctl_value(cval, cval->control << 8, &val);
|
||||
if (err < 0 && cval->mixer->ignore_ctl_error) {
|
||||
if (err < 0) {
|
||||
ucontrol->value.integer.value[0] = cval->min;
|
||||
return 0;
|
||||
return filter_error(cval, err);
|
||||
}
|
||||
if (err < 0)
|
||||
return err;
|
||||
val = get_relative_value(cval, val);
|
||||
ucontrol->value.integer.value[0] = val;
|
||||
return 0;
|
||||
@@ -1648,11 +1647,8 @@ static int mixer_ctl_procunit_put(struct snd_kcontrol *kcontrol,
|
||||
int val, oval, err;
|
||||
|
||||
err = get_cur_ctl_value(cval, cval->control << 8, &oval);
|
||||
if (err < 0) {
|
||||
if (cval->mixer->ignore_ctl_error)
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
if (err < 0)
|
||||
return filter_error(cval, err);
|
||||
val = ucontrol->value.integer.value[0];
|
||||
val = get_abs_value(cval, val);
|
||||
if (val != oval) {
|
||||
@@ -1814,8 +1810,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid,
|
||||
cval = kzalloc(sizeof(*cval), GFP_KERNEL);
|
||||
if (!cval)
|
||||
return -ENOMEM;
|
||||
cval->mixer = state->mixer;
|
||||
cval->id = unitid;
|
||||
snd_usb_mixer_elem_init_std(&cval->head, state->mixer, unitid);
|
||||
cval->control = valinfo->control;
|
||||
cval->val_type = valinfo->val_type;
|
||||
cval->channels = 1;
|
||||
@@ -1847,7 +1842,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid,
|
||||
kfree(cval);
|
||||
return -ENOMEM;
|
||||
}
|
||||
kctl->private_free = usb_mixer_elem_free;
|
||||
kctl->private_free = snd_usb_mixer_elem_free;
|
||||
|
||||
if (check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name))) {
|
||||
/* nothing */ ;
|
||||
@@ -1868,10 +1863,10 @@ static int build_audio_procunit(struct mixer_build *state, int unitid,
|
||||
|
||||
usb_audio_dbg(state->chip,
|
||||
"[%d] PU [%s] ch = %d, val = %d/%d\n",
|
||||
cval->id, kctl->id.name, cval->channels,
|
||||
cval->head.id, kctl->id.name, cval->channels,
|
||||
cval->min, cval->max);
|
||||
|
||||
err = snd_usb_mixer_add_control(state->mixer, kctl);
|
||||
err = snd_usb_mixer_add_control(&cval->head, kctl);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
@@ -1924,11 +1919,8 @@ static int mixer_ctl_selector_get(struct snd_kcontrol *kcontrol,
|
||||
|
||||
err = get_cur_ctl_value(cval, cval->control << 8, &val);
|
||||
if (err < 0) {
|
||||
if (cval->mixer->ignore_ctl_error) {
|
||||
ucontrol->value.enumerated.item[0] = 0;
|
||||
return 0;
|
||||
}
|
||||
return err;
|
||||
ucontrol->value.enumerated.item[0] = 0;
|
||||
return filter_error(cval, err);
|
||||
}
|
||||
val = get_relative_value(cval, val);
|
||||
ucontrol->value.enumerated.item[0] = val;
|
||||
@@ -1943,11 +1935,8 @@ static int mixer_ctl_selector_put(struct snd_kcontrol *kcontrol,
|
||||
int val, oval, err;
|
||||
|
||||
err = get_cur_ctl_value(cval, cval->control << 8, &oval);
|
||||
if (err < 0) {
|
||||
if (cval->mixer->ignore_ctl_error)
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
if (err < 0)
|
||||
return filter_error(cval, err);
|
||||
val = ucontrol->value.enumerated.item[0];
|
||||
val = get_abs_value(cval, val);
|
||||
if (val != oval) {
|
||||
@@ -2024,8 +2013,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid,
|
||||
cval = kzalloc(sizeof(*cval), GFP_KERNEL);
|
||||
if (!cval)
|
||||
return -ENOMEM;
|
||||
cval->mixer = state->mixer;
|
||||
cval->id = unitid;
|
||||
snd_usb_mixer_elem_init_std(&cval->head, state->mixer, unitid);
|
||||
cval->val_type = USB_MIXER_U8;
|
||||
cval->channels = 1;
|
||||
cval->min = 1;
|
||||
@@ -2096,11 +2084,8 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid,
|
||||
}
|
||||
|
||||
usb_audio_dbg(state->chip, "[%d] SU [%s] items = %d\n",
|
||||
cval->id, kctl->id.name, desc->bNrInPins);
|
||||
if ((err = snd_usb_mixer_add_control(state->mixer, kctl)) < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
cval->head.id, kctl->id.name, desc->bNrInPins);
|
||||
return snd_usb_mixer_add_control(&cval->head, kctl);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2245,25 +2230,21 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer)
|
||||
|
||||
void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, int unitid)
|
||||
{
|
||||
struct usb_mixer_elem_info *info;
|
||||
struct usb_mixer_elem_list *list;
|
||||
|
||||
for (info = mixer->id_elems[unitid]; info; info = info->next_id_elem)
|
||||
for (list = mixer->id_elems[unitid]; list; list = list->next_id_elem)
|
||||
snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
|
||||
info->elem_id);
|
||||
&list->kctl->id);
|
||||
}
|
||||
|
||||
static void snd_usb_mixer_dump_cval(struct snd_info_buffer *buffer,
|
||||
int unitid,
|
||||
struct usb_mixer_elem_info *cval)
|
||||
struct usb_mixer_elem_list *list)
|
||||
{
|
||||
struct usb_mixer_elem_info *cval = (struct usb_mixer_elem_info *)list;
|
||||
static char *val_types[] = {"BOOLEAN", "INV_BOOLEAN",
|
||||
"S8", "U8", "S16", "U16"};
|
||||
snd_iprintf(buffer, " Unit: %i\n", unitid);
|
||||
if (cval->elem_id)
|
||||
snd_iprintf(buffer, " Control: name=\"%s\", index=%i\n",
|
||||
cval->elem_id->name, cval->elem_id->index);
|
||||
snd_iprintf(buffer, " Info: id=%i, control=%i, cmask=0x%x, "
|
||||
"channels=%i, type=\"%s\"\n", cval->id,
|
||||
"channels=%i, type=\"%s\"\n", cval->head.id,
|
||||
cval->control, cval->cmask, cval->channels,
|
||||
val_types[cval->val_type]);
|
||||
snd_iprintf(buffer, " Volume: min=%i, max=%i, dBmin=%i, dBmax=%i\n",
|
||||
@@ -2275,7 +2256,7 @@ static void snd_usb_mixer_proc_read(struct snd_info_entry *entry,
|
||||
{
|
||||
struct snd_usb_audio *chip = entry->private_data;
|
||||
struct usb_mixer_interface *mixer;
|
||||
struct usb_mixer_elem_info *cval;
|
||||
struct usb_mixer_elem_list *list;
|
||||
int unitid;
|
||||
|
||||
list_for_each_entry(mixer, &chip->mixer_list, list) {
|
||||
@@ -2285,9 +2266,17 @@ static void snd_usb_mixer_proc_read(struct snd_info_entry *entry,
|
||||
mixer->ignore_ctl_error);
|
||||
snd_iprintf(buffer, "Card: %s\n", chip->card->longname);
|
||||
for (unitid = 0; unitid < MAX_ID_ELEMS; unitid++) {
|
||||
for (cval = mixer->id_elems[unitid]; cval;
|
||||
cval = cval->next_id_elem)
|
||||
snd_usb_mixer_dump_cval(buffer, unitid, cval);
|
||||
for (list = mixer->id_elems[unitid]; list;
|
||||
list = list->next_id_elem) {
|
||||
snd_iprintf(buffer, " Unit: %i\n", list->id);
|
||||
if (list->kctl)
|
||||
snd_iprintf(buffer,
|
||||
" Control: name=\"%s\", index=%i\n",
|
||||
list->kctl->id.name,
|
||||
list->kctl->id.index);
|
||||
if (list->dump)
|
||||
list->dump(buffer, list);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2295,7 +2284,7 @@ static void snd_usb_mixer_proc_read(struct snd_info_entry *entry,
|
||||
static void snd_usb_mixer_interrupt_v2(struct usb_mixer_interface *mixer,
|
||||
int attribute, int value, int index)
|
||||
{
|
||||
struct usb_mixer_elem_info *info;
|
||||
struct usb_mixer_elem_list *list;
|
||||
__u8 unitid = (index >> 8) & 0xff;
|
||||
__u8 control = (value >> 8) & 0xff;
|
||||
__u8 channel = value & 0xff;
|
||||
@@ -2307,7 +2296,13 @@ static void snd_usb_mixer_interrupt_v2(struct usb_mixer_interface *mixer,
|
||||
return;
|
||||
}
|
||||
|
||||
for (info = mixer->id_elems[unitid]; info; info = info->next_id_elem) {
|
||||
for (list = mixer->id_elems[unitid]; list; list = list->next_id_elem) {
|
||||
struct usb_mixer_elem_info *info;
|
||||
|
||||
if (!list->kctl)
|
||||
continue;
|
||||
|
||||
info = (struct usb_mixer_elem_info *)list;
|
||||
if (info->control != control)
|
||||
continue;
|
||||
|
||||
@@ -2320,7 +2315,7 @@ static void snd_usb_mixer_interrupt_v2(struct usb_mixer_interface *mixer,
|
||||
info->cached = 0;
|
||||
|
||||
snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
|
||||
info->elem_id);
|
||||
&info->head.kctl->id);
|
||||
break;
|
||||
|
||||
case UAC2_CS_RANGE:
|
||||
@@ -2485,11 +2480,8 @@ _error:
|
||||
return err;
|
||||
}
|
||||
|
||||
void snd_usb_mixer_disconnect(struct list_head *p)
|
||||
void snd_usb_mixer_disconnect(struct usb_mixer_interface *mixer)
|
||||
{
|
||||
struct usb_mixer_interface *mixer;
|
||||
|
||||
mixer = list_entry(p, struct usb_mixer_interface, list);
|
||||
usb_kill_urb(mixer->urb);
|
||||
usb_kill_urb(mixer->rc_urb);
|
||||
}
|
||||
@@ -2521,8 +2513,9 @@ int snd_usb_mixer_suspend(struct usb_mixer_interface *mixer)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int restore_mixer_value(struct usb_mixer_elem_info *cval)
|
||||
static int restore_mixer_value(struct usb_mixer_elem_list *list)
|
||||
{
|
||||
struct usb_mixer_elem_info *cval = (struct usb_mixer_elem_info *)list;
|
||||
int c, err, idx;
|
||||
|
||||
if (cval->cmask) {
|
||||
@@ -2531,7 +2524,7 @@ static int restore_mixer_value(struct usb_mixer_elem_info *cval)
|
||||
if (!(cval->cmask & (1 << c)))
|
||||
continue;
|
||||
if (cval->cached & (1 << c)) {
|
||||
err = set_cur_mix_value(cval, c + 1, idx,
|
||||
err = snd_usb_set_cur_mix_value(cval, c + 1, idx,
|
||||
cval->cache_val[idx]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
@@ -2541,7 +2534,7 @@ static int restore_mixer_value(struct usb_mixer_elem_info *cval)
|
||||
} else {
|
||||
/* master */
|
||||
if (cval->cached) {
|
||||
err = set_cur_mix_value(cval, 0, 0, *cval->cache_val);
|
||||
err = snd_usb_set_cur_mix_value(cval, 0, 0, *cval->cache_val);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
@@ -2552,19 +2545,19 @@ static int restore_mixer_value(struct usb_mixer_elem_info *cval)
|
||||
|
||||
int snd_usb_mixer_resume(struct usb_mixer_interface *mixer, bool reset_resume)
|
||||
{
|
||||
struct usb_mixer_elem_info *cval;
|
||||
struct usb_mixer_elem_list *list;
|
||||
int id, err;
|
||||
|
||||
/* FIXME: any mixer quirks? */
|
||||
|
||||
if (reset_resume) {
|
||||
/* restore cached mixer values */
|
||||
for (id = 0; id < MAX_ID_ELEMS; id++) {
|
||||
for (cval = mixer->id_elems[id]; cval;
|
||||
cval = cval->next_id_elem) {
|
||||
err = restore_mixer_value(cval);
|
||||
if (err < 0)
|
||||
return err;
|
||||
for (list = mixer->id_elems[id]; list;
|
||||
list = list->next_id_elem) {
|
||||
if (list->resume) {
|
||||
err = list->resume(list);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2572,3 +2565,15 @@ int snd_usb_mixer_resume(struct usb_mixer_interface *mixer, bool reset_resume)
|
||||
return snd_usb_mixer_activate(mixer);
|
||||
}
|
||||
#endif
|
||||
|
||||
void snd_usb_mixer_elem_init_std(struct usb_mixer_elem_list *list,
|
||||
struct usb_mixer_interface *mixer,
|
||||
int unitid)
|
||||
{
|
||||
list->mixer = mixer;
|
||||
list->id = unitid;
|
||||
list->dump = snd_usb_mixer_dump_cval;
|
||||
#ifdef CONFIG_PM
|
||||
list->resume = restore_mixer_value;
|
||||
#endif
|
||||
}
|
||||
|
@@ -1,6 +1,8 @@
|
||||
#ifndef __USBMIXER_H
|
||||
#define __USBMIXER_H
|
||||
|
||||
#include <sound/info.h>
|
||||
|
||||
struct usb_mixer_interface {
|
||||
struct snd_usb_audio *chip;
|
||||
struct usb_host_interface *hostif;
|
||||
@@ -8,7 +10,7 @@ struct usb_mixer_interface {
|
||||
unsigned int ignore_ctl_error;
|
||||
struct urb *urb;
|
||||
/* array[MAX_ID_ELEMS], indexed by unit id */
|
||||
struct usb_mixer_elem_info **id_elems;
|
||||
struct usb_mixer_elem_list **id_elems;
|
||||
|
||||
/* the usb audio specification version this interface complies to */
|
||||
int protocol;
|
||||
@@ -20,9 +22,6 @@ struct usb_mixer_interface {
|
||||
struct urb *rc_urb;
|
||||
struct usb_ctrlrequest *rc_setup_packet;
|
||||
u8 rc_buffer[6];
|
||||
|
||||
u8 audigy2nx_leds[3];
|
||||
u8 xonar_u1_status;
|
||||
};
|
||||
|
||||
#define MAX_CHANNELS 16 /* max logical channels */
|
||||
@@ -36,11 +35,21 @@ enum {
|
||||
USB_MIXER_U16,
|
||||
};
|
||||
|
||||
struct usb_mixer_elem_info {
|
||||
typedef void (*usb_mixer_elem_dump_func_t)(struct snd_info_buffer *buffer,
|
||||
struct usb_mixer_elem_list *list);
|
||||
typedef int (*usb_mixer_elem_resume_func_t)(struct usb_mixer_elem_list *elem);
|
||||
|
||||
struct usb_mixer_elem_list {
|
||||
struct usb_mixer_interface *mixer;
|
||||
struct usb_mixer_elem_info *next_id_elem; /* list of controls with same id */
|
||||
struct snd_ctl_elem_id *elem_id;
|
||||
struct usb_mixer_elem_list *next_id_elem; /* list of controls with same id */
|
||||
struct snd_kcontrol *kctl;
|
||||
unsigned int id;
|
||||
usb_mixer_elem_dump_func_t dump;
|
||||
usb_mixer_elem_resume_func_t resume;
|
||||
};
|
||||
|
||||
struct usb_mixer_elem_info {
|
||||
struct usb_mixer_elem_list head;
|
||||
unsigned int control; /* CS or ICN (high byte) */
|
||||
unsigned int cmask; /* channel mask bitmap: 0 = master */
|
||||
unsigned int idx_off; /* Control index offset */
|
||||
@@ -53,20 +62,25 @@ struct usb_mixer_elem_info {
|
||||
int cached;
|
||||
int cache_val[MAX_CHANNELS];
|
||||
u8 initialized;
|
||||
void *private_data;
|
||||
};
|
||||
|
||||
int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
|
||||
int ignore_error);
|
||||
void snd_usb_mixer_disconnect(struct list_head *p);
|
||||
void snd_usb_mixer_disconnect(struct usb_mixer_interface *mixer);
|
||||
|
||||
void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, int unitid);
|
||||
|
||||
int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
|
||||
int request, int validx, int value_set);
|
||||
|
||||
int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer,
|
||||
int snd_usb_mixer_add_control(struct usb_mixer_elem_list *list,
|
||||
struct snd_kcontrol *kctl);
|
||||
|
||||
void snd_usb_mixer_elem_init_std(struct usb_mixer_elem_list *list,
|
||||
struct usb_mixer_interface *mixer,
|
||||
int unitid);
|
||||
|
||||
int snd_usb_mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
|
||||
unsigned int size, unsigned int __user *_tlv);
|
||||
|
||||
@@ -75,4 +89,12 @@ int snd_usb_mixer_suspend(struct usb_mixer_interface *mixer);
|
||||
int snd_usb_mixer_resume(struct usb_mixer_interface *mixer, bool reset_resume);
|
||||
#endif
|
||||
|
||||
int snd_usb_set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel,
|
||||
int index, int value);
|
||||
|
||||
int snd_usb_get_cur_mix_value(struct usb_mixer_elem_info *cval,
|
||||
int channel, int index, int *value);
|
||||
|
||||
extern void snd_usb_mixer_elem_free(struct snd_kcontrol *kctl);
|
||||
|
||||
#endif /* __USBMIXER_H */
|
||||
|
@@ -179,6 +179,11 @@ static struct usbmix_name_map audigy2nx_map[] = {
|
||||
{ 0 } /* terminator */
|
||||
};
|
||||
|
||||
static struct usbmix_name_map mbox1_map[] = {
|
||||
{ 1, "Clock" },
|
||||
{ 0 } /* terminator */
|
||||
};
|
||||
|
||||
static struct usbmix_selector_map c400_selectors[] = {
|
||||
{
|
||||
.id = 0x80,
|
||||
@@ -415,6 +420,10 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = {
|
||||
.id = USB_ID(0x0ccd, 0x0028),
|
||||
.map = aureon_51_2_map,
|
||||
},
|
||||
{
|
||||
.id = USB_ID(0x0dba, 0x1000),
|
||||
.map = mbox1_map,
|
||||
},
|
||||
{
|
||||
.id = USB_ID(0x13e5, 0x0001),
|
||||
.map = scratch_live_map,
|
||||
|
ファイル差分が大きすぎるため省略します
差分を読み込み
1004
sound/usb/mixer_scarlett.c
ノーマルファイル
1004
sound/usb/mixer_scarlett.c
ノーマルファイル
ファイル差分が大きすぎるため省略します
差分を読み込み
6
sound/usb/mixer_scarlett.h
ノーマルファイル
6
sound/usb/mixer_scarlett.h
ノーマルファイル
@@ -0,0 +1,6 @@
|
||||
#ifndef __USB_MIXER_SCARLETT_H
|
||||
#define __USB_MIXER_SCARLETT_H
|
||||
|
||||
int snd_scarlett_controls_create(struct usb_mixer_interface *mixer);
|
||||
|
||||
#endif /* __USB_MIXER_SCARLETT_H */
|
@@ -482,6 +482,11 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
|
||||
/* set interface */
|
||||
if (subs->interface != fmt->iface ||
|
||||
subs->altset_idx != fmt->altset_idx) {
|
||||
|
||||
err = snd_usb_select_mode_quirk(subs, fmt);
|
||||
if (err < 0)
|
||||
return -EIO;
|
||||
|
||||
err = usb_set_interface(dev, fmt->iface, fmt->altsetting);
|
||||
if (err < 0) {
|
||||
dev_err(&dev->dev,
|
||||
|
@@ -2667,57 +2667,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
|
||||
.type = QUIRK_MIDI_NOVATION
|
||||
}
|
||||
},
|
||||
{
|
||||
/*
|
||||
* Focusrite Scarlett 18i6
|
||||
*
|
||||
* Avoid mixer creation, which otherwise fails because some of
|
||||
* the interface descriptor subtypes for interface 0 are
|
||||
* unknown. That should be fixed or worked-around but this at
|
||||
* least allows the device to be used successfully with a DAW
|
||||
* and an external mixer. See comments below about other
|
||||
* ignored interfaces.
|
||||
*/
|
||||
USB_DEVICE(0x1235, 0x8004),
|
||||
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
|
||||
.vendor_name = "Focusrite",
|
||||
.product_name = "Scarlett 18i6",
|
||||
.ifnum = QUIRK_ANY_INTERFACE,
|
||||
.type = QUIRK_COMPOSITE,
|
||||
.data = & (const struct snd_usb_audio_quirk[]) {
|
||||
{
|
||||
/* InterfaceSubClass 1 (Control Device) */
|
||||
.ifnum = 0,
|
||||
.type = QUIRK_IGNORE_INTERFACE
|
||||
},
|
||||
{
|
||||
.ifnum = 1,
|
||||
.type = QUIRK_AUDIO_STANDARD_INTERFACE
|
||||
},
|
||||
{
|
||||
.ifnum = 2,
|
||||
.type = QUIRK_AUDIO_STANDARD_INTERFACE
|
||||
},
|
||||
{
|
||||
/* InterfaceSubClass 1 (Control Device) */
|
||||
.ifnum = 3,
|
||||
.type = QUIRK_IGNORE_INTERFACE
|
||||
},
|
||||
{
|
||||
.ifnum = 4,
|
||||
.type = QUIRK_MIDI_STANDARD_INTERFACE
|
||||
},
|
||||
{
|
||||
/* InterfaceSubClass 1 (Device Firmware Update) */
|
||||
.ifnum = 5,
|
||||
.type = QUIRK_IGNORE_INTERFACE
|
||||
},
|
||||
{
|
||||
.ifnum = -1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/* Access Music devices */
|
||||
{
|
||||
@@ -2856,7 +2805,7 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
|
||||
.data = (const struct snd_usb_audio_quirk[]){
|
||||
{
|
||||
.ifnum = 0,
|
||||
.type = QUIRK_IGNORE_INTERFACE,
|
||||
.type = QUIRK_AUDIO_STANDARD_MIXER,
|
||||
},
|
||||
{
|
||||
.ifnum = 1,
|
||||
@@ -2867,16 +2816,40 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
|
||||
.iface = 1,
|
||||
.altsetting = 1,
|
||||
.altset_idx = 1,
|
||||
.attributes = UAC_EP_CS_ATTR_SAMPLE_RATE,
|
||||
.attributes = 0x4,
|
||||
.endpoint = 0x02,
|
||||
.ep_attr = 0x01,
|
||||
.rates = SNDRV_PCM_RATE_44100 |
|
||||
SNDRV_PCM_RATE_48000,
|
||||
.rate_min = 44100,
|
||||
.ep_attr = USB_ENDPOINT_XFER_ISOC |
|
||||
USB_ENDPOINT_SYNC_SYNC,
|
||||
.maxpacksize = 0x130,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.rate_min = 48000,
|
||||
.rate_max = 48000,
|
||||
.nr_rates = 2,
|
||||
.nr_rates = 1,
|
||||
.rate_table = (unsigned int[]) {
|
||||
44100, 48000
|
||||
48000
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
.ifnum = 1,
|
||||
.type = QUIRK_AUDIO_FIXED_ENDPOINT,
|
||||
.data = &(const struct audioformat) {
|
||||
.formats = SNDRV_PCM_FMTBIT_S24_3BE,
|
||||
.channels = 2,
|
||||
.iface = 1,
|
||||
.altsetting = 1,
|
||||
.altset_idx = 1,
|
||||
.attributes = 0x4,
|
||||
.endpoint = 0x81,
|
||||
.ep_attr = USB_ENDPOINT_XFER_ISOC |
|
||||
USB_ENDPOINT_SYNC_ASYNC,
|
||||
.maxpacksize = 0x130,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.rate_min = 48000,
|
||||
.rate_max = 48000,
|
||||
.nr_rates = 1,
|
||||
.rate_table = (unsigned int[]) {
|
||||
48000
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -2884,7 +2857,6 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
|
||||
.ifnum = -1
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
@@ -3113,6 +3085,46 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
/*
|
||||
* ZOOM R16/24 in audio interface mode.
|
||||
* Mixer descriptors are garbage, further quirks will be needed
|
||||
* to make any of it functional, thus disabled for now.
|
||||
* Playback stream appears to start and run fine but no sound
|
||||
* is produced, so also disabled for now.
|
||||
*/
|
||||
USB_DEVICE(0x1686, 0x00dd),
|
||||
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
|
||||
.ifnum = QUIRK_ANY_INTERFACE,
|
||||
.type = QUIRK_COMPOSITE,
|
||||
.data = (const struct snd_usb_audio_quirk[]) {
|
||||
{
|
||||
/* Mixer */
|
||||
.ifnum = 0,
|
||||
.type = QUIRK_IGNORE_INTERFACE,
|
||||
},
|
||||
{
|
||||
/* Playback */
|
||||
.ifnum = 1,
|
||||
.type = QUIRK_IGNORE_INTERFACE,
|
||||
},
|
||||
{
|
||||
/* Capture */
|
||||
.ifnum = 2,
|
||||
.type = QUIRK_AUDIO_STANDARD_INTERFACE,
|
||||
},
|
||||
{
|
||||
/* Midi */
|
||||
.ifnum = 3,
|
||||
.type = QUIRK_MIDI_STANDARD_INTERFACE
|
||||
},
|
||||
{
|
||||
.ifnum = -1
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
/*
|
||||
* Some USB MIDI devices don't have an audio control interface,
|
||||
|
@@ -43,12 +43,13 @@
|
||||
static int create_composite_quirk(struct snd_usb_audio *chip,
|
||||
struct usb_interface *iface,
|
||||
struct usb_driver *driver,
|
||||
const struct snd_usb_audio_quirk *quirk)
|
||||
const struct snd_usb_audio_quirk *quirk_comp)
|
||||
{
|
||||
int probed_ifnum = get_iface_desc(iface->altsetting)->bInterfaceNumber;
|
||||
const struct snd_usb_audio_quirk *quirk;
|
||||
int err;
|
||||
|
||||
for (quirk = quirk->data; quirk->ifnum >= 0; ++quirk) {
|
||||
for (quirk = quirk_comp->data; quirk->ifnum >= 0; ++quirk) {
|
||||
iface = usb_ifnum_to_if(chip->dev, quirk->ifnum);
|
||||
if (!iface)
|
||||
continue;
|
||||
@@ -58,9 +59,17 @@ static int create_composite_quirk(struct snd_usb_audio *chip,
|
||||
err = snd_usb_create_quirk(chip, iface, driver, quirk);
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (quirk->ifnum != probed_ifnum)
|
||||
}
|
||||
|
||||
for (quirk = quirk_comp->data; quirk->ifnum >= 0; ++quirk) {
|
||||
iface = usb_ifnum_to_if(chip->dev, quirk->ifnum);
|
||||
if (!iface)
|
||||
continue;
|
||||
if (quirk->ifnum != probed_ifnum &&
|
||||
!usb_interface_claimed(iface))
|
||||
usb_driver_claim_interface(driver, iface, (void *)-1L);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1102,6 +1111,44 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Marantz/Denon USB DACs need a vendor cmd to switch
|
||||
* between PCM and native DSD mode
|
||||
*/
|
||||
int snd_usb_select_mode_quirk(struct snd_usb_substream *subs,
|
||||
struct audioformat *fmt)
|
||||
{
|
||||
struct usb_device *dev = subs->dev;
|
||||
int err;
|
||||
|
||||
switch (subs->stream->chip->usb_id) {
|
||||
case USB_ID(0x154e, 0x3005): /* Marantz HD-DAC1 */
|
||||
case USB_ID(0x154e, 0x3006): /* Marantz SA-14S1 */
|
||||
|
||||
/* First switch to alt set 0, otherwise the mode switch cmd
|
||||
* will not be accepted by the DAC
|
||||
*/
|
||||
err = usb_set_interface(dev, fmt->iface, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
mdelay(20); /* Delay needed after setting the interface */
|
||||
|
||||
switch (fmt->altsetting) {
|
||||
case 2: /* DSD mode requested */
|
||||
case 1: /* PCM mode requested */
|
||||
err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), 0,
|
||||
USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE,
|
||||
fmt->altsetting - 1, 1, NULL, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
break;
|
||||
}
|
||||
mdelay(20);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void snd_usb_endpoint_start_quirk(struct snd_usb_endpoint *ep)
|
||||
{
|
||||
/*
|
||||
@@ -1160,6 +1207,14 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe,
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Zoom R16/24 needs a tiny delay here, otherwise requests like
|
||||
* get/set frequency return as failed despite actually succeeding.
|
||||
*/
|
||||
if ((le16_to_cpu(dev->descriptor.idVendor) == 0x1686) &&
|
||||
(le16_to_cpu(dev->descriptor.idProduct) == 0x00dd) &&
|
||||
(requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
|
||||
mdelay(1);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1204,5 +1259,16 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
|
||||
break;
|
||||
}
|
||||
|
||||
/* Denon/Marantz devices with USB DAC functionality */
|
||||
switch (chip->usb_id) {
|
||||
case USB_ID(0x154e, 0x3005): /* Marantz HD-DAC1 */
|
||||
case USB_ID(0x154e, 0x3006): /* Marantz SA-14S1 */
|
||||
if (fp->altsetting == 2)
|
||||
return SNDRV_PCM_FMTBIT_DSD_U32_BE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -31,6 +31,9 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe,
|
||||
__u8 request, __u8 requesttype, __u16 value,
|
||||
__u16 index, void *data, __u16 size);
|
||||
|
||||
int snd_usb_select_mode_quirk(struct snd_usb_substream *subs,
|
||||
struct audioformat *fmt);
|
||||
|
||||
u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
|
||||
struct audioformat *fp,
|
||||
unsigned int sample_bytes);
|
||||
|
@@ -272,13 +272,8 @@ static void usX2Y_clients_stop(struct usX2Ydev *usX2Y)
|
||||
for (s = 0; s < 4; s++) {
|
||||
struct snd_usX2Y_substream *subs = usX2Y->subs[s];
|
||||
if (subs) {
|
||||
if (atomic_read(&subs->state) >= state_PRERUNNING) {
|
||||
unsigned long flags;
|
||||
|
||||
snd_pcm_stream_lock_irqsave(subs->pcm_substream, flags);
|
||||
snd_pcm_stop(subs->pcm_substream, SNDRV_PCM_STATE_XRUN);
|
||||
snd_pcm_stream_unlock_irqrestore(subs->pcm_substream, flags);
|
||||
}
|
||||
if (atomic_read(&subs->state) >= state_PRERUNNING)
|
||||
snd_pcm_stop_xrun(subs->pcm_substream);
|
||||
for (u = 0; u < NRURBS; u++) {
|
||||
struct urb *urb = subs->urb[u];
|
||||
if (NULL != urb)
|
||||
|
新しいイシューから参照
ユーザーをブロックする