summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/core/init.c36
-rw-r--r--sound/core/oss/mixer_oss.c2
-rw-r--r--sound/core/seq/oss/seq_oss_synth.c3
-rw-r--r--sound/pci/ac97/ac97_patch.c48
-rw-r--r--sound/pci/emu10k1/emu10k1_main.c1
-rw-r--r--sound/pci/emu10k1/emumixer.c13
-rw-r--r--sound/pci/hda/patch_analog.c33
-rw-r--r--sound/usb/usbaudio.c35
-rw-r--r--sound/usb/usbquirks.h75
9 files changed, 151 insertions, 95 deletions
diff --git a/sound/core/init.c b/sound/core/init.c
index e3338d6071ef..6200f428033b 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -311,6 +311,9 @@ int snd_card_disconnect(struct snd_card *card)
struct file *file;
int err;
+ if (!card)
+ return -EINVAL;
+
spin_lock(&card->files_lock);
if (card->shutdown) {
spin_unlock(&card->files_lock);
@@ -322,6 +325,7 @@ int snd_card_disconnect(struct snd_card *card)
/* phase 1: disable fops (user space) operations for ALSA API */
mutex_lock(&snd_card_mutex);
snd_cards[card->number] = NULL;
+ snd_cards_lock &= ~(1 << card->number);
mutex_unlock(&snd_card_mutex);
/* phase 2: replace file->f_op with special dummy operations */
@@ -360,6 +364,15 @@ int snd_card_disconnect(struct snd_card *card)
snd_printk(KERN_ERR "not all devices for card %i can be disconnected\n", card->number);
snd_info_card_disconnect(card);
+#ifndef CONFIG_SYSFS_DEPRECATED
+ if (card->card_dev) {
+ device_unregister(card->card_dev);
+ card->card_dev = NULL;
+ }
+#endif
+#ifdef CONFIG_PM
+ wake_up(&card->power_sleep);
+#endif
return 0;
}
@@ -401,33 +414,14 @@ static int snd_card_do_free(struct snd_card *card)
snd_printk(KERN_WARNING "unable to free card info\n");
/* Not fatal error */
}
-#ifndef CONFIG_SYSFS_DEPRECATED
- if (card->card_dev)
- device_unregister(card->card_dev);
-#endif
kfree(card);
return 0;
}
-static int snd_card_free_prepare(struct snd_card *card)
-{
- if (card == NULL)
- return -EINVAL;
- (void) snd_card_disconnect(card);
- mutex_lock(&snd_card_mutex);
- snd_cards[card->number] = NULL;
- snd_cards_lock &= ~(1 << card->number);
- mutex_unlock(&snd_card_mutex);
-#ifdef CONFIG_PM
- wake_up(&card->power_sleep);
-#endif
- return 0;
-}
-
int snd_card_free_when_closed(struct snd_card *card)
{
int free_now = 0;
- int ret = snd_card_free_prepare(card);
+ int ret = snd_card_disconnect(card);
if (ret)
return ret;
@@ -447,7 +441,7 @@ EXPORT_SYMBOL(snd_card_free_when_closed);
int snd_card_free(struct snd_card *card)
{
- int ret = snd_card_free_prepare(card);
+ int ret = snd_card_disconnect(card);
if (ret)
return ret;
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c
index 75daed298a15..581aa2c60e65 100644
--- a/sound/core/oss/mixer_oss.c
+++ b/sound/core/oss/mixer_oss.c
@@ -1257,6 +1257,8 @@ static void snd_mixer_oss_build(struct snd_mixer_oss *mixer)
{ SOUND_MIXER_DIGITAL3, "Digital", 2 },
{ SOUND_MIXER_PHONEIN, "Phone", 0 },
{ SOUND_MIXER_PHONEOUT, "Master Mono", 0 },
+ { SOUND_MIXER_PHONEOUT, "Speaker", 0 }, /*fallback*/
+ { SOUND_MIXER_PHONEOUT, "Mono", 0 }, /*fallback*/
{ SOUND_MIXER_PHONEOUT, "Phone", 0 }, /* fallback */
{ SOUND_MIXER_VIDEO, "Video", 0 },
{ SOUND_MIXER_RADIO, "Radio", 0 },
diff --git a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c
index ab570a0a6183..2490259472a2 100644
--- a/sound/core/seq/oss/seq_oss_synth.c
+++ b/sound/core/seq/oss/seq_oss_synth.c
@@ -599,6 +599,9 @@ snd_seq_oss_synth_make_info(struct seq_oss_devinfo *dp, int dev, struct synth_in
{
struct seq_oss_synth *rec;
+ if (dev < 0 || dev >= dp->max_synthdev)
+ return -ENXIO;
+
if (dp->synths[dev].is_midi) {
struct midi_info minf;
snd_seq_oss_midi_make_info(dp, dp->synths[dev].midi_mapped, &minf);
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
index fa993d3e34ce..90e5620f0eb4 100644
--- a/sound/pci/ac97/ac97_patch.c
+++ b/sound/pci/ac97/ac97_patch.c
@@ -1960,6 +1960,9 @@ static int snd_ac97_ad1888_lohpsel_get(struct snd_kcontrol *kcontrol, struct snd
val = ac97->regs[AC97_AD_MISC];
ucontrol->value.integer.value[0] = !(val & AC97_AD198X_LOSEL);
+ if (ac97->spec.ad18xx.lo_as_master)
+ ucontrol->value.integer.value[0] =
+ !ucontrol->value.integer.value[0];
return 0;
}
@@ -1968,8 +1971,10 @@ static int snd_ac97_ad1888_lohpsel_put(struct snd_kcontrol *kcontrol, struct snd
struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
unsigned short val;
- val = !ucontrol->value.integer.value[0]
- ? (AC97_AD198X_LOSEL | AC97_AD198X_HPSEL) : 0;
+ val = !ucontrol->value.integer.value[0];
+ if (ac97->spec.ad18xx.lo_as_master)
+ val = !val;
+ val = val ? (AC97_AD198X_LOSEL | AC97_AD198X_HPSEL) : 0;
return snd_ac97_update_bits(ac97, AC97_AD_MISC,
AC97_AD198X_LOSEL | AC97_AD198X_HPSEL, val);
}
@@ -2020,7 +2025,7 @@ static void ad1888_update_jacks(struct snd_ac97 *ac97)
{
unsigned short val = 0;
/* clear LODIS if shared jack is to be used for Surround out */
- if (is_shared_linein(ac97))
+ if (!ac97->spec.ad18xx.lo_as_master && is_shared_linein(ac97))
val |= (1 << 12);
/* clear CLDIS if shared jack is to be used for C/LFE out */
if (is_shared_micin(ac97))
@@ -2057,9 +2062,13 @@ static const struct snd_kcontrol_new snd_ac97_ad1888_controls[] = {
static int patch_ad1888_specific(struct snd_ac97 *ac97)
{
- /* rename 0x04 as "Master" and 0x02 as "Master Surround" */
- snd_ac97_rename_vol_ctl(ac97, "Master Playback", "Master Surround Playback");
- snd_ac97_rename_vol_ctl(ac97, "Headphone Playback", "Master Playback");
+ if (!ac97->spec.ad18xx.lo_as_master) {
+ /* rename 0x04 as "Master" and 0x02 as "Master Surround" */
+ snd_ac97_rename_vol_ctl(ac97, "Master Playback",
+ "Master Surround Playback");
+ snd_ac97_rename_vol_ctl(ac97, "Headphone Playback",
+ "Master Playback");
+ }
return patch_build_controls(ac97, snd_ac97_ad1888_controls, ARRAY_SIZE(snd_ac97_ad1888_controls));
}
@@ -2078,16 +2087,27 @@ static int patch_ad1888(struct snd_ac97 * ac97)
patch_ad1881(ac97);
ac97->build_ops = &patch_ad1888_build_ops;
- /* Switch FRONT/SURROUND LINE-OUT/HP-OUT default connection */
- /* it seems that most vendors connect line-out connector to headphone out of AC'97 */
+
+ /*
+ * LO can be used as a real line-out on some devices,
+ * and we need to revert the front/surround mixer switches
+ */
+ if (ac97->subsystem_vendor == 0x1043 &&
+ ac97->subsystem_device == 0x1193) /* ASUS A9T laptop */
+ ac97->spec.ad18xx.lo_as_master = 1;
+
+ misc = snd_ac97_read(ac97, AC97_AD_MISC);
/* AD-compatible mode */
/* Stereo mutes enabled */
- misc = snd_ac97_read(ac97, AC97_AD_MISC);
- snd_ac97_write_cache(ac97, AC97_AD_MISC, misc |
- AC97_AD198X_LOSEL |
- AC97_AD198X_HPSEL |
- AC97_AD198X_MSPLT |
- AC97_AD198X_AC97NC);
+ misc |= AC97_AD198X_MSPLT | AC97_AD198X_AC97NC;
+ if (!ac97->spec.ad18xx.lo_as_master)
+ /* Switch FRONT/SURROUND LINE-OUT/HP-OUT default connection */
+ /* it seems that most vendors connect line-out connector to
+ * headphone out of AC'97
+ */
+ misc |= AC97_AD198X_LOSEL | AC97_AD198X_HPSEL;
+
+ snd_ac97_write_cache(ac97, AC97_AD_MISC, misc);
ac97->flags |= AC97_STEREO_MUTES;
return 0;
}
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index d0330d8ea095..df278baf053a 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -1527,6 +1527,7 @@ static struct snd_emu_chip_details emu_chip_details[] = {
.ca0151_chip = 1,
.spk71 = 1,
.spdif_bug = 1,
+ .invert_shared_spdif = 1, /* digital/analog switch swapped */
.adc_1361t = 1, /* 24 bit capture instead of 16bit. Fixes ALSA bug#324 */
.ac97_chip = 1} ,
{.vendor = 0x1102, .device = 0x0004, .revision = 0x04,
diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c
index fd221209abcb..9f77692c9c11 100644
--- a/sound/pci/emu10k1/emumixer.c
+++ b/sound/pci/emu10k1/emumixer.c
@@ -1578,6 +1578,10 @@ static int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol,
ucontrol->value.integer.value[0] = inl(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0;
else
ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0;
+ if (emu->card_capabilities->invert_shared_spdif)
+ ucontrol->value.integer.value[0] =
+ !ucontrol->value.integer.value[0];
+
return 0;
}
@@ -1586,15 +1590,18 @@ static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol,
{
unsigned long flags;
struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
- unsigned int reg, val;
+ unsigned int reg, val, sw;
int change = 0;
+ sw = ucontrol->value.integer.value[0];
+ if (emu->card_capabilities->invert_shared_spdif)
+ sw = !sw;
spin_lock_irqsave(&emu->reg_lock, flags);
if ( emu->card_capabilities->i2c_adc) {
/* Do nothing for Audigy 2 ZS Notebook */
} else if (emu->audigy) {
reg = inl(emu->port + A_IOCFG);
- val = ucontrol->value.integer.value[0] ? A_IOCFG_GPOUT0 : 0;
+ val = sw ? A_IOCFG_GPOUT0 : 0;
change = (reg & A_IOCFG_GPOUT0) != val;
if (change) {
reg &= ~A_IOCFG_GPOUT0;
@@ -1603,7 +1610,7 @@ static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol,
}
}
reg = inl(emu->port + HCFG);
- val = ucontrol->value.integer.value[0] ? HCFG_GPOUT0 : 0;
+ val = sw ? HCFG_GPOUT0 : 0;
change |= (reg & HCFG_GPOUT0) != val;
if (change) {
reg &= ~HCFG_GPOUT0;
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index c8649282c2cf..d7cba536d305 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -1563,6 +1563,7 @@ static const char *ad1981_models[AD1981_MODELS] = {
static struct snd_pci_quirk ad1981_cfg_tbl[] = {
SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD),
+ SND_PCI_QUIRK(0x1014, 0x05b7, "Lenovo Z60m", AD1981_THINKPAD),
/* All HP models */
SND_PCI_QUIRK(0x103c, 0, "HP nx", AD1981_HP),
SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba U205", AD1981_TOSHIBA),
@@ -2557,7 +2558,7 @@ static int ad1988_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
{
struct ad198x_spec *spec = codec->spec;
hda_nid_t nid;
- int idx, err;
+ int i, idx, err;
char name[32];
if (! pin)
@@ -2565,16 +2566,26 @@ static int ad1988_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
idx = ad1988_pin_idx(pin);
nid = ad1988_idx_to_dac(codec, idx);
- /* specify the DAC as the extra output */
- if (! spec->multiout.hp_nid)
- spec->multiout.hp_nid = nid;
- else
- spec->multiout.extra_out_nid[0] = nid;
- /* control HP volume/switch on the output mixer amp */
- sprintf(name, "%s Playback Volume", pfx);
- if ((err = add_control(spec, AD_CTL_WIDGET_VOL, name,
- HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0)
- return err;
+ /* check whether the corresponding DAC was already taken */
+ for (i = 0; i < spec->autocfg.line_outs; i++) {
+ hda_nid_t pin = spec->autocfg.line_out_pins[i];
+ hda_nid_t dac = ad1988_idx_to_dac(codec, ad1988_pin_idx(pin));
+ if (dac == nid)
+ break;
+ }
+ if (i >= spec->autocfg.line_outs) {
+ /* specify the DAC as the extra output */
+ if (!spec->multiout.hp_nid)
+ spec->multiout.hp_nid = nid;
+ else
+ spec->multiout.extra_out_nid[0] = nid;
+ /* control HP volume/switch on the output mixer amp */
+ sprintf(name, "%s Playback Volume", pfx);
+ err = add_control(spec, AD_CTL_WIDGET_VOL, name,
+ HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ }
nid = ad1988_mixer_nids[idx];
sprintf(name, "%s Playback Switch", pfx);
if ((err = add_control(spec, AD_CTL_BIND_MUTE, name,
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c
index f48838a078cb..d0bc98896349 100644
--- a/sound/usb/usbaudio.c
+++ b/sound/usb/usbaudio.c
@@ -1762,8 +1762,10 @@ static int check_hw_params_convention(struct snd_usb_substream *subs)
channels = kcalloc(MAX_MASK, sizeof(u32), GFP_KERNEL);
rates = kcalloc(MAX_MASK, sizeof(u32), GFP_KERNEL);
- if (!channels || !rates)
+ if (!channels || !rates) {
+ err = -ENOMEM;
goto __out;
+ }
list_for_each(p, &subs->fmt_list) {
struct audioformat *f;
@@ -1916,7 +1918,10 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre
1000 * MIN_PACKS_URB,
/*(nrpacks * MAX_URBS) * 1000*/ UINT_MAX);
- if (check_hw_params_convention(subs)) {
+ err = check_hw_params_convention(subs);
+ if (err < 0)
+ return err;
+ else if (err) {
hwc_debug("setting extra hw constraints...\n");
if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
hw_rule_rate, subs,
@@ -2463,11 +2468,12 @@ static int parse_audio_format_i_type(struct snd_usb_audio *chip, struct audiofor
}
break;
case USB_AUDIO_FORMAT_PCM8:
- /* Dallas DS4201 workaround */
+ pcm_format = SNDRV_PCM_FORMAT_U8;
+
+ /* Dallas DS4201 workaround: it advertises U8 format, but really
+ supports S8. */
if (chip->usb_id == USB_ID(0x04fa, 0x4201))
pcm_format = SNDRV_PCM_FORMAT_S8;
- else
- pcm_format = SNDRV_PCM_FORMAT_U8;
break;
case USB_AUDIO_FORMAT_IEEE_FLOAT:
pcm_format = SNDRV_PCM_FORMAT_FLOAT_LE;
@@ -2671,12 +2677,23 @@ static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
int format;
struct audioformat *fp;
unsigned char *fmt, *csep;
+ int num;
dev = chip->dev;
/* parse the interface's altsettings */
iface = usb_ifnum_to_if(dev, iface_no);
- for (i = 0; i < iface->num_altsetting; i++) {
+
+ num = iface->num_altsetting;
+
+ /*
+ * Dallas DS4201 workaround: It presents 5 altsettings, but the last
+ * one misses syncpipe, and does not produce any sound.
+ */
+ if (chip->usb_id == USB_ID(0x04fa, 0x4201))
+ num = 4;
+
+ for (i = 0; i < num; i++) {
alts = &iface->altsetting[i];
altsd = get_iface_desc(alts);
/* skip invalid one */
@@ -3406,7 +3423,6 @@ static void snd_usb_audio_create_proc(struct snd_usb_audio *chip)
static int snd_usb_audio_free(struct snd_usb_audio *chip)
{
- usb_chip[chip->index] = NULL;
kfree(chip);
return 0;
}
@@ -3600,8 +3616,8 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
snd_card_set_dev(chip->card, &intf->dev);
break;
}
- if (! chip) {
- snd_printk(KERN_ERR "no available usb audio device\n");
+ if (!chip) {
+ printk(KERN_ERR "no available usb audio device\n");
goto __error;
}
}
@@ -3671,6 +3687,7 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr)
list_for_each(p, &chip->mixer_list) {
snd_usb_mixer_disconnect(p);
}
+ usb_chip[chip->index] = NULL;
mutex_unlock(&register_mutex);
snd_card_free_when_closed(card);
} else {
diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h
index 938dff5f9cef..82a8d14c26af 100644
--- a/sound/usb/usbquirks.h
+++ b/sound/usb/usbquirks.h
@@ -39,6 +39,30 @@
.idProduct = prod, \
.bInterfaceClass = USB_CLASS_VENDOR_SPEC
+/* Creative/E-Mu devices */
+{
+ USB_DEVICE(0x041e, 0x3010),
+ .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+ .vendor_name = "Creative Labs",
+ .product_name = "Sound Blaster MP3+",
+ .ifnum = QUIRK_NO_INTERFACE
+ }
+},
+{
+ /* E-Mu 0202 USB */
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE,
+ .idVendor = 0x041e,
+ .idProduct = 0x3f02,
+ .bInterfaceClass = USB_CLASS_AUDIO,
+},
+{
+ /* E-Mu 0404 USB */
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE,
+ .idVendor = 0x041e,
+ .idProduct = 0x3f04,
+ .bInterfaceClass = USB_CLASS_AUDIO,
+},
+
/*
* Logitech QuickCam: bDeviceClass is vendor-specific, so generic interface
* class matches do not take effect without an explicit ID match.
@@ -97,19 +121,7 @@
.bInterfaceClass = USB_CLASS_AUDIO,
.bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL
},
-/* E-Mu devices */
-{
- .match_flags = USB_DEVICE_ID_MATCH_DEVICE,
- .idVendor = 0x041e,
- .idProduct = 0x3f02,
- .bInterfaceClass = USB_CLASS_AUDIO,
-},
-{
- .match_flags = USB_DEVICE_ID_MATCH_DEVICE,
- .idVendor = 0x041e,
- .idProduct = 0x3f04,
- .bInterfaceClass = USB_CLASS_AUDIO,
-},
+
/*
* Yamaha devices
*/
@@ -1165,19 +1177,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
}
},
-{
- USB_DEVICE(0x582, 0x00a6),
- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
- .vendor_name = "Roland",
- .product_name = "Juno-G",
- .ifnum = 0,
- .type = QUIRK_MIDI_FIXED_ENDPOINT,
- .data = & (const struct snd_usb_midi_endpoint_info) {
- .out_cables = 0x0001,
- .in_cables = 0x0001
- }
- }
-},
{ /*
* This quirk is for the "Advanced" modes of the Edirol UA-25.
* If the switch is not in an advanced setting, the UA-25 has
@@ -1336,6 +1335,19 @@ YAMAHA_DEVICE(0x7010, "UB99"),
},
/* TODO: add Edirol MD-P1 support */
{
+ USB_DEVICE(0x582, 0x00a6),
+ .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+ .vendor_name = "Roland",
+ .product_name = "Juno-G",
+ .ifnum = 0,
+ .type = QUIRK_MIDI_FIXED_ENDPOINT,
+ .data = & (const struct snd_usb_midi_endpoint_info) {
+ .out_cables = 0x0001,
+ .in_cables = 0x0001
+ }
+ }
+},
+{
/* Roland SH-201 */
USB_DEVICE(0x0582, 0x00ad),
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
@@ -1719,17 +1731,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
},
-{
- /* Creative Sound Blaster MP3+ */
- USB_DEVICE(0x041e, 0x3010),
- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
- .vendor_name = "Creative Labs",
- .product_name = "Sound Blaster MP3+",
- .ifnum = QUIRK_NO_INTERFACE
- }
-
-},
-
/* Emagic devices */
{
USB_DEVICE(0x086a, 0x0001),