Commit 09cefbb6 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6: (26 commits)
  ASoC: Fix power down for widgetless per-card DAPM context case
  ASoC: wm1250-ev1: Define "WM1250 Output" with SND_SOC_DAPM_OUTPUT
  ASoC: Remove duplicate linux/delay.h inclusion.
  ASoC: sam9g20_wm8731: use the proper SYSCKL value
  ASoC: wm8731: fix wm8731_check_osc() connected condition
  ALSA: hda - Reorganize controller quriks with bit flags
  ALSA: hda - Use snd_printd() in snd_hda_parse_pin_def_config()
  ALSA: core: remove unused variables.
  ALSA: HDA: Increase MAX_HDMI_PINS
  ALSA: PCM - Don't check DMA time-out too shortly
  MAINTAINERS: add FireWire audio maintainer
  ALSA: usb-audio: more control quirks for M-Audio FastTrack devices
  ALSA: usb-audio: add new quirk type QUIRK_AUDIO_STANDARD_MIXER
  ALSA: usb-audio: export snd_usb_feature_unit_ctl
  ALSA: usb-audio: rework add_control_to_empty()
  ALSA: usb-audio: move assignment of chip->ctrl_intf
  ALSA: hda - Use model=auto for Lenovo G555
  ALSA: HDA: Unify HDMI hotplug handling.
  ALSA: hda - Force AD1988_6STACK_DIG for Asus M3N-HT Deluxe
  ASoC: core - remove superfluous new line.
  ...
