diff options
Diffstat (limited to 'sound')
51 files changed, 590 insertions, 362 deletions
diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c index 7d39aac..7fbd68f 100644 --- a/sound/arm/aaci.c +++ b/sound/arm/aaci.c @@ -90,7 +90,7 @@ static void aaci_ac97_write(struct snd_ac97 *ac97, unsigned short reg, */ do { v = readl(aaci->base + AACI_SLFR); - } while ((v & (SLFR_1TXB|SLFR_2TXB)) && timeout--); + } while ((v & (SLFR_1TXB|SLFR_2TXB)) && --timeout); if (!timeout) dev_err(&aaci->dev->dev, @@ -126,7 +126,7 @@ static unsigned short aaci_ac97_read(struct snd_ac97 *ac97, unsigned short reg) */ do { v = readl(aaci->base + AACI_SLFR); - } while ((v & SLFR_1TXB) && timeout--); + } while ((v & SLFR_1TXB) && --timeout); if (!timeout) { dev_err(&aaci->dev->dev, "timeout on slot 1 TX busy\n"); @@ -147,7 +147,7 @@ static unsigned short aaci_ac97_read(struct snd_ac97 *ac97, unsigned short reg) do { cond_resched(); v = readl(aaci->base + AACI_SLFR) & (SLFR_1RXV|SLFR_2RXV); - } while ((v != (SLFR_1RXV|SLFR_2RXV)) && timeout--); + } while ((v != (SLFR_1RXV|SLFR_2RXV)) && --timeout); if (!timeout) { dev_err(&aaci->dev->dev, "timeout on RX valid\n"); diff --git a/sound/core/jack.c b/sound/core/jack.c index dd4a12d..077a852 100644 --- a/sound/core/jack.c +++ b/sound/core/jack.c @@ -47,7 +47,7 @@ static int snd_jack_dev_register(struct snd_device *device) int err; snprintf(jack->name, sizeof(jack->name), "%s %s", - card->longname, jack->id); + card->shortname, jack->id); jack->input_dev->name = jack->name; /* Default to the sound card device. */ diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index 4690b8b..e570649 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c @@ -692,6 +692,9 @@ static int snd_mixer_oss_put_volume1(struct snd_mixer_oss_file *fmixer, snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right); if (slot->present & SNDRV_MIXER_OSS_PRESENT_CVOLUME) snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CVOLUME], left, right); + } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_CVOLUME) { + snd_mixer_oss_put_volume1_vol(fmixer, pslot, + slot->numid[SNDRV_MIXER_OSS_ITEM_CVOLUME], left, right); } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GVOLUME) { snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GVOLUME], left, right); } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GLOBAL) { diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index e178366..699d289 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -1767,7 +1767,7 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file) AFMT_S8 | AFMT_U16_LE | AFMT_U16_BE | AFMT_S32_LE | AFMT_S32_BE | - AFMT_S24_LE | AFMT_S24_LE | + AFMT_S24_LE | AFMT_S24_BE | AFMT_S24_PACKED; params = kmalloc(sizeof(*params), GFP_KERNEL); if (!params) @@ -2872,7 +2872,7 @@ static void snd_pcm_oss_proc_write(struct snd_info_entry *entry, setup = kmalloc(sizeof(*setup), GFP_KERNEL); if (! setup) { buffer->error = -ENOMEM; - mutex_lock(&pstr->oss.setup_mutex); + mutex_unlock(&pstr->oss.setup_mutex); return; } if (pstr->oss.setup_list == NULL) @@ -2886,7 +2886,7 @@ static void snd_pcm_oss_proc_write(struct snd_info_entry *entry, if (! template.task_name) { kfree(setup); buffer->error = -ENOMEM; - mutex_lock(&pstr->oss.setup_mutex); + mutex_unlock(&pstr->oss.setup_mutex); return; } } diff --git a/sound/core/oss/rate.c b/sound/core/oss/rate.c index a466443..2fa9299 100644 --- a/sound/core/oss/rate.c +++ b/sound/core/oss/rate.c @@ -157,7 +157,7 @@ static void resample_shrink(struct snd_pcm_plugin *plugin, while (dst_frames1 > 0) { S1 = S2; if (src_frames1-- > 0) { - S1 = *src; + S2 = *src; src += src_step; } if (pos & ~R_MASK) { diff --git a/sound/core/sgbuf.c b/sound/core/sgbuf.c index d4564ed..4e7ec2b 100644 --- a/sound/core/sgbuf.c +++ b/sound/core/sgbuf.c @@ -38,6 +38,10 @@ int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab) if (! sgbuf) return -EINVAL; + if (dmab->area) + vunmap(dmab->area); + dmab->area = NULL; + tmpb.dev.type = SNDRV_DMA_TYPE_DEV; tmpb.dev.dev = sgbuf->dev; for (i = 0; i < sgbuf->pages; i++) { @@ -48,9 +52,6 @@ int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab) tmpb.bytes = (sgbuf->table[i].addr & ~PAGE_MASK) << PAGE_SHIFT; snd_dma_free_pages(&tmpb); } - if (dmab->area) - vunmap(dmab->area); - dmab->area = NULL; kfree(sgbuf->table); kfree(sgbuf->page_table); diff --git a/sound/drivers/mtpav.c b/sound/drivers/mtpav.c index c3e9833..0e17d2b 100644 --- a/sound/drivers/mtpav.c +++ b/sound/drivers/mtpav.c @@ -706,7 +706,6 @@ static int __devinit snd_mtpav_probe(struct platform_device *dev) mtp_card->card = card; mtp_card->irq = -1; mtp_card->share_irq = 0; - mtp_card->inmidiport = 0xffffffff; mtp_card->inmidistate = 0; mtp_card->outmidihwport = 0xffffffff; init_timer(&mtp_card->timer); @@ -719,6 +718,8 @@ static int __devinit snd_mtpav_probe(struct platform_device *dev) if (err < 0) goto __error; + mtp_card->inmidiport = mtp_card->num_ports + MTPAV_PIDX_BROADCAST; + err = snd_mtpav_get_ISA(mtp_card); if (err < 0) goto __error; diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c index 645491a..63e5137 100644 --- a/sound/isa/opl3sa2.c +++ b/sound/isa/opl3sa2.c @@ -550,21 +550,27 @@ static int __devinit snd_opl3sa2_mixer(struct snd_card *card) #ifdef CONFIG_PM static int snd_opl3sa2_suspend(struct snd_card *card, pm_message_t state) { - struct snd_opl3sa2 *chip = card->private_data; + if (card) { + struct snd_opl3sa2 *chip = card->private_data; - snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - chip->wss->suspend(chip->wss); - /* power down */ - snd_opl3sa2_write(chip, OPL3SA2_PM_CTRL, OPL3SA2_PM_D3); + snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); + chip->wss->suspend(chip->wss); + /* power down */ + snd_opl3sa2_write(chip, OPL3SA2_PM_CTRL, OPL3SA2_PM_D3); + } return 0; } static int snd_opl3sa2_resume(struct snd_card *card) { - struct snd_opl3sa2 *chip = card->private_data; + struct snd_opl3sa2 *chip; int i; + if (!card) + return 0; + + chip = card->private_data; /* power up */ snd_opl3sa2_write(chip, OPL3SA2_PM_CTRL, OPL3SA2_PM_D0); diff --git a/sound/oss/dmasound/dmasound_atari.c b/sound/oss/dmasound/dmasound_atari.c index 4d45bd6..38931f2 100644 --- a/sound/oss/dmasound/dmasound_atari.c +++ b/sound/oss/dmasound/dmasound_atari.c @@ -847,22 +847,23 @@ static int __init AtaIrqInit(void) of events. So all we need to keep the music playing is to provide the sound hardware with new data upon an interrupt from timer A. */ - mfp.tim_ct_a = 0; /* ++roman: Stop timer before programming! */ - mfp.tim_dt_a = 1; /* Cause interrupt after first event. */ - mfp.tim_ct_a = 8; /* Turn on event counting. */ + st_mfp.tim_ct_a = 0; /* ++roman: Stop timer before programming! */ + st_mfp.tim_dt_a = 1; /* Cause interrupt after first event. */ + st_mfp.tim_ct_a = 8; /* Turn on event counting. */ /* Register interrupt handler. */ - request_irq(IRQ_MFP_TIMA, AtaInterrupt, IRQ_TYPE_SLOW, "DMA sound", - AtaInterrupt); - mfp.int_en_a |= 0x20; /* Turn interrupt on. */ - mfp.int_mk_a |= 0x20; + if (request_irq(IRQ_MFP_TIMA, AtaInterrupt, IRQ_TYPE_SLOW, "DMA sound", + AtaInterrupt)) + return 0; + st_mfp.int_en_a |= 0x20; /* Turn interrupt on. */ + st_mfp.int_mk_a |= 0x20; return 1; } #ifdef MODULE static void AtaIrqCleanUp(void) { - mfp.tim_ct_a = 0; /* stop timer */ - mfp.int_en_a &= ~0x20; /* turn interrupt off */ + st_mfp.tim_ct_a = 0; /* stop timer */ + st_mfp.int_en_a &= ~0x20; /* turn interrupt off */ free_irq(IRQ_MFP_TIMA, AtaInterrupt); } #endif /* MODULE */ @@ -1598,7 +1599,7 @@ static int __init dmasound_atari_init(void) is_falcon = 0; } else return -ENODEV; - if ((mfp.int_en_a & mfp.int_mk_a & 0x20) == 0) + if ((st_mfp.int_en_a & st_mfp.int_mk_a & 0x20) == 0) return dmasound_init(); else { printk("DMA sound driver: Timer A interrupt already in use\n"); diff --git a/sound/oss/dmasound/dmasound_q40.c b/sound/oss/dmasound/dmasound_q40.c index 1855b14..99bcb21 100644 --- a/sound/oss/dmasound/dmasound_q40.c +++ b/sound/oss/dmasound/dmasound_q40.c @@ -371,8 +371,9 @@ static void Q40Free(void *ptr, unsigned int size) static int __init Q40IrqInit(void) { /* Register interrupt handler. */ - request_irq(Q40_IRQ_SAMPLE, Q40StereoInterrupt, 0, - "DMA sound", Q40Interrupt); + if (request_irq(Q40_IRQ_SAMPLE, Q40StereoInterrupt, 0, + "DMA sound", Q40Interrupt)) + return 0; return(1); } @@ -401,6 +402,7 @@ static void Q40PlayNextFrame(int index) u_char *start; u_long size; u_char speed; + int error; /* used by Q40Play() if all doubts whether there really is something * to be played are already wiped out. @@ -419,11 +421,13 @@ static void Q40PlayNextFrame(int index) master_outb( 0,SAMPLE_ENABLE_REG); free_irq(Q40_IRQ_SAMPLE, Q40Interrupt); if (dmasound.soft.stereo) - request_irq(Q40_IRQ_SAMPLE, Q40StereoInterrupt, 0, - "Q40 sound", Q40Interrupt); + error = request_irq(Q40_IRQ_SAMPLE, Q40StereoInterrupt, 0, + "Q40 sound", Q40Interrupt); else - request_irq(Q40_IRQ_SAMPLE, Q40MonoInterrupt, 0, - "Q40 sound", Q40Interrupt); + error = request_irq(Q40_IRQ_SAMPLE, Q40MonoInterrupt, 0, + "Q40 sound", Q40Interrupt); + if (error && printk_ratelimit()) + pr_err("Couldn't register sound interrupt\n"); master_outb( speed, SAMPLE_RATE_REG); master_outb( 1,SAMPLE_CLEAR_REG); diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 6e3a184..82b9bdd 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -744,8 +744,8 @@ config SND_VIRTUOSO select SND_OXYGEN_LIB help Say Y here to include support for sound cards based on the - Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X and - HDAV1.3 (Deluxe). + Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2 and D2X. + Support for the HDAV1.3 (Deluxe) is very experimental. To compile this driver as a module, choose M here: the module will be called snd-virtuoso. diff --git a/sound/pci/aw2/aw2-alsa.c b/sound/pci/aw2/aw2-alsa.c index eefcbf6..8eea29f 100644 --- a/sound/pci/aw2/aw2-alsa.c +++ b/sound/pci/aw2/aw2-alsa.c @@ -165,7 +165,7 @@ module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "Enable Audiowerk2 soundcard."); static struct pci_device_id snd_aw2_ids[] = { - {PCI_VENDOR_ID_SAA7146, PCI_DEVICE_ID_SAA7146, PCI_ANY_ID, PCI_ANY_ID, + {PCI_VENDOR_ID_SAA7146, PCI_DEVICE_ID_SAA7146, 0, 0, 0, 0, 0}, {0} }; diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 7958006..101a1c1 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -1528,6 +1528,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 */ .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10021102, .driver = "Audigy2", .name = "SB Audigy 2 Platinum [SB0240P]", diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c index e00421c..960fd79 100644 --- a/sound/pci/hda/hda_beep.c +++ b/sound/pci/hda/hda_beep.c @@ -135,7 +135,6 @@ void snd_hda_detach_beep_device(struct hda_codec *codec) struct hda_beep *beep = codec->beep; if (beep) { cancel_work_sync(&beep->beep_work); - flush_scheduled_work(); input_unregister_device(beep->dev); kfree(beep); diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index e16cf63..d03f992 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -373,7 +373,7 @@ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex) unsol->queue[wp] = res; unsol->queue[wp + 1] = res_ex; - schedule_work(&unsol->work); + queue_work(bus->workq, &unsol->work); return 0; } @@ -437,15 +437,17 @@ static int snd_hda_bus_free(struct hda_bus *bus) if (!bus) return 0; - if (bus->unsol) { - flush_scheduled_work(); + if (bus->workq) + flush_workqueue(bus->workq); + if (bus->unsol) kfree(bus->unsol); - } list_for_each_entry_safe(codec, n, &bus->codec_list, list) { snd_hda_codec_free(codec); } if (bus->ops.private_free) bus->ops.private_free(bus); + if (bus->workq) + destroy_workqueue(bus->workq); kfree(bus); return 0; } @@ -514,6 +516,16 @@ int /*__devinit*/ snd_hda_bus_new(struct snd_card *card, mutex_init(&bus->cmd_mutex); INIT_LIST_HEAD(&bus->codec_list); + snprintf(bus->workq_name, sizeof(bus->workq_name), + "hd-audio%d", card->number); + bus->workq = create_singlethread_workqueue(bus->workq_name); + if (!bus->workq) { + snd_printk(KERN_ERR "cannot create workqueue %s\n", + bus->workq_name); + kfree(bus); + return -ENOMEM; + } + err = snd_device_new(card, SNDRV_DEV_BUS, bus, &dev_ops); if (err < 0) { snd_hda_bus_free(bus); @@ -684,7 +696,7 @@ static void snd_hda_codec_free(struct hda_codec *codec) return; #ifdef CONFIG_SND_HDA_POWER_SAVE cancel_delayed_work(&codec->power_work); - flush_scheduled_work(); + flush_workqueue(codec->bus->workq); #endif list_del(&codec->list); snd_array_free(&codec->mixers); @@ -735,6 +747,7 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr codec->bus = bus; codec->addr = codec_addr; mutex_init(&codec->spdif_mutex); + mutex_init(&codec->control_mutex); init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); snd_array_init(&codec->mixers, sizeof(struct snd_kcontrol *), 32); @@ -1272,7 +1285,7 @@ void snd_hda_codec_reset(struct hda_codec *codec) #ifdef CONFIG_SND_HDA_POWER_SAVE cancel_delayed_work(&codec->power_work); - flush_scheduled_work(); + flush_workqueue(codec->bus->workq); #endif snd_hda_ctls_clear(codec); /* relase PCMs */ @@ -1418,12 +1431,12 @@ int snd_hda_mixer_bind_switch_get(struct snd_kcontrol *kcontrol, unsigned long pval; int err; - mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ + mutex_lock(&codec->control_mutex); pval = kcontrol->private_value; kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */ err = snd_hda_mixer_amp_switch_get(kcontrol, ucontrol); kcontrol->private_value = pval; - mutex_unlock(&codec->spdif_mutex); + mutex_unlock(&codec->control_mutex); return err; } EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_switch_get); @@ -1435,7 +1448,7 @@ int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol, unsigned long pval; int i, indices, err = 0, change = 0; - mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ + mutex_lock(&codec->control_mutex); pval = kcontrol->private_value; indices = (pval & AMP_VAL_IDX_MASK) >> AMP_VAL_IDX_SHIFT; for (i = 0; i < indices; i++) { @@ -1447,7 +1460,7 @@ int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol, change |= err; } kcontrol->private_value = pval; - mutex_unlock(&codec->spdif_mutex); + mutex_unlock(&codec->control_mutex); return err < 0 ? err : change; } EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_switch_put); @@ -1462,12 +1475,12 @@ int snd_hda_mixer_bind_ctls_info(struct snd_kcontrol *kcontrol, struct hda_bind_ctls *c; int err; - mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ + mutex_lock(&codec->control_mutex); c = (struct hda_bind_ctls *)kcontrol->private_value; kcontrol->private_value = *c->values; err = c->ops->info(kcontrol, uinfo); kcontrol->private_value = (long)c; - mutex_unlock(&codec->spdif_mutex); + mutex_unlock(&codec->control_mutex); return err; } EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_info); @@ -1479,12 +1492,12 @@ int snd_hda_mixer_bind_ctls_get(struct snd_kcontrol *kcontrol, struct hda_bind_ctls *c; int err; - mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ + mutex_lock(&codec->control_mutex); c = (struct hda_bind_ctls *)kcontrol->private_value; kcontrol->private_value = *c->values; err = c->ops->get(kcontrol, ucontrol); kcontrol->private_value = (long)c; - mutex_unlock(&codec->spdif_mutex); + mutex_unlock(&codec->control_mutex); return err; } EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_get); @@ -1497,7 +1510,7 @@ int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol, unsigned long *vals; int err = 0, change = 0; - mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ + mutex_lock(&codec->control_mutex); c = (struct hda_bind_ctls *)kcontrol->private_value; for (vals = c->values; *vals; vals++) { kcontrol->private_value = *vals; @@ -1507,7 +1520,7 @@ int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol, change |= err; } kcontrol->private_value = (long)c; - mutex_unlock(&codec->spdif_mutex); + mutex_unlock(&codec->control_mutex); return err < 0 ? err : change; } EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_put); @@ -1519,12 +1532,12 @@ int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag, struct hda_bind_ctls *c; int err; - mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ + mutex_lock(&codec->control_mutex); c = (struct hda_bind_ctls *)kcontrol->private_value; kcontrol->private_value = *c->values; err = c->ops->tlv(kcontrol, op_flag, size, tlv); kcontrol->private_value = (long)c; - mutex_unlock(&codec->spdif_mutex); + mutex_unlock(&codec->control_mutex); return err; } EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_tlv); @@ -2712,6 +2725,67 @@ int snd_hda_check_board_config(struct hda_codec *codec, EXPORT_SYMBOL_HDA(snd_hda_check_board_config); /** + * snd_hda_check_board_codec_sid_config - compare the current codec + subsystem ID with the + config table + + This is important for Gateway notebooks with SB450 HDA Audio + where the vendor ID of the PCI device is: + ATI Technologies Inc SB450 HDA Audio [1002:437b] + and the vendor/subvendor are found only at the codec. + + * @codec: the HDA codec + * @num_configs: number of config enums + * @models: array of model name strings + * @tbl: configuration table, terminated by null entries + * + * Compares the modelname or PCI subsystem id of the current codec with the + * given configuration table. If a matching entry is found, returns its + * config value (supposed to be 0 or positive). + * + * If no entries are matching, the function returns a negative value. + */ +int snd_hda_check_board_codec_sid_config(struct hda_codec *codec, + int num_configs, const char **models, + const struct snd_pci_quirk *tbl) +{ + const struct snd_pci_quirk *q; + + /* Search for codec ID */ + for (q = tbl; q->subvendor; q++) { + unsigned long vendorid = (q->subdevice) | (q->subvendor << 16); + + if (vendorid == codec->subsystem_id) + break; + } + + if (!q->subvendor) + return -1; + + tbl = q; + + if (tbl->value >= 0 && tbl->value < num_configs) { +#ifdef CONFIG_SND_DEBUG_DETECT + char tmp[10]; + const char *model = NULL; + if (models) + model = models[tbl->value]; + if (!model) { + sprintf(tmp, "#%d", tbl->value); + model = tmp; + } + snd_printdd(KERN_INFO "hda_codec: model '%s' is selected " + "for config %x:%x (%s)\n", + model, tbl->subvendor, tbl->subdevice, + (tbl->name ? tbl->name : "Unknown device")); +#endif + return tbl->value; + } + return -1; +} +EXPORT_SYMBOL_HDA(snd_hda_check_board_codec_sid_config); + +/** * snd_hda_add_new_ctls - create controls from the array * @codec: the HDA codec * @knew: the array of struct snd_kcontrol_new @@ -2803,7 +2877,7 @@ void snd_hda_power_down(struct hda_codec *codec) return; if (power_save(codec)) { codec->power_transition = 1; /* avoid reentrance */ - schedule_delayed_work(&codec->power_work, + queue_delayed_work(codec->bus->workq, &codec->power_work, msecs_to_jiffies(power_save(codec) * 1000)); } } @@ -3014,6 +3088,16 @@ int snd_hda_multi_out_dig_prepare(struct hda_codec *codec, } EXPORT_SYMBOL_HDA(snd_hda_multi_out_dig_prepare); +int snd_hda_multi_out_dig_cleanup(struct hda_codec *codec, + struct hda_multi_out *mout) +{ + mutex_lock(&codec->spdif_mutex); + cleanup_dig_out_stream(codec, mout->dig_out_nid); + mutex_unlock(&codec->spdif_mutex); + return 0; +} +EXPORT_SYMBOL_HDA(snd_hda_multi_out_dig_cleanup); + /* * release the digital out */ diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 729fc764..09a332a 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -614,6 +614,8 @@ struct hda_bus { /* unsolicited event queue */ struct hda_bus_unsolicited *unsol; + char workq_name[16]; + struct workqueue_struct *workq; /* common workqueue for codecs */ /* assigned PCMs */ DECLARE_BITMAP(pcm_dev_bits, SNDRV_PCM_DEVICES); @@ -771,6 +773,7 @@ struct hda_codec { struct hda_cache_rec cmd_cache; /* cache for other commands */ struct mutex spdif_mutex; + struct mutex control_mutex; unsigned int spdif_status; /* IEC958 status bits */ unsigned short spdif_ctls; /* SPDIF control bits */ unsigned int spdif_in_enable; /* SPDIF input enable? */ diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index 300ab40..4ae51dc 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c @@ -175,7 +175,7 @@ static int reconfig_codec(struct hda_codec *codec) err = snd_hda_codec_build_controls(codec); if (err < 0) return err; - return 0; + return snd_card_register(codec->bus->card); } /* @@ -277,18 +277,19 @@ static ssize_t init_verbs_store(struct device *dev, { struct snd_hwdep *hwdep = dev_get_drvdata(dev); struct hda_codec *codec = hwdep->private_data; - char *p; - struct hda_verb verb, *v; + struct hda_verb *v; + int nid, verb, param; - verb.nid = simple_strtoul(buf, &p, 0); - verb.verb = simple_strtoul(p, &p, 0); - verb.param = simple_strtoul(p, &p, 0); - if (!verb.nid || !verb.verb || !verb.param) + if (sscanf(buf, "%i %i %i", &nid, &verb, ¶m) != 3) + return -EINVAL; + if (!nid || !verb) return -EINVAL; v = snd_array_new(&codec->init_verbs); if (!v) return -ENOMEM; - *v = verb; + v->nid = nid; + v->verb = verb; + v->param = param; return count; } diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index ad5df2a..3683978 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -996,10 +996,11 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id) spin_unlock(&chip->reg_lock); snd_pcm_period_elapsed(azx_dev->substream); spin_lock(&chip->reg_lock); - } else { + } else if (chip->bus && chip->bus->workq) { /* bogus IRQ, process it later */ azx_dev->irq_pending = 1; - schedule_work(&chip->irq_pending_work); + queue_work(chip->bus->workq, + &chip->irq_pending_work); } } } @@ -1741,7 +1742,6 @@ static void azx_clear_irq_pending(struct azx *chip) for (i = 0; i < chip->num_streams; i++) chip->azx_dev[i].irq_pending = 0; spin_unlock_irq(&chip->reg_lock); - flush_scheduled_work(); } static struct snd_pcm_ops azx_pcm_ops = { @@ -1947,16 +1947,13 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state) return 0; } -static int azx_resume_early(struct pci_dev *pci) -{ - return pci_restore_state(pci); -} - static int azx_resume(struct pci_dev *pci) { struct snd_card *card = pci_get_drvdata(pci); struct azx *chip = card->private_data; + pci_set_power_state(pci, PCI_D0); + pci_restore_state(pci); if (pci_enable_device(pci) < 0) { printk(KERN_ERR "hda-intel: pci_enable_device failed, " "disabling device\n"); @@ -2062,26 +2059,31 @@ static int __devinit check_position_fix(struct azx *chip, int fix) { const struct snd_pci_quirk *q; - /* Check VIA HD Audio Controller exist */ - if (chip->pci->vendor == PCI_VENDOR_ID_VIA && - chip->pci->device == VIA_HDAC_DEVICE_ID) { + switch (fix) { + case POS_FIX_LPIB: + case POS_FIX_POSBUF: + return fix; + } + + /* Check VIA/ATI HD Audio Controller exist */ + switch (chip->driver_type) { + case AZX_DRIVER_VIA: + case AZX_DRIVER_ATI: chip->via_dmapos_patch = 1; /* Use link position directly, avoid any transfer problem. */ return POS_FIX_LPIB; } chip->via_dmapos_patch = 0; - if (fix == POS_FIX_AUTO) { - q = snd_pci_quirk_lookup(chip->pci, position_fix_list); - if (q) { - printk(KERN_INFO - "hda_intel: position_fix set to %d " - "for device %04x:%04x\n", - q->value, q->subvendor, q->subdevice); - return q->value; - } + q = snd_pci_quirk_lookup(chip->pci, position_fix_list); + if (q) { + printk(KERN_INFO + "hda_intel: position_fix set to %d " + "for device %04x:%04x\n", + q->value, q->subvendor, q->subdevice); + return q->value; } - return fix; + return POS_FIX_AUTO; } /* @@ -2098,6 +2100,8 @@ static struct snd_pci_quirk probe_mask_list[] __devinitdata = { SND_PCI_QUIRK(0x1028, 0x20ac, "Dell Studio Desktop", 0x01), /* including bogus ALC268 in slot#2 that conflicts with ALC888 */ SND_PCI_QUIRK(0x17c0, 0x4085, "Medion MD96630", 0x01), + /* conflict of ALC268 in slot#3 (digital I/O); a temporary fix */ + SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba laptop", 0x03), {} }; @@ -2211,9 +2215,17 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, gcap = azx_readw(chip, GCAP); snd_printdd("chipset global capabilities = 0x%x\n", gcap); + /* ATI chips seems buggy about 64bit DMA addresses */ + if (chip->driver_type == AZX_DRIVER_ATI) + gcap &= ~0x01; + /* allow 64bit DMA address if supported by H/W */ if ((gcap & 0x01) && !pci_set_dma_mask(pci, DMA_64BIT_MASK)) pci_set_consistent_dma_mask(pci, DMA_64BIT_MASK); + else { + pci_set_dma_mask(pci, DMA_32BIT_MASK); + pci_set_consistent_dma_mask(pci, DMA_32BIT_MASK); + } /* read number of streams from GCAP register instead of using * hardcoded value @@ -2468,7 +2480,6 @@ static struct pci_driver driver = { .remove = __devexit_p(azx_remove), #ifdef CONFIG_PM .suspend = azx_suspend, - .resume_early = azx_resume_early, .resume = azx_resume, #endif }; diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 6f2fe0f..44f189c 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -251,6 +251,8 @@ int snd_hda_multi_out_dig_prepare(struct hda_codec *codec, unsigned int stream_tag, unsigned int format, struct snd_pcm_substream *substream); +int snd_hda_multi_out_dig_cleanup(struct hda_codec *codec, + struct hda_multi_out *mout); int snd_hda_multi_out_analog_open(struct hda_codec *codec, struct hda_multi_out *mout, struct snd_pcm_substream *substream, @@ -296,6 +298,9 @@ void snd_print_pcm_bits(int pcm, char *buf, int buflen); int snd_hda_check_board_config(struct hda_codec *codec, int num_configs, const char **modelnames, const struct snd_pci_quirk *pci_list); +int snd_hda_check_board_codec_sid_config(struct hda_codec *codec, + int num_configs, const char **models, + const struct snd_pci_quirk *tbl); int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew); diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 7ca66d6..144b852 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -399,7 +399,8 @@ static void print_conn_list(struct snd_info_buffer *buffer, { int c, curr = -1; - if (conn_len > 1 && wid_type != AC_WID_AUD_MIX) + if (conn_len > 1 && wid_type != AC_WID_AUD_MIX && + wid_type != AC_WID_VOL_KNB) curr = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0); snd_iprintf(buffer, " Connection: %d\n", conn_len); diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 26247cf..e486123 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -275,6 +275,14 @@ static int ad198x_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, format, substream); } +static int ad198x_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct ad198x_spec *spec = codec->spec; + return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout); +} + /* * Analog capture */ @@ -333,7 +341,8 @@ static struct hda_pcm_stream ad198x_pcm_digital_playback = { .ops = { .open = ad198x_dig_playback_pcm_open, .close = ad198x_dig_playback_pcm_close, - .prepare = ad198x_dig_playback_pcm_prepare + .prepare = ad198x_dig_playback_pcm_prepare, + .cleanup = ad198x_dig_playback_pcm_cleanup }, }; @@ -1885,8 +1894,8 @@ static hda_nid_t ad1988_capsrc_nids[3] = { #define AD1988_SPDIF_OUT_HDMI 0x0b #define AD1988_SPDIF_IN 0x07 -static hda_nid_t ad1989b_slave_dig_outs[2] = { - AD1988_SPDIF_OUT, AD1988_SPDIF_OUT_HDMI +static hda_nid_t ad1989b_slave_dig_outs[] = { + AD1988_SPDIF_OUT, AD1988_SPDIF_OUT_HDMI, 0 }; static struct hda_input_mux ad1988_6stack_capture_source = { @@ -3900,6 +3909,7 @@ static const char *ad1884a_models[AD1884A_MODELS] = { static struct snd_pci_quirk ad1884a_cfg_tbl[] = { SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE), + SND_PCI_QUIRK(0x103c, 0x3037, "HP 2230s", AD1884A_LAPTOP), SND_PCI_QUIRK(0x103c, 0x3056, "HP", AD1884A_MOBILE), SND_PCI_QUIRK(0x103c, 0x30e6, "HP 6730b", AD1884A_LAPTOP), SND_PCI_QUIRK(0x103c, 0x30e7, "HP EliteBook 8530p", AD1884A_LAPTOP), @@ -4262,13 +4272,13 @@ static int patch_ad1882(struct hda_codec *codec) spec->num_adc_nids = ARRAY_SIZE(ad1882_adc_nids); spec->adc_nids = ad1882_adc_nids; spec->capsrc_nids = ad1882_capsrc_nids; - if (codec->vendor_id == 0x11d1882) + if (codec->vendor_id == 0x11d41882) spec->input_mux = &ad1882_capture_source; else spec->input_mux = &ad1882a_capture_source; spec->num_mixers = 2; spec->mixers[0] = ad1882_base_mixers; - if (codec->vendor_id == 0x11d1882) + if (codec->vendor_id == 0x11d41882) spec->mixers[1] = ad1882_loopback_mixers; else spec->mixers[1] = ad1882a_loopback_mixers; diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 75de40a..0177ef8 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -347,6 +347,7 @@ static int conexant_mux_enum_put(struct snd_kcontrol *kcontrol, &spec->cur_mux[adc_idx]); } +#ifdef CONFIG_SND_JACK static int conexant_add_jack(struct hda_codec *codec, hda_nid_t nid, int type) { @@ -394,7 +395,6 @@ static void conexant_report_jack(struct hda_codec *codec, hda_nid_t nid) static int conexant_init_jacks(struct hda_codec *codec) { -#ifdef CONFIG_SND_JACK struct conexant_spec *spec = codec->spec; int i; @@ -422,10 +422,19 @@ static int conexant_init_jacks(struct hda_codec *codec) ++hv; } } -#endif return 0; } +#else +static inline void conexant_report_jack(struct hda_codec *codec, hda_nid_t nid) +{ +} + +static inline int conexant_init_jacks(struct hda_codec *codec) +{ + return 0; +} +#endif static int conexant_init(struct hda_codec *codec) { @@ -1566,6 +1575,7 @@ static struct snd_pci_quirk cxt5047_cfg_tbl[] = { SND_PCI_QUIRK(0x103c, 0x30a5, "HP DV5200T/DV8000T", CXT5047_LAPTOP_HP), SND_PCI_QUIRK(0x103c, 0x30b2, "HP DV2000T/DV3000T", CXT5047_LAPTOP), SND_PCI_QUIRK(0x103c, 0x30b5, "HP DV2000Z", CXT5047_LAPTOP), + SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV6700", CXT5047_LAPTOP), SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P100", CXT5047_LAPTOP_EAPD), {} }; diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 3564f4e..fcc77fe 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -49,11 +49,6 @@ static struct hda_verb pinout_enable_verb[] = { {} /* terminator */ }; -static struct hda_verb pinout_disable_verb[] = { - {PIN_NID, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00}, - {} -}; - static struct hda_verb unsolicited_response_verb[] = { {PIN_NID, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | INTEL_HDMI_EVENT_TAG}, @@ -248,10 +243,6 @@ static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t nid, static void hdmi_enable_output(struct hda_codec *codec) { - /* Enable Audio InfoFrame Transmission */ - hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0); - snd_hda_codec_write(codec, PIN_NID, 0, AC_VERB_SET_HDMI_DIP_XMIT, - AC_DIPXMIT_BEST); /* Unmute */ if (get_wcaps(codec, PIN_NID) & AC_WCAP_OUT_AMP) snd_hda_codec_write(codec, PIN_NID, 0, @@ -260,17 +251,24 @@ static void hdmi_enable_output(struct hda_codec *codec) snd_hda_sequence_write(codec, pinout_enable_verb); } -static void hdmi_disable_output(struct hda_codec *codec) +/* + * Enable Audio InfoFrame Transmission + */ +static void hdmi_start_infoframe_trans(struct hda_codec *codec) { - snd_hda_sequence_write(codec, pinout_disable_verb); - if (get_wcaps(codec, PIN_NID) & AC_WCAP_OUT_AMP) - snd_hda_codec_write(codec, PIN_NID, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); + hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0); + snd_hda_codec_write(codec, PIN_NID, 0, AC_VERB_SET_HDMI_DIP_XMIT, + AC_DIPXMIT_BEST); +} - /* - * FIXME: noises may arise when playing music after reloading the - * kernel module, until the next X restart or monitor repower. - */ +/* + * Disable Audio InfoFrame Transmission + */ +static void hdmi_stop_infoframe_trans(struct hda_codec *codec) +{ + hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0); + snd_hda_codec_write(codec, PIN_NID, 0, AC_VERB_SET_HDMI_DIP_XMIT, + AC_DIPXMIT_DISABLE); } static int hdmi_get_channel_count(struct hda_codec *codec) @@ -368,11 +366,16 @@ static void hdmi_fill_audio_infoframe(struct hda_codec *codec, struct hdmi_audio_infoframe *ai) { u8 *params = (u8 *)ai; + u8 sum = 0; int i; hdmi_debug_dip_size(codec); hdmi_clear_dip_buffers(codec); /* be paranoid */ + for (i = 0; i < sizeof(ai); i++) + sum += params[i]; + ai->checksum = - sum; + hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0); for (i = 0; i < sizeof(ai); i++) hdmi_write_dip_byte(codec, PIN_NID, params[i]); @@ -419,14 +422,18 @@ static int hdmi_setup_channel_allocation(struct hda_codec *codec, /* * CA defaults to 0 for basic stereo audio */ - if (!eld->eld_ver) - return 0; - if (!eld->spk_alloc) - return 0; if (channels <= 2) return 0; /* + * HDMI sink's ELD info cannot always be retrieved for now, e.g. + * in console or for audio devices. Assume the highest speakers + * configuration, to _not_ prohibit multi-channel audio playback. + */ + if (!eld->spk_alloc) + eld->spk_alloc = 0xffff; + + /* * expand ELD's speaker allocation mask * * ELD tells the speaker mask in a compact(paired) form, @@ -485,6 +492,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hdmi_setup_channel_mapping(codec, &ai); hdmi_fill_audio_infoframe(codec, &ai); + hdmi_start_infoframe_trans(codec); } @@ -562,7 +570,7 @@ static int intel_hdmi_playback_pcm_close(struct hda_pcm_stream *hinfo, { struct intel_hdmi_spec *spec = codec->spec; - hdmi_disable_output(codec); + hdmi_stop_infoframe_trans(codec); return snd_hda_multi_out_dig_close(codec, &spec->multiout); } @@ -582,8 +590,6 @@ static int intel_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, hdmi_setup_audio_infoframe(codec, substream); - hdmi_enable_output(codec); - return 0; } @@ -628,8 +634,7 @@ static int intel_hdmi_build_controls(struct hda_codec *codec) static int intel_hdmi_init(struct hda_codec *codec) { - /* disable audio output as early as possible */ - hdmi_disable_output(codec); + hdmi_enable_output(codec); snd_hda_sequence_write(codec, unsolicited_response_verb); @@ -679,6 +684,7 @@ static struct hda_codec_preset snd_hda_preset_intelhdmi[] = { { .id = 0x80862801, .name = "G45 DEVBLC", .patch = patch_intel_hdmi }, { .id = 0x80862802, .name = "G45 DEVCTG", .patch = patch_intel_hdmi }, { .id = 0x80862803, .name = "G45 DEVELK", .patch = patch_intel_hdmi }, + { .id = 0x80862804, .name = "G45 DEVIBX", .patch = patch_intel_hdmi }, { .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_intel_hdmi }, {} /* terminator */ }; @@ -687,6 +693,7 @@ MODULE_ALIAS("snd-hda-codec-id:808629fb"); MODULE_ALIAS("snd-hda-codec-id:80862801"); MODULE_ALIAS("snd-hda-codec-id:80862802"); MODULE_ALIAS("snd-hda-codec-id:80862803"); +MODULE_ALIAS("snd-hda-codec-id:80862804"); MODULE_ALIAS("snd-hda-codec-id:10951392"); MODULE_LICENSE("GPL"); diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c index 0270fda..d57d813 100644 --- a/sound/pci/hda/patch_nvhdmi.c +++ b/sound/pci/hda/patch_nvhdmi.c @@ -160,14 +160,18 @@ static int patch_nvhdmi(struct hda_codec *codec) */ static struct hda_codec_preset snd_hda_preset_nvhdmi[] = { { .id = 0x10de0002, .name = "MCP78 HDMI", .patch = patch_nvhdmi }, + { .id = 0x10de0006, .name = "MCP78 HDMI", .patch = patch_nvhdmi }, { .id = 0x10de0007, .name = "MCP7A HDMI", .patch = patch_nvhdmi }, { .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi }, + { .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi }, {} /* terminator */ }; MODULE_ALIAS("snd-hda-codec-id:10de0002"); +MODULE_ALIAS("snd-hda-codec-id:10de0006"); MODULE_ALIAS("snd-hda-codec-id:10de0007"); MODULE_ALIAS("snd-hda-codec-id:10de0067"); +MODULE_ALIAS("snd-hda-codec-id:10de8001"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Nvidia HDMI HD-audio codec"); diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 9065ebf..6c26afc 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -1037,6 +1037,7 @@ do_sku: case 0x10ec0267: case 0x10ec0268: case 0x10ec0269: + case 0x10ec0272: case 0x10ec0660: case 0x10ec0662: case 0x10ec0663: @@ -1065,6 +1066,7 @@ do_sku: case 0x10ec0882: case 0x10ec0883: case 0x10ec0885: + case 0x10ec0887: case 0x10ec0889: snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7); @@ -1502,11 +1504,11 @@ static int alc_cap_vol_info(struct snd_kcontrol *kcontrol, struct alc_spec *spec = codec->spec; int err; - mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ + mutex_lock(&codec->control_mutex); kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0, HDA_INPUT); err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo); - mutex_unlock(&codec->spdif_mutex); /* reuse spdif_mutex */ + mutex_unlock(&codec->control_mutex); return err; } @@ -1517,11 +1519,11 @@ static int alc_cap_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, struct alc_spec *spec = codec->spec; int err; - mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ + mutex_lock(&codec->control_mutex); kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0, HDA_INPUT); err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv); - mutex_unlock(&codec->spdif_mutex); /* reuse spdif_mutex */ + mutex_unlock(&codec->control_mutex); return err; } @@ -1537,11 +1539,11 @@ static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol, unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); int err; - mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ + mutex_lock(&codec->control_mutex); kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[adc_idx], 3, 0, HDA_INPUT); err = func(kcontrol, ucontrol); - mutex_unlock(&codec->spdif_mutex); /* reuse spdif_mutex */ + mutex_unlock(&codec->control_mutex); return err; } @@ -7012,12 +7014,15 @@ static int patch_alc882(struct hda_codec *codec) break; case 0x106b1000: /* iMac 24 */ case 0x106b2800: /* AppleTV */ + case 0x106b3e00: /* iMac 24 Aluminium */ board_config = ALC885_IMAC24; break; + case 0x106b00a0: /* MacBookPro3,1 - Another revision */ case 0x106b00a1: /* Macbook (might be wrong - PCI SSID?) */ case 0x106b00a4: /* MacbookPro4,1 */ case 0x106b2c00: /* Macbook Pro rev3 */ case 0x106b3600: /* Macbook 3.1 */ + case 0x106b3800: /* MacbookPro4,1 - latter revision */ board_config = ALC885_MBP3; break; default: @@ -8461,6 +8466,12 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE), SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G", ALC888_ACER_ASPIRE_4930G), + SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G", + ALC888_ACER_ASPIRE_4930G), + SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G", + ALC888_ACER_ASPIRE_4930G), + SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G", + ALC888_ACER_ASPIRE_4930G), SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), /* default Acer */ SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL), SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG), @@ -8470,10 +8481,12 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { SND_PCI_QUIRK(0x103c, 0x2a66, "HP Acacia", ALC888_3ST_HP), SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V), SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG), + SND_PCI_QUIRK(0x1043, 0x8284, "Asus Z37E", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1043, 0x82fe, "Asus P5Q-EM HDMI", ALC1200_ASUS_P5Q), SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601), SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG), SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x1071, 0x8227, "Mitac 82801H", ALC883_MITAC), SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC), SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD), SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL), @@ -8508,6 +8521,8 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { SND_PCI_QUIRK(0x1558, 0, "Clevo laptop", ALC883_LAPTOP_EAPD), SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch), SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION), + SND_PCI_QUIRK(0x1734, 0x1107, "FSC AMILO Xi2550", + ALC883_FUJITSU_PI2515), SND_PCI_QUIRK(0x1734, 0x1108, "Fujitsu AMILO Pi2515", ALC883_FUJITSU_PI2515), SND_PCI_QUIRK(0x1734, 0x113d, "Fujitsu AMILO Xa3530", ALC888_FUJITSU_XA3530), @@ -8522,6 +8537,8 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66), SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL), SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL), + SND_PCI_QUIRK(0x8086, 0x2503, "82801H", ALC883_MITAC), + SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC883_3ST_6ch_INTEL), SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch), {} }; @@ -10540,6 +10557,7 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = { SND_PCI_QUIRK(0x103c, 0x1309, "HP xw4*00", ALC262_HP_BPC), SND_PCI_QUIRK(0x103c, 0x130a, "HP xw6*00", ALC262_HP_BPC), SND_PCI_QUIRK(0x103c, 0x130b, "HP xw8*00", ALC262_HP_BPC), + SND_PCI_QUIRK(0x103c, 0x170b, "HP xw*", ALC262_HP_BPC), SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL), SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF), SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL), @@ -10568,6 +10586,7 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = { SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU), SND_PCI_QUIRK(0x144d, 0xc032, "Samsung Q1 Ultra", ALC262_ULTRA), SND_PCI_QUIRK(0x144d, 0xc039, "Samsung Q1U EL", ALC262_ULTRA), + SND_PCI_QUIRK(0x144d, 0xc510, "Samsung Q45", ALC262_HIPPO), SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000), SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8), SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31), @@ -11689,6 +11708,7 @@ static struct snd_pci_quirk alc268_cfg_tbl[] = { SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One", ALC268_ACER_ASPIRE_ONE), SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL), + SND_PCI_QUIRK(0x1028, 0x02b0, "Dell Inspiron Mini9", ALC268_DELL), SND_PCI_QUIRK(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA), SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST), SND_PCI_QUIRK(0x1179, 0xff10, "TOSHIBA A205", ALC268_TOSHIBA), diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 35b83dc..6094344 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -55,7 +55,8 @@ enum { STAC_9200_DELL_M25, STAC_9200_DELL_M26, STAC_9200_DELL_M27, - STAC_9200_GATEWAY, + STAC_9200_M4, + STAC_9200_M4_2, STAC_9200_PANASONIC, STAC_9200_MODELS }; @@ -80,6 +81,7 @@ enum { enum { STAC_92HD83XXX_REF, + STAC_92HD83XXX_PWR_REF, STAC_92HD83XXX_MODELS }; @@ -89,14 +91,19 @@ enum { STAC_DELL_M4_2, STAC_DELL_M4_3, STAC_HP_M4, + STAC_HP_DV5, STAC_92HD71BXX_MODELS }; enum { STAC_925x_REF, + STAC_M1, + STAC_M1_2, + STAC_M2, STAC_M2_2, - STAC_MA6, - STAC_PA6, + STAC_M3, + STAC_M5, + STAC_M6, STAC_925x_MODELS }; @@ -328,7 +335,11 @@ static hda_nid_t stac92hd83xxx_slave_dig_outs[2] = { }; static unsigned int stac92hd83xxx_pwr_mapping[4] = { - 0x03, 0x0c, 0x10, 0x40, + 0x03, 0x0c, 0x20, 0x40, +}; + +static hda_nid_t stac92hd83xxx_amp_nids[1] = { + 0xc, }; static hda_nid_t stac92hd71bxx_pwr_nids[3] = { @@ -831,10 +842,6 @@ static struct hda_verb stac92hd73xx_10ch_core_init[] = { }; static struct hda_verb stac92hd83xxx_core_init[] = { - /* start of config #1 */ - { 0xe, AC_VERB_SET_CONNECT_SEL, 0x3}, - - /* start of config #2 */ { 0xa, AC_VERB_SET_CONNECT_SEL, 0x0}, { 0xb, AC_VERB_SET_CONNECT_SEL, 0x0}, { 0xd, AC_VERB_SET_CONNECT_SEL, 0x1}, @@ -875,6 +882,8 @@ static struct hda_verb stac92hd71bxx_analog_core_init[] = { static struct hda_verb stac925x_core_init[] = { /* set dac0mux for dac converter */ { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* mute the master volume */ + { 0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, {} }; @@ -1126,6 +1135,8 @@ static struct snd_kcontrol_new stac92hd71bxx_mixer[] = { }; static struct snd_kcontrol_new stac925x_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x0e, 0, HDA_OUTPUT), + HDA_CODEC_MUTE("Master Playback Switch", 0x0e, 0, HDA_OUTPUT), STAC_INPUT_SOURCE(1), HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x14, 0, HDA_OUTPUT), @@ -1196,7 +1207,7 @@ static const char *slave_vols[] = { "LFE Playback Volume", "Side Playback Volume", "Headphone Playback Volume", - "Headphone Playback Volume", + "Headphone2 Playback Volume", "Speaker Playback Volume", "External Speaker Playback Volume", "Speaker2 Playback Volume", @@ -1210,7 +1221,7 @@ static const char *slave_sws[] = { "LFE Playback Switch", "Side Playback Switch", "Headphone Playback Switch", - "Headphone Playback Switch", + "Headphone2 Playback Switch", "Speaker Playback Switch", "External Speaker Playback Switch", "Speaker2 Playback Switch", @@ -1334,7 +1345,16 @@ static unsigned int ref9200_pin_configs[8] = { 0x02a19020, 0x01a19021, 0x90100140, 0x01813122, }; -/* +static unsigned int gateway9200_m4_pin_configs[8] = { + 0x400000fe, 0x404500f4, 0x400100f0, 0x90110010, + 0x400100f1, 0x02a1902e, 0x500000f2, 0x500000f3, +}; +static unsigned int gateway9200_m4_2_pin_configs[8] = { + 0x400000fe, 0x404500f4, 0x400100f0, 0x90110010, + 0x400100f1, 0x02a1902e, 0x500000f2, 0x500000f3, +}; + +/* STAC 9200 pin configs for 102801A8 102801DE @@ -1464,6 +1484,8 @@ static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = { [STAC_9200_DELL_M25] = dell9200_m25_pin_configs, [STAC_9200_DELL_M26] = dell9200_m26_pin_configs, [STAC_9200_DELL_M27] = dell9200_m27_pin_configs, + [STAC_9200_M4] = gateway9200_m4_pin_configs, + [STAC_9200_M4_2] = gateway9200_m4_2_pin_configs, [STAC_9200_PANASONIC] = ref9200_pin_configs, }; @@ -1480,7 +1502,8 @@ static const char *stac9200_models[STAC_9200_MODELS] = { [STAC_9200_DELL_M25] = "dell-m25", [STAC_9200_DELL_M26] = "dell-m26", [STAC_9200_DELL_M27] = "dell-m27", - [STAC_9200_GATEWAY] = "gateway", + [STAC_9200_M4] = "gateway-m4", + [STAC_9200_M4_2] = "gateway-m4-2", [STAC_9200_PANASONIC] = "panasonic", }; @@ -1550,11 +1573,9 @@ static struct snd_pci_quirk stac9200_cfg_tbl[] = { /* Panasonic */ SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_9200_PANASONIC), /* Gateway machines needs EAPD to be set on resume */ - SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_GATEWAY), - SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*", - STAC_9200_GATEWAY), - SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707", - STAC_9200_GATEWAY), + SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_M4), + SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*", STAC_9200_M4_2), + SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707", STAC_9200_M4_2), /* OQO Mobile */ SND_PCI_QUIRK(0x1106, 0x3288, "OQO Model 2", STAC_9200_OQO), {} /* terminator */ @@ -1565,44 +1586,85 @@ static unsigned int ref925x_pin_configs[8] = { 0x90a70320, 0x02214210, 0x01019020, 0x9033032e, }; -static unsigned int stac925x_MA6_pin_configs[8] = { - 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021, - 0x90a70320, 0x90100211, 0x400003f1, 0x9033032e, +static unsigned int stac925xM1_pin_configs[8] = { + 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, + 0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e, }; -static unsigned int stac925x_PA6_pin_configs[8] = { - 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021, - 0x50a103f0, 0x90100211, 0x400003f1, 0x9033032e, +static unsigned int stac925xM1_2_pin_configs[8] = { + 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, + 0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e, +}; + +static unsigned int stac925xM2_pin_configs[8] = { + 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, + 0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e, }; static unsigned int stac925xM2_2_pin_configs[8] = { - 0x40c003f3, 0x424503f2, 0x04180011, 0x02a19020, - 0x50a103f0, 0x90100212, 0x400003f1, 0x9033032e, + 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, + 0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e, +}; + +static unsigned int stac925xM3_pin_configs[8] = { + 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, + 0x40a000f0, 0x90100210, 0x400003f1, 0x503303f3, +}; + +static unsigned int stac925xM5_pin_configs[8] = { + 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, + 0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e, +}; + +static unsigned int stac925xM6_pin_configs[8] = { + 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, + 0x40a000f0, 0x90100210, 0x400003f1, 0x90330320, }; static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = { [STAC_REF] = ref925x_pin_configs, + [STAC_M1] = stac925xM1_pin_configs, + [STAC_M1_2] = stac925xM1_2_pin_configs, + [STAC_M2] = stac925xM2_pin_configs, [STAC_M2_2] = stac925xM2_2_pin_configs, - [STAC_MA6] = stac925x_MA6_pin_configs, - [STAC_PA6] = stac925x_PA6_pin_configs, + [STAC_M3] = stac925xM3_pin_configs, + [STAC_M5] = stac925xM5_pin_configs, + [STAC_M6] = stac925xM6_pin_configs, }; static const char *stac925x_models[STAC_925x_MODELS] = { [STAC_REF] = "ref", + [STAC_M1] = "m1", + [STAC_M1_2] = "m1-2", + [STAC_M2] = "m2", [STAC_M2_2] = "m2-2", - [STAC_MA6] = "m6", - [STAC_PA6] = "pa6", + [STAC_M3] = "m3", + [STAC_M5] = "m5", + [STAC_M6] = "m6", +}; + +static struct snd_pci_quirk stac925x_codec_id_cfg_tbl[] = { + SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_M2), + SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_M5), + SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_M1), + SND_PCI_QUIRK(0x107b, 0x0681, "Gateway NX860", STAC_M2), + SND_PCI_QUIRK(0x107b, 0x0367, "Gateway MX6453", STAC_M1_2), + /* Not sure about the brand name for those */ + SND_PCI_QUIRK(0x107b, 0x0281, "Gateway mobile", STAC_M1), + SND_PCI_QUIRK(0x107b, 0x0507, "Gateway mobile", STAC_M3), + SND_PCI_QUIRK(0x107b, 0x0281, "Gateway mobile", STAC_M6), + SND_PCI_QUIRK(0x107b, 0x0685, "Gateway mobile", STAC_M2_2), + {} /* terminator */ }; static struct snd_pci_quirk stac925x_cfg_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF), SND_PCI_QUIRK(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF), - SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_REF), - SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_REF), - SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_MA6), - SND_PCI_QUIRK(0x107b, 0x0681, "Gateway NX860", STAC_PA6), - SND_PCI_QUIRK(0x1002, 0x437b, "Gateway MX6453", STAC_M2_2), + + /* Default table for unknown ID */ + SND_PCI_QUIRK(0x1002, 0x437b, "Gateway mobile", STAC_M2_2), + {} /* terminator */ }; @@ -1673,16 +1735,18 @@ static unsigned int ref92hd83xxx_pin_configs[14] = { static unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = { [STAC_92HD83XXX_REF] = ref92hd83xxx_pin_configs, + [STAC_92HD83XXX_PWR_REF] = ref92hd83xxx_pin_configs, }; static const char *stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = { [STAC_92HD83XXX_REF] = "ref", + [STAC_92HD83XXX_PWR_REF] = "mic-ref", }; static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, - "DFI LanParty", STAC_92HD71BXX_REF), + "DFI LanParty", STAC_92HD83XXX_REF), {} /* terminator */ }; @@ -1716,6 +1780,7 @@ static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = { [STAC_DELL_M4_2] = dell_m4_2_pin_configs, [STAC_DELL_M4_3] = dell_m4_3_pin_configs, [STAC_HP_M4] = NULL, + [STAC_HP_DV5] = NULL, }; static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = { @@ -1724,6 +1789,7 @@ static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = { [STAC_DELL_M4_2] = "dell-m4-2", [STAC_DELL_M4_3] = "dell-m4-3", [STAC_HP_M4] = "hp-m4", + [STAC_HP_DV5] = "hp-dv5", }; static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = { @@ -1733,9 +1799,15 @@ static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = { SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f2, "HP dv5", STAC_HP_M4), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f4, - "HP dv7", STAC_HP_M4), + "HP dv7", STAC_HP_DV5), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f7, + "HP dv4", STAC_HP_DV5), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30fc, "HP dv7", STAC_HP_M4), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3600, + "HP dv5", STAC_HP_DV5), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3603, + "HP dv5", STAC_HP_DV5), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361a, "unknown HP", STAC_HP_M4), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233, @@ -2370,6 +2442,14 @@ static int stac92xx_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, stream_tag, format, substream); } +static int stac92xx_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct sigmatel_spec *spec = codec->spec; + return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout); +} + /* * Analog capture callbacks @@ -2414,7 +2494,8 @@ static struct hda_pcm_stream stac92xx_pcm_digital_playback = { .ops = { .open = stac92xx_dig_playback_pcm_open, .close = stac92xx_dig_playback_pcm_close, - .prepare = stac92xx_dig_playback_pcm_prepare + .prepare = stac92xx_dig_playback_pcm_prepare, + .cleanup = stac92xx_dig_playback_pcm_cleanup }, }; @@ -2469,6 +2550,8 @@ static int stac92xx_build_pcms(struct hda_codec *codec) info->name = "STAC92xx Analog"; info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = + spec->multiout.dac_nids[0]; info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture; info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adcs; @@ -3433,6 +3516,7 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out if (! spec->autocfg.line_outs) return 0; /* can't find valid pin config */ +#if 0 /* FIXME: temporarily disabled */ /* If we have no real line-out pin and multiple hp-outs, HPs should * be set up as multi-channel outputs. */ @@ -3452,6 +3536,7 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out spec->autocfg.line_out_type = AUTO_PIN_HP_OUT; spec->autocfg.hp_outs = 0; } +#endif /* FIXME: temporarily disabled */ if (spec->autocfg.mono_out_pin) { int dir = get_wcaps(codec, spec->autocfg.mono_out_pin) & (AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP); @@ -3506,13 +3591,12 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out err = stac92xx_auto_fill_dac_nids(codec); if (err < 0) return err; + err = stac92xx_auto_create_multi_out_ctls(codec, + &spec->autocfg); + if (err < 0) + return err; } - err = stac92xx_auto_create_multi_out_ctls(codec, &spec->autocfg); - - if (err < 0) - return err; - /* setup analog beep controls */ if (spec->anabeep_nid > 0) { err = stac92xx_auto_create_beep_ctls(codec, @@ -4163,8 +4247,19 @@ static void stac92xx_hp_detect(struct hda_codec *codec) continue; if (presence) stac92xx_set_pinctl(codec, cfg->hp_pins[i], val); +#if 0 /* FIXME */ +/* Resetting the pinctl like below may lead to (a sort of) regressions + * on some devices since they use the HP pin actually for line/speaker + * outs although the default pin config shows a different pin (that is + * wrong and useless). + * + * So, it's basically a problem of default pin configs, likely a BIOS issue. + * But, disabling the code below just works around it, and I'm too tired of + * bug reports with such devices... + */ else stac92xx_reset_pinctl(codec, cfg->hp_pins[i], val); +#endif /* FIXME */ } } @@ -4390,7 +4485,8 @@ static int patch_stac9200(struct hda_codec *codec) spec->num_adcs = 1; spec->num_pwrs = 0; - if (spec->board_config == STAC_9200_GATEWAY || + if (spec->board_config == STAC_9200_M4 || + spec->board_config == STAC_9200_M4_2 || spec->board_config == STAC_9200_OQO) spec->init = stac9200_eapd_init; else @@ -4408,6 +4504,12 @@ static int patch_stac9200(struct hda_codec *codec) return err; } + /* CF-74 has no headphone detection, and the driver should *NOT* + * do detection and HP/speaker toggle because the hardware does it. + */ + if (spec->board_config == STAC_9200_PANASONIC) + spec->hp_detect = 0; + codec->patch_ops = stac92xx_patch_ops; return 0; @@ -4425,12 +4527,22 @@ static int patch_stac925x(struct hda_codec *codec) codec->spec = spec; spec->num_pins = ARRAY_SIZE(stac925x_pin_nids); spec->pin_nids = stac925x_pin_nids; - spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS, + + /* Check first for codec ID */ + spec->board_config = snd_hda_check_board_codec_sid_config(codec, + STAC_925x_MODELS, + stac925x_models, + stac925x_codec_id_cfg_tbl); + + /* Now checks for PCI ID, if codec ID is not found */ + if (spec->board_config < 0) + spec->board_config = snd_hda_check_board_config(codec, + STAC_925x_MODELS, stac925x_models, stac925x_cfg_tbl); again: if (spec->board_config < 0) { - snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x," + snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x," "using BIOS defaults\n"); err = stac92xx_save_bios_config_regs(codec); } else @@ -4658,7 +4770,9 @@ static struct hda_input_mux stac92hd83xxx_dmux = { static int patch_stac92hd83xxx(struct hda_codec *codec) { struct sigmatel_spec *spec; + hda_nid_t conn[STAC92HD83_DAC_COUNT + 1]; int err; + int num_dacs; spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) @@ -4672,23 +4786,26 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) spec->dmux_nids = stac92hd83xxx_dmux_nids; spec->adc_nids = stac92hd83xxx_adc_nids; spec->pwr_nids = stac92hd83xxx_pwr_nids; + spec->amp_nids = stac92hd83xxx_amp_nids; spec->pwr_mapping = stac92hd83xxx_pwr_mapping; spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids); spec->multiout.dac_nids = spec->dac_nids; - spec->init = stac92hd83xxx_core_init; - switch (codec->vendor_id) { - case 0x111d7605: - break; - default: - spec->num_pwrs--; - spec->init++; /* switch to config #2 */ - } + /* set port 0xe to select the last DAC + */ + num_dacs = snd_hda_get_connections(codec, 0x0e, + conn, STAC92HD83_DAC_COUNT + 1) - 1; + + snd_hda_codec_write_cache(codec, 0xe, 0, + AC_VERB_SET_CONNECT_SEL, num_dacs); + + spec->init = stac92hd83xxx_core_init; spec->mixer = stac92hd83xxx_mixer; spec->num_pins = ARRAY_SIZE(stac92hd83xxx_pin_nids); spec->num_dmuxes = ARRAY_SIZE(stac92hd83xxx_dmux_nids); spec->num_adcs = ARRAY_SIZE(stac92hd83xxx_adc_nids); + spec->num_amps = ARRAY_SIZE(stac92hd83xxx_amp_nids); spec->num_dmics = STAC92HD83XXX_NUM_DMICS; spec->dinput_mux = &stac92hd83xxx_dmux; spec->pin_nids = stac92hd83xxx_pin_nids; @@ -4709,6 +4826,15 @@ again: return err; } + switch (codec->vendor_id) { + case 0x111d7604: + case 0x111d7605: + if (spec->board_config == STAC_92HD83XXX_PWR_REF) + break; + spec->num_pwrs = 0; + break; + } + err = stac92xx_parse_auto_config(codec, 0x1d, 0); if (!err) { if (spec->board_config < 0) { @@ -4865,7 +4991,7 @@ again: case STAC_DELL_M4_3: spec->num_dmics = 1; spec->num_smuxes = 0; - spec->num_dmuxes = 0; + spec->num_dmuxes = 1; break; default: spec->num_dmics = STAC92HD71BXX_NUM_DMICS; diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 671ff65..608655e 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -617,7 +617,7 @@ static int snd_intel8x0_ali_codec_semaphore(struct intel8x0 *chip) int time = 100; if (chip->buggy_semaphore) return 0; /* just ignore ... */ - while (time-- && (igetdword(chip, ICHREG(ALI_CAS)) & ALI_CAS_SEM_BUSY)) + while (--time && (igetdword(chip, ICHREG(ALI_CAS)) & ALI_CAS_SEM_BUSY)) udelay(1); if (! time && ! chip->in_ac97_init) snd_printk(KERN_WARNING "ali_codec_semaphore timeout\n"); diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c index bfc19e3..c1eb84a 100644 --- a/sound/pci/mixart/mixart.c +++ b/sound/pci/mixart/mixart.c @@ -607,6 +607,7 @@ static int snd_mixart_hw_params(struct snd_pcm_substream *subs, /* set the format to the board */ err = mixart_set_format(stream, format); if(err < 0) { + mutex_unlock(&mgr->setup_mutex); return err; } diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c index 98c6a8c..6c870c1 100644 --- a/sound/pci/oxygen/virtuoso.c +++ b/sound/pci/oxygen/virtuoso.c @@ -676,7 +676,7 @@ static void xonar_hdav_uart_input(struct oxygen *chip) if (chip->uart_input_count >= 2 && chip->uart_input[chip->uart_input_count - 2] == 'O' && chip->uart_input[chip->uart_input_count - 1] == 'K') { - printk(KERN_DEBUG "message from Xonar HDAV HDMI chip received:"); + printk(KERN_DEBUG "message from Xonar HDAV HDMI chip received:\n"); print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, chip->uart_input, chip->uart_input_count); chip->uart_input_count = 0; @@ -899,6 +899,7 @@ static const struct oxygen_model model_xonar_hdav = { .dac_channels = 8, .dac_volume_min = 0x0f, .dac_volume_max = 0xff, + .misc_flags = OXYGEN_MISC_MIDI, .function_flags = OXYGEN_FUNCTION_2WIRE, .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, diff --git a/sound/pci/pcxhr/pcxhr.h b/sound/pci/pcxhr/pcxhr.h index 84131a9..69d87de 100644 --- a/sound/pci/pcxhr/pcxhr.h +++ b/sound/pci/pcxhr/pcxhr.h @@ -97,12 +97,12 @@ struct pcxhr_mgr { int capture_chips; int fw_file_set; int firmware_num; - int is_hr_stereo:1; - int board_has_aes1:1; /* if 1 board has AES1 plug and SRC */ - int board_has_analog:1; /* if 0 the board is digital only */ - int board_has_mic:1; /* if 1 the board has microphone input */ - int board_aes_in_192k:1;/* if 1 the aes input plugs do support 192kHz */ - int mono_capture:1; /* if 1 the board does mono capture */ + unsigned int is_hr_stereo:1; + unsigned int board_has_aes1:1; /* if 1 board has AES1 plug and SRC */ + unsigned int board_has_analog:1; /* if 0 the board is digital only */ + unsigned int board_has_mic:1; /* if 1 the board has microphone input */ + unsigned int board_aes_in_192k:1;/* if 1 the aes input plugs do support 192kHz */ + unsigned int mono_capture:1; /* if 1 the board does mono capture */ struct snd_dma_buffer hostport; diff --git a/sound/ppc/snd_ps3.c b/sound/ppc/snd_ps3.c index ef2c3f4..f361c26 100644 --- a/sound/ppc/snd_ps3.c +++ b/sound/ppc/snd_ps3.c @@ -477,7 +477,7 @@ static int snd_ps3_pcm_prepare(struct snd_pcm_substream *substream) card->dma_start_bus_addr[SND_PS3_CH_R] = runtime->dma_addr + (runtime->dma_bytes / 2); - pr_debug("%s: vaddr=%p bus=%#lx\n", __func__, + pr_debug("%s: vaddr=%p bus=%#llx\n", __func__, card->dma_start_vaddr[SND_PS3_CH_L], card->dma_start_bus_addr[SND_PS3_CH_L]); @@ -1028,7 +1028,7 @@ static int __init snd_ps3_driver_probe(struct ps3_system_bus_device *dev) pr_info("%s: nullbuffer alloc failed\n", __func__); goto clean_preallocate; } - pr_debug("%s: null vaddr=%p dma=%#lx\n", __func__, + pr_debug("%s: null vaddr=%p dma=%#llx\n", __func__, the_card.null_buffer_start_vaddr, the_card.null_buffer_start_dma_addr); /* set default sample rate/word width */ diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c index 1fac5ef..3dcdc4e 100644 --- a/sound/soc/atmel/atmel-pcm.c +++ b/sound/soc/atmel/atmel-pcm.c @@ -44,8 +44,6 @@ #include <sound/pcm_params.h> #include <sound/soc.h> -#include <mach/hardware.h> - #include "atmel-pcm.h" diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index c5d6790..ff0054b 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -10,7 +10,7 @@ * Based on at91-ssc.c by * Frank Mandarino <fmandarino@endrelia.com> * Based on pxa2xx Platform drivers by - * Liam Girdwood <liam.girdwood@wolfsonmicro.com> + * Liam Girdwood <lrg@slimlogic.co.uk> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sound/soc/atmel/atmel_ssc_dai.h b/sound/soc/atmel/atmel_ssc_dai.h index a828746..391135f 100644 --- a/sound/soc/atmel/atmel_ssc_dai.h +++ b/sound/soc/atmel/atmel_ssc_dai.h @@ -10,7 +10,7 @@ * Based on at91-ssc.c by * Frank Mandarino <fmandarino@endrelia.com> * Based on pxa2xx Platform drivers by - * Liam Girdwood <liam.girdwood@wolfsonmicro.com> + * Liam Girdwood <lrg@slimlogic.co.uk> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index b47a749..aea0cb7 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -165,10 +165,13 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); - int reg = kcontrol->private_value & 0xff; - int shift = (kcontrol->private_value >> 8) & 0x0f; - int mask = (kcontrol->private_value >> 16) & 0xff; - int invert = (kcontrol->private_value >> 24) & 0x01; + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + unsigned int reg = mc->reg; + unsigned int shift = mc->shift; + int max = mc->max; + unsigned int mask = (1 << fls(max)) - 1; + unsigned int invert = mc->invert; unsigned short val, val_mask; int ret; struct snd_soc_dapm_path *path; diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index fd0f338..ea370a4 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -197,7 +197,7 @@ static const char *twl4030_earpiece_texts[] = static const unsigned int twl4030_earpiece_values[] = {0x0, 0x1, 0x2, 0x4}; -static const struct soc_value_enum twl4030_earpiece_enum = +static const struct soc_enum twl4030_earpiece_enum = SOC_VALUE_ENUM_SINGLE(TWL4030_REG_EAR_CTL, 1, 0x7, ARRAY_SIZE(twl4030_earpiece_texts), twl4030_earpiece_texts, @@ -213,7 +213,7 @@ static const char *twl4030_predrivel_texts[] = static const unsigned int twl4030_predrivel_values[] = {0x0, 0x1, 0x2, 0x4}; -static const struct soc_value_enum twl4030_predrivel_enum = +static const struct soc_enum twl4030_predrivel_enum = SOC_VALUE_ENUM_SINGLE(TWL4030_REG_PREDL_CTL, 1, 0x7, ARRAY_SIZE(twl4030_predrivel_texts), twl4030_predrivel_texts, @@ -229,7 +229,7 @@ static const char *twl4030_predriver_texts[] = static const unsigned int twl4030_predriver_values[] = {0x0, 0x1, 0x2, 0x4}; -static const struct soc_value_enum twl4030_predriver_enum = +static const struct soc_enum twl4030_predriver_enum = SOC_VALUE_ENUM_SINGLE(TWL4030_REG_PREDR_CTL, 1, 0x7, ARRAY_SIZE(twl4030_predriver_texts), twl4030_predriver_texts, @@ -317,7 +317,7 @@ static const char *twl4030_analoglmic_texts[] = static const unsigned int twl4030_analoglmic_values[] = {0x0, 0x1, 0x2, 0x4, 0x8}; -static const struct soc_value_enum twl4030_analoglmic_enum = +static const struct soc_enum twl4030_analoglmic_enum = SOC_VALUE_ENUM_SINGLE(TWL4030_REG_ANAMICL, 0, 0xf, ARRAY_SIZE(twl4030_analoglmic_texts), twl4030_analoglmic_texts, @@ -333,7 +333,7 @@ static const char *twl4030_analogrmic_texts[] = static const unsigned int twl4030_analogrmic_values[] = {0x0, 0x1, 0x4}; -static const struct soc_value_enum twl4030_analogrmic_enum = +static const struct soc_enum twl4030_analogrmic_enum = SOC_VALUE_ENUM_SINGLE(TWL4030_REG_ANAMICR, 0, 0x5, ARRAY_SIZE(twl4030_analogrmic_texts), twl4030_analogrmic_texts, @@ -1280,6 +1280,8 @@ static int twl4030_remove(struct platform_device *pdev) struct snd_soc_codec *codec = socdev->codec; printk(KERN_INFO "TWL4030 Audio Codec remove\n"); + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); kfree(codec); return 0; diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index e3989d4..35d9975 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -3,7 +3,7 @@ * * Copyright (C) 2007, 2008 Wolfson Microelectronics PLC. * - * Author: Liam Girdwood <lg@opensource.wolfsonmicro.com> + * Author: Liam Girdwood <lrg@slimlogic.co.uk> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index 6c21b50..77620ab 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -1451,7 +1451,14 @@ static const struct snd_soc_dai wm8753_all_dai[] = { }, }; -struct snd_soc_dai wm8753_dai[2]; +struct snd_soc_dai wm8753_dai[] = { + { + .name = "WM8753 DAI 0", + }, + { + .name = "WM8753 DAI 1", + }, +}; EXPORT_SYMBOL_GPL(wm8753_dai); static void wm8753_set_dai_mode(struct snd_soc_codec *codec, unsigned int mode) diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 5b5afc1..a5731fa 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -2,8 +2,7 @@ * wm8990.c -- WM8990 ALSA Soc Audio driver * * Copyright 2008 Wolfson Microelectronics PLC. - * Author: Liam Girdwood - * lg@opensource.wolfsonmicro.com or linux@wolfsonmicro.com + * Author: Liam Girdwood <lrg@slimlogic.co.uk> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -177,7 +176,9 @@ static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - int reg = kcontrol->private_value & 0xff; + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int reg = mc->reg; int ret; u16 val; diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c index bcec3f6..acf39a6 100644 --- a/sound/soc/fsl/mpc8610_hpcd.c +++ b/sound/soc/fsl/mpc8610_hpcd.c @@ -183,16 +183,6 @@ static struct snd_soc_ops mpc8610_hpcd_ops = { }; /** - * mpc8610_hpcd_machine: ASoC machine data - */ -static struct snd_soc_card mpc8610_hpcd_machine = { - .probe = mpc8610_hpcd_machine_probe, - .remove = mpc8610_hpcd_machine_remove, - .name = "MPC8610 HPCD", - .num_links = 1, -}; - -/** * mpc8610_hpcd_probe: OF probe function for the fabric driver * * This function gets called when an SSI node is found in the device tree. @@ -455,7 +445,11 @@ static int mpc8610_hpcd_probe(struct of_device *ofdev, machine_data->dai.codec_dai = &cs4270_dai; /* The codec_dai we want */ machine_data->dai.ops = &mpc8610_hpcd_ops; - mpc8610_hpcd_machine.dai_link = &machine_data->dai; + machine_data->machine.probe = mpc8610_hpcd_machine_probe; + machine_data->machine.remove = mpc8610_hpcd_machine_remove; + machine_data->machine.name = "MPC8610 HPCD"; + machine_data->machine.num_links = 1; + machine_data->machine.dai_link = &machine_data->dai; /* Allocate a new audio platform device structure */ sound_device = platform_device_alloc("soc-audio", -1); @@ -465,7 +459,7 @@ static int mpc8610_hpcd_probe(struct of_device *ofdev, goto error; } - machine_data->sound_devdata.card = &mpc8610_hpcd_machine; + machine_data->sound_devdata.card = &machine_data->machine; machine_data->sound_devdata.codec_dev = &soc_codec_device_cs4270; machine_data->machine.platform = &fsl_soc_platform; diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index ec5e18a..05dd5ab 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -302,6 +302,10 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai, regs->spcr1 |= RINTM(3); regs->rcr2 |= RFIG; regs->xcr2 |= XFIG; + if (cpu_is_omap2430() || cpu_is_omap34xx()) { + regs->xccr = DXENDLY(1) | XDMAEN; + regs->rccr = RFULL_CYCLE | RDMAEN; + } switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index b0362df..dd3bb29 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c @@ -175,9 +175,10 @@ static int omap_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_pcm_runtime *runtime = substream->runtime; struct omap_runtime_data *prtd = runtime->private_data; + unsigned long flags; int ret = 0; - spin_lock_irq(&prtd->lock); + spin_lock_irqsave(&prtd->lock, flags); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: @@ -195,7 +196,7 @@ static int omap_pcm_trigger(struct snd_pcm_substream *substream, int cmd) default: ret = -EINVAL; } - spin_unlock_irq(&prtd->lock); + spin_unlock_irqrestore(&prtd->lock, flags); return ret; } diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c index ad97836..e226fa7 100644 --- a/sound/soc/omap/sdp3430.c +++ b/sound/soc/omap/sdp3430.c @@ -91,7 +91,7 @@ static struct snd_soc_dai_link sdp3430_dai = { }; /* Audio machine driver */ -static struct snd_soc_machine snd_soc_machine_sdp3430 = { +static struct snd_soc_card snd_soc_sdp3430 = { .name = "SDP3430", .platform = &omap_soc_platform, .dai_link = &sdp3430_dai, @@ -100,7 +100,7 @@ static struct snd_soc_machine snd_soc_machine_sdp3430 = { /* Audio subsystem */ static struct snd_soc_device sdp3430_snd_devdata = { - .machine = &snd_soc_machine_sdp3430, + .card = &snd_soc_sdp3430, .codec_dev = &soc_codec_dev_twl4030, }; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 318dfdd..637f0d1 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1385,7 +1385,10 @@ int snd_soc_init_card(struct snd_soc_device *socdev) mutex_lock(&codec->mutex); #ifdef CONFIG_SND_SOC_AC97_BUS - if (ac97) { + /* Only instantiate AC97 if not already done by the adaptor + * for the generic AC97 subsystem. + */ + if (ac97 && strcmp(codec->name, "AC97") != 0) { ret = soc_ac97_dev_register(codec); if (ret < 0) { printk(KERN_ERR "asoc: AC97 device register failed\n"); @@ -1585,37 +1588,6 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, EXPORT_SYMBOL_GPL(snd_soc_put_enum_double); /** - * snd_soc_info_value_enum_double - semi enumerated double mixer info callback - * @kcontrol: mixer control - * @uinfo: control element information - * - * Callback to provide information about a double semi enumerated - * mixer control. - * - * Semi enumerated mixer: the enumerated items are referred as values. Can be - * used for handling bitfield coded enumeration for example. - * - * Returns 0 for success. - */ -int snd_soc_info_value_enum_double(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct soc_value_enum *e = (struct soc_value_enum *) - kcontrol->private_value; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = e->shift_l == e->shift_r ? 1 : 2; - uinfo->value.enumerated.items = e->max; - - if (uinfo->value.enumerated.item > e->max - 1) - uinfo->value.enumerated.item = e->max - 1; - strcpy(uinfo->value.enumerated.name, - e->texts[uinfo->value.enumerated.item]); - return 0; -} -EXPORT_SYMBOL_GPL(snd_soc_info_value_enum_double); - -/** * snd_soc_get_value_enum_double - semi enumerated double mixer get callback * @kcontrol: mixer control * @ucontrol: control element information @@ -1631,8 +1603,7 @@ int snd_soc_get_value_enum_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct soc_value_enum *e = (struct soc_value_enum *) - kcontrol->private_value; + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; unsigned short reg_val, val, mux; reg_val = snd_soc_read(codec, e->reg); @@ -1671,8 +1642,7 @@ int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct soc_value_enum *e = (struct soc_value_enum *) - kcontrol->private_value; + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; unsigned short val; unsigned short mask; diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index ad0d801..a2f1da8 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -137,7 +137,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, } break; case snd_soc_dapm_value_mux: { - struct soc_value_enum *e = (struct soc_value_enum *) + struct soc_enum *e = (struct soc_enum *) w->kcontrols[i].private_value; int val, item; @@ -200,30 +200,6 @@ static int dapm_connect_mux(struct snd_soc_codec *codec, return -ENODEV; } -/* connect value_mux widget to it's interconnecting audio paths */ -static int dapm_connect_value_mux(struct snd_soc_codec *codec, - struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, - struct snd_soc_dapm_path *path, const char *control_name, - const struct snd_kcontrol_new *kcontrol) -{ - struct soc_value_enum *e = (struct soc_value_enum *) - kcontrol->private_value; - int i; - - for (i = 0; i < e->max; i++) { - if (!(strcmp(control_name, e->texts[i]))) { - list_add(&path->list, &codec->dapm_paths); - list_add(&path->list_sink, &dest->sources); - list_add(&path->list_source, &src->sinks); - path->name = (char *)e->texts[i]; - dapm_set_path_status(dest, path, 0); - return 0; - } - } - - return -ENODEV; -} - /* connect mixer widget to it's interconnecting audio paths */ static int dapm_connect_mixer(struct snd_soc_codec *codec, struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, @@ -744,7 +720,8 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, struct snd_soc_dapm_path *path; int found = 0; - if (widget->id != snd_soc_dapm_mux) + if (widget->id != snd_soc_dapm_mux && + widget->id != snd_soc_dapm_value_mux) return -ENODEV; if (!snd_soc_test_bits(widget->codec, e->reg, mask, val)) @@ -774,45 +751,6 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, return 0; } -/* test and update the power status of a value_mux widget */ -static int dapm_value_mux_update_power(struct snd_soc_dapm_widget *widget, - struct snd_kcontrol *kcontrol, int mask, - int mux, int val, struct soc_value_enum *e) -{ - struct snd_soc_dapm_path *path; - int found = 0; - - if (widget->id != snd_soc_dapm_value_mux) - return -ENODEV; - - if (!snd_soc_test_bits(widget->codec, e->reg, mask, val)) - return 0; - - /* find dapm widget path assoc with kcontrol */ - list_for_each_entry(path, &widget->codec->dapm_paths, list) { - if (path->kcontrol != kcontrol) - continue; - - if (!path->name || !e->texts[mux]) - continue; - - found = 1; - /* we now need to match the string in the enum to the path */ - if (!(strcmp(path->name, e->texts[mux]))) - path->connect = 1; /* new connection */ - else - path->connect = 0; /* old connection must be - powered down */ - } - - if (found) { - dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP); - dump_dapm(widget->codec, "mux power update"); - } - - return 0; -} - /* test and update the power status of a mixer or switch widget */ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, struct snd_kcontrol *kcontrol, int reg, @@ -1045,17 +983,12 @@ static int snd_soc_dapm_add_route(struct snd_soc_codec *codec, path->connect = 1; return 0; case snd_soc_dapm_mux: + case snd_soc_dapm_value_mux: ret = dapm_connect_mux(codec, wsource, wsink, path, control, &wsink->kcontrols[0]); if (ret != 0) goto err; break; - case snd_soc_dapm_value_mux: - ret = dapm_connect_value_mux(codec, wsource, wsink, path, - control, &wsink->kcontrols[0]); - if (ret != 0) - goto err; - break; case snd_soc_dapm_switch: case snd_soc_dapm_mixer: ret = dapm_connect_mixer(codec, wsource, wsink, path, control); @@ -1382,8 +1315,7 @@ int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); - struct soc_value_enum *e = (struct soc_value_enum *) - kcontrol->private_value; + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; unsigned short reg_val, val, mux; reg_val = snd_soc_read(widget->codec, e->reg); @@ -1423,8 +1355,7 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); - struct soc_value_enum *e = (struct soc_value_enum *) - kcontrol->private_value; + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; unsigned short val, mux; unsigned short mask; int ret = 0; @@ -1443,7 +1374,7 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, mutex_lock(&widget->codec->mutex); widget->value = val; - dapm_value_mux_update_power(widget, kcontrol, mask, mux, val, e); + dapm_mux_update_power(widget, kcontrol, mask, mux, val, e); if (widget->event) { if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { ret = widget->event(widget, diff --git a/sound/usb/caiaq/caiaq-device.c b/sound/usb/caiaq/caiaq-device.c index 55a9075..09aed23 100644 --- a/sound/usb/caiaq/caiaq-device.c +++ b/sound/usb/caiaq/caiaq-device.c @@ -42,7 +42,7 @@ #endif MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>"); -MODULE_DESCRIPTION("caiaq USB audio, version 1.3.9"); +MODULE_DESCRIPTION("caiaq USB audio, version 1.3.10"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2}," "{Native Instruments, RigKontrol3}," diff --git a/sound/usb/caiaq/caiaq-device.h b/sound/usb/caiaq/caiaq-device.h index f9fbdbae..ab56e73 100644 --- a/sound/usb/caiaq/caiaq-device.h +++ b/sound/usb/caiaq/caiaq-device.h @@ -75,6 +75,7 @@ struct snd_usb_caiaqdev { wait_queue_head_t ep1_wait_queue; wait_queue_head_t prepare_wait_queue; int spec_received, audio_parm_answer; + int midi_out_active; char vendor_name[CAIAQ_USB_STR_LEN]; char product_name[CAIAQ_USB_STR_LEN]; diff --git a/sound/usb/caiaq/caiaq-midi.c b/sound/usb/caiaq/caiaq-midi.c index 30b57f9..f19fd36 100644 --- a/sound/usb/caiaq/caiaq-midi.c +++ b/sound/usb/caiaq/caiaq-midi.c @@ -59,6 +59,11 @@ static int snd_usb_caiaq_midi_output_open(struct snd_rawmidi_substream *substrea static int snd_usb_caiaq_midi_output_close(struct snd_rawmidi_substream *substream) { + struct snd_usb_caiaqdev *dev = substream->rmidi->private_data; + if (dev->midi_out_active) { + usb_kill_urb(&dev->midi_out_urb); + dev->midi_out_active = 0; + } return 0; } @@ -69,7 +74,8 @@ static void snd_usb_caiaq_midi_send(struct snd_usb_caiaqdev *dev, dev->midi_out_buf[0] = EP1_CMD_MIDI_WRITE; dev->midi_out_buf[1] = 0; /* port */ - len = snd_rawmidi_transmit_peek(substream, dev->midi_out_buf+3, EP1_BUFSIZE-3); + len = snd_rawmidi_transmit(substream, dev->midi_out_buf + 3, + EP1_BUFSIZE - 3); if (len <= 0) return; @@ -79,24 +85,24 @@ static void snd_usb_caiaq_midi_send(struct snd_usb_caiaqdev *dev, ret = usb_submit_urb(&dev->midi_out_urb, GFP_ATOMIC); if (ret < 0) - log("snd_usb_caiaq_midi_send(%p): usb_submit_urb() failed, %d\n", - substream, ret); + log("snd_usb_caiaq_midi_send(%p): usb_submit_urb() failed," + "ret=%d, len=%d\n", + substream, ret, len); + else + dev->midi_out_active = 1; } static void snd_usb_caiaq_midi_output_trigger(struct snd_rawmidi_substream *substream, int up) { struct snd_usb_caiaqdev *dev = substream->rmidi->private_data; - if (dev->midi_out_substream != NULL) - return; - - if (!up) { + if (up) { + dev->midi_out_substream = substream; + if (!dev->midi_out_active) + snd_usb_caiaq_midi_send(dev, substream); + } else { dev->midi_out_substream = NULL; - return; } - - dev->midi_out_substream = substream; - snd_usb_caiaq_midi_send(dev, substream); } @@ -161,16 +167,14 @@ int snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *device) void snd_usb_caiaq_midi_output_done(struct urb* urb) { struct snd_usb_caiaqdev *dev = urb->context; - char *buf = urb->transfer_buffer; + dev->midi_out_active = 0; if (urb->status != 0) return; if (!dev->midi_out_substream) return; - snd_rawmidi_transmit_ack(dev->midi_out_substream, buf[2]); - dev->midi_out_substream = NULL; snd_usb_caiaq_midi_send(dev, dev->midi_out_substream); } diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index eec32e1..8f3cdb3 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -2524,7 +2524,6 @@ static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioform * build the rate table and bitmap flags */ int r, idx; - unsigned int nonzero_rates = 0; fp->rate_table = kmalloc(sizeof(int) * nr_rates, GFP_KERNEL); if (fp->rate_table == NULL) { @@ -2532,24 +2531,27 @@ static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioform return -1; } - fp->nr_rates = nr_rates; - fp->rate_min = fp->rate_max = combine_triple(&fmt[8]); + fp->nr_rates = 0; + fp->rate_min = fp->rate_max = 0; for (r = 0, idx = offset + 1; r < nr_rates; r++, idx += 3) { unsigned int rate = combine_triple(&fmt[idx]); + if (!rate) + continue; /* C-Media CM6501 mislabels its 96 kHz altsetting */ if (rate == 48000 && nr_rates == 1 && - chip->usb_id == USB_ID(0x0d8c, 0x0201) && + (chip->usb_id == USB_ID(0x0d8c, 0x0201) || + chip->usb_id == USB_ID(0x0d8c, 0x0102)) && fp->altsetting == 5 && fp->maxpacksize == 392) rate = 96000; - fp->rate_table[r] = rate; - nonzero_rates |= rate; - if (rate < fp->rate_min) + fp->rate_table[fp->nr_rates] = rate; + if (!fp->rate_min || rate < fp->rate_min) fp->rate_min = rate; - else if (rate > fp->rate_max) + if (!fp->rate_max || rate > fp->rate_max) fp->rate_max = rate; fp->rates |= snd_pcm_rate_to_rate_bit(rate); + fp->nr_rates++; } - if (!nonzero_rates) { + if (!fp->nr_rates) { hwc_debug("All rates were zero. Skipping format!\n"); return -1; } @@ -2966,6 +2968,7 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip, return -EINVAL; } alts = &iface->altsetting[fp->altset_idx]; + fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); usb_set_interface(chip->dev, fp->iface, 0); init_usb_pitch(chip->dev, fp->iface, alts, fp); init_usb_sample_rate(chip->dev, fp->iface, alts, fp, fp->rate_max); diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index 320641a..26bad37 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c @@ -1625,6 +1625,7 @@ static int snd_usbmidi_create_endpoints_midiman(struct snd_usb_midi* umidi, } ep_info.out_ep = get_endpoint(hostif, 2)->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + ep_info.out_interval = 0; ep_info.out_cables = endpoint->out_cables & 0x5555; err = snd_usbmidi_out_endpoint_create(umidi, &ep_info, &umidi->endpoints[0]); if (err < 0) diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h index 9211575..5d8ef09 100644 --- a/sound/usb/usbquirks.h +++ b/sound/usb/usbquirks.h @@ -128,6 +128,14 @@ .bInterfaceClass = USB_CLASS_AUDIO, .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL }, +{ + USB_DEVICE(0x046d, 0x0990), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .vendor_name = "Logitech, Inc.", + .product_name = "QuickCam Pro 9000", + .ifnum = QUIRK_NO_INTERFACE + } +}, /* * Yamaha devices |