Merge branch 'for-next' into for-linus
这个提交包含在:
@@ -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);
|
||||
|
@@ -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 */
|
||||
{
|
||||
@@ -2944,7 +2893,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
|
||||
.data = (const struct snd_usb_audio_quirk[]){
|
||||
{
|
||||
.ifnum = 0,
|
||||
.type = QUIRK_IGNORE_INTERFACE,
|
||||
.type = QUIRK_AUDIO_STANDARD_MIXER,
|
||||
},
|
||||
{
|
||||
.ifnum = 1,
|
||||
@@ -2955,16 +2904,40 @@ YAMAHA_DEVICE(0x7010, "UB99"),
|
||||
.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
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -2972,7 +2945,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
|
||||
.ifnum = -1
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
@@ -3201,6 +3173,46 @@ YAMAHA_DEVICE(0x7010, "UB99"),
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
/*
|
||||
* 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)
|
||||
|
在新工单中引用
屏蔽一个用户