parents dc7acbb2 cf73df1e
...@@ -2584,6 +2584,13 @@ S: Maintained ...@@ -2584,6 +2584,13 @@ S: Maintained
F: drivers/hwmon/f75375s.c F: drivers/hwmon/f75375s.c
F: include/linux/f75375s.h F: include/linux/f75375s.h
FIREWIRE AUDIO DRIVERS
M: Clemens Ladisch <clemens@ladisch.de>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
T: git git://git.alsa-project.org/alsa-kernel.git
S: Maintained
F: sound/firewire/
FIREWIRE SUBSYSTEM FIREWIRE SUBSYSTEM
M: Stefan Richter <stefanr@s5r6.in-berlin.de> M: Stefan Richter <stefanr@s5r6.in-berlin.de>
L: linux1394-devel@lists.sourceforge.net L: linux1394-devel@lists.sourceforge.net
......
...@@ -704,13 +704,12 @@ static int snd_ctl_elem_list(struct snd_card *card, ...@@ -704,13 +704,12 @@ static int snd_ctl_elem_list(struct snd_card *card,
struct snd_ctl_elem_list list; struct snd_ctl_elem_list list;
struct snd_kcontrol *kctl; struct snd_kcontrol *kctl;
struct snd_ctl_elem_id *dst, *id; struct snd_ctl_elem_id *dst, *id;
unsigned int offset, space, first, jidx; unsigned int offset, space, jidx;
if (copy_from_user(&list, _list, sizeof(list))) if (copy_from_user(&list, _list, sizeof(list)))
return -EFAULT; return -EFAULT;
offset = list.offset; offset = list.offset;
space = list.space; space = list.space;
first = 0;
/* try limit maximum space */ /* try limit maximum space */
if (space > 16384) if (space > 16384)
return -ENOMEM; return -ENOMEM;
......
...@@ -342,7 +342,6 @@ static const struct file_operations snd_shutdown_f_ops = ...@@ -342,7 +342,6 @@ static const struct file_operations snd_shutdown_f_ops =
int snd_card_disconnect(struct snd_card *card) int snd_card_disconnect(struct snd_card *card)
{ {
struct snd_monitor_file *mfile; struct snd_monitor_file *mfile;
struct file *file;
int err; int err;
if (!card) if (!card)
...@@ -366,8 +365,6 @@ int snd_card_disconnect(struct snd_card *card) ...@@ -366,8 +365,6 @@ int snd_card_disconnect(struct snd_card *card)
spin_lock(&card->files_lock); spin_lock(&card->files_lock);
list_for_each_entry(mfile, &card->files_list, list) { list_for_each_entry(mfile, &card->files_list, list) {
file = mfile->file;
/* it's critical part, use endless loop */ /* it's critical part, use endless loop */
/* we have no room to fail */ /* we have no room to fail */
mfile->disconnected_f_op = mfile->file->f_op; mfile->disconnected_f_op = mfile->file->f_op;
......
...@@ -90,11 +90,8 @@ static snd_pcm_sframes_t linear_transfer(struct snd_pcm_plugin *plugin, ...@@ -90,11 +90,8 @@ static snd_pcm_sframes_t linear_transfer(struct snd_pcm_plugin *plugin,
struct snd_pcm_plugin_channel *dst_channels, struct snd_pcm_plugin_channel *dst_channels,
snd_pcm_uframes_t frames) snd_pcm_uframes_t frames)
{ {
struct linear_priv *data;
if (snd_BUG_ON(!plugin || !src_channels || !dst_channels)) if (snd_BUG_ON(!plugin || !src_channels || !dst_channels))
return -ENXIO; return -ENXIO;
data = (struct linear_priv *)plugin->extra_data;
if (frames == 0) if (frames == 0)
return 0; return 0;
#ifdef CONFIG_SND_DEBUG #ifdef CONFIG_SND_DEBUG
......
...@@ -1756,8 +1756,18 @@ static int wait_for_avail(struct snd_pcm_substream *substream, ...@@ -1756,8 +1756,18 @@ static int wait_for_avail(struct snd_pcm_substream *substream,
wait_queue_t wait; wait_queue_t wait;
int err = 0; int err = 0;
snd_pcm_uframes_t avail = 0; snd_pcm_uframes_t avail = 0;
long tout; long wait_time, tout;
if (runtime->no_period_wakeup)
wait_time = MAX_SCHEDULE_TIMEOUT;
else {
wait_time = 10;
if (runtime->rate) {
long t = runtime->period_size * 2 / runtime->rate;
wait_time = max(t, wait_time);
}
wait_time = msecs_to_jiffies(wait_time * 1000);
}
init_waitqueue_entry(&wait, current); init_waitqueue_entry(&wait, current);
add_wait_queue(&runtime->tsleep, &wait); add_wait_queue(&runtime->tsleep, &wait);
for (;;) { for (;;) {
...@@ -1765,9 +1775,8 @@ static int wait_for_avail(struct snd_pcm_substream *substream, ...@@ -1765,9 +1775,8 @@ static int wait_for_avail(struct snd_pcm_substream *substream,
err = -ERESTARTSYS; err = -ERESTARTSYS;
break; break;
} }
set_current_state(TASK_INTERRUPTIBLE);
snd_pcm_stream_unlock_irq(substream); snd_pcm_stream_unlock_irq(substream);
tout = schedule_timeout(msecs_to_jiffies(10000)); tout = schedule_timeout_interruptible(wait_time);
snd_pcm_stream_lock_irq(substream); snd_pcm_stream_lock_irq(substream);
switch (runtime->status->state) { switch (runtime->status->state) {
case SNDRV_PCM_STATE_SUSPENDED: case SNDRV_PCM_STATE_SUSPENDED:
......
...@@ -1481,11 +1481,20 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream, ...@@ -1481,11 +1481,20 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
break; /* all drained */ break; /* all drained */
init_waitqueue_entry(&wait, current); init_waitqueue_entry(&wait, current);
add_wait_queue(&to_check->sleep, &wait); add_wait_queue(&to_check->sleep, &wait);
set_current_state(TASK_INTERRUPTIBLE);
snd_pcm_stream_unlock_irq(substream); snd_pcm_stream_unlock_irq(substream);
up_read(&snd_pcm_link_rwsem); up_read(&snd_pcm_link_rwsem);
snd_power_unlock(card); snd_power_unlock(card);
tout = schedule_timeout(10 * HZ); if (runtime->no_period_wakeup)
tout = MAX_SCHEDULE_TIMEOUT;
else {
tout = 10;
if (runtime->rate) {
long t = runtime->period_size * 2 / runtime->rate;
tout = max(t, tout);
}
tout = msecs_to_jiffies(tout * 1000);
}
tout = schedule_timeout_interruptible(tout);
snd_power_lock(card); snd_power_lock(card);
down_read(&snd_pcm_link_rwsem); down_read(&snd_pcm_link_rwsem);
snd_pcm_stream_lock_irq(substream); snd_pcm_stream_lock_irq(substream);
...@@ -1518,13 +1527,11 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream, ...@@ -1518,13 +1527,11 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
static int snd_pcm_drop(struct snd_pcm_substream *substream) static int snd_pcm_drop(struct snd_pcm_substream *substream)
{ {
struct snd_pcm_runtime *runtime; struct snd_pcm_runtime *runtime;
struct snd_card *card;
int result = 0; int result = 0;
if (PCM_RUNTIME_CHECK(substream)) if (PCM_RUNTIME_CHECK(substream))
return -ENXIO; return -ENXIO;
runtime = substream->runtime; runtime = substream->runtime;
card = substream->pcm->card;
if (runtime->status->state == SNDRV_PCM_STATE_OPEN || if (runtime->status->state == SNDRV_PCM_STATE_OPEN ||
runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED || runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED ||
...@@ -2056,7 +2063,6 @@ static int snd_pcm_open_file(struct file *file, ...@@ -2056,7 +2063,6 @@ static int snd_pcm_open_file(struct file *file,
{ {
struct snd_pcm_file *pcm_file; struct snd_pcm_file *pcm_file;
struct snd_pcm_substream *substream; struct snd_pcm_substream *substream;
struct snd_pcm_str *str;
int err; int err;
if (rpcm_file) if (rpcm_file)
...@@ -2073,7 +2079,6 @@ static int snd_pcm_open_file(struct file *file, ...@@ -2073,7 +2079,6 @@ static int snd_pcm_open_file(struct file *file,
} }
pcm_file->substream = substream; pcm_file->substream = substream;
if (substream->ref_count == 1) { if (substream->ref_count == 1) {
str = substream->pstr;
substream->file = pcm_file; substream->file = pcm_file;
substream->pcm_release = pcm_release_private; substream->pcm_release = pcm_release_private;
} }
...@@ -3015,11 +3020,9 @@ static const struct vm_operations_struct snd_pcm_vm_ops_status = ...@@ -3015,11 +3020,9 @@ static const struct vm_operations_struct snd_pcm_vm_ops_status =
static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file *file, static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file *file,
struct vm_area_struct *area) struct vm_area_struct *area)
{ {
struct snd_pcm_runtime *runtime;
long size; long size;
if (!(area->vm_flags & VM_READ)) if (!(area->vm_flags & VM_READ))
return -EINVAL; return -EINVAL;
runtime = substream->runtime;
size = area->vm_end - area->vm_start; size = area->vm_end - area->vm_start;
if (size != PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status))) if (size != PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status)))
return -EINVAL; return -EINVAL;
...@@ -3054,11 +3057,9 @@ static const struct vm_operations_struct snd_pcm_vm_ops_control = ...@@ -3054,11 +3057,9 @@ static const struct vm_operations_struct snd_pcm_vm_ops_control =
static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file *file, static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file *file,
struct vm_area_struct *area) struct vm_area_struct *area)
{ {
struct snd_pcm_runtime *runtime;
long size; long size;
if (!(area->vm_flags & VM_READ)) if (!(area->vm_flags & VM_READ))
return -EINVAL; return -EINVAL;
runtime = substream->runtime;
size = area->vm_end - area->vm_start; size = area->vm_end - area->vm_start;
if (size != PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control))) if (size != PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control)))
return -EINVAL; return -EINVAL;
......
...@@ -467,13 +467,11 @@ int snd_seq_queue_timer_open(int queueid) ...@@ -467,13 +467,11 @@ int snd_seq_queue_timer_open(int queueid)
int snd_seq_queue_timer_close(int queueid) int snd_seq_queue_timer_close(int queueid)
{ {
struct snd_seq_queue *queue; struct snd_seq_queue *queue;
struct snd_seq_timer *tmr;
int result = 0; int result = 0;
queue = queueptr(queueid); queue = queueptr(queueid);
if (queue == NULL) if (queue == NULL)
return -EINVAL; return -EINVAL;
tmr = queue->timer;
snd_seq_timer_close(queue); snd_seq_timer_close(queue);
queuefree(queue); queuefree(queue);
return result; return result;
......
...@@ -4719,7 +4719,7 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, ...@@ -4719,7 +4719,7 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
cfg->dig_out_pins[0], cfg->dig_out_pins[1]); cfg->dig_out_pins[0], cfg->dig_out_pins[1]);
snd_printd(" inputs:"); snd_printd(" inputs:");
for (i = 0; i < cfg->num_inputs; i++) { for (i = 0; i < cfg->num_inputs; i++) {
snd_printdd(" %s=0x%x", snd_printd(" %s=0x%x",
hda_get_autocfg_input_label(codec, cfg, i), hda_get_autocfg_input_label(codec, cfg, i),
cfg->inputs[i].pin); cfg->inputs[i].pin);
} }
......
...@@ -312,23 +312,6 @@ static int hdmi_update_eld(struct hdmi_eld *e, ...@@ -312,23 +312,6 @@ static int hdmi_update_eld(struct hdmi_eld *e,
return -EINVAL; return -EINVAL;
} }
static int hdmi_eld_valid(struct hda_codec *codec, hda_nid_t nid)
{
int eldv;
int present;
present = snd_hda_pin_sense(codec, nid);
eldv = (present & AC_PINSENSE_ELDV);
present = (present & AC_PINSENSE_PRESENCE);
#ifdef CONFIG_SND_DEBUG_VERBOSE
printk(KERN_INFO "HDMI: sink_present = %d, eld_valid = %d\n",
!!present, !!eldv);
#endif
return eldv && present;
}
int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid) int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid)
{ {
return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE, return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE,
...@@ -343,7 +326,7 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld, ...@@ -343,7 +326,7 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld,
int size; int size;
unsigned char *buf; unsigned char *buf;
if (!hdmi_eld_valid(codec, nid)) if (!eld->eld_valid)
return -ENOENT; return -ENOENT;
size = snd_hdmi_get_eld_size(codec, nid); size = snd_hdmi_get_eld_size(codec, nid);
...@@ -477,6 +460,8 @@ static void hdmi_print_eld_info(struct snd_info_entry *entry, ...@@ -477,6 +460,8 @@ static void hdmi_print_eld_info(struct snd_info_entry *entry,
snd_iprintf(buffer, "monitor_present\t\t%d\n", e->monitor_present); snd_iprintf(buffer, "monitor_present\t\t%d\n", e->monitor_present);
snd_iprintf(buffer, "eld_valid\t\t%d\n", e->eld_valid); snd_iprintf(buffer, "eld_valid\t\t%d\n", e->eld_valid);
if (!e->eld_valid)
return;
snd_iprintf(buffer, "monitor_name\t\t%s\n", e->monitor_name); snd_iprintf(buffer, "monitor_name\t\t%s\n", e->monitor_name);
snd_iprintf(buffer, "connection_type\t\t%s\n", snd_iprintf(buffer, "connection_type\t\t%s\n",
eld_connection_type_names[e->conn_type]); eld_connection_type_names[e->conn_type]);
......
This diff is collapsed.
...@@ -3159,6 +3159,7 @@ static const struct snd_pci_quirk ad1988_cfg_tbl[] = { ...@@ -3159,6 +3159,7 @@ static const struct snd_pci_quirk ad1988_cfg_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x81ec, "Asus P5B-DLX", AD1988_6STACK_DIG), SND_PCI_QUIRK(0x1043, 0x81ec, "Asus P5B-DLX", AD1988_6STACK_DIG),
SND_PCI_QUIRK(0x1043, 0x81f6, "Asus M2N-SLI", AD1988_6STACK_DIG), SND_PCI_QUIRK(0x1043, 0x81f6, "Asus M2N-SLI", AD1988_6STACK_DIG),
SND_PCI_QUIRK(0x1043, 0x8277, "Asus P5K-E/WIFI-AP", AD1988_6STACK_DIG), SND_PCI_QUIRK(0x1043, 0x8277, "Asus P5K-E/WIFI-AP", AD1988_6STACK_DIG),
SND_PCI_QUIRK(0x1043, 0x82c0, "Asus M3N-HT Deluxe", AD1988_6STACK_DIG),
SND_PCI_QUIRK(0x1043, 0x8311, "Asus P5Q-Premium/Pro", AD1988_6STACK_DIG), SND_PCI_QUIRK(0x1043, 0x8311, "Asus P5Q-Premium/Pro", AD1988_6STACK_DIG),
{} {}
}; };
......
...@@ -3098,7 +3098,9 @@ static const struct snd_pci_quirk cxt5066_cfg_tbl[] = { ...@@ -3098,7 +3098,9 @@ static const struct snd_pci_quirk cxt5066_cfg_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD),
SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT5066_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT5066_THINKPAD),
SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT5066_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT5066_THINKPAD),
SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo U350", CXT5066_ASUS),
SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G560", CXT5066_ASUS), SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G560", CXT5066_ASUS),
SND_PCI_QUIRK(0x17aa, 0x3938, "Lenovo G565", CXT5066_AUTO),
SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", CXT5066_IDEAPAD), /* Fallback for Lenovos without dock mic */ SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", CXT5066_IDEAPAD), /* Fallback for Lenovos without dock mic */
{} {}
}; };
...@@ -3433,7 +3435,9 @@ static void cx_auto_parse_output(struct hda_codec *codec) ...@@ -3433,7 +3435,9 @@ static void cx_auto_parse_output(struct hda_codec *codec)
break; break;
} }
} }
if (spec->auto_mute && cfg->line_out_pins[0] && if (spec->auto_mute &&
cfg->line_out_pins[0] &&
cfg->line_out_type != AUTO_PIN_SPEAKER_OUT &&
cfg->line_out_pins[0] != cfg->hp_pins[0] && cfg->line_out_pins[0] != cfg->hp_pins[0] &&
cfg->line_out_pins[0] != cfg->speaker_pins[0]) { cfg->line_out_pins[0] != cfg->speaker_pins[0]) {
for (i = 0; i < cfg->line_outs; i++) { for (i = 0; i < cfg->line_outs; i++) {
...@@ -3481,25 +3485,32 @@ static void cx_auto_update_speakers(struct hda_codec *codec) ...@@ -3481,25 +3485,32 @@ static void cx_auto_update_speakers(struct hda_codec *codec)
{ {
struct conexant_spec *spec = codec->spec; struct conexant_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->autocfg; struct auto_pin_cfg *cfg = &spec->autocfg;
int on; int on = 1;
if (!spec->auto_mute) /* turn on HP EAPD when HP jacks are present */
on = 0; if (spec->auto_mute)
else on = spec->hp_present;
on = spec->hp_present | spec->line_present;
cx_auto_turn_eapd(codec, cfg->hp_outs, cfg->hp_pins, on); cx_auto_turn_eapd(codec, cfg->hp_outs, cfg->hp_pins, on);
do_automute(codec, cfg->speaker_outs, cfg->speaker_pins, !on); /* mute speakers in auto-mode if HP or LO jacks are plugged */
if (spec->auto_mute)
on = !(spec->hp_present ||
(spec->detect_line && spec->line_present));
do_automute(codec, cfg->speaker_outs, cfg->speaker_pins, on);
/* toggle line-out mutes if needed, too */ /* toggle line-out mutes if needed, too */
/* if LO is a copy of either HP or Speaker, don't need to handle it */ /* if LO is a copy of either HP or Speaker, don't need to handle it */
if (cfg->line_out_pins[0] == cfg->hp_pins[0] || if (cfg->line_out_pins[0] == cfg->hp_pins[0] ||
cfg->line_out_pins[0] == cfg->speaker_pins[0]) cfg->line_out_pins[0] == cfg->speaker_pins[0])
return; return;
if (!spec->automute_lines || !spec->auto_mute) if (spec->auto_mute) {
on = 0; /* mute LO in auto-mode when HP jack is present */
else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT ||
on = spec->hp_present; spec->automute_lines)
do_automute(codec, cfg->line_outs, cfg->line_out_pins, !on); on = !spec->hp_present;
else
on = 1;
}
do_automute(codec, cfg->line_outs, cfg->line_out_pins, on);
} }
static void cx_auto_hp_automute(struct hda_codec *codec) static void cx_auto_hp_automute(struct hda_codec *codec)
...@@ -3696,13 +3707,14 @@ static int cx_auto_mux_enum_update(struct hda_codec *codec, ...@@ -3696,13 +3707,14 @@ static int cx_auto_mux_enum_update(struct hda_codec *codec,
{ {
struct conexant_spec *spec = codec->spec; struct conexant_spec *spec = codec->spec;
hda_nid_t adc; hda_nid_t adc;
int changed = 1;
if (!imux->num_items) if (!imux->num_items)
return 0; return 0;
if (idx >= imux->num_items) if (idx >= imux->num_items)
idx = imux->num_items - 1; idx = imux->num_items - 1;
if (spec->cur_mux[0] == idx) if (spec->cur_mux[0] == idx)
return 0; changed = 0;
adc = spec->imux_info[idx].adc; adc = spec->imux_info[idx].adc;
select_input_connection(codec, spec->imux_info[idx].adc, select_input_connection(codec, spec->imux_info[idx].adc,
spec->imux_info[idx].pin); spec->imux_info[idx].pin);
...@@ -3715,7 +3727,7 @@ static int cx_auto_mux_enum_update(struct hda_codec *codec, ...@@ -3715,7 +3727,7 @@ static int cx_auto_mux_enum_update(struct hda_codec *codec,
spec->cur_adc_format); spec->cur_adc_format);
} }
spec->cur_mux[0] = idx; spec->cur_mux[0] = idx;
return 1; return changed;
} }
static int cx_auto_mux_enum_put(struct snd_kcontrol *kcontrol, static int cx_auto_mux_enum_put(struct snd_kcontrol *kcontrol,
...@@ -3789,7 +3801,7 @@ static void cx_auto_check_auto_mic(struct hda_codec *codec) ...@@ -3789,7 +3801,7 @@ static void cx_auto_check_auto_mic(struct hda_codec *codec)
int pset[INPUT_PIN_ATTR_NORMAL + 1]; int pset[INPUT_PIN_ATTR_NORMAL + 1];
int i; int i;
for (i = 0; i < INPUT_PIN_ATTR_NORMAL; i++) for (i = 0; i < ARRAY_SIZE(pset); i++)
pset[i] = -1; pset[i] = -1;
for (i = 0; i < spec->private_imux.num_items; i++) { for (i = 0; i < spec->private_imux.num_items; i++) {
hda_nid_t pin = spec->imux_info[i].pin; hda_nid_t pin = spec->imux_info[i].pin;
......
...@@ -48,8 +48,8 @@ MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info"); ...@@ -48,8 +48,8 @@ MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info");
* *
* The HDA correspondence of pipes/ports are converter/pin nodes. * The HDA correspondence of pipes/ports are converter/pin nodes.
*/ */
#define MAX_HDMI_CVTS 3 #define MAX_HDMI_CVTS 4
#define MAX_HDMI_PINS 3 #define MAX_HDMI_PINS 4
struct hdmi_spec { struct hdmi_spec {
int num_cvts; int num_cvts;
...@@ -78,10 +78,6 @@ struct hdmi_spec { ...@@ -78,10 +78,6 @@ struct hdmi_spec {
*/ */
struct hda_multi_out multiout; struct hda_multi_out multiout;
const struct hda_pcm_stream *pcm_playback; const struct hda_pcm_stream *pcm_playback;
/* misc flags */
/* PD bit indicates only the update, not the current state */
unsigned int old_pin_detect:1;
}; };
...@@ -300,13 +296,6 @@ static int hda_node_index(hda_nid_t *nids, hda_nid_t nid) ...@@ -300,13 +296,6 @@ static int hda_node_index(hda_nid_t *nids, hda_nid_t nid)
return -EINVAL; return -EINVAL;
} }
static void hdmi_get_show_eld(struct hda_codec *codec, hda_nid_t pin_nid,
struct hdmi_eld *eld)
{
if (!snd_hdmi_get_eld(eld, codec, pin_nid))
snd_hdmi_show_eld(eld);
}
#ifdef BE_PARANOID #ifdef BE_PARANOID
static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t pin_nid, static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t pin_nid,
int *packet_index, int *byte_index) int *packet_index, int *byte_index)
...@@ -694,35 +683,20 @@ static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid, ...@@ -694,35 +683,20 @@ static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid,
static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
{ {
struct hdmi_spec *spec = codec->spec; struct hdmi_spec *spec = codec->spec;
int tag = res >> AC_UNSOL_RES_TAG_SHIFT; int pin_nid = res >> AC_UNSOL_RES_TAG_SHIFT;
int pind = !!(res & AC_UNSOL_RES_PD); int pd = !!(res & AC_UNSOL_RES_PD);
int eldv = !!(res & AC_UNSOL_RES_ELDV); int eldv = !!(res & AC_UNSOL_RES_ELDV);
int index; int index;
printk(KERN_INFO printk(KERN_INFO
"HDMI hot plug event: Pin=%d Presence_Detect=%d ELD_Valid=%d\n", "HDMI hot plug event: Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
tag, pind, eldv); pin_nid, pd, eldv);
index = hda_node_index(spec->pin, tag); index = hda_node_index(spec->pin, pin_nid);
if (index < 0) if (index < 0)
return; return;
if (spec->old_pin_detect) { hdmi_present_sense(codec, pin_nid, &spec->sink_eld[index]);
if (pind)
hdmi_present_sense(codec, tag, &spec->sink_eld[index]);
pind = spec->sink_eld[index].monitor_present;
}
spec->sink_eld[index].monitor_present = pind;
spec->sink_eld[index].eld_valid = eldv;
if (pind && eldv) {
hdmi_get_show_eld(codec, spec->pin[index],
&spec->sink_eld[index]);
/* TODO: do real things about ELD */
}
snd_hda_input_jack_report(codec, tag);
} }
static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
...@@ -903,13 +877,33 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, hda_nid_t pin_nid) ...@@ -903,13 +877,33 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, hda_nid_t pin_nid)
static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid, static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid,
struct hdmi_eld *eld) struct hdmi_eld *eld)
{ {
/*
* Always execute a GetPinSense verb here, even when called from
* hdmi_intrinsic_event; for some NVIDIA HW, the unsolicited
* response's PD bit is not the real PD value, but indicates that
* the real PD value changed. An older version of the HD-audio
* specification worked this way. Hence, we just ignore the data in
* the unsolicited response to avoid custom WARs.
*/
int present = snd_hda_pin_sense(codec, pin_nid); int present = snd_hda_pin_sense(codec, pin_nid);
memset(eld, 0, sizeof(*eld));
eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE); eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE);
eld->eld_valid = !!(present & AC_PINSENSE_ELDV); if (eld->monitor_present)
eld->eld_valid = !!(present & AC_PINSENSE_ELDV);
else
eld->eld_valid = 0;
if (present & AC_PINSENSE_ELDV) printk(KERN_INFO
hdmi_get_show_eld(codec, pin_nid, eld); "HDMI status: Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
pin_nid, eld->monitor_present, eld->eld_valid);
if (eld->eld_valid)
if (!snd_hdmi_get_eld(eld, codec, pin_nid))
snd_hdmi_show_eld(eld);
snd_hda_input_jack_report(codec, pin_nid);
} }
static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
...@@ -927,7 +921,6 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) ...@@ -927,7 +921,6 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
SND_JACK_VIDEOOUT, NULL); SND_JACK_VIDEOOUT, NULL);
if (err < 0) if (err < 0)
return err; return err;
snd_hda_input_jack_report(codec, pin_nid);
hdmi_present_sense(codec, pin_nid, &spec->sink_eld[spec->num_pins]); hdmi_present_sense(codec, pin_nid, &spec->sink_eld[spec->num_pins]);
...@@ -1034,6 +1027,7 @@ static char *generic_hdmi_pcm_names[MAX_HDMI_CVTS] = { ...@@ -1034,6 +1027,7 @@ static char *generic_hdmi_pcm_names[MAX_HDMI_CVTS] = {
"HDMI 0", "HDMI 0",
"HDMI 1", "HDMI 1",
"HDMI 2", "HDMI 2",
"HDMI 3",
}; };
/* /*
...@@ -1490,18 +1484,6 @@ static const struct hda_codec_ops nvhdmi_patch_ops_2ch = { ...@@ -1490,18 +1484,6 @@ static const struct hda_codec_ops nvhdmi_patch_ops_2ch = {
.free = generic_hdmi_free, .free = generic_hdmi_free,
}; };
static int patch_nvhdmi_8ch_89(struct hda_codec *codec)
{
struct hdmi_spec *spec;
int err = patch_generic_hdmi(codec);
if (err < 0)
return err;
spec = codec->spec;
spec->old_pin_detect = 1;
return 0;
}
static int patch_nvhdmi_2ch(struct hda_codec *codec) static int patch_nvhdmi_2ch(struct hda_codec *codec)
{ {
struct hdmi_spec *spec; struct hdmi_spec *spec;
...@@ -1515,7 +1497,6 @@ static int patch_nvhdmi_2ch(struct hda_codec *codec) ...@@ -1515,7 +1497,6 @@ static int patch_nvhdmi_2ch(struct hda_codec *codec)
spec->multiout.num_dacs = 0; /* no analog */ spec->multiout.num_dacs = 0; /* no analog */
spec->multiout.max_channels = 2; spec->multiout.max_channels = 2;
spec->multiout.dig_out_nid = nvhdmi_master_con_nid_7x; spec->multiout.dig_out_nid = nvhdmi_master_con_nid_7x;
spec->old_pin_detect = 1;
spec->num_cvts = 1; spec->num_cvts = 1;
spec->cvt[0] = nvhdmi_master_con_nid_7x; spec->cvt[0] = nvhdmi_master_con_nid_7x;
spec->pcm_playback = &nvhdmi_pcm_playback_2ch; spec->pcm_playback = &nvhdmi_pcm_playback_2ch;
...@@ -1658,28 +1639,28 @@ static const struct hda_codec_preset snd_hda_preset_hdmi[] = { ...@@ -1658,28 +1639,28 @@ static const struct hda_codec_preset snd_hda_preset_hdmi[] = {
{ .id = 0x10de0005, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x }, { .id = 0x10de0005, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x },
{ .id = 0x10de0006, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x }, { .id = 0x10de0006, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x },
{ .id = 0x10de0007, .name = "MCP79/7A HDMI", .patch = patch_nvhdmi_8ch_7x }, { .id = 0x10de0007, .name = "MCP79/7A HDMI", .patch = patch_nvhdmi_8ch_7x },
{ .id = 0x10de000a, .name = "GPU 0a HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, { .id = 0x10de000a, .name = "GPU 0a HDMI/DP", .patch = patch_generic_hdmi },
{ .id = 0x10de000b, .name = "GPU 0b HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, { .id = 0x10de000b, .name = "GPU 0b HDMI/DP", .patch = patch_generic_hdmi },
{ .id = 0x10de000c, .name = "MCP89 HDMI", .patch = patch_nvhdmi_8ch_89 }, { .id = 0x10de000c, .name = "MCP89 HDMI", .patch = patch_generic_hdmi },
{ .id = 0x10de000d, .name = "GPU 0d HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, { .id = 0x10de000d, .name = "GPU 0d HDMI/DP", .patch = patch_generic_hdmi },
{ .id = 0x10de0010, .name = "GPU 10 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, { .id = 0x10de0010, .name = "GPU 10 HDMI/DP", .patch = patch_generic_hdmi },
{ .id = 0x10de0011, .name = "GPU 11 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, { .id = 0x10de0011, .name = "GPU 11 HDMI/DP", .patch = patch_generic_hdmi },
{ .id = 0x10de0012, .name = "GPU 12 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, { .id = 0x10de0012, .name = "GPU 12 HDMI/DP", .patch = patch_generic_hdmi },
{ .id = 0x10de0013, .name = "GPU 13 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, { .id = 0x10de0013, .name = "GPU 13 HDMI/DP", .patch = patch_generic_hdmi },
{ .id = 0x10de0014, .name = "GPU 14 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, { .id = 0x10de0014, .name = "GPU 14 HDMI/DP", .patch = patch_generic_hdmi },
{ .id = 0x10de0015, .name = "GPU 15 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, { .id = 0x10de0015, .name = "GPU 15 HDMI/DP", .patch = patch_generic_hdmi },
{ .id = 0x10de0016, .name = "GPU 16 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, { .id = 0x10de0016, .name = "GPU 16 HDMI/DP", .patch = patch_generic_hdmi },
/* 17 is known to be absent */ /* 17 is known to be absent */
{ .id = 0x10de0018, .name = "GPU 18 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, { .id = 0x10de0018, .name = "GPU 18 HDMI/DP", .patch = patch_generic_hdmi },
{ .id = 0x10de0019, .name = "GPU 19 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, { .id = 0x10de0019, .name = "GPU 19 HDMI/DP", .patch = patch_generic_hdmi },
{ .id = 0x10de001a, .name = "GPU 1a HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, { .id = 0x10de001a, .name = "GPU 1a HDMI/DP", .patch = patch_generic_hdmi },
{ .id = 0x10de001b, .name = "GPU 1b HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, { .id = 0x10de001b, .name = "GPU 1b HDMI/DP", .patch = patch_generic_hdmi },
{ .id = 0x10de001c, .name = "GPU 1c HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, { .id = 0x10de001c, .name = "GPU 1c HDMI/DP", .patch = patch_generic_hdmi },
{ .id = 0x10de0040, .name = "GPU 40 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, { .id = 0x10de0040, .name = "GPU 40 HDMI/DP", .patch = patch_generic_hdmi },
{ .id = 0x10de0041, .name = "GPU 41 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, { .id = 0x10de0041, .name = "GPU 41 HDMI/DP", .patch = patch_generic_hdmi },
{ .id = 0x10de0042, .name = "GPU 42 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, { .id = 0x10de0042, .name = "GPU 42 HDMI/DP", .patch = patch_generic_hdmi },
{ .id = 0x10de0043, .name = "GPU 43 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, { .id = 0x10de0043, .name = "GPU 43 HDMI/DP", .patch = patch_generic_hdmi },
{ .id = 0x10de0044, .name = "GPU 44 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, { .id = 0x10de0044, .name = "GPU 44 HDMI/DP", .patch = patch_generic_hdmi },
{ .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch }, { .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch },
{ .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi_2ch }, { .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi_2ch },
{ .id = 0x80860054, .name = "IbexPeak HDMI", .patch = patch_generic_hdmi }, { .id = 0x80860054, .name = "IbexPeak HDMI", .patch = patch_generic_hdmi },
......
...@@ -146,7 +146,7 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd) ...@@ -146,7 +146,7 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd)
"at91sam9g20ek_wm8731 " "at91sam9g20ek_wm8731 "
": at91sam9g20ek_wm8731_init() called\n"); ": at91sam9g20ek_wm8731_init() called\n");
ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL, ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_MCLK,
MCLK_RATE, SND_SOC_CLOCK_IN); MCLK_RATE, SND_SOC_CLOCK_IN);
if (ret < 0) { if (ret < 0) {
printk(KERN_ERR "Failed to set WM8731 SYSCLK: %d\n", ret); printk(KERN_ERR "Failed to set WM8731 SYSCLK: %d\n", ret);
......
...@@ -22,7 +22,7 @@ SND_SOC_DAPM_ADC("ADC", "wm1250-ev1 Capture", SND_SOC_NOPM, 0, 0), ...@@ -22,7 +22,7 @@ SND_SOC_DAPM_ADC("ADC", "wm1250-ev1 Capture", SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_DAC("DAC", "wm1250-ev1 Playback", SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_DAC("DAC", "wm1250-ev1 Playback", SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_INPUT("WM1250 Input"), SND_SOC_DAPM_INPUT("WM1250 Input"),
SND_SOC_DAPM_INPUT("WM1250 Output"), SND_SOC_DAPM_OUTPUT("WM1250 Output"),
}; };
static const struct snd_soc_dapm_route wm1250_ev1_dapm_routes[] = { static const struct snd_soc_dapm_route wm1250_ev1_dapm_routes[] = {
......
...@@ -198,7 +198,7 @@ static int wm8731_check_osc(struct snd_soc_dapm_widget *source, ...@@ -198,7 +198,7 @@ static int wm8731_check_osc(struct snd_soc_dapm_widget *source,
{ {
struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(source->codec); struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(source->codec);
return wm8731->sysclk_type == WM8731_SYSCLK_MCLK; return wm8731->sysclk_type == WM8731_SYSCLK_XTAL;
} }
static const struct snd_soc_dapm_route wm8731_intercon[] = { static const struct snd_soc_dapm_route wm8731_intercon[] = {
......
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
#include <linux/gcd.h> #include <linux/gcd.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
......
...@@ -151,13 +151,13 @@ static struct snd_soc_ops raumfeld_cs4270_ops = { ...@@ -151,13 +151,13 @@ static struct snd_soc_ops raumfeld_cs4270_ops = {
.hw_params = raumfeld_cs4270_hw_params, .hw_params = raumfeld_cs4270_hw_params,
}; };
static int raumfeld_line_suspend(struct snd_soc_card *card) static int raumfeld_analog_suspend(struct snd_soc_card *card)
{ {
raumfeld_enable_audio(false); raumfeld_enable_audio(false);
return 0; return 0;
} }
static int raumfeld_line_resume(struct snd_soc_card *card) static int raumfeld_analog_resume(struct snd_soc_card *card)
{ {
raumfeld_enable_audio(true); raumfeld_enable_audio(true);
return 0; return 0;
...@@ -225,32 +225,53 @@ static struct snd_soc_ops raumfeld_ak4104_ops = { ...@@ -225,32 +225,53 @@ static struct snd_soc_ops raumfeld_ak4104_ops = {
.hw_params = raumfeld_ak4104_hw_params, .hw_params = raumfeld_ak4104_hw_params,
}; };
static struct snd_soc_dai_link raumfeld_dai[] = { #define DAI_LINK_CS4270 \
{ \
.name = "CS4270", \
.stream_name = "CS4270", \
.cpu_dai_name = "pxa-ssp-dai.0", \
.platform_name = "pxa-pcm-audio", \
.codec_dai_name = "cs4270-hifi", \
.codec_name = "cs4270-codec.0-0048", \
.ops = &raumfeld_cs4270_ops, \
}
#define DAI_LINK_AK4104 \
{ \
.name = "ak4104", \
.stream_name = "Playback", \
.cpu_dai_name = "pxa-ssp-dai.1", \
.codec_dai_name = "ak4104-hifi", \
.platform_name = "pxa-pcm-audio", \
.ops = &raumfeld_ak4104_ops, \
.codec_name = "spi0.0", \
}
static struct snd_soc_dai_link snd_soc_raumfeld_connector_dai[] =
{ {
.name = "ak4104", DAI_LINK_CS4270,
.stream_name = "Playback", DAI_LINK_AK4104,
.cpu_dai_name = "pxa-ssp-dai.1", };
.codec_dai_name = "ak4104-hifi",
.platform_name = "pxa-pcm-audio", static struct snd_soc_dai_link snd_soc_raumfeld_speaker_dai[] =
.ops = &raumfeld_ak4104_ops,
.codec_name = "ak4104-codec.0",
},
{ {
.name = "CS4270", DAI_LINK_CS4270,
.stream_name = "CS4270", };
.cpu_dai_name = "pxa-ssp-dai.0",
.platform_name = "pxa-pcm-audio", static struct snd_soc_card snd_soc_raumfeld_connector = {
.codec_dai_name = "cs4270-hifi", .name = "Raumfeld Connector",
.codec_name = "cs4270-codec.0-0048", .dai_link = snd_soc_raumfeld_connector_dai,
.ops = &raumfeld_cs4270_ops, .num_links = ARRAY_SIZE(snd_soc_raumfeld_connector_dai),
},}; .suspend_post = raumfeld_analog_suspend,
.resume_pre = raumfeld_analog_resume,
static struct snd_soc_card snd_soc_raumfeld = { };
.name = "Raumfeld",
.dai_link = raumfeld_dai, static struct snd_soc_card snd_soc_raumfeld_speaker = {
.suspend_post = raumfeld_line_suspend, .name = "Raumfeld Speaker",
.resume_pre = raumfeld_line_resume, .dai_link = snd_soc_raumfeld_speaker_dai,
.num_links = ARRAY_SIZE(raumfeld_dai), .num_links = ARRAY_SIZE(snd_soc_raumfeld_speaker_dai),
.suspend_post = raumfeld_analog_suspend,
.resume_pre = raumfeld_analog_resume,
}; };
static struct platform_device *raumfeld_audio_device; static struct platform_device *raumfeld_audio_device;
...@@ -271,22 +292,25 @@ static int __init raumfeld_audio_init(void) ...@@ -271,22 +292,25 @@ static int __init raumfeld_audio_init(void)
set_max9485_clk(MAX9485_MCLK_FREQ_122880); set_max9485_clk(MAX9485_MCLK_FREQ_122880);
/* Register LINE and SPDIF */ /* Register analog device */
raumfeld_audio_device = platform_device_alloc("soc-audio", 0); raumfeld_audio_device = platform_device_alloc("soc-audio", 0);
if (!raumfeld_audio_device) if (!raumfeld_audio_device)
return -ENOMEM; return -ENOMEM;
platform_set_drvdata(raumfeld_audio_device,
&snd_soc_raumfeld);
ret = platform_device_add(raumfeld_audio_device);
/* no S/PDIF on Speakers */
if (machine_is_raumfeld_speaker()) if (machine_is_raumfeld_speaker())
platform_set_drvdata(raumfeld_audio_device,
&snd_soc_raumfeld_speaker);
if (machine_is_raumfeld_connector())
platform_set_drvdata(raumfeld_audio_device,
&snd_soc_raumfeld_connector);
ret = platform_device_add(raumfeld_audio_device);
if (ret < 0)
return ret; return ret;
raumfeld_enable_audio(true); raumfeld_enable_audio(true);
return 0;
return ret;
} }
static void __exit raumfeld_audio_exit(void) static void __exit raumfeld_audio_exit(void)
......
...@@ -1306,10 +1306,6 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) ...@@ -1306,10 +1306,6 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
/* no, then find CPU DAI from registered DAIs*/ /* no, then find CPU DAI from registered DAIs*/
list_for_each_entry(cpu_dai, &dai_list, list) { list_for_each_entry(cpu_dai, &dai_list, list) {
if (!strcmp(cpu_dai->name, dai_link->cpu_dai_name)) { if (!strcmp(cpu_dai->name, dai_link->cpu_dai_name)) {
if (!try_module_get(cpu_dai->dev->driver->owner))
return -ENODEV;
rtd->cpu_dai = cpu_dai; rtd->cpu_dai = cpu_dai;
goto find_codec; goto find_codec;
} }
...@@ -1622,11 +1618,15 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num) ...@@ -1622,11 +1618,15 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num)
/* probe the cpu_dai */ /* probe the cpu_dai */
if (!cpu_dai->probed) { if (!cpu_dai->probed) {
if (!try_module_get(cpu_dai->dev->driver->owner))
return -ENODEV;
if (cpu_dai->driver->probe) { if (cpu_dai->driver->probe) {
ret = cpu_dai->driver->probe(cpu_dai); ret = cpu_dai->driver->probe(cpu_dai);
if (ret < 0) { if (ret < 0) {
printk(KERN_ERR "asoc: failed to probe CPU DAI %s\n", printk(KERN_ERR "asoc: failed to probe CPU DAI %s\n",
cpu_dai->name); cpu_dai->name);
module_put(cpu_dai->dev->driver->owner);
return ret; return ret;
} }
} }
......
...@@ -1110,7 +1110,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) ...@@ -1110,7 +1110,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
trace_snd_soc_dapm_start(card); trace_snd_soc_dapm_start(card);
list_for_each_entry(d, &card->dapm_list, list) list_for_each_entry(d, &card->dapm_list, list)
if (d->n_widgets) if (d->n_widgets || d->codec == NULL)
d->dev_power = 0; d->dev_power = 0;
/* Check which widgets we need to power and store them in /* Check which widgets we need to power and store them in
......
...@@ -48,6 +48,7 @@ ...@@ -48,6 +48,7 @@
#include <linux/usb/audio.h> #include <linux/usb/audio.h>
#include <linux/usb/audio-v2.h> #include <linux/usb/audio-v2.h>
#include <sound/control.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/info.h> #include <sound/info.h>
#include <sound/pcm.h> #include <sound/pcm.h>
...@@ -492,14 +493,6 @@ static void *snd_usb_audio_probe(struct usb_device *dev, ...@@ -492,14 +493,6 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
} }
} }
chip->txfr_quirk = 0;
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)
goto __error;
}
/* /*
* For devices with more than one control interface, we assume the * For devices with more than one control interface, we assume the
* first contains the audio controls. We might need a more specific * first contains the audio controls. We might need a more specific
...@@ -508,6 +501,14 @@ static void *snd_usb_audio_probe(struct usb_device *dev, ...@@ -508,6 +501,14 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
if (!chip->ctrl_intf) if (!chip->ctrl_intf)
chip->ctrl_intf = alts; chip->ctrl_intf = alts;
chip->txfr_quirk = 0;
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)
goto __error;
}
if (err > 0) { if (err > 0) {
/* create normal USB audio interfaces */ /* create normal USB audio interfaces */
if (snd_usb_create_streams(chip, ifnum) < 0 || if (snd_usb_create_streams(chip, ifnum) < 0 ||
......
...@@ -86,16 +86,6 @@ struct mixer_build { ...@@ -86,16 +86,6 @@ struct mixer_build {
const struct usbmix_selector_map *selector_map; const struct usbmix_selector_map *selector_map;
}; };
enum {
USB_MIXER_BOOLEAN,
USB_MIXER_INV_BOOLEAN,
USB_MIXER_S8,
USB_MIXER_U8,
USB_MIXER_S16,
USB_MIXER_U16,
};
/*E-mu 0202/0404/0204 eXtension Unit(XU) control*/ /*E-mu 0202/0404/0204 eXtension Unit(XU) control*/
enum { enum {
USB_XU_CLOCK_RATE = 0xe301, USB_XU_CLOCK_RATE = 0xe301,
...@@ -535,20 +525,21 @@ static int check_matrix_bitmap(unsigned char *bmap, int ich, int och, int num_ou ...@@ -535,20 +525,21 @@ static int check_matrix_bitmap(unsigned char *bmap, int ich, int och, int num_ou
* if failed, give up and free the control instance. * if failed, give up and free the control instance.
*/ */
static int add_control_to_empty(struct mixer_build *state, struct snd_kcontrol *kctl) int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer,
struct snd_kcontrol *kctl)
{ {
struct usb_mixer_elem_info *cval = kctl->private_data; struct usb_mixer_elem_info *cval = kctl->private_data;
int err; int err;
while (snd_ctl_find_id(state->chip->card, &kctl->id)) while (snd_ctl_find_id(mixer->chip->card, &kctl->id))
kctl->id.index++; kctl->id.index++;
if ((err = snd_ctl_add(state->chip->card, kctl)) < 0) { if ((err = snd_ctl_add(mixer->chip->card, kctl)) < 0) {
snd_printd(KERN_ERR "cannot add control (err = %d)\n", err); snd_printd(KERN_ERR "cannot add control (err = %d)\n", err);
return err; return err;
} }
cval->elem_id = &kctl->id; cval->elem_id = &kctl->id;
cval->next_id_elem = state->mixer->id_elems[cval->id]; cval->next_id_elem = mixer->id_elems[cval->id];
state->mixer->id_elems[cval->id] = cval; mixer->id_elems[cval->id] = cval;
return 0; return 0;
} }
...@@ -984,6 +975,9 @@ static struct snd_kcontrol_new usb_feature_unit_ctl_ro = { ...@@ -984,6 +975,9 @@ static struct snd_kcontrol_new usb_feature_unit_ctl_ro = {
.put = NULL, .put = NULL,
}; };
/* This symbol is exported in order to allow the mixer quirks to
* hook up to the standard feature unit control mechanism */
struct snd_kcontrol_new *snd_usb_feature_unit_ctl = &usb_feature_unit_ctl;
/* /*
* build a feature control * build a feature control
...@@ -1176,7 +1170,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, ...@@ -1176,7 +1170,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
snd_printdd(KERN_INFO "[%d] FU [%s] ch = %d, val = %d/%d/%d\n", snd_printdd(KERN_INFO "[%d] FU [%s] ch = %d, val = %d/%d/%d\n",
cval->id, kctl->id.name, cval->channels, cval->min, cval->max, cval->res); cval->id, kctl->id.name, cval->channels, cval->min, cval->max, cval->res);
add_control_to_empty(state, kctl); snd_usb_mixer_add_control(state->mixer, kctl);
} }
...@@ -1340,7 +1334,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state, ...@@ -1340,7 +1334,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state,
snd_printdd(KERN_INFO "[%d] MU [%s] ch = %d, val = %d/%d\n", snd_printdd(KERN_INFO "[%d] MU [%s] ch = %d, val = %d/%d\n",
cval->id, kctl->id.name, cval->channels, cval->min, cval->max); cval->id, kctl->id.name, cval->channels, cval->min, cval->max);
add_control_to_empty(state, kctl); snd_usb_mixer_add_control(state->mixer, kctl);
} }
...@@ -1641,7 +1635,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, void *raw ...@@ -1641,7 +1635,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, void *raw
snd_printdd(KERN_INFO "[%d] PU [%s] ch = %d, val = %d/%d\n", snd_printdd(KERN_INFO "[%d] PU [%s] ch = %d, val = %d/%d\n",
cval->id, kctl->id.name, cval->channels, cval->min, cval->max); cval->id, kctl->id.name, cval->channels, cval->min, cval->max);
if ((err = add_control_to_empty(state, kctl)) < 0) if ((err = snd_usb_mixer_add_control(state->mixer, kctl)) < 0)
return err; return err;
} }
return 0; return 0;
...@@ -1858,7 +1852,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void ...@@ -1858,7 +1852,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void
snd_printdd(KERN_INFO "[%d] SU [%s] items = %d\n", snd_printdd(KERN_INFO "[%d] SU [%s] items = %d\n",
cval->id, kctl->id.name, desc->bNrInPins); cval->id, kctl->id.name, desc->bNrInPins);
if ((err = add_control_to_empty(state, kctl)) < 0) if ((err = snd_usb_mixer_add_control(state->mixer, kctl)) < 0)
return err; return err;
return 0; return 0;
......
...@@ -24,7 +24,16 @@ struct usb_mixer_interface { ...@@ -24,7 +24,16 @@ struct usb_mixer_interface {
u8 xonar_u1_status; u8 xonar_u1_status;
}; };
#define MAX_CHANNELS 10 /* max logical channels */ #define MAX_CHANNELS 16 /* max logical channels */
enum {
USB_MIXER_BOOLEAN,
USB_MIXER_INV_BOOLEAN,
USB_MIXER_S8,
USB_MIXER_U8,
USB_MIXER_S16,
USB_MIXER_U16,
};
struct usb_mixer_elem_info { struct usb_mixer_elem_info {
struct usb_mixer_interface *mixer; struct usb_mixer_interface *mixer;
...@@ -55,4 +64,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, ...@@ -55,4 +64,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
void snd_usb_mixer_inactivate(struct usb_mixer_interface *mixer); void snd_usb_mixer_inactivate(struct usb_mixer_interface *mixer);
int snd_usb_mixer_activate(struct usb_mixer_interface *mixer); int snd_usb_mixer_activate(struct usb_mixer_interface *mixer);
int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer,
struct snd_kcontrol *kctl);
#endif /* __USBMIXER_H */ #endif /* __USBMIXER_H */
...@@ -40,6 +40,8 @@ ...@@ -40,6 +40,8 @@
#include "mixer_quirks.h" #include "mixer_quirks.h"
#include "helper.h" #include "helper.h"
extern struct snd_kcontrol_new *snd_usb_feature_unit_ctl;
/* /*
* Sound Blaster remote control configuration * Sound Blaster remote control configuration
* *
...@@ -492,6 +494,69 @@ static int snd_nativeinstruments_create_mixer(struct usb_mixer_interface *mixer, ...@@ -492,6 +494,69 @@ static int snd_nativeinstruments_create_mixer(struct usb_mixer_interface *mixer,
return err; return err;
} }
/* M-Audio FastTrack Ultra quirks */
/* private_free callback */
static void usb_mixer_elem_free(struct snd_kcontrol *kctl)
{
kfree(kctl->private_data);
kctl->private_data = NULL;
}
static int snd_maudio_ftu_create_ctl(struct usb_mixer_interface *mixer,
int in, int out, const char *name)
{
struct usb_mixer_elem_info *cval;
struct snd_kcontrol *kctl;
cval = kzalloc(sizeof(*cval), GFP_KERNEL);
if (!cval)
return -ENOMEM;
cval->id = 5;
cval->mixer = mixer;
cval->val_type = USB_MIXER_S16;
cval->channels = 1;
cval->control = out + 1;
cval->cmask = 1 << in;
kctl = snd_ctl_new1(snd_usb_feature_unit_ctl, cval);
if (!kctl) {
kfree(cval);
return -ENOMEM;
}
snprintf(kctl->id.name, sizeof(kctl->id.name), name);
kctl->private_free = usb_mixer_elem_free;
return snd_usb_mixer_add_control(mixer, kctl);
}
static int snd_maudio_ftu_create_mixer(struct usb_mixer_interface *mixer)
{
char name[64];
int in, out, err;
for (out = 0; out < 8; out++) {
for (in = 0; in < 8; in++) {
snprintf(name, sizeof(name),
"AIn%d - Out%d Capture Volume", in + 1, out + 1);
err = snd_maudio_ftu_create_ctl(mixer, in, out, name);
if (err < 0)
return err;
}
for (in = 8; in < 16; in++) {
snprintf(name, sizeof(name),
"DIn%d - Out%d Playback Volume", in - 7, out + 1);
err = snd_maudio_ftu_create_ctl(mixer, in, out, name);
if (err < 0)
return err;
}
}
return 0;
}
void snd_emuusb_set_samplerate(struct snd_usb_audio *chip, void snd_emuusb_set_samplerate(struct snd_usb_audio *chip,
unsigned char samplerate_id) unsigned char samplerate_id)
{ {
...@@ -533,6 +598,11 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) ...@@ -533,6 +598,11 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
snd_audigy2nx_proc_read); snd_audigy2nx_proc_read);
break; break;
case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra */
case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */
err = snd_maudio_ftu_create_mixer(mixer);
break;
case USB_ID(0x0b05, 0x1739): case USB_ID(0x0b05, 0x1739):
case USB_ID(0x0b05, 0x1743): case USB_ID(0x0b05, 0x1743):
err = snd_xonar_u1_controls_create(mixer); err = snd_xonar_u1_controls_create(mixer);
......
...@@ -1988,7 +1988,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), ...@@ -1988,7 +1988,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
.data = & (const struct snd_usb_audio_quirk[]) { .data = & (const struct snd_usb_audio_quirk[]) {
{ {
.ifnum = 0, .ifnum = 0,
.type = QUIRK_IGNORE_INTERFACE .type = QUIRK_AUDIO_STANDARD_MIXER,
}, },
{ {
.ifnum = 1, .ifnum = 1,
...@@ -2055,7 +2055,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), ...@@ -2055,7 +2055,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
.data = & (const struct snd_usb_audio_quirk[]) { .data = & (const struct snd_usb_audio_quirk[]) {
{ {
.ifnum = 0, .ifnum = 0,
.type = QUIRK_IGNORE_INTERFACE .type = QUIRK_AUDIO_STANDARD_MIXER,
}, },
{ {
.ifnum = 1, .ifnum = 1,
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/usb/audio.h> #include <linux/usb/audio.h>
#include <sound/control.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/info.h> #include <sound/info.h>
#include <sound/pcm.h> #include <sound/pcm.h>
...@@ -262,6 +263,20 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip, ...@@ -262,6 +263,20 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip,
return 0; return 0;
} }
/*
* Create a standard mixer for the specified interface.
*/
static int create_standard_mixer_quirk(struct snd_usb_audio *chip,
struct usb_interface *iface,
struct usb_driver *driver,
const struct snd_usb_audio_quirk *quirk)
{
if (quirk->ifnum < 0)
return 0;
return snd_usb_create_mixer(chip, quirk->ifnum, 0);
}
/* /*
* audio-interface quirks * audio-interface quirks
* *
...@@ -294,7 +309,8 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip, ...@@ -294,7 +309,8 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip,
[QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk, [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk,
[QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk, [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk,
[QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk, [QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk,
[QUIRK_AUDIO_ALIGN_TRANSFER] = create_align_transfer_quirk [QUIRK_AUDIO_ALIGN_TRANSFER] = create_align_transfer_quirk,
[QUIRK_AUDIO_STANDARD_MIXER] = create_standard_mixer_quirk,
}; };
if (quirk->type < QUIRK_TYPE_COUNT) { if (quirk->type < QUIRK_TYPE_COUNT) {
......
...@@ -84,6 +84,7 @@ enum quirk_type { ...@@ -84,6 +84,7 @@ enum quirk_type {
QUIRK_AUDIO_FIXED_ENDPOINT, QUIRK_AUDIO_FIXED_ENDPOINT,
QUIRK_AUDIO_EDIROL_UAXX, QUIRK_AUDIO_EDIROL_UAXX,
QUIRK_AUDIO_ALIGN_TRANSFER, QUIRK_AUDIO_ALIGN_TRANSFER,
QUIRK_AUDIO_STANDARD_MIXER,
QUIRK_TYPE_COUNT QUIRK_TYPE_COUNT
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